org.ejbca.ra.RaCasPageBean.java Source code

Java tutorial

Introduction

Here is the source code for org.ejbca.ra.RaCasPageBean.java

Source

/*************************************************************************
 *                                                                       *
 *  EJBCA Community: The OpenSource Certificate Authority                *
 *                                                                       *
 *  This software is free software; you can redistribute it and/or       *
 *  modify it under the terms of the GNU Lesser General Public           *
 *  License as published by the Free Software Foundation; either         *
 *  version 2.1 of the License, or any later version.                    *
 *                                                                       *
 *  See terms of license at gnu.org.                                     *
 *                                                                       *
 *************************************************************************/
package org.ejbca.ra;

import java.io.Serializable;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;

import org.bouncycastle.util.encoders.Base64;
import org.cesecore.certificates.ca.CAInfo;
import org.cesecore.certificates.crl.CRLInfo;
import org.cesecore.certificates.crl.CrlStoreSessionLocal;
import org.cesecore.util.CertTools;
import org.ejbca.config.WebConfiguration;
import org.ejbca.core.model.era.RaMasterApiProxyBeanLocal;

/**
 * Backing bean for Certificate and CRLs download page. 
 * 
 * @version $Id$
 */
@ManagedBean
@ViewScoped
public class RaCasPageBean implements Serializable {

    /** Representation of a CA in a chain with links to CRL download locations. */
    public class CaAndCrl {
        private final String name;
        private final String subjectDn;
        private final int caId;
        private String crlLink;
        private String deltaCrlLink;
        private final int position;
        private final List<String> chainNames;
        private boolean x509 = false;

        CaAndCrl(final String name, final String subjectDn, final int caId, final int position,
                final List<String> chainNames) {
            this.name = name;
            this.subjectDn = subjectDn;
            this.caId = caId;
            this.position = position;
            this.chainNames = chainNames;
        }

        public String getName() {
            return name;
        }

        public String getSubjectDn() {
            return subjectDn;
        }

        public int getCaId() {
            return caId;
        }

        public String getCrlLink() {
            return crlLink;
        }

        public String getDeltaCrlLink() {
            return deltaCrlLink;
        }

        public int getPosition() {
            return position;
        }

        public boolean isX509() {
            return x509;
        }

        @Override
        public int hashCode() {
            return subjectDn.hashCode();
        }

        @Override
        public boolean equals(final Object obj) {
            return obj instanceof CaAndCrl && subjectDn.equals(((CaAndCrl) obj).subjectDn);
        }
    }

    private static final long serialVersionUID = 1L;
    //private static final Logger log = Logger.getLogger(RaCasPageBean.class);
    private static final String RFC4387_DEFAULT_EJBCA_URL = WebConfiguration.getCrlStoreContextRoot()
            + "/search.cgi";
    private static final int NO_CAID_AVAILABLE = 0;

    @EJB
    private CrlStoreSessionLocal crlSession;
    @EJB
    private RaMasterApiProxyBeanLocal raMasterApiProxyBean;

    @ManagedProperty(value = "#{raAuthenticationBean}")
    private RaAuthenticationBean raAuthenticationBean;

    public void setRaAuthenticationBean(final RaAuthenticationBean raAuthenticationBean) {
        this.raAuthenticationBean = raAuthenticationBean;
    }

    @ManagedProperty(value = "#{raLocaleBean}")
    private RaLocaleBean raLocaleBean;

    public void setRaLocaleBean(final RaLocaleBean raLocaleBean) {
        this.raLocaleBean = raLocaleBean;
    }

    private List<CaAndCrl> casAndCrlItems = null;
    private boolean atLeastOneCrlLinkPresent = false;

    /** @return true if at least one of the CAs available via #getCasAndCrlItems() has CRLs present on this system. */
    public boolean isAtLeastOneCrlLinkPresent() {
        getCasAndCrlItems();
        return atLeastOneCrlLinkPresent && WebConfiguration.isCrlStoreEnabled();
    }

