it.cnr.icar.eric.client.ui.thin.RegistrationInfoBean.java Source code

Java tutorial

Introduction

Here is the source code for it.cnr.icar.eric.client.ui.thin.RegistrationInfoBean.java

Source

/*
 * ====================================================================
 * This file is part of the ebXML Registry by Icar Cnr v3.2 
 * ("eRICv32" in the following disclaimer).
 *
 * "eRICv32" is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * "eRICv32" is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License Version 3
 * along with "eRICv32".  If not, see <http://www.gnu.org/licenses/>.
 *
 * eRICv32 is a forked, derivative work, based on:
 *    - freebXML Registry, a royalty-free, open source implementation of the ebXML Registry standard,
 *      which was published under the "freebxml License, Version 1.1";
 *   - ebXML OMAR v3.2 Edition, published under the GNU GPL v3 by S. Krushe & P. Arwanitis.
 * 
 * All derivative software changes and additions are made under
 *
 * Copyright (C) 2013 Ing. Antonio Messina <messina@pa.icar.cnr.it>
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the freebxml Software Foundation.  For more
 * information on the freebxml Software Foundation, please see
 * "http://www.freebxml.org/".
 *
 * This product includes software developed by the Apache Software
 * Foundation (http://www.apache.org/).
 *
 * ====================================================================
 */
package it.cnr.icar.eric.client.ui.thin;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.Serializable;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import javax.faces.context.FacesContext;
import javax.faces.application.FacesMessage;
import javax.faces.event.ValueChangeEvent;
import javax.xml.registry.JAXRException;
import javax.xml.registry.BulkResponse;
import javax.xml.registry.JAXRResponse;
import javax.xml.registry.infomodel.User;
import javax.xml.registry.infomodel.EmailAddress;
import javax.xml.registry.infomodel.PostalAddress;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import it.cnr.icar.eric.client.ui.thin.security.SecurityUtil;
import it.cnr.icar.eric.client.xml.registry.BusinessLifeCycleManagerImpl;
import it.cnr.icar.eric.client.xml.registry.util.CertificateUtil;
import it.cnr.icar.eric.client.xml.registry.util.ProviderProperties;
import it.cnr.icar.eric.client.xml.registry.util.UserRegistrationInfo;
import it.cnr.icar.eric.common.security.X509Parser;

import sun.security.x509.X500Name;

/**
 * This bean acts as the backing bean for the Registration Wizard. It requires
 * RegistryObjectCollectionBean to be prepared for user registration by calling
 * doRegister() in that bean.
 *
 * The Registration Wizzard has 4 steps:
 * - 1. Info
 * - 2. User Details
 * - 3. Auth Details and actual registration
 * - 4. Sucess message, download key (if generated), links to browser key import.
 *
 * Current step is accessible through 'currentStep' field, 0 (zero) being a
 * special step meaning wizard is not 'active'.
 *
 * @author  dhilder
 * @author  Diego Ballve / Digital Artefacts Europe
 */
public class RegistrationInfoBean implements Serializable {

    /**
    * 
    */
    private static final long serialVersionUID = -8827586058880525180L;

    private static final Log log = LogFactory.getLog(RegistrationInfoBean.class);

    // properties initialized by doClear - START
    private transient String alias;
    private transient String password;
    private transient String passwordRepeat;
    private transient X500Bean x500Bean;
    private transient X509Certificate x509Cert;
    private transient String generatePrivateKey;
    private transient FileUploadBean fileUploadBean;
    private transient KeyStore keystore;
    private transient int currentStep = 0;
    // properties initialized by doClear - END

    public RegistrationInfoBean() {
        // reset fields
        doClear();
    }

    @SuppressWarnings("unchecked")
    public static RegistrationInfoBean getInstance() {
        RegistrationInfoBean riBean = (RegistrationInfoBean) FacesContext.getCurrentInstance().getExternalContext()
                .getSessionMap().get("registrationInfo");
        if (riBean == null) {
            riBean = new RegistrationInfoBean();
            FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("registrationInfo", riBean);
        }
        return riBean;
    }

    public String getRequiredFieldFlag() {
        String requiredField = "";
        if (currentStep == 2) {
            requiredField = "*";
        }
        return requiredField;
    }

