Package com.sun.enterprise.security.auth.login

Source Code of com.sun.enterprise.security.auth.login.LoginContextDriver

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2012 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.auth.login;

import org.glassfish.security.common.Group;
import java.util.Set;
import java.util.Iterator;
import java.util.Enumeration;
import java.security.Principal;
import java.util.logging.*;
import java.security.PrivilegedAction;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.x500.X500Principal;
import sun.security.x509.X500Name;
import com.sun.logging.*;
import com.sun.enterprise.common.iiop.security.GSSUPName;
import com.sun.enterprise.common.iiop.security.AnonCredential;
import com.sun.enterprise.security.SecurityContext;
import com.sun.enterprise.security.SecurityServicesUtil;
import com.sun.enterprise.security.common.AppservAccessController;
//import com.sun.enterprise.security.SecurityContext;
import com.sun.enterprise.security.auth.login.common.PasswordCredential;
import com.sun.enterprise.security.auth.login.common.X509CertificateCredential;
import com.sun.enterprise.security.auth.login.common.ServerLoginCallbackHandler;
import com.sun.enterprise.security.auth.login.common.LoginException;
import com.sun.enterprise.security.auth.realm.Realm;
import com.sun.enterprise.security.auth.realm.certificate.CertificateRealm;
import com.sun.enterprise.security.audit.AuditManager;

// FIXME: ACC methods need to be moved to ACC-specific class.
import com.sun.enterprise.security.auth.realm.InvalidOperationException;
import com.sun.enterprise.security.auth.realm.NoSuchRealmException;
import com.sun.enterprise.security.auth.realm.NoSuchUserException;
import com.sun.enterprise.security.common.ClientSecurityContext;
//import com.sun.enterprise.appclient.AppContainer;
import com.sun.enterprise.security.common.SecurityConstants;
import org.glassfish.internal.api.Globals;


/**
*
* This class is invoked implicitly by the server to log in the user
* information that was sent on the wire by the client. Clients will
* use the <i>doClientLogin</i> method to simulate authentication to the
* server.
*
* @author Harpreet Singh (hsingh@eng.sun.com)
* @author Jyri Virkki
*
*/
public class LoginContextDriver  {

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

    private static final ServerLoginCallbackHandler
        dummyCallback = new ServerLoginCallbackHandler();

    // moved to SecurityConstants.
//    private static final String CLIENT_JAAS_PASSWORD = "default";
//    private static final String CLIENT_JAAS_CERTIFICATE = "certificate";

    public static final String CERT_REALMNAME = "certificate";
 
    private  static volatile AuditManager AUDIT_MANAGER=null;
   
    /** This class cannot be instantiated
     *
     */
    private LoginContextDriver(){
    }

    private static AuditManager getAuditManager() {
        if(AUDIT_MANAGER != null) {
            return AUDIT_MANAGER;
        }
        return _getAuditManager();
    }

    private static synchronized AuditManager _getAuditManager() {
        if(AUDIT_MANAGER == null) {
            SecurityServicesUtil secServUtil  = Globals.get(SecurityServicesUtil.class);
            AUDIT_MANAGER = secServUtil.getAuditManager();
        }
        return AUDIT_MANAGER;
    }

    /**
     * This method is  just a convenience wrapper for
     * <i>login(Subject, Class)</i> method. It will construct a
     * PasswordCredential class.
     *
     * @param String username
     * @param String password
     * @param String realmName the name of the realm to login into, if realmName
     * is null, we login into the default realm  
     */
   
    public static void login(String username, char[] password, String realmName){

        if(realmName == null || !(Realm.isValidRealm(realmName))){   
            realmName = Realm.getDefaultRealm();
        }        
        final Subject fs = new Subject();
        final PasswordCredential pc =
            new PasswordCredential(username, password, realmName);
       
        AppservAccessController.doPrivileged(new PrivilegedAction(){
            public java.lang.Object run(){
                fs.getPrivateCredentials().add(pc);
                return fs;
            }
        });

        LoginContextDriver.login(fs, PasswordCredential.class);
    }


