/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sample.loginmodule;

import com.sun.appserv.security.AppservCertificateLoginModule;
import com.sun.enterprise.security.auth.realm.Realm;
import javax.naming.ldap.LdapName;
import javax.security.auth.login.LoginException;
import org.glassfish.security.common.PrincipalImpl;
import sample.realm.LDAPRealm;

/**
 *
 * Sample certificate login module that just get CN part of the certificate
 * (exactly the first part) and searches and LDAP repository to associate 
 * the user. To do that a LDAPRealm is used (this realm is just a slight 
 * modified Realm od glassfish default).
 * 
 * @author ricky
 */
public class CertLdapLoginModule extends AppservCertificateLoginModule {

    /**
     * The option parameter that has the realm for LDAP access.
     */
    final public static String REALM_OPTION = "realm";
    
    /**
     * Perform authentication decision.
     *
     * Method returns silently on success and returns a LoginException
     * on failure. In this case the realm is got and the search against 
     * the ldap is performed.
     *
     * <p>Must be overridden to add custom functionality.
     * @throws LoginException on authentication failure.
     *
     */
    @Override
    protected void authenticateUser() throws LoginException {
        String realm = _options.get(REALM_OPTION).toString();
        if (realm == null) {
            throw new LoginException("LoginModule has not 'realm' option to get the LDAP realm!");
        }
        try {
            // get the user from the certificate
            LdapName name = new LdapName(this.getX500Principal().getName());
            String certName = name.getRdn(name.size() - 1).getValue().toString();
            // get the real 
            LDAPRealm ldap = (LDAPRealm) Realm.getInstance(realm);
            if (ldap == null) {
                throw new LoginException("Realm'" + realm + "' does not exists!");
            }
            String[] grpList = ldap.findAndBind(certName, null, false);
            // add the short user as a user principal
            // LoginContextDriver sets the whole cert subject as the name of the user
            // this let the user to set roles based on user (uid) names
            getSubject().getPrincipals().add(new PrincipalImpl(certName));
            // add groups => commit sets them as group principals
            commitUserAuthentication(grpList);
        } catch (Exception e) {
            //e.printStackTrace();
            throw new LoginException(e.getMessage());
        }
    }
}