    public boolean isFieldRequired() {
        boolean fieldRequired = false;
        if (currentStep == 2) {
            fieldRequired = true;
        }
        return fieldRequired;
    }

    /**
     * Getter for property alias.
     * @return Value of property alias.
     */
    public String getAlias() {
        return this.alias;
    }

    /**
     * Setter for property alias.
     * @param alias New value of property alias.
     */
    public void setAlias(String alias) {
        this.alias = alias;
    }

    /**
     * Getter for property password.
     * @return Value of property password.
     */
    public String getPassword() {
        return this.password;
    }

    /**
     * Setter for property password.
     * @param password New value of property password.
     */
    public void setPassword(String password) {
        this.password = password;
    }

    /**
     * Getter for property passwordRepeat.
     * @return Value of property passwordRepeat.
     */
    public String getPasswordRepeat() {
        return this.passwordRepeat;
    }

    /**
     * Setter for property passwordRepeat.
     * @param passwordRepeat New value of property passwordRepeat.
     */
    public void setPasswordRepeat(String passwordRepeat) {
        this.passwordRepeat = passwordRepeat;
    }

    /**
     * Getter for property generatePrivateKey.
     * @return Value of property generatePrivateKey.
     */
    public String getGeneratePrivateKey() {
        if (this.generatePrivateKey == null) {
            this.generatePrivateKey = "true";
        }
        return this.generatePrivateKey;
    }

    public boolean generatePrivateKey() {
        return "true".equals(getGeneratePrivateKey());
    }

    /**
     * Setter for property generatePrivateKey.
     * @param generatePrivateKey New value of property generatePrivateKey.
     */
    public void setGeneratePrivateKey(String generatePrivateKey) {
        this.generatePrivateKey = generatePrivateKey;
    }

    /**
     * Getter for property x500Bean.
     * @return Value of property x500Bean.
     */
    public X500Bean getX500Bean() {
        if (x500Bean == null) {
            x500Bean = new X500Bean();
        }
        return this.x500Bean;
    }

    /**
     * Getter for property keystore.
     * @return Value of property keystore.
     */
    public KeyStore getKeystore() {
        return this.keystore;
    }

    /**
     * Getter for property fileUploadBean.
     * @return Value of property fileUploadBean.
     */
    public FileUploadBean getFileUploadBean() {
        //TODO: Clean this workaround to initialize bean
        //why faces managed property did not set this?!
        if (this.fileUploadBean == null) {
            this.fileUploadBean = FileUploadBean.getInstance();
        }

        return this.fileUploadBean;
    }

    /**
     * Setter for property fileUploadBean.
     * @param fileUploadBean New value of property fileUploadBean.
     */
    public void setFileUploadBean(it.cnr.icar.eric.client.ui.thin.FileUploadBean fileUploadBean) {

        this.fileUploadBean = fileUploadBean;
    }

    /**
     * Event method for setting flag for generatePrivateKey.
     *
     * @param ValueChangeEvent
     */
    public void changeGeneratePrivateKey(ValueChangeEvent event) {
        if (null != event.getNewValue()) {
            String value = (String) event.getNewValue();
            if (value.equalsIgnoreCase("true")) {
                setGeneratePrivateKey("true");
            } else {
                setGeneratePrivateKey("false");
            }
        }
    }

    /**
     * Getter for property currentStep.
     * @return Value of property currentStep.
     */
    public int getCurrentStep() {
        return this.currentStep;
    }

    /**
     *
     */
    public void doNext() {
        if (currentStep < 4) {
            currentStep++;
        } else if (currentStep == 4) {
            //reset wizard
            currentStep = 0;
        }
    }

    /**
     *
     */
    public void doPrev() {
        // no going back from step 4
        if (currentStep > 1 && currentStep < 4) {
            currentStep--;
        }
    }

    /**
     * Clear all the properties in this bean.
     */
    public String doClear() {
        log.trace("doClear started");

        doClearUser();
        doClearAuth();

        currentStep = 0;
        return "clear";
    }

    /**
     * Clear all user properties in this bean.
     */
    public String doClearUser() {
        log.trace("doClearUser started");

        RegistryObjectCollectionBean.getInstance().doRegister();

        return "clear";
    }

    /**
     * Clear all auth properties in this bean.
     */
    public String doClearAuth() {
        log.trace("doClearAuth started");

        getFileUploadBean().doClear();
        alias = null;
        password = null;
        passwordRepeat = null;
        keystore = null;
        getX500Bean().clear();
        x509Cert = null;
        generatePrivateKey = "true";
        return "clear";
    }