    public static void login(AssertedCredentials asrtCred) throws javax.security.auth.login.LoginException {
        Subject subject = new Subject();
        subject.getPrivateCredentials().add(asrtCred);
        String jaasCtx = null;
        try {
            jaasCtx = Realm.getInstance(asrtCred.getRealmName()).getJAASContext();
        } catch (Exception ex) {
            if (ex instanceof LoginException) {
                throw (LoginException) ex;
            } else {
                throw (LoginException) new LoginException(ex.toString()).initCause(ex);
            }
        }

        try {
            // A dummyCallback is used to satisfy JAAS but it is never used.
            // name/pwd info is already contained in Subject's Credential
            LoginContext lg = new LoginContext(jaasCtx, subject, dummyCallback);
            lg.login();
        } catch (Exception e) {
            if (_logger.isLoggable(Level.INFO)) {
                _logger.log(Level.INFO, "java_security.audit_auth_refused", asrtCred.getUserName());
            }
            if (_logger.isLoggable(Level.FINEST)) {
                _logger.log(Level.FINEST, "doPasswordLogin fails", e);
            }
            if (AUDIT_MANAGER.isAuditOn()) {
                AUDIT_MANAGER.authentication(asrtCred.getUserName(), asrtCred.getRealmName(), false);
            }
            if (e instanceof LoginException) {
                throw (LoginException) e;
            } else {
                throw (LoginException) new LoginException("Login failed: " + e.getMessage()).initCause(e);
            }
        }

        setSecurityContext(asrtCred.getUserName(), subject, asrtCred.getRealmName());
    }


    /**
     * This method performs the login on the server side.
     *
     * <P>This method is the main login method for S1AS. It is called
     * with a Subject and the type (class) of credential which should
     * be checked. The Subject must contain a credential of the
     * specified type or login will fail.
     *
     * <P>While the implementation has been cleaned up, the login
     * process still consists of a number of special cases which are
     * treated separately at the realm level. In the future tighter
     * JAAS integration could clean some of this up.
     *
     * <P>The following credential types are recognized at this time:
     * <ul>
     <li>PasswordCredential - This is the general case for all login
     *      methods which rely on the client providing a name and password.
     *      It can be used with any realms/JAAS login modules which expect
     *      such data (e.g. file realm, LDAP realm, UNIX realm)
     *  <LI>X509CertificateCredential - Special case for SSL client auth.
     *      Here authentication has already been done by the SSL subsystem
     *      so this login only creates a security context based on the
     *      certificate data.
     *  <LI>AnonCredential - Unauthenticated session, set anonymous security
     *      context.
     *  <LI>GSSUPName - Retrieve user and realm and set security context.
     *  <LI>X500Name - Retrieve user and realm and set security context.
     * </ul>
     *
     * @param Subject the subject of the client
     * @param Class the class of the credential packaged in the subject.
     *
     */
    public static void login(Subject subject, Class cls)
        throws LoginException
    {
        if (_logger.isLoggable(Level.FINEST)) {
            _logger.log(Level.FINEST,
                        "Processing login with credentials of type: "+
                        cls.toString());
        }
       
        if(cls.equals(PasswordCredential.class)) {
            doPasswordLogin(subject);

        } else if (cls.equals(X509CertificateCredential.class)) {
            doCertificateLogin(subject);
           
        } else if (cls.equals(AnonCredential.class)) {
            doAnonLogin();
           
        } else if (cls.equals(GSSUPName.class)) {
            doGSSUPLogin(subject);
           
        } else if (cls.equals(X500Name.class)) {
            doX500Login(subject, null);
           
        } else {
            _logger.log(Level.INFO, "java_security.unknown_credential",
                        cls.toString());
            throw new
                LoginException("Unknown credential type, cannot login.");
        }
    }


