alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Glassfish example source code file (J2EEKeyManager.java)

This example Glassfish source code file (J2EEKeyManager.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Glassfish tags/keywords

getting, log, logincontext, loginexception, net, network, object, principal, principal, privilegedaction, privilegedaction, security, ssl, string, string, subject, util, x509certificatecredential, x509keymanager, x509keymanager

The Glassfish J2EEKeyManager.java source code

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package com.sun.enterprise.security.ssl;

import java.net.Socket;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.X509KeyManager;
import javax.security.auth.Subject;

//import com.sun.enterprise.Switch;
import com.sun.enterprise.security.common.ClientSecurityContext;
import com.sun.enterprise.security.auth.login.common.X509CertificateCredential;
//copied code from LoginContextDriver to break dependency
//import com.sun.enterprise.security.auth.login.common.LoginContextDriver;
import com.sun.enterprise.security.auth.login.common.LoginException;
import com.sun.enterprise.security.auth.login.common.PasswordCredential;
import com.sun.enterprise.security.common.AppservAccessController;
import com.sun.enterprise.security.common.SecurityConstants;
import com.sun.enterprise.security.common.Util;

import java.util.logging.*;
import com.sun.logging.*;
import java.security.PrivilegedAction;
import java.util.Set;
import javax.net.ssl.X509ExtendedKeyManager;
import javax.security.auth.login.LoginContext;
import com.sun.enterprise.security.ssl.manager.UnifiedX509KeyManager;

/**
 * This a J2EE specific Key Manager class that is used to select 
 * user certificates for SSL client authentication. It delegates most
 * of the functionality to the provider specific KeyManager class.
 * @author Vivek Nagar
 * @author Harpreet Singh
 */
public final class J2EEKeyManager /*implements X509KeyManager */ extends X509ExtendedKeyManager {

    private static final Logger _logger = LogDomains.getLogger(J2EEKeyManager.class, LogDomains.SECURITY_LOGGER);

    private X509KeyManager mgr = null; // delegate
    
    private String alias = null;

    private Map<String, X509KeyManager> tokenName2MgrMap = null;
    private boolean supportTokenAlias = false;

    public J2EEKeyManager(X509KeyManager mgr, String alias) {
        this.mgr = mgr;
	this.alias = alias;

        if (mgr instanceof UnifiedX509KeyManager) {
            UnifiedX509KeyManager umgr = (UnifiedX509KeyManager)mgr;
            X509KeyManager[] mgrs = umgr.getX509KeyManagers();
            String[] tokenNames = umgr.getTokenNames();

            tokenName2MgrMap = new HashMap<String, X509KeyManager>();
            for (int i = 0; i < mgrs.length; i++) {
                if (tokenNames[i] != null) {
                    tokenName2MgrMap.put(tokenNames[i], mgrs[i]);
                }
            }
            supportTokenAlias = (tokenName2MgrMap.size() > 0);
        }
    }

    public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) {
        return mgr.chooseClientAlias(keyType, issuers, null);
    }

    public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) {
        return alias;
    }

    /**
     * Choose the client alias that will be used to select the client
     * certificate for SSL client auth.
     * @param the keytype
     * @param the certificate issuers.
     * @param the socket used for this connection. This parameter can be null,
     *        in which case the method will return the most generic alias to use.
     * @return the alias.
     */
    public String chooseClientAlias(String[] keyType, Principal[] issuers,
    Socket socket) {
        
        String clientAlias = null;
        
        if(this.alias == null){
            //InvocationManager im = Switch.getSwitch().getInvocationManager();
            //if (im == null) {
            if(Util.getInstance().isNotServerORACC()) {
                // standalone client
                clientAlias = mgr.chooseClientAlias(keyType, issuers, socket);
            } else {
                //ComponentInvocation ci = im.getCurrentInvocation();
                //if (ci == null) {       // 4646060
                //    throw new InvocationException();
                //}
                //Object containerContext = ci.getContainerContext();
                //if(containerContext != null &&
                //(containerContext instanceof AppContainer)) {
                   if (Util.getInstance().isACC()) {
                    ClientSecurityContext ctx = ClientSecurityContext.getCurrent();
                    Subject s = ctx.getSubject();
                    if (s == null) {
                        // pass the handler and do the login
                        //TODO V3: LoginContextDriver.doClientLogin(AppContainer.CERTIFICATE,
                        //AppContainer.getCallbackHandler());
                        doClientLogin(SecurityConstants.CERTIFICATE,
                                Util.getInstance().getCallbackHandler());
                        s = ctx.getSubject();
                    }
                    Iterator itr = s.getPrivateCredentials().iterator();
                    while(itr.hasNext()) {
                        Object o = itr.next();
                        if(o instanceof X509CertificateCredential) {
                            X509CertificateCredential crt =
                            (X509CertificateCredential) o;
                            clientAlias = crt.getAlias();
                            break;
                        }
                    }
                }
            }
        }else{
            clientAlias = this.alias;
        }
        if(_logger.isLoggable(Level.FINE)){
            _logger.log(Level.FINE, "Choose client Alias :{0}", clientAlias);
        }
        return clientAlias;
    }

    /**
     * Choose the server alias that will be used to select the server
     * certificate for SSL server auth.
     * @param the keytype
     * @param the certificate issuers.
     * @param the socket used for this connection. This parameter can be null,
     *        in which case the method will return the most generic alias to use.
     * @return the alias
     */
    public String chooseServerAlias(String keyType, Principal[] issuers,
            Socket socket) {

        String serverAlias = null;
        if(this.alias != null){
            serverAlias = this.alias;
        }else{
            serverAlias =  mgr.chooseServerAlias(keyType, issuers, socket);
	}
        if(_logger.isLoggable(Level.FINE)){
            _logger.log(Level.FINE, "Choosing server alias :{0}", serverAlias);
        }         
        return serverAlias;
    }

    /**
     * Return the certificate chain for the specified alias.
     * @param the alias.
     * @return the chain of X509 Certificates.
     */
    public X509Certificate[] getCertificateChain(String alias) {
        if(_logger.isLoggable(Level.FINE)){
            _logger.log(Level.FINE,"Getting certificate chain");
        }
        X509KeyManager keyMgr = getManagerFromToken(alias);
        if (keyMgr != null) {
            String aliasName = alias.substring(alias.indexOf(':') + 1);
            return keyMgr.getCertificateChain(aliasName);
        } else {
            return mgr.getCertificateChain(alias);
        }
    }

    /**
     * Return all the available client aliases for the specified key type.
     * @param the keytype
     * @param the certificate issuers.
     * @return the array of aliases.
     */
    public String[] getClientAliases(String keyType, Principal[] issuers) {
        if(_logger.isLoggable(Level.FINE)){
	    _logger.log(Level.FINE,"Getting client aliases");
        }
	return mgr.getClientAliases(keyType, issuers);
    }

    /**
     * Return all the available server aliases for the specified key type.
     * @param the keytype
     * @param the certificate issuers.
     * @return the array of aliases.
     */
    public String[] getServerAliases(String keyType, Principal[] issuers) {
        if(_logger.isLoggable(Level.FINE)){
            _logger.log(Level.FINE,"Getting server aliases");
        }
        return mgr.getServerAliases(keyType, issuers);
    }

    /**
     * Return the private key for the specified alias.
     * @param the alias.
     * @return the private key.
     */
    public PrivateKey getPrivateKey(String alias) {
        if(_logger.isLoggable(Level.FINE)){
	    _logger.log(Level.FINE, "Getting private key for alias:{0}", alias);
	}
        X509KeyManager keyMgr = getManagerFromToken(alias);
        if (keyMgr != null) {
            String aliasName = alias.substring(alias.indexOf(':') + 1);
            return keyMgr.getPrivateKey(aliasName);
        } else {
            return mgr.getPrivateKey(alias);
        }
    }    

    
    /**
     * Find the corresponding X509KeyManager associated to token in alias.
     * It returns null if there is n
     * @param tokenAlias of the form <tokenName>:<aliasName>
     */
    private X509KeyManager getManagerFromToken(String tokenAlias) {
        X509KeyManager keyMgr = null;
        int ind = -1;
        if (supportTokenAlias && tokenAlias != null && (ind = tokenAlias.indexOf(':')) != -1) {
            String tokenName = alias.substring(0, ind);
            keyMgr = tokenName2MgrMap.get(tokenName);
        }
        return keyMgr;
    }
    
    //TODO:V3 copied all method(s)below from LoginContextDriver to break dependencies among modules
     private static final String CLIENT_JAAS_PASSWORD = "default";
    /**
     * Perform login on the client side.
     * It just simulates the login on the client side.
     * The method uses the callback handlers and generates correct
     * credential information that will be later sent to the server
     * @param int type whether it is <i> username_password or 
     * <i> certificate  based login.
     * @param CallbackHandler the callback handler to gather user information.
     * @exception LoginException the exception thrown by the callback handler.
     */
    public  static Subject doClientLogin(int type,
                     javax.security.auth.callback.CallbackHandler jaasHandler)
        throws LoginException
    {
        final javax.security.auth.callback.CallbackHandler handler =
            jaasHandler;
        // the subject will actually be filled in with a PasswordCredential
        // required by the csiv2 layer in the LoginModule.
        // we create the dummy credential here and call the 
        // set security context. Thus, we have 2  credentials, one each for
        // the csiv2 layer and the other for the RI.
        final Subject subject = new Subject();
        //V3:Commented : TODO uncomment later for Appcontainer
        if (type == SecurityConstants.USERNAME_PASSWORD){
            AppservAccessController.doPrivileged(new PrivilegedAction() {
                public java.lang.Object run() {
                    try{
                        LoginContext lg = 
                            new LoginContext(SecurityConstants.CLIENT_JAAS_PASSWORD, 
                                             subject, handler);
                        lg.login();
                    }catch(javax.security.auth.login.LoginException e){
                        throw (LoginException)
                            new LoginException(e.toString()).initCause(e);
                    }
                    
                    return null;
                }
            });
            postClientAuth(subject, PasswordCredential.class);
            return subject;
        } else if (type == SecurityConstants.CERTIFICATE){
            AppservAccessController.doPrivileged(new PrivilegedAction() {
                public java.lang.Object run() {
                    try{
                        LoginContext lg = 
                            new LoginContext(SecurityConstants.CLIENT_JAAS_CERTIFICATE,
                                             subject, handler);
                        lg.login();
                    }catch(javax.security.auth.login.LoginException e){
                        throw (LoginException)
                            new LoginException(e.toString()).initCause(e);
                    }
                    
                    return null;
                }
            });
            postClientAuth(subject, X509CertificateCredential.class);
            return subject;
        } else if (type == SecurityConstants.ALL){
            AppservAccessController.doPrivileged(new PrivilegedAction() {
                public java.lang.Object run() {
                    try{
                        LoginContext lgup =
                            new LoginContext(SecurityConstants.CLIENT_JAAS_PASSWORD,
                                             subject, handler);
                        LoginContext lgc = 
                            new LoginContext(SecurityConstants.CLIENT_JAAS_CERTIFICATE,
                                                 subject, handler);
                        lgup.login();
                        postClientAuth(subject, PasswordCredential.class);
                        
                        lgc.login();
                        postClientAuth(subject,
                                       X509CertificateCredential.class);
                    }catch(javax.security.auth.login.LoginException e){
                        throw (LoginException)
                            new LoginException(e.toString()).initCause(e);
                    }
                    
                    return null;
                }
            });
            return subject;
        } else{ 
            AppservAccessController.doPrivileged(new PrivilegedAction() {
                public java.lang.Object run() {
                    try{
                        LoginContext lg =
                            new LoginContext(SecurityConstants.CLIENT_JAAS_PASSWORD, 
                                             subject, handler);
                        lg.login();
                        postClientAuth(subject, PasswordCredential.class);
                    }catch(javax.security.auth.login.LoginException e){
                        throw (LoginException)
                            new LoginException(e.toString()).initCause(e);
                    }
                    return null;
                }
            });
            return subject;
        }
    }
    
     /**
     * Extract the relevant username and realm information from the
     * subject and sets the correct state in the security context. The
     * relevant information is set into the Thread Local Storage from
     * which then is extracted to send over the wire.
     *
     * @param Subject the subject returned by the JAAS login.
     * @param Class the class of the credential object stored in the subject
     *
     */
    private  static void postClientAuth(Subject subject, Class<?> clazz){
        final Class<?> clas = clazz;
        final Subject fs = subject;
        Set credset = 
            (Set) AppservAccessController.doPrivileged(new PrivilegedAction<Set>() {
                public Set run() {
                if(_logger.isLoggable(Level.FINEST)){
                    _logger.log(Level.FINEST, "LCD post login subject :{0}", fs);
                }
                    return fs.getPrivateCredentials(clas);
                }
            });
        final Iterator iter = credset.iterator();
        while(iter.hasNext()) {
            Object obj = null;    
            try{
                obj = AppservAccessController.doPrivileged(new PrivilegedAction(){
                    public java.lang.Object run(){
                        return iter.next();
                    }
                });
            } catch (Exception e){
                // should never come here 
                _logger.log(Level.SEVERE,
                            "java_security.accesscontroller_action_exception",
                            e);
            }
            if(obj instanceof PasswordCredential) {
                PasswordCredential p = (PasswordCredential) obj;
                String user = p.getUser();
                if(_logger.isLoggable(Level.FINEST)){
                    String realm = p.getRealm();
                    _logger.log(Level.FINEST, "In LCD user-pass login:{0} realm :{1}",
                            new Object[]{user, realm});
                }
                setClientSecurityContext(user, fs);
                return;
            } else if (obj instanceof X509CertificateCredential){
                X509CertificateCredential p = (X509CertificateCredential) obj;
                String user = p.getAlias();
                if(_logger.isLoggable(Level.FINEST)){
                    String realm = p.getRealm();
                    _logger.log(Level.FINEST, "In LCD cert-login::{0} realm :{1}",
                            new Object[]{user, realm});
                }
                setClientSecurityContext(user, fs);
                return;
            }
        }
    }

     /**
     * Sets the security context on the appclient side.
     * It sets the relevant information into the TLS
     * @param String username is the user who authenticated
     * @param Subject is the subject representation of the user
     * @param Credentials the credentials that the server associated with it
     */
    private static void setClientSecurityContext(String username, 
                                                 Subject subject) {
                                                 
        ClientSecurityContext securityContext =
            new ClientSecurityContext(username, subject);
        ClientSecurityContext.setCurrent(securityContext);
    }

}

Other Glassfish examples (source code examples)

Here is a short list of links related to this Glassfish J2EEKeyManager.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.