    public String doCheckUserDetails() {
        log.trace("doCheckUserDetails started");
        boolean valid = true;
        FacesContext context = FacesContext.getCurrentInstance();
        UserPreferencesBean userPreferenceBean = (UserPreferencesBean) context.getExternalContext().getSessionMap()
                .get("userPreferencesBean");

        User user = (User) RegistryObjectCollectionBean.getInstance().getCurrentRegistryObjectBean()
                .getRegistryObject();

        try {
            if (user.getPersonName().getFirstName() == null
                    || "".equals(user.getPersonName().getFirstName().trim())) {
                String msg = WebUIResourceBundle.getInstance().getString("requiredFieldMissing");
                context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, null));
                valid = false;
            } else if (user.getPersonName().getLastName() == null
                    || "".equals(user.getPersonName().getLastName().trim())) {
                String msg = WebUIResourceBundle.getInstance().getString("requiredFieldMissing");
                context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, null));
                valid = false;
            } else if (user.getPostalAddresses() == null || user.getPostalAddresses().size() == 0) {
                String msg = WebUIResourceBundle.getInstance().getString("requiredFieldMissing");
                context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, null));
                valid = false;
            } else {
                PostalAddress address = (PostalAddress) user.getPostalAddresses().iterator().next();
                if (address.getCity() == null || "".equals(address.getCity().trim())
                        || (ProviderProperties.getInstance().getProperty("noStateOrProvince")
                                .indexOf(userPreferenceBean.getContentLocale().getLanguage()) == -1
                                && (address.getStateOrProvince() == null
                                        || "".equals(address.getStateOrProvince().trim())))
                        || address.getCountry() == null || "".equals(address.getCountry().trim())) {
                    String msg = WebUIResourceBundle.getInstance().getString("requiredFieldMissing");
                    context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, null));
                    valid = false;
                } else if (address.getCountry().trim().length() != 2) {
                    String msg = WebUIResourceBundle.getInstance().getString("countryDefinedByTwoChars");
                    context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, null));
                    valid = false;
                }
            }
        } catch (JAXRException e) {
            OutputExceptions.error(log, WebUIResourceBundle.getInstance().getString("message.ExceptionOccured"), e);
            valid = false;
        }

        if (valid) {
            try {
                getX500Bean().setName(user.getPersonName().getFullName());
                if (user.getPostalAddresses() != null && user.getPostalAddresses().size() > 0) {
                    PostalAddress address = (PostalAddress) user.getPostalAddresses().iterator().next();
                    getX500Bean().setCity(address.getCity());
                    getX500Bean().setStateOrProvince(address.getStateOrProvince());
                    getX500Bean().setCountry(address.getCountry());
                }
            } catch (JAXRException e) {
                OutputExceptions.error(log, WebUIResourceBundle.getInstance().getString("message.ExceptionOccured"),
                        e);
                valid = false;
            }
        }

        if (valid) {
            doNext();
            return "ok";
        } else {
            return "error";
        }
    }

    public boolean doCheckAuthDetails() {
        log.trace("doCheckAuthDetails started");
        boolean valid = true;
        FacesContext context = FacesContext.getCurrentInstance();
        UserPreferencesBean userPreferenceBean = (UserPreferencesBean) context.getExternalContext().getSessionMap()
                .get("userPreferencesBean");

        if (generatePrivateKey()) {
            /*
            ** ??? Following code enforces neither password length
            ** ??? restrictions nor alias uniqueness requirements, caught only
            ** ??? when certificate generation attempted
            */
            // verify fields, generate keystore
            if (alias == null || "".equals(alias) || password == null || "".equals(password)
                    || passwordRepeat == null || "".equals(passwordRepeat) || getX500Bean().getName() == null
                    || "".equals(getX500Bean().getName()) || getX500Bean().getUnit() == null
                    || "".equals(getX500Bean().getUnit()) || getX500Bean().getOrganization() == null
                    || "".equals(getX500Bean().getOrganization()) || getX500Bean().getCity() == null
                    || "".equals(getX500Bean().getCity())
                    || (ProviderProperties.getInstance().getProperty("noStateOrProvince")
                            .indexOf(userPreferenceBean.getContentLocale().getLanguage()) == -1
                            && (getX500Bean().getStateOrProvince() == null
                                    || "".equals(getX500Bean().getStateOrProvince())))
                    || getX500Bean().getCountry() == null || "".equals(getX500Bean().getCountry())) {
                String msg = WebUIResourceBundle.getInstance().getString("requiredFieldMissing");
                context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, null));
                valid = false;
            } else if (password != null && passwordRepeat != null && !passwordRepeat.equals(password)) {
                String msg = WebUIResourceBundle.getInstance().getString("passwordsDoNotMatch");
                context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, null));
                valid = false;
            } else if (password.length() < 6) {
                String msg = WebUIResourceBundle.getInstance().getString("passwordLengthInvalid");
                context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, null));
                valid = false;
            }

            if (valid) {
                // Creates a new private key with a self signed certificate, in PKCS12 KeyStore
                @SuppressWarnings("unused")
                X500Name x500Name = getX500Bean().toX500Name();
                keystore = createPKCS12KeyStore(getX500Bean(), alias, password.toCharArray());
                if (keystore == null) {
                    // createPKCS12KeyStore() has already swallowed (and
                    // displayed) any useful error information.
                    valid = false;
                    x509Cert = null;
                } else {
                    try {
                        x509Cert = (X509Certificate) keystore.getCertificate(alias);
                    } catch (KeyStoreException e) {
                        // should never happen
                        OutputExceptions.error(log, WebUIResourceBundle.getInstance()
                                .getString("message.ExceptionOnKeystoregetCertificate"), e);
                        valid = false;
                    }
                }
            } else {
                keystore = null;
                x509Cert = null;
            }

        } else {
            // accept uploaded x509 cert
            if (valid && getFileUploadBean().getFile() == null) {
                String msg = WebUIResourceBundle.getInstance().getString("requiredFieldMissing");
                context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, null));
                valid = false;
            }

            if (valid) {
                try {
                    FileInputStream inStream = new FileInputStream(getFileUploadBean().getFile());
                    x509Cert = X509Parser.parseX509Certificate(inStream);
                } catch (Exception e) {
                    String msg = WebUIResourceBundle.getInstance().getString("x509DERParseFail");
                    context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, null));
                    log.error(msg);
                    msg = WebUIResourceBundle.getInstance().getString("verifyCert");
                    OutputExceptions.error(log, msg, e);
                    valid = false;
                }
            }

            keystore = null;
        }

        return valid;
    }

    /**
     * Cancel the wizard.
     */
    public String doCancel() {
        log.trace("doCancel started");
        FacesContext context = FacesContext.getCurrentInstance();

        doClear();

        // add success message
        String msg = WebUIResourceBundle.getInstance().getString("registrationCancelled");
        context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, msg, null));

        // reset current step
        currentStep = 0;
        return "clear";
    }

    /*
    ** ??? Unsucessful registration which encounters an exception in
    ** ??? saveObjects() corrupts the JSP context.  Numerous errors occur.
    ** ??? To reproduce, make the database connection read only and hit
    ** ??? 'Previous' button after errors that result at step 3.  clear
    ** ??? credentials attempt in finally clause may not be working completely
    */
    public String doRegister() {
        log.trace("doRegister started");
        String result = "unknown";
        FacesContext context = FacesContext.getCurrentInstance();

        if (!doCheckAuthDetails()) {
            return result;
        }

        try {
            User user = (User) RegistryObjectCollectionBean.getInstance().getCurrentRegistryObjectBean()
                    .getRegistryObject();
            Collection<?> emails = user.getEmailAddresses();
            ArrayList<EmailAddress> newList = new ArrayList<EmailAddress>();

            Iterator<?> iters = emails.iterator();
            while (iters.hasNext()) {
                EmailAddress email = (EmailAddress) iters.next();
                if (null != email.getAddress() && email.getAddress().length() > 0) {
                    newList.add(email);
                }
            }
            user.setEmailAddresses(newList);

            List<User> users = new ArrayList<User>();
            users.add(user);
            BusinessLifeCycleManagerImpl blcm = RegistryBrowser.getBLCM();
            handleAuth();
            log.trace("calling saveObjects()");
            BulkResponse resp = blcm.saveObjects(users);
            log.trace("saveObjects() returned");
            if ((resp != null) && (resp.getStatus() != JAXRResponse.STATUS_SUCCESS)) {
                Collection<?> exceptions = resp.getExceptions();
                if (exceptions != null && !exceptions.isEmpty()) {
                    String msg = WebUIResourceBundle.getInstance().getString("errorRegistrationNeeded");
                    context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, null));
                    log.error(msg);

                    Iterator<?> iter = exceptions.iterator();
                    while (iter.hasNext()) {
                        Exception e = (Exception) iter.next();
                        OutputExceptions.error(log, e);
                    }
                } else {
                    String msg = WebUIResourceBundle.getInstance().getString("registrationFailed");
                    context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, null));
                    log.error(WebUIResourceBundle.getInstance().getString("message.RegistrationFailed"));
                }
                result = "error";
            } else {
                // ??? Is (null == resp) really success?
                result = "registered";
                doNext();
            }
        } catch (Throwable t) {
            OutputExceptions.error(log, WebUIResourceBundle.getInstance().getString("message.RegistrationFailed"),
                    WebUIResourceBundle.getInstance().getString("registrationFailed"), t);
            result = "error";
        } finally {
            try {
                RegistryBrowser.getInstance().clearCredentials();
            } catch (Throwable t) {
                // User doesn't need to hear about a cleanup problem
                OutputExceptions.logWarning(log,
                        WebUIResourceBundle.getInstance().getString("message.couldNotClearCredentials"), t);
            }
        }

        return result;
    }

    /**
     * Handle authentication, according to provided authentication details.
     */
    private void handleAuth() throws Exception {
        // if user provided a certificate file, use it, otherwise use old code
        if (x509Cert == null) {
            // ??? By this point in process, when will this case be true?
            log.trace("Creating user credentials from RegistryBrowser Principal");
            // Should be done somewhere else already?
        } else {
            log.trace("Creating user credentials uploaded file");
            SecurityUtil.getInstance().handleCredentials(x509Cert, RegistryBrowser.getConnection());
        }
    }

    private KeyStore createPKCS12KeyStore(X500Bean x500Bean, String alias, char[] keyPassword) {
        KeyStore ks = null;
        try {
            User user = (User) RegistryObjectCollectionBean.getInstance().getCurrentRegistryObjectBean()
                    .getRegistryObject();
            char[] storePassword = ProviderProperties.getInstance().getProperty("jaxr-ebxml.security.storepass")
                    .toCharArray();
            UserRegistrationInfo userRegInfo = new UserRegistrationInfo(user);

            userRegInfo.setCAIssuedCert(true); // ??? Registry-generated
            userRegInfo.setAlias(alias);
            userRegInfo.setKeyPassword(keyPassword);
            userRegInfo.setStorePassword(storePassword);
            userRegInfo.setP12File(System.getProperty("java.io.tmpdir") + "/." + alias + ".p12");
            userRegInfo.setOrganization(x500Bean.getOrganization());
            userRegInfo.setOrganizationUnit(x500Bean.getUnit());
            CertificateUtil.generateRegistryIssuedCertificate(userRegInfo);

            //Remove certificate from client keystore (which is on server in this case)
            //since private key should not be held anywhere other than client machine.
            try {
                CertificateUtil.removeCertificate(alias, storePassword);
            } catch (Exception e) {
                // User doesn't need to hear about a cleanup problem
                OutputExceptions.logWarning(log, e);
            }

            File p12File = null;
            try {
                p12File = new File(userRegInfo.getP12File());
                if (p12File.exists()) {
                    InputStream is = new FileInputStream(p12File);
                    ks = KeyStore.getInstance("PKCS12");
                    ks.load(is, keyPassword);
                    is.close();
                } else {
                    throw new JAXRException(
                            WebUIResourceBundle.getInstance().getString("message.FailedToCreatePKCS12Keystore"));
                }
            } finally {
                try {
                    if (p12File != null) {
                        p12File.delete();
                    }
                } catch (Exception e) {
                    // User doesn't need to hear about a cleanup problem
                    OutputExceptions.logWarning(log, e);
                }
            }
            return ks;
        } catch (Exception e) {
            OutputExceptions.error(log,
                    WebUIResourceBundle.getInstance().getString("message.FailedToCreatePKCS12Keystore"), e);
            return null;
        }
    }
}