    /**
     * This method is used for logging in a run As principal. It creates
     * a JAAS subject whose credential is to type GSSUPName.
     * This is used primarily for runas
     *
     */
    public static void loginPrincipal(String username, String realmName)
        throws LoginException {

        // no realm provided, assuming default
        if(realmName == null || realmName.length() == 0){
            realmName = Realm.getDefaultRealm();
        }
       
        final Subject s = new Subject();

        final org.glassfish.security.common.PrincipalImpl p
            = new org.glassfish.security.common.PrincipalImpl(username);

        final GSSUPName name = new GSSUPName(username, realmName);

        AppservAccessController.doPrivileged(new PrivilegedAction() {
            public java.lang.Object run() {
                s.getPrincipals().add(p);
                s.getPublicCredentials().add(name);
                return null;
            }
        });

       try {
            Realm realm = Realm.getInstance(realmName);
            Enumeration en = realm.getGroupNames(username);
            Set<Principal> principalSet = s.getPrincipals();
            while (en.hasMoreElements()) {
                principalSet.add(new Group((String) en.nextElement()));
            }

        } catch (InvalidOperationException ex) {
            _logger.warning("Realm " + realmName + ": " + ex.toString());
        } catch (NoSuchUserException ex){
            _logger.warning("Realm " + realmName + ": " + ex.toString());
        } catch (NoSuchRealmException ex) {
            LoginException lex = new LoginException(ex.toString());
            lex.initCause(ex);
            throw lex;
        }
        setSecurityContext(username, s, realmName);
    }

   
    /**
     * This method logs out the user by clearing the security context.
     *
     */
    public static void logout() throws LoginException {
        unsetSecurityContext();
    }


    /**
     * Log in subject with PasswordCredential. This is a generic login
     * which applies to all login mechanisms which process PasswordCredential.
     * In other words, any mechanism which receives an actual username, realm
     * and password set from the client.
     *
     * <P>The realm contained in the credential is checked, and a JAAS
     * LoginContext is created using a context name obtained from the
     * appropriate Realm instance. The applicable JAAS LoginModule
     * is initialized (based on the jaas login configuration) and login()
     * is invoked on it.
     *
     * <P>RI code makes several assumptions which are retained here:
     * <ul>
     <li>The PasswordCredential is stored as a private credential of
     *      the subject.
     *  <li>There is only one such credential present (actually, only
     *      the first one is relevant if more are present).
     * </ui>
     *
     * @param s Subject to be authenticated.
     * @throws LoginException Thrown if the login fails.
     *
     */
    private static void doPasswordLogin(Subject subject)
        throws LoginException
    {
        final Subject s = subject;
       
        Object obj = getPrivateCredentials(s, PasswordCredential.class);
        assert obj != null;
       
        PasswordCredential p = (PasswordCredential) obj;
        String user = p.getUser();
        char[] pwd = p.getPassword();
        String realm = p.getRealm();
        String jaasCtx = null;
        try {
            jaasCtx = Realm.getInstance(realm).getJAASContext();
        } catch(Exception ex) {
            if( ex instanceof LoginException )
                throw (LoginException)ex;
            else
                throw (LoginException)new LoginException(ex.toString()).initCause(ex);
        }

        assert user != null;
        assert pwd != null;
        assert realm != null;
        assert jaasCtx != null;

        if (_logger.isLoggable(Level.FINE)) {
            _logger.fine("Logging in user [" + user + "] into realm: " +
                         realm + " using JAAS module: "+jaasCtx);
        }

        try {
            // A dummyCallback is used to satisfy JAAS but it is never used.
            // name/pwd info is already contained in Subject's Credential
            LoginContext lg = new LoginContext(jaasCtx, s, dummyCallback);
            lg.login();
           
        } catch (Exception e) {
            if (_logger.isLoggable(Level.FINEST)) {
                _logger.log(Level.FINEST, "doPasswordLogin fails", e);
            }
            if(getAuditManager() != null && getAuditManager().isAuditOn()){
                getAuditManager().authentication(user, realm, false);
            }
            if( e instanceof LoginException )
                throw (LoginException)e;
            else
                throw (LoginException)
                    new LoginException("Login failed: " + e.getMessage()).initCause(e);
        }
        if(getAuditManager() != null && getAuditManager().isAuditOn()){
            getAuditManager().authentication(user, realm, true);
        }
        if (_logger.isLoggable(Level.FINE)) {
            _logger.fine("Password login succeeded for : " + user);
        }

        setSecurityContext(user, s, realm);
        if (_logger.isLoggable(Level.FINE)) {
            _logger.log(Level.FINE, "Set security context as user: "+user);
        }
    }

