jndiloginmodule.java

来自「JAVA 所有包」· Java 代码 · 共 752 行 · 第 1/2 页

JAVA
752
字号
/* * @(#)JndiLoginModule.java	1.12 05/11/17 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */package com.sun.security.auth.module;import javax.security.auth.*;import javax.security.auth.callback.*;import javax.security.auth.login.*;import javax.security.auth.spi.*;import javax.naming.*;import javax.naming.directory.*;import java.io.IOException;import java.util.Map;import java.util.LinkedList;import java.util.ResourceBundle;import com.sun.security.auth.UnixPrincipal;import com.sun.security.auth.UnixNumericUserPrincipal;import com.sun.security.auth.UnixNumericGroupPrincipal;import sun.security.util.AuthResources; /** * <p> The module prompts for a username and password * and then verifies the password against the password stored in * a directory service configured under JNDI. * * <p> This <code>LoginModule</code> interoperates with * any conformant JNDI service provider.  To direct this * <code>LoginModule</code> to use a specific JNDI service provider, * two options must be specified in the login <code>Configuration</code> * for this <code>LoginModule</code>. * <pre> *	user.provider.url=<b>name_service_url</b> *	group.provider.url=<b>name_service_url</b> * </pre> * * <b>name_service_url</b> specifies * the directory service and path where this <code>LoginModule</code> * can access the relevant user and group information.  Because this * <code>LoginModule</code> only performs one-level searches to * find the relevant user information, the <code>URL</code> * must point to a directory one level above where the user and group * information is stored in the directory service. * For example, to instruct this <code>LoginModule</code> * to contact a NIS server, the following URLs must be specified: * <pre> *    user.provider.url="nis://<b>NISServerHostName</b>/<b>NISDomain</b>/user" *    group.provider.url="nis://<b>NISServerHostName</b>/<b>NISDomain</b>/system/group" * </pre> * * <b>NISServerHostName</b> specifies the server host name of the * NIS server (for example, <i>nis.sun.com</i>, and <b>NISDomain</b> * specifies the domain for that NIS server (for example, <i>jaas.sun.com</i>. * To contact an LDAP server, the following URLs must be specified: * <pre> *    user.provider.url="ldap://<b>LDAPServerHostName</b>/<b>LDAPName</b>" *    group.provider.url="ldap://<b>LDAPServerHostName</b>/<b>LDAPName</b>" * </pre> * * <b>LDAPServerHostName</b> specifies the server host name of the * LDAP server, which may include a port number * (for example, <i>ldap.sun.com:389</i>), * and <b>LDAPName</b> specifies the entry name in the LDAP directory * (for example, <i>ou=People,o=Sun,c=US</i> and <i>ou=Groups,o=Sun,c=US</i> * for user and group information, respectively). * * <p> The format in which the user's information must be stored in * the directory service is specified in RFC 2307.  Specifically, * this <code>LoginModule</code> will search for the user's entry in the * directory service using the user's <i>uid</i> attribute, * where <i>uid=<b>username</b></i>.  If the search succeeds, * this <code>LoginModule</code> will then * obtain the user's encrypted password from the retrieved entry * using the <i>userPassword</i> attribute. * This <code>LoginModule</code> assumes that the password is stored * as a byte array, which when converted to a <code>String</code>, * has the following format: * <pre> *	"{crypt}<b>encrypted_password</b>" * </pre> *  * The LDAP directory server must be configured * to permit read access to the userPassword attribute. * If the user entered a valid username and password, * this <code>LoginModule</code> associates a * <code>UnixPrincipal</code>, <code>UnixNumericUserPrincipal</code>, * and the relevant UnixNumericGroupPrincipals with the * <code>Subject</code>. *  * <p> This LoginModule also recognizes the following <code>Configuration</code> * options: * <pre> *    debug          if, true, debug messages are output to System.out. * *    useFirstPass   if, true, this LoginModule retrieves the *                   username and password from the module's shared state, *                   using "javax.security.auth.login.name" and *                   "javax.security.auth.login.password" as the respective *                   keys.  The retrieved values are used for authentication. *                   If authentication fails, no attempt for a retry is made, *                   and the failure is reported back to the calling *                   application. * *    tryFirstPass   if, true, this LoginModule retrieves the *                   the username and password from the module's shared state, *                   using "javax.security.auth.login.name" and *                   "javax.security.auth.login.password" as the respective *                   keys.  The retrieved values are used for authentication. *                   If authentication fails, the module uses the *                   CallbackHandler to retrieve a new username and password, *                   and another attempt to authenticate is made. *                   If the authentication fails, the failure is reported *                   back to the calling application. * *    storePass      if, true, this LoginModule stores the username and password *                   obtained from the CallbackHandler in the module's *                   shared state, using "javax.security.auth.login.name" and *                   "javax.security.auth.login.password" as the respective *                   keys.  This is not performed if existing values already *                   exist for the username and password in the shared state, *                   or if authentication fails. * *    clearPass     if, true, this <code>LoginModule</code> clears the *                  username and password stored in the module's shared state *                  after both phases of authentication (login and commit) *                  have completed. * </pre> * * @version 1.12, 11/17/05 */public class JndiLoginModule implements LoginModule {    static final java.util.ResourceBundle rb =        java.util.ResourceBundle.getBundle("sun.security.util.AuthResources");    /** JNDI Provider */    public final String USER_PROVIDER = "user.provider.url";    public final String GROUP_PROVIDER = "group.provider.url";    // configurable options    private boolean debug = false;    private boolean strongDebug = false;    private String userProvider;    private String groupProvider;    private boolean useFirstPass = false;    private boolean tryFirstPass = false;    private boolean storePass = false;    private boolean clearPass = false;    // the authentication status    private boolean succeeded = false;    private boolean commitSucceeded = false;    // username, password, and JNDI context    private String username;    private char[] password;    DirContext ctx;    // the user (assume it is a UnixPrincipal)    private UnixPrincipal userPrincipal;    private UnixNumericUserPrincipal UIDPrincipal;    private UnixNumericGroupPrincipal GIDPrincipal;    private LinkedList supplementaryGroups = new LinkedList();    // initial state    private Subject subject;    private CallbackHandler callbackHandler;    private Map sharedState;    private Map options;    private static final String CRYPT = "{crypt}";    private static final String USER_PWD = "userPassword";    private static final String USER_UID = "uidNumber";    private static final String USER_GID = "gidNumber";    private static final String GROUP_ID = "gidNumber";    private static final String NAME = "javax.security.auth.login.name";    private static final String PWD = "javax.security.auth.login.password";    /**     * Initialize this <code>LoginModule</code>.     *     * <p>     *     * @param subject the <code>Subject</code> to be authenticated. <p>     *     * @param callbackHandler a <code>CallbackHandler</code> for communicating     *			with the end user (prompting for usernames and     *			passwords, for example). <p>     *     * @param sharedState shared <code>LoginModule</code> state. <p>     *     * @param options options specified in the login     *			<code>Configuration</code> for this particular     *			<code>LoginModule</code>.     */    public void initialize(Subject subject, CallbackHandler callbackHandler,			   Map<String,?> sharedState,			   Map<String,?> options) {	this.subject = subject;	this.callbackHandler = callbackHandler;	this.sharedState = sharedState;	this.options = options;	// initialize any configured options	debug = "true".equalsIgnoreCase((String)options.get("debug"));	strongDebug =		"true".equalsIgnoreCase((String)options.get("strongDebug"));	userProvider = (String)options.get(USER_PROVIDER);	groupProvider = (String)options.get(GROUP_PROVIDER);	tryFirstPass =		"true".equalsIgnoreCase((String)options.get("tryFirstPass"));	useFirstPass =		"true".equalsIgnoreCase((String)options.get("useFirstPass"));	storePass =		"true".equalsIgnoreCase((String)options.get("storePass"));	clearPass =		"true".equalsIgnoreCase((String)options.get("clearPass"));    }    /**     * <p> Prompt for username and password.     * Verify the password against the relevant name service.     *     * <p>     *     * @return true always, since this <code>LoginModule</code>     *		should not be ignored.     *     * @exception FailedLoginException if the authentication fails. <p>     *     * @exception LoginException if this <code>LoginModule</code>     *		is unable to perform the authentication.     */    public boolean login() throws LoginException {	if (userProvider == null) {	    throw new LoginException		("Error: Unable to locate JNDI user provider");	}	if (groupProvider == null) {	    throw new LoginException		("Error: Unable to locate JNDI group provider");	}	if (debug) {	    System.out.println("\t\t[JndiLoginModule] user provider: " +				userProvider);	    System.out.println("\t\t[JndiLoginModule] group provider: " +				groupProvider);	}	// attempt the authentication	if (tryFirstPass) {	    try {		// attempt the authentication by getting the		// username and password from shared state		attemptAuthentication(true);		// authentication succeeded		succeeded = true;		if (debug) {		    System.out.println("\t\t[JndiLoginModule] " +				"tryFirstPass succeeded");		}		return true;	    } catch (LoginException le) {		// authentication failed -- try again below by prompting		cleanState();		if (debug) {		    System.out.println("\t\t[JndiLoginModule] " +				"tryFirstPass failed with:" +				le.toString());		}	    }	} else if (useFirstPass) {	    try {		// attempt the authentication by getting the		// username and password from shared state		attemptAuthentication(true);		// authentication succeeded		succeeded = true;		if (debug) {		    System.out.println("\t\t[JndiLoginModule] " +				"useFirstPass succeeded");		}		return true;	    } catch (LoginException le) {		// authentication failed		cleanState();		if (debug) {		    System.out.println("\t\t[JndiLoginModule] " +				"useFirstPass failed");		}		throw le;	    }	}	// attempt the authentication by prompting for the username and pwd	try {	    attemptAuthentication(false);	    // authentication succeeded	   succeeded = true;	    if (debug) {		System.out.println("\t\t[JndiLoginModule] " +				"regular authentication succeeded");	    }	    return true;	} catch (LoginException le) {	    cleanState();	    if (debug) {		System.out.println("\t\t[JndiLoginModule] " +				"regular authentication failed");	    }	    throw le;	}    }    /**     * Abstract method to commit the authentication process (phase 2).     *     * <p> This method is called if the LoginContext's     * overall authentication succeeded     * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules     * succeeded).     *     * <p> If this LoginModule's own authentication attempt     * succeeded (checked by retrieving the private state saved by the     * <code>login</code> method), then this method associates a     * <code>UnixPrincipal</code>     * with the <code>Subject</code> located in the     * <code>LoginModule</code>.  If this LoginModule's own     * authentication attempted failed, then this method removes     * any state that was originally saved.     *     * <p>     *     * @exception LoginException if the commit fails     *     * @return true if this LoginModule's own login and commit     *		attempts succeeded, or false otherwise.     */    public boolean commit() throws LoginException {	if (succeeded == false) {	    return false;	} else {	    if (subject.isReadOnly()) {		cleanState();		throw new LoginException ("Subject is Readonly");	    } 	    // add Principals to the Subject	    if (!subject.getPrincipals().contains(userPrincipal))		subject.getPrincipals().add(userPrincipal);	    if (!subject.getPrincipals().contains(UIDPrincipal))		subject.getPrincipals().add(UIDPrincipal);	    if (!subject.getPrincipals().contains(GIDPrincipal))		subject.getPrincipals().add(GIDPrincipal);	    for (int i = 0; i < supplementaryGroups.size(); i++) {		if (!subject.getPrincipals().contains		    ((UnixNumericGroupPrincipal)supplementaryGroups.get(i)))		    subject.getPrincipals().add((UnixNumericGroupPrincipal)						supplementaryGroups.get(i));	    }	    

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?