diff -r 836adbf7a2cd -r 3317bb8137f4 jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/UnixLoginModule.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/UnixLoginModule.java Sun Aug 17 15:54:13 2014 +0100 @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.security.auth.module; + +import java.util.*; +import java.io.IOException; +import javax.security.auth.*; +import javax.security.auth.callback.*; +import javax.security.auth.login.*; +import javax.security.auth.spi.*; +import com.sun.security.auth.UnixPrincipal; +import com.sun.security.auth.UnixNumericUserPrincipal; +import com.sun.security.auth.UnixNumericGroupPrincipal; + +/** + *

This LoginModule imports a user's Unix + * Principal information (UnixPrincipal, + * UnixNumericUserPrincipal, + * and UnixNumericGroupPrincipal) + * and associates them with the current Subject. + * + *

This LoginModule recognizes the debug option. + * If set to true in the login Configuration, + * debug messages will be output to the output stream, System.out. + * + */ +@jdk.Exported +public class UnixLoginModule implements LoginModule { + + // initial state + private Subject subject; + private CallbackHandler callbackHandler; + private Map sharedState; + private Map options; + + // configurable option + private boolean debug = true; + + // UnixSystem to retrieve underlying system info + private UnixSystem ss; + + // the authentication status + private boolean succeeded = false; + private boolean commitSucceeded = false; + + // Underlying system info + private UnixPrincipal userPrincipal; + private UnixNumericUserPrincipal UIDPrincipal; + private UnixNumericGroupPrincipal GIDPrincipal; + private LinkedList supplementaryGroups = + new LinkedList<>(); + + /** + * Initialize this LoginModule. + * + *

+ * + * @param subject the Subject to be authenticated.

+ * + * @param callbackHandler a CallbackHandler for communicating + * with the end user (prompting for usernames and + * passwords, for example).

+ * + * @param sharedState shared LoginModule state.

+ * + * @param options options specified in the login + * Configuration for this particular + * LoginModule. + */ + public void initialize(Subject subject, CallbackHandler callbackHandler, + Map sharedState, + Map options) { + + this.subject = subject; + this.callbackHandler = callbackHandler; + this.sharedState = sharedState; + this.options = options; + + // initialize any configured options + debug = "true".equalsIgnoreCase((String)options.get("debug")); + } + + /** + * Authenticate the user (first phase). + * + *

The implementation of this method attempts to retrieve the user's + * Unix Subject information by making a native Unix + * system call. + * + *

+ * + * @exception FailedLoginException if attempts to retrieve the underlying + * system information fail. + * + * @return true in all cases (this LoginModule + * should not be ignored). + */ + public boolean login() throws LoginException { + + long[] unixGroups = null; + + try { + ss = new UnixSystem(); + } catch (UnsatisfiedLinkError ule) { + succeeded = false; + throw new FailedLoginException + ("Failed in attempt to import " + + "the underlying system identity information" + + " on " + System.getProperty("os.name")); + } + userPrincipal = new UnixPrincipal(ss.getUsername()); + UIDPrincipal = new UnixNumericUserPrincipal(ss.getUid()); + GIDPrincipal = new UnixNumericGroupPrincipal(ss.getGid(), true); + if (ss.getGroups() != null && ss.getGroups().length > 0) { + unixGroups = ss.getGroups(); + for (int i = 0; i < unixGroups.length; i++) { + UnixNumericGroupPrincipal ngp = + new UnixNumericGroupPrincipal + (unixGroups[i], false); + if (!ngp.getName().equals(GIDPrincipal.getName())) + supplementaryGroups.add(ngp); + } + } + if (debug) { + System.out.println("\t\t[UnixLoginModule]: " + + "succeeded importing info: "); + System.out.println("\t\t\tuid = " + ss.getUid()); + System.out.println("\t\t\tgid = " + ss.getGid()); + unixGroups = ss.getGroups(); + for (int i = 0; i < unixGroups.length; i++) { + System.out.println("\t\t\tsupp gid = " + unixGroups[i]); + } + } + succeeded = true; + return true; + } + + /** + * Commit the authentication (second phase). + * + *

This method is called if the LoginContext's + * overall authentication succeeded + * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules + * succeeded). + * + *

If this LoginModule's own authentication attempt + * succeeded (the importing of the Unix authentication information + * succeeded), then this method associates the Unix Principals + * with the Subject currently tied to the + * LoginModule. If this LoginModule's + * authentication attempted failed, then this method removes + * any state that was originally saved. + * + *

+ * + * @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) { + if (debug) { + System.out.println("\t\t[UnixLoginModule]: " + + "did not add any Principals to Subject " + + "because own authentication failed."); + } + return false; + } else { + if (subject.isReadOnly()) { + throw new LoginException + ("commit Failed: Subject is Readonly"); + } + 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 + (supplementaryGroups.get(i))) + subject.getPrincipals().add(supplementaryGroups.get(i)); + } + + if (debug) { + System.out.println("\t\t[UnixLoginModule]: " + + "added UnixPrincipal,"); + System.out.println("\t\t\t\tUnixNumericUserPrincipal,"); + System.out.println("\t\t\t\tUnixNumericGroupPrincipal(s),"); + System.out.println("\t\t\t to Subject"); + } + + commitSucceeded = true; + return true; + } + } + + /** + * Abort the authentication (second phase). + * + *

This method is called if the LoginContext's + * overall authentication failed. + * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules + * did not succeed). + * + *

This method cleans up any state that was originally saved + * as part of the authentication attempt from the login + * and commit methods. + * + *

+ * + * @exception LoginException if the abort fails + * + * @return false if this LoginModule's own login and/or commit attempts + * failed, and true otherwise. + */ + public boolean abort() throws LoginException { + if (debug) { + System.out.println("\t\t[UnixLoginModule]: " + + "aborted authentication attempt"); + } + + if (succeeded == false) { + return false; + } else if (succeeded == true && commitSucceeded == false) { + + // Clean out state + succeeded = false; + ss = null; + userPrincipal = null; + UIDPrincipal = null; + GIDPrincipal = null; + supplementaryGroups = new LinkedList(); + } else { + // overall authentication succeeded and commit succeeded, + // but someone else's commit failed + logout(); + } + return true; + } + + /** + * Logout the user + * + *

This method removes the Principals associated + * with the Subject. + * + *

+ * + * @exception LoginException if the logout fails + * + * @return true in all cases (this LoginModule + * should not be ignored). + */ + public boolean logout() throws LoginException { + + if (subject.isReadOnly()) { + throw new LoginException + ("logout Failed: Subject is Readonly"); + } + // remove the added Principals from the Subject + subject.getPrincipals().remove(userPrincipal); + subject.getPrincipals().remove(UIDPrincipal); + subject.getPrincipals().remove(GIDPrincipal); + for (int i = 0; i < supplementaryGroups.size(); i++) { + subject.getPrincipals().remove(supplementaryGroups.get(i)); + } + + // clean out state + ss = null; + succeeded = false; + commitSucceeded = false; + userPrincipal = null; + UIDPrincipal = null; + GIDPrincipal = null; + supplementaryGroups = new LinkedList(); + + if (debug) { + System.out.println("\t\t[UnixLoginModule]: " + + "logged out Subject"); + } + return true; + } +}