   /** Performs login for JMAC security. The difference between this
     * method and others is that it just verifies whether the login will succeed
     * in the given realm.
     * It does not set the result of the authentication in the appserver runtime
     * environment
     * A silent return from this method means that the given user succeeding in
     * authenticating with the given password in the given realm
     * @param subject
     * @param username
     * @param password
     * @param realmName the realm to authenticate under
     * @returns Subject on successful authentication
     * @throws LoginException
     */
    public static Subject jmacLogin(Subject subject,
            String username, char[] password, String realmName)
            throws LoginException {

        if(realmName == null || !(Realm.isValidRealm(realmName))){
            realmName = Realm.getDefaultRealm();
        }
        if (subject == null) {
            subject = new Subject();
        }
        final Subject fs = subject;
        final PasswordCredential pc =
            new PasswordCredential(username, password, realmName);

        AppservAccessController.doPrivileged(new PrivilegedAction(){
            public java.lang.Object run(){
                fs.getPrivateCredentials().add(pc);
                return fs;
            }
        });

        String jaasCtx = null;
        try {
            jaasCtx = Realm.getInstance(realmName).getJAASContext();
        } catch(Exception ex) {
            if( ex instanceof LoginException )
                throw (LoginException)ex;
            else
                throw (LoginException)
                    new LoginException(ex.toString()).initCause(ex);
        }

        if (_logger.isLoggable(Level.FINE)) {
            _logger.fine("jmac login user [" + username + "] into realm: " +
                         realmName + " using JAAS module: "+jaasCtx);
        }

        try{
            // A dummyCallback is used to satisfy JAAS but it is never used.
            // name/pwd info is already contained in Subject's Credential
            LoginContext lg = new LoginContext(jaasCtx, fs, dummyCallback);
            lg.login();
        } catch (Exception e) {
            if (_logger.isLoggable(Level.INFO)) {
                _logger.log(Level.INFO, "java_security.audit_auth_refused",
                            username);
            }
            if(getAuditManager().isAuditOn()){
                getAuditManager().authentication(username, realmName, false);
            }

            if( e instanceof LoginException )
                throw (LoginException)e;
            else
                throw (LoginException)
                    new LoginException("Login failed: " + e.getMessage()).initCause(e);
        }
        if(getAuditManager().isAuditOn()){
            getAuditManager().authentication(username, realmName, true);
        }
        if (_logger.isLoggable(Level.FINE)) {
            _logger.fine("jmac Password login succeeded for : " + username);
        }

        return subject;
        // do not set the security Context
    }

    public static Subject jmacLogin(Subject subject,
            X500Principal x500Principal) throws LoginException {

        if (subject == null) {
            subject = new Subject();
        }

        final Subject fs = subject;

        String userName = "";
        try {
            final X500Name x500Name = new X500Name(
                x500Principal.getName(X500Principal.RFC1779));
            userName = x500Name.toString();

            AppservAccessController.doPrivileged(new PrivilegedAction(){
                public java.lang.Object run(){
                    fs.getPublicCredentials().add(x500Name);
                    return fs;
                }
            });

            Realm realm = Realm.getInstance(CertificateRealm.AUTH_TYPE);
            CertificateRealm certRealm = (CertificateRealm)realm;
            String jaasCtx = certRealm.getJAASContext();
            if (jaasCtx != null) {
                // The subject has the Cretificate Credential.
                LoginContext lg = new LoginContext(jaasCtx, fs, dummyCallback);
                lg.login();
            }
            certRealm.authenticate(fs, x500Name);
        } catch(Exception ex) {
            if (_logger.isLoggable(Level.INFO)) {
                _logger.log(Level.INFO, "java_security.audit_auth_refused",
                            userName);
            }
            if (getAuditManager().isAuditOn()){
                getAuditManager().authentication(userName,
                    CertificateRealm.AUTH_TYPE, false);
            }
            if (ex instanceof LoginException) {
                throw (LoginException)ex;
            } else {
                throw (LoginException)
                    new LoginException(ex.toString()).initCause(ex);
            }
        }

        if (_logger.isLoggable(Level.FINE)) {
            _logger.fine("jmac cert login succeeded for: " + userName);
        }

        if (getAuditManager().isAuditOn()){
            getAuditManager().authentication(userName,
                CertificateRealm.AUTH_TYPE, true);
        }
        // do not set the security Context

        return subject;
    }

