org.ejbca.ra.RaAuthenticationBean.java Source code

Java tutorial

Introduction

Here is the source code for org.ejbca.ra.RaAuthenticationBean.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.X509Certificate;
import java.util.Arrays;
import java.util.HashSet;

import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSessionEvent;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.cesecore.authentication.tokens.AuthenticationSubject;
import org.cesecore.authentication.tokens.AuthenticationToken;
import org.cesecore.authentication.tokens.PublicAccessAuthenticationToken;
import org.cesecore.authentication.tokens.X509CertificateAuthenticationToken;
import org.cesecore.util.CertTools;
import org.ejbca.core.ejb.authentication.web.WebAuthenticationProviderSessionLocal;

/**
 * JSF Managed Bean for handling authentication of clients.
 * 
 * @version $Id$
 */
@ManagedBean
@SessionScoped
public class RaAuthenticationBean implements Serializable {

    private static final long serialVersionUID = 1L;
    private static final Logger log = Logger.getLogger(RaAuthenticationBean.class);

    @EJB
    private WebAuthenticationProviderSessionLocal webAuthenticationProviderSession;

    private AuthenticationToken authenticationToken = null;
    private String authenticationTokenTlsSessionId = null;
    private String x509AuthenticationTokenFingerprint = null;

    /** @return the X509CertificateAuthenticationToken if the client has provided a certificate or a PublicAccessAuthenticationToken otherwise. */
    public AuthenticationToken getAuthenticationToken() {
        final String currentTlsSessionId = getTlsSessionId();
        if (authenticationToken == null
                || !StringUtils.equals(authenticationTokenTlsSessionId, currentTlsSessionId)) {
            // Set the current TLS session 
            authenticationTokenTlsSessionId = currentTlsSessionId;
            final X509Certificate x509Certificate = getClientX509Certificate();
            if (x509Certificate == null && x509AuthenticationTokenFingerprint != null) {
                log.warn("Suspected session hijacking attempt from " + getHttpServletRequest().getRemoteAddr()
                        + ". RA client presented no TLS certificate in HTTP session previously authenticated with client certificate.");
                authenticationToken = null;
                x509AuthenticationTokenFingerprint = null;
            }
            if (x509Certificate != null) {
                final String fingerprint = CertTools.getFingerprintAsString(x509Certificate);
                if (x509AuthenticationTokenFingerprint != null) {
                    final X509Certificate authenticatedCert = ((X509CertificateAuthenticationToken) authenticationToken)
                            .getCertificate();
                    if (!StringUtils.equals(CertTools.getFingerprintAsString(authenticatedCert),
                            x509AuthenticationTokenFingerprint)) {
                        log.warn("Suspected session hijacking attempt from "
                                + getHttpServletRequest().getRemoteAddr()
                                + ". RA client presented a different TLS certificate in the same HTTP session."
                                + " new certificate had subject '" + CertTools.getSubjectDN(x509Certificate)
                                + "'.");
                        authenticationToken = null;
                        x509AuthenticationTokenFingerprint = null;
                    }
                }
                if (log.isDebugEnabled()) {
                    log.debug("RA client presented client TLS certificate with subject DN '"
                            + CertTools.getSubjectDN(x509Certificate) + "'.");
                }
                // No need to perform re-authentication if the client certificate was the same
                if (authenticationToken == null) {
                    final AuthenticationSubject subject = new AuthenticationSubject(null,
                            new HashSet<X509Certificate>(Arrays.asList(new X509Certificate[] { x509Certificate })));
                    authenticationToken = webAuthenticationProviderSession.authenticate(subject);
                }
                x509AuthenticationTokenFingerprint = authenticationToken == null ? null : fingerprint;
            }
            if (authenticationToken == null) {
                authenticationToken = new PublicAccessAuthenticationToken(
                        "Public access from " + getHttpServletRequest().getRemoteAddr());
            }
        }
        return authenticationToken;
    }

    private X509Certificate getClientX509Certificate() {
        final X509Certificate[] certificates = (X509Certificate[]) getHttpServletRequest()
                .getAttribute("javax.servlet.request.X509Certificate");
        return certificates == null || certificates.length == 0 ? null : certificates[0];
    }

    private String getTlsSessionId() {
        final String sslSessionIdServletsStandard = (String) getHttpServletRequest()
                .getAttribute("javax.servlet.request.ssl_session_id");
        final String sslSessionIdJBoss7 = (String) getHttpServletRequest()
                .getAttribute("javax.servlet.request.ssl_session");
        return sslSessionIdJBoss7 == null ? sslSessionIdServletsStandard : sslSessionIdJBoss7;
    }

    private HttpServletRequest getHttpServletRequest() {
        return (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
    }

    /** Invoked from RaHttpSessionListener when a session expires/is destroyed */
    public void onSessionDestroyed(final HttpSessionEvent httpSessionEvent) {
        log.info("HTTP session from client with authentication " + authenticationToken + " ended.");
        if (log.isDebugEnabled()) {
            log.debug("HTTP session from client with authentication " + authenticationToken + " ended. jsessionid="
                    + httpSessionEvent.getSession().getId());
        }
        // Insert additional clean up (if any) needed on logout.
        // (Note that FacesContext is not available any more, but injected SSBs or bean fetched via httpSessionEvent.getSession().getAttribute("beanName") still can be used.)
    }
}