    /** @return a list of all known authorized CAs with links to CRLs (if present) */
    public List<CaAndCrl> getCasAndCrlItems() {
        if (casAndCrlItems == null) {
            final List<CAInfo> caInfos = new ArrayList<>(
                    raMasterApiProxyBean.getAuthorizedCas(raAuthenticationBean.getAuthenticationToken()));
            // First build a mapping of all subjects and their short names
            final Map<String, String> caSubjectToNameMap = new HashMap<>();
            for (final CAInfo caInfo : caInfos) {
                caSubjectToNameMap.put(caInfo.getSubjectDN(), caInfo.getName());
            }
            // Convert all CA's chains into CA objects (use a Set to avoid duplicates)
            final Set<CaAndCrl> cas = new HashSet<>();
            for (final CAInfo caInfo : caInfos) {
                final List<Certificate> chain = new ArrayList<>(caInfo.getCertificateChain());
                Collections.reverse(chain);
                final List<String> chainNames = new ArrayList<>();
                final int caId = caInfo.getCAId();
                for (final Certificate caCertificate : chain) {
                    final String subjectDn = CertTools.getSubjectDN(caCertificate);
                    String name = caSubjectToNameMap.get(subjectDn);
                    if (name == null) {
                        name = subjectDn;
                    }
                    chainNames.add(name);
                    final CaAndCrl caAndCrl = new CaAndCrl(name, subjectDn,
                            chainNames.size() == chain.size() ? caId : NO_CAID_AVAILABLE, chainNames.size() - 1,
                            new ArrayList<>(chainNames));
                    // Construct links to RFC4387 CRL Download Servlet
                    if (caCertificate instanceof X509Certificate) {
                        caAndCrl.x509 = true;
                        final CRLInfo crlInfoFull = crlSession.getLastCRLInfo(subjectDn, false);
                        if (crlInfoFull != null) {
                            atLeastOneCrlLinkPresent = true;
                            caAndCrl.crlLink = RFC4387_DEFAULT_EJBCA_URL + "?iHash="
                                    + getSubjectPrincipalHashAsUnpaddedBase64((X509Certificate) caCertificate);
                            final CRLInfo crlInfoDelta = crlSession.getLastCRLInfo(subjectDn, true);
                            if (crlInfoDelta != null) {
                                caAndCrl.deltaCrlLink = RFC4387_DEFAULT_EJBCA_URL + "?iHash="
                                        + getSubjectPrincipalHashAsUnpaddedBase64((X509Certificate) caCertificate)
                                        + "&delta=";
                            }
                        }
                    }
                    // Add missing items and replace items when we know the CAId
                    if (caAndCrl.getCaId() != NO_CAID_AVAILABLE) {
                        cas.remove(caAndCrl);
                    }
                    if (!cas.contains(caAndCrl)) {
                        cas.add(caAndCrl);
                    }
                }
            }
            casAndCrlItems = new ArrayList<>(cas);
            // Sort by higher level CAs
            Collections.sort(casAndCrlItems, new Comparator<CaAndCrl>() {
                @Override
                public int compare(final CaAndCrl caAndCrl1, final CaAndCrl caAndCrl) {
                    final int size1 = caAndCrl1.chainNames.size();
                    final int size2 = caAndCrl.chainNames.size();
                    // Avoid checking if chain length is the same
                    for (int i = 0; i < Math.min(size1, size2); i++) {
                        final String name1 = caAndCrl1.chainNames.get(i);
                        final String name2 = caAndCrl.chainNames.get(i);
                        final int compareTo = name1.compareTo(name2);
                        if (compareTo != 0) {
                            return compareTo;
                        }
                    }
                    return size1 - size2;
                }
            });
        }
        return casAndCrlItems;
    }

    /** @return the issuer hash in base64 encoding without padding which is the way RFC4387 search function expects the iHash parameter. */
    private String getSubjectPrincipalHashAsUnpaddedBase64(final X509Certificate x509Certificate) {
        final byte[] hashSubjectX500Principal = CertTools
                .generateSHA1Fingerprint(x509Certificate.getSubjectX500Principal().getEncoded());
        return new String(Base64.encode(hashSubjectX500Principal)).substring(0, 27).replaceAll("\\+", "%2B");
    }
}