    public static Subject jmacLogin(Subject subject, String identityAssertion, String realm) throws LoginException {

        if (subject == null) {
            subject = new Subject();
        }
        final Subject fs = subject;
        String userName = identityAssertion;

        try {
            if (realm == null || "".equals(realm)) {
                realm = Realm.getDefaultRealm();
            }
            Realm realmInst = Realm.getInstance(realm);
            final Enumeration groups = realmInst.getGroupNames(userName);
            if (groups != null && groups.hasMoreElements()) {
                AppservAccessController.doPrivileged(new PrivilegedAction() {

                    public java.lang.Object run() {
                        while (groups.hasMoreElements()) {
                            String grp = (String) groups.nextElement();
                            fs.getPrincipals().add(new Group(grp));
                        }
                        return fs;
                    }
                });
            }
        } catch (Exception ex) {
            if (_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE, "Exception when trying to populate groups for CallerPrincipal " + identityAssertion, ex);
            }
        }
        return subject;
    }

    /**
     * A special case login for handling X509CertificateCredential.
     * This does not get triggered based on current RI code. See X500Login.
     *
     */
    private static void doCertificateLogin(Subject s)
        throws LoginException
    {
        if(_logger.isLoggable(Level.FINE)){
            _logger.log(Level.FINE, "Processing X509 certificate login.");
        }
        String realm = CertificateRealm.AUTH_TYPE;
        String user = null;
        try{
            Object obj = getPublicCredentials(s, X509CertificateCredential.class);

            X509CertificateCredential xp = (X509CertificateCredential) obj;
            user = xp.getAlias();
            if(_logger.isLoggable(Level.FINE)){
                _logger.log(Level.FINE,"Set security context as user: "+user);
            }
            setSecurityContext(user, s, realm);
            if(getAuditManager().isAuditOn()){
                getAuditManager().authentication(user, realm, true);
            }
        } catch(LoginException le){
            if(getAuditManager().isAuditOn()){
                getAuditManager().authentication(user, realm, false);
            }
            throw le;
        }
    }


    /**
     * A special case login for anonymous credentials (no login info).
     *
     */
    private static void doAnonLogin()
        throws LoginException
    {
        // instance of anononymous credential login with guest
        SecurityContext.setUnauthenticatedContext();
       if(_logger.isLoggable(Level.FINE)){
            _logger.log(Level.FINE,"Set anonymous security context.");
       
    }


    /**
     * A special case login for GSSUPName credentials.
     *
     */
    private static void doGSSUPLogin(Subject s)
        throws LoginException
    {
       if(_logger.isLoggable(Level.FINE)){
             _logger.fine("Processing GSSUP login.");
       }
       String user = null;
       String realm = Realm.getDefaultRealm();
       try{
            Object obj = getPublicCredentials(s, GSSUPName.class);

            user = ((GSSUPName)obj).getUser();
   
            setSecurityContext(user, s, realm);
            if(getAuditManager().isAuditOn()){
                getAuditManager().authentication(user, realm, true);       
            }
            if (_logger.isLoggable(Level.FINE)) {
                _logger.fine("GSSUP login succeeded for : " + user);
            }
       } catch (LoginException le){
           if(getAuditManager().isAuditOn()){
               getAuditManager().authentication(user, realm, false);
           }
           throw le;
       }
    }


    /**
     * A special case login for X500Name credentials.
     * This is invoked for certificate login because the containers
     * extract the X.500 name from the X.509 certificate before calling
     * into this class.
     *
     */
    public static void doX500Login(Subject s, String appModuleID)
        throws LoginException
    {
       if(_logger.isLoggable(Level.FINE)){       
            _logger.fine("Processing X.500 name login.");
       }
       String user = null;
       String realm_name = null;
       try{
            X500Name x500name = (X500Name)getPublicCredentials(s, X500Name.class);
            user = x500name.getName();
       
            // In the RI-inherited implementation this directly creates
            // some credentials and sets the security context. This means
            // that the certificate realm does not get an opportunity to
            // process the request. While the realm will not do any
            // authentication (already done by this point) it can choose
            // to adjust the groups or principal name or other variables
            // of the security context. Of course, bug 4646134 needs to be
            // kept in mind at all times.

            Realm realm = Realm.getInstance(CertificateRealm.AUTH_TYPE);

            if (realm instanceof CertificateRealm) { // should always be true
   
                CertificateRealm certRealm = (CertificateRealm)realm;
                String jaasCtx = certRealm.getJAASContext();
                if (jaasCtx != null) {
                    // The subject has the Cretificate Credential.
                    LoginContext lg = new LoginContext(jaasCtx, s, new ServerLoginCallbackHandler(user, null, appModuleID));
                    lg.login();
                }
                certRealm.authenticate(s, x500name);
                realm_name = CertificateRealm.AUTH_TYPE;
                if(getAuditManager().isAuditOn()){
                    getAuditManager().authentication(user, realm_name, true);
                }
            } else {           
                _logger.warning("certlogin.badrealm");           
                realm_name = realm.getName();
                setSecurityContext(user, s, realm_name);
            }
       
            if (_logger.isLoggable(Level.FINE)) {
                _logger.fine("X.500 name login succeeded for : " + user);
            }
       } catch (LoginException le){
           if(getAuditManager().isAuditOn()){
               getAuditManager().authentication(user, realm_name, false);
           }
           throw le;
       } catch (Exception ex) {
           throw (LoginException)new LoginException(ex.toString()).initCause(ex);
       }
    }


    /**
     * Retrieve a public credential of the given type (java class) from the
     * subject.
     *
     * <P>This method retains the RI assumption that only the first
     * credential of the given type is used.
     *
     */
    private static Object getPublicCredentials(Subject s, Class<?> cls)
        throws LoginException
    {
        Set credset = s.getPublicCredentials(cls);
       
        final Iterator iter = credset.iterator();

        if(!iter.hasNext()) {
            String credmsg = cls.toString();
            if(_logger.isLoggable(Level.FINER)){
                _logger.finer("Expected public credentials of type : " +
                          credmsg + " but none found.");
            }
            throw new LoginException("Expected public credential of type: "+
                                     credmsg + " but none found.");
        }
       
        Object obj = null;   
        try{
            obj = AppservAccessController.doPrivileged(new PrivilegedAction(){
                public java.lang.Object run(){
                    return iter.next();
                }
            });
        } catch (Exception e){
            // should never come here
            if( e instanceof LoginException )
                throw (LoginException)e;
            else
                throw (LoginException)
                    new LoginException("Failed to retrieve public credential: "+
                                       e.getMessage()).initCause(e);
        }

        return obj;
    }


    /**
     * Retrieve a private credential of the given type (java class) from the
     * subject.
     *
     * <P>This method retains the RI assumption that only the first
     * credential of the given type is used.
     *
     */
    private static Object getPrivateCredentials(Subject subject,
                                                Class<?> cls)
        throws LoginException
    {
        final Subject s = subject;
        final Class<?> cl = cls;
       
        final Set credset = (Set)
            AppservAccessController.doPrivileged(new PrivilegedAction() {
                public java.lang.Object run() {
                    return
                        s.getPrivateCredentials(cl);
                }
            });

        final Iterator iter = credset.iterator();

        if (!iter.hasNext()) {
           String credmsg = cls.toString();
           if(_logger.isLoggable(Level.FINER)){
                 _logger.finer("Expected private credential of type: "+
                              credmsg + " but none found.");
           }
            throw new LoginException("Expected private credential of type: "+
                                     credmsg + " but none found.");
        }

        // retrieve only first credential of give type
        Object obj = null;
        try{
            obj = AppservAccessController.doPrivileged(new PrivilegedAction(){
                public java.lang.Object run(){
                    return iter.next();
                }
            });
        } catch (Exception e){
            // should never come here
            if( e instanceof LoginException )
                throw (LoginException)e;
            else
                throw (LoginException)
                    new LoginException("Failed to retrieve private credential: "+
                                     e.getMessage()).initCause(e);
        }

        return obj;
    }

   
    /**
     * This method sets the security context on the current Thread Local
     * Storage
     * @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 setSecurityContext(String userName,
            Subject subject, String realm) {

        SecurityContext securityContext = new SecurityContext(userName, subject, realm);
        SecurityContext.setCurrent(securityContext);
    }

    /**
     * Set the current security context on the Thread Local Storage to null.
     *
     */
    private static void unsetSecurityContext() {
        SecurityContext.setCurrent((SecurityContext)null);
    }
    /**
     * 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</i> or
     * <i> certificate </i> 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();
       
        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;
        }
    }

    /**
     * Perform logout on the client side.
     * @exception LoginException
     */
    public static void doClientLogout() throws LoginException {
        unsetClientSecurityContext();
    }
     /**
     * Performs Digest authentication based on RFC 2617. It
     *
     * @param digestCred DigestCredentials
     */
    public static void login(DigestCredentials digestCred) throws javax.security.auth.login.LoginException {
        Subject subject = new Subject();
        subject.getPrivateCredentials().add(digestCred);
        String jaasCtx = null;
        try {
            jaasCtx = Realm.getInstance(digestCred.getRealmName()).getJAASContext();
        } catch (Exception ex) {
            if (ex instanceof LoginException) {
                throw (LoginException) ex;
            } else {
                throw (LoginException) new LoginException(ex.toString()).initCause(ex);
            }
        }

        try {
            // A dummyCallback is used to satisfy JAAS but it is never used.
            // name/pwd info is already contained in Subject's Credential
            LoginContext lg = new LoginContext(jaasCtx, subject, dummyCallback);
            lg.login();
        } catch (Exception e) {
            if (_logger.isLoggable(Level.INFO)) {
                _logger.log(Level.INFO, "java_security.audit_auth_refused", digestCred.getUserName());
            }
            if (_logger.isLoggable(Level.FINEST)) {
                _logger.log(Level.FINEST, "doPasswordLogin fails", e);
            }
            if (getAuditManager().isAuditOn()) {
                getAuditManager().authentication(digestCred.getUserName(), digestCred.getRealmName(), false);
            }
            if (e instanceof LoginException) {
                throw (LoginException) e;
            } else {
                throw (LoginException) new LoginException("Login failed: " + e.getMessage()).initCause(e);
            }
        }

        setSecurityContext(digestCred.getUserName(), subject, digestCred.getRealmName());
    }

    /**
     * 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() {
                public java.lang.Object run() {
                if(_logger.isLoggable(Level.FINEST)){
                    _logger.log(Level.FINEST,"LCD post login subject :" + 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:" +
                            user +" realm :" + 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::" +
                                user +" realm :" + 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);
    }

   
    /**
     * Unsets the current appclient security context on the Thread
     * Local Storage
     */
    private  static void unsetClientSecurityContext() {
        ClientSecurityContext.setCurrent(null);
    }

}
TOP

Related Classes of com.sun.enterprise.security.auth.login.LoginContextDriver

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.