Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/security/auth/login/LoginContext.java
38918 views
/*1* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.security.auth.login;2627import java.lang.reflect.Constructor;28import java.lang.reflect.Method;29import java.lang.reflect.InvocationTargetException;30import java.util.LinkedList;31import java.util.Map;32import java.util.HashMap;33import java.text.MessageFormat;34import javax.security.auth.Subject;35import javax.security.auth.AuthPermission;36import javax.security.auth.callback.*;37import java.security.AccessController;38import java.security.AccessControlContext;39import sun.security.util.PendingException;40import sun.security.util.ResourcesMgr;4142/**43* <p> The {@code LoginContext} class describes the basic methods used44* to authenticate Subjects and provides a way to develop an45* application independent of the underlying authentication technology.46* A {@code Configuration} specifies the authentication technology, or47* {@code LoginModule}, to be used with a particular application.48* Different LoginModules can be plugged in under an application49* without requiring any modifications to the application itself.50*51* <p> In addition to supporting <i>pluggable</i> authentication, this class52* also supports the notion of <i>stacked</i> authentication.53* Applications may be configured to use more than one54* LoginModule. For example, one could55* configure both a Kerberos LoginModule and a smart card56* LoginModule under an application.57*58* <p> A typical caller instantiates a LoginContext with59* a <i>name</i> and a {@code CallbackHandler}.60* LoginContext uses the <i>name</i> as the index into a61* Configuration to determine which LoginModules should be used,62* and which ones must succeed in order for the overall authentication to63* succeed. The {@code CallbackHandler} is passed to the underlying64* LoginModules so they may communicate and interact with users65* (prompting for a username and password via a graphical user interface,66* for example).67*68* <p> Once the caller has instantiated a LoginContext,69* it invokes the {@code login} method to authenticate70* a {@code Subject}. The {@code login} method invokes71* the configured modules to perform their respective types of authentication72* (username/password, smart card pin verification, etc.).73* Note that the LoginModules will not attempt authentication retries nor74* introduce delays if the authentication fails.75* Such tasks belong to the LoginContext caller.76*77* <p> If the {@code login} method returns without78* throwing an exception, then the overall authentication succeeded.79* The caller can then retrieve80* the newly authenticated Subject by invoking the81* {@code getSubject} method. Principals and Credentials associated82* with the Subject may be retrieved by invoking the Subject's83* respective {@code getPrincipals}, {@code getPublicCredentials},84* and {@code getPrivateCredentials} methods.85*86* <p> To logout the Subject, the caller calls87* the {@code logout} method. As with the {@code login}88* method, this {@code logout} method invokes the {@code logout}89* method for the configured modules.90*91* <p> A LoginContext should not be used to authenticate92* more than one Subject. A separate LoginContext93* should be used to authenticate each different Subject.94*95* <p> The following documentation applies to all LoginContext constructors:96* <ol>97*98* <li> {@code Subject}99* <ul>100* <li> If the constructor has a Subject101* input parameter, the LoginContext uses the caller-specified102* Subject object.103*104* <li> If the caller specifies a {@code null} Subject105* and a {@code null} value is permitted,106* the LoginContext instantiates a new Subject.107*108* <li> If the constructor does <b>not</b> have a Subject109* input parameter, the LoginContext instantiates a new Subject.110* <p>111* </ul>112*113* <li> {@code Configuration}114* <ul>115* <li> If the constructor has a Configuration116* input parameter and the caller specifies a non-null Configuration,117* the LoginContext uses the caller-specified Configuration.118* <p>119* If the constructor does <b>not</b> have a Configuration120* input parameter, or if the caller specifies a {@code null}121* Configuration object, the constructor uses the following call to122* get the installed Configuration:123* <pre>124* config = Configuration.getConfiguration();125* </pre>126* For both cases,127* the <i>name</i> argument given to the constructor is passed to the128* {@code Configuration.getAppConfigurationEntry} method.129* If the Configuration has no entries for the specified <i>name</i>,130* then the {@code LoginContext} calls131* {@code getAppConfigurationEntry} with the name, "<i>other</i>"132* (the default entry name). If there is no entry for "<i>other</i>",133* then a {@code LoginException} is thrown.134*135* <li> When LoginContext uses the installed Configuration, the caller136* requires the createLoginContext.<em>name</em> and possibly137* createLoginContext.other AuthPermissions. Furthermore, the138* LoginContext will invoke configured modules from within an139* {@code AccessController.doPrivileged} call so that modules that140* perform security-sensitive tasks (such as connecting to remote hosts,141* and updating the Subject) will require the respective permissions, but142* the callers of the LoginContext will not require those permissions.143*144* <li> When LoginContext uses a caller-specified Configuration, the caller145* does not require any createLoginContext AuthPermission. The LoginContext146* saves the {@code AccessControlContext} for the caller,147* and invokes the configured modules from within an148* {@code AccessController.doPrivileged} call constrained by that context.149* This means the caller context (stored when the LoginContext was created)150* must have sufficient permissions to perform any security-sensitive tasks151* that the modules may perform.152* <p>153* </ul>154*155* <li> {@code CallbackHandler}156* <ul>157* <li> If the constructor has a CallbackHandler158* input parameter, the LoginContext uses the caller-specified159* CallbackHandler object.160*161* <li> If the constructor does <b>not</b> have a CallbackHandler162* input parameter, or if the caller specifies a {@code null}163* CallbackHandler object (and a {@code null} value is permitted),164* the LoginContext queries the165* {@code auth.login.defaultCallbackHandler} security property for the166* fully qualified class name of a default handler167* implementation. If the security property is not set,168* then the underlying modules will not have a169* CallbackHandler for use in communicating170* with users. The caller thus assumes that the configured171* modules have alternative means for authenticating the user.172*173*174* <li> When the LoginContext uses the installed Configuration (instead of175* a caller-specified Configuration, see above),176* then this LoginContext must wrap any177* caller-specified or default CallbackHandler implementation178* in a new CallbackHandler implementation179* whose {@code handle} method implementation invokes the180* specified CallbackHandler's {@code handle} method in a181* {@code java.security.AccessController.doPrivileged} call182* constrained by the caller's current {@code AccessControlContext}.183* </ul>184* </ol>185*186* @see java.security.Security187* @see javax.security.auth.AuthPermission188* @see javax.security.auth.Subject189* @see javax.security.auth.callback.CallbackHandler190* @see javax.security.auth.login.Configuration191* @see javax.security.auth.spi.LoginModule192* @see java.security.Security security properties193*/194public class LoginContext {195196private static final String INIT_METHOD = "initialize";197private static final String LOGIN_METHOD = "login";198private static final String COMMIT_METHOD = "commit";199private static final String ABORT_METHOD = "abort";200private static final String LOGOUT_METHOD = "logout";201private static final String OTHER = "other";202private static final String DEFAULT_HANDLER =203"auth.login.defaultCallbackHandler";204private Subject subject = null;205private boolean subjectProvided = false;206private boolean loginSucceeded = false;207private CallbackHandler callbackHandler;208private Map<String,?> state = new HashMap<String,Object>();209210private Configuration config;211private AccessControlContext creatorAcc = null; // customized config only212private ModuleInfo[] moduleStack;213private ClassLoader contextClassLoader = null;214private static final Class<?>[] PARAMS = { };215216// state saved in the event a user-specified asynchronous exception217// was specified and thrown218219private int moduleIndex = 0;220private LoginException firstError = null;221private LoginException firstRequiredError = null;222private boolean success = false;223224private static final sun.security.util.Debug debug =225sun.security.util.Debug.getInstance("logincontext", "\t[LoginContext]");226227private void init(String name) throws LoginException {228229SecurityManager sm = System.getSecurityManager();230if (sm != null && creatorAcc == null) {231sm.checkPermission(new AuthPermission232("createLoginContext." + name));233}234235if (name == null)236throw new LoginException237(ResourcesMgr.getString("Invalid.null.input.name"));238239// get the Configuration240if (config == null) {241config = java.security.AccessController.doPrivileged242(new java.security.PrivilegedAction<Configuration>() {243public Configuration run() {244return Configuration.getConfiguration();245}246});247}248249// get the LoginModules configured for this application250AppConfigurationEntry[] entries = config.getAppConfigurationEntry(name);251if (entries == null) {252253if (sm != null && creatorAcc == null) {254sm.checkPermission(new AuthPermission255("createLoginContext." + OTHER));256}257258entries = config.getAppConfigurationEntry(OTHER);259if (entries == null) {260MessageFormat form = new MessageFormat(ResourcesMgr.getString261("No.LoginModules.configured.for.name"));262Object[] source = {name};263throw new LoginException(form.format(source));264}265}266moduleStack = new ModuleInfo[entries.length];267for (int i = 0; i < entries.length; i++) {268// clone returned array269moduleStack[i] = new ModuleInfo270(new AppConfigurationEntry271(entries[i].getLoginModuleName(),272entries[i].getControlFlag(),273entries[i].getOptions()),274null);275}276277contextClassLoader = java.security.AccessController.doPrivileged278(new java.security.PrivilegedAction<ClassLoader>() {279public ClassLoader run() {280ClassLoader loader =281Thread.currentThread().getContextClassLoader();282if (loader == null) {283// Don't use bootstrap class loader directly to ensure284// proper package access control!285loader = ClassLoader.getSystemClassLoader();286}287288return loader;289}290});291}292293private void loadDefaultCallbackHandler() throws LoginException {294295// get the default handler class296try {297298final ClassLoader finalLoader = contextClassLoader;299300this.callbackHandler = java.security.AccessController.doPrivileged(301new java.security.PrivilegedExceptionAction<CallbackHandler>() {302public CallbackHandler run() throws Exception {303String defaultHandler = java.security.Security.getProperty304(DEFAULT_HANDLER);305if (defaultHandler == null || defaultHandler.length() == 0)306return null;307Class<? extends CallbackHandler> c = Class.forName(308defaultHandler, true,309finalLoader).asSubclass(CallbackHandler.class);310return c.newInstance();311}312});313} catch (java.security.PrivilegedActionException pae) {314throw new LoginException(pae.getException().toString());315}316317// secure it with the caller's ACC318if (this.callbackHandler != null && creatorAcc == null) {319this.callbackHandler = new SecureCallbackHandler320(java.security.AccessController.getContext(),321this.callbackHandler);322}323}324325/**326* Instantiate a new {@code LoginContext} object with a name.327*328* @param name the name used as the index into the329* {@code Configuration}.330*331* @exception LoginException if the caller-specified {@code name}332* does not appear in the {@code Configuration}333* and there is no {@code Configuration} entry334* for "<i>other</i>", or if the335* <i>auth.login.defaultCallbackHandler</i>336* security property was set, but the implementation337* class could not be loaded.338* <p>339* @exception SecurityException if a SecurityManager is set and340* the caller does not have341* AuthPermission("createLoginContext.<i>name</i>"),342* or if a configuration entry for <i>name</i> does not exist and343* the caller does not additionally have344* AuthPermission("createLoginContext.other")345*/346public LoginContext(String name) throws LoginException {347init(name);348loadDefaultCallbackHandler();349}350351/**352* Instantiate a new {@code LoginContext} object with a name353* and a {@code Subject} object.354*355* <p>356*357* @param name the name used as the index into the358* {@code Configuration}. <p>359*360* @param subject the {@code Subject} to authenticate.361*362* @exception LoginException if the caller-specified {@code name}363* does not appear in the {@code Configuration}364* and there is no {@code Configuration} entry365* for "<i>other</i>", if the caller-specified {@code subject}366* is {@code null}, or if the367* <i>auth.login.defaultCallbackHandler</i>368* security property was set, but the implementation369* class could not be loaded.370* <p>371* @exception SecurityException if a SecurityManager is set and372* the caller does not have373* AuthPermission("createLoginContext.<i>name</i>"),374* or if a configuration entry for <i>name</i> does not exist and375* the caller does not additionally have376* AuthPermission("createLoginContext.other")377*/378public LoginContext(String name, Subject subject)379throws LoginException {380init(name);381if (subject == null)382throw new LoginException383(ResourcesMgr.getString("invalid.null.Subject.provided"));384this.subject = subject;385subjectProvided = true;386loadDefaultCallbackHandler();387}388389/**390* Instantiate a new {@code LoginContext} object with a name391* and a {@code CallbackHandler} object.392*393* <p>394*395* @param name the name used as the index into the396* {@code Configuration}. <p>397*398* @param callbackHandler the {@code CallbackHandler} object used by399* LoginModules to communicate with the user.400*401* @exception LoginException if the caller-specified {@code name}402* does not appear in the {@code Configuration}403* and there is no {@code Configuration} entry404* for "<i>other</i>", or if the caller-specified405* {@code callbackHandler} is {@code null}.406* <p>407* @exception SecurityException if a SecurityManager is set and408* the caller does not have409* AuthPermission("createLoginContext.<i>name</i>"),410* or if a configuration entry for <i>name</i> does not exist and411* the caller does not additionally have412* AuthPermission("createLoginContext.other")413*/414public LoginContext(String name, CallbackHandler callbackHandler)415throws LoginException {416init(name);417if (callbackHandler == null)418throw new LoginException(ResourcesMgr.getString419("invalid.null.CallbackHandler.provided"));420this.callbackHandler = new SecureCallbackHandler421(java.security.AccessController.getContext(),422callbackHandler);423}424425/**426* Instantiate a new {@code LoginContext} object with a name,427* a {@code Subject} to be authenticated, and a428* {@code CallbackHandler} object.429*430* <p>431*432* @param name the name used as the index into the433* {@code Configuration}. <p>434*435* @param subject the {@code Subject} to authenticate. <p>436*437* @param callbackHandler the {@code CallbackHandler} object used by438* LoginModules to communicate with the user.439*440* @exception LoginException if the caller-specified {@code name}441* does not appear in the {@code Configuration}442* and there is no {@code Configuration} entry443* for "<i>other</i>", or if the caller-specified444* {@code subject} is {@code null},445* or if the caller-specified446* {@code callbackHandler} is {@code null}.447* <p>448* @exception SecurityException if a SecurityManager is set and449* the caller does not have450* AuthPermission("createLoginContext.<i>name</i>"),451* or if a configuration entry for <i>name</i> does not exist and452* the caller does not additionally have453* AuthPermission("createLoginContext.other")454*/455public LoginContext(String name, Subject subject,456CallbackHandler callbackHandler) throws LoginException {457this(name, subject);458if (callbackHandler == null)459throw new LoginException(ResourcesMgr.getString460("invalid.null.CallbackHandler.provided"));461this.callbackHandler = new SecureCallbackHandler462(java.security.AccessController.getContext(),463callbackHandler);464}465466/**467* Instantiate a new {@code LoginContext} object with a name,468* a {@code Subject} to be authenticated,469* a {@code CallbackHandler} object, and a login470* {@code Configuration}.471*472* <p>473*474* @param name the name used as the index into the caller-specified475* {@code Configuration}. <p>476*477* @param subject the {@code Subject} to authenticate,478* or {@code null}. <p>479*480* @param callbackHandler the {@code CallbackHandler} object used by481* LoginModules to communicate with the user, or {@code null}.482* <p>483*484* @param config the {@code Configuration} that lists the485* login modules to be called to perform the authentication,486* or {@code null}.487*488* @exception LoginException if the caller-specified {@code name}489* does not appear in the {@code Configuration}490* and there is no {@code Configuration} entry491* for "<i>other</i>".492* <p>493* @exception SecurityException if a SecurityManager is set,494* <i>config</i> is {@code null},495* and either the caller does not have496* AuthPermission("createLoginContext.<i>name</i>"),497* or if a configuration entry for <i>name</i> does not exist and498* the caller does not additionally have499* AuthPermission("createLoginContext.other")500*501* @since 1.5502*/503public LoginContext(String name, Subject subject,504CallbackHandler callbackHandler,505Configuration config) throws LoginException {506this.config = config;507if (config != null) {508creatorAcc = java.security.AccessController.getContext();509}510511init(name);512if (subject != null) {513this.subject = subject;514subjectProvided = true;515}516if (callbackHandler == null) {517loadDefaultCallbackHandler();518} else if (creatorAcc == null) {519this.callbackHandler = new SecureCallbackHandler520(java.security.AccessController.getContext(),521callbackHandler);522} else {523this.callbackHandler = callbackHandler;524}525}526527/**528* Perform the authentication.529*530* <p> This method invokes the {@code login} method for each531* LoginModule configured for the <i>name</i> specified to the532* {@code LoginContext} constructor, as determined by the login533* {@code Configuration}. Each {@code LoginModule}534* then performs its respective type of authentication535* (username/password, smart card pin verification, etc.).536*537* <p> This method completes a 2-phase authentication process by538* calling each configured LoginModule's {@code commit} method539* if the overall authentication succeeded (the relevant REQUIRED,540* REQUISITE, SUFFICIENT, and OPTIONAL LoginModules succeeded),541* or by calling each configured LoginModule's {@code abort} method542* if the overall authentication failed. If authentication succeeded,543* each successful LoginModule's {@code commit} method associates544* the relevant Principals and Credentials with the {@code Subject}.545* If authentication failed, each LoginModule's {@code abort} method546* removes/destroys any previously stored state.547*548* <p> If the {@code commit} phase of the authentication process549* fails, then the overall authentication fails and this method550* invokes the {@code abort} method for each configured551* {@code LoginModule}.552*553* <p> If the {@code abort} phase554* fails for any reason, then this method propagates the555* original exception thrown either during the {@code login} phase556* or the {@code commit} phase. In either case, the overall557* authentication fails.558*559* <p> In the case where multiple LoginModules fail,560* this method propagates the exception raised by the first561* {@code LoginModule} which failed.562*563* <p> Note that if this method enters the {@code abort} phase564* (either the {@code login} or {@code commit} phase failed),565* this method invokes all LoginModules configured for the566* application regardless of their respective {@code Configuration}567* flag parameters. Essentially this means that {@code Requisite}568* and {@code Sufficient} semantics are ignored during the569* {@code abort} phase. This guarantees that proper cleanup570* and state restoration can take place.571*572* <p>573*574* @exception LoginException if the authentication fails.575*/576public void login() throws LoginException {577578loginSucceeded = false;579580if (subject == null) {581subject = new Subject();582}583584try {585// module invoked in doPrivileged586invokePriv(LOGIN_METHOD);587invokePriv(COMMIT_METHOD);588loginSucceeded = true;589} catch (LoginException le) {590try {591invokePriv(ABORT_METHOD);592} catch (LoginException le2) {593throw le;594}595throw le;596}597}598599/**600* Logout the {@code Subject}.601*602* <p> This method invokes the {@code logout} method for each603* {@code LoginModule} configured for this {@code LoginContext}.604* Each {@code LoginModule} performs its respective logout procedure605* which may include removing/destroying606* {@code Principal} and {@code Credential} information607* from the {@code Subject} and state cleanup.608*609* <p> Note that this method invokes all LoginModules configured for the610* application regardless of their respective611* {@code Configuration} flag parameters. Essentially this means612* that {@code Requisite} and {@code Sufficient} semantics are613* ignored for this method. This guarantees that proper cleanup614* and state restoration can take place.615*616* <p>617*618* @exception LoginException if the logout fails.619*/620public void logout() throws LoginException {621if (subject == null) {622throw new LoginException(ResourcesMgr.getString623("null.subject.logout.called.before.login"));624}625626// module invoked in doPrivileged627invokePriv(LOGOUT_METHOD);628}629630/**631* Return the authenticated Subject.632*633* <p>634*635* @return the authenticated Subject. If the caller specified a636* Subject to this LoginContext's constructor,637* this method returns the caller-specified Subject.638* If a Subject was not specified and authentication succeeds,639* this method returns the Subject instantiated and used for640* authentication by this LoginContext.641* If a Subject was not specified, and authentication fails or642* has not been attempted, this method returns null.643*/644public Subject getSubject() {645if (!loginSucceeded && !subjectProvided)646return null;647return subject;648}649650private void clearState() {651moduleIndex = 0;652firstError = null;653firstRequiredError = null;654success = false;655}656657private void throwException(LoginException originalError, LoginException le)658throws LoginException {659660// first clear state661clearState();662663// throw the exception664LoginException error = (originalError != null) ? originalError : le;665throw error;666}667668/**669* Invokes the login, commit, and logout methods670* from a LoginModule inside a doPrivileged block restricted671* by creatorAcc (may be null).672*673* This version is called if the caller did not instantiate674* the LoginContext with a Configuration object.675*/676private void invokePriv(final String methodName) throws LoginException {677try {678java.security.AccessController.doPrivileged679(new java.security.PrivilegedExceptionAction<Void>() {680public Void run() throws LoginException {681invoke(methodName);682return null;683}684}, creatorAcc);685} catch (java.security.PrivilegedActionException pae) {686throw (LoginException)pae.getException();687}688}689690private void invoke(String methodName) throws LoginException {691692// start at moduleIndex693// - this can only be non-zero if methodName is LOGIN_METHOD694695for (int i = moduleIndex; i < moduleStack.length; i++, moduleIndex++) {696try {697698int mIndex = 0;699Method[] methods = null;700701if (moduleStack[i].module != null) {702methods = moduleStack[i].module.getClass().getMethods();703} else {704705// instantiate the LoginModule706//707// Allow any object to be a LoginModule as long as it708// conforms to the interface.709Class<?> c = Class.forName(710moduleStack[i].entry.getLoginModuleName(),711true,712contextClassLoader);713714Constructor<?> constructor = c.getConstructor(PARAMS);715Object[] args = { };716moduleStack[i].module = constructor.newInstance(args);717718// call the LoginModule's initialize method719methods = moduleStack[i].module.getClass().getMethods();720for (mIndex = 0; mIndex < methods.length; mIndex++) {721if (methods[mIndex].getName().equals(INIT_METHOD)) {722break;723}724}725726Object[] initArgs = {subject,727callbackHandler,728state,729moduleStack[i].entry.getOptions() };730// invoke the LoginModule initialize method731//732// Throws ArrayIndexOutOfBoundsException if no such733// method defined. May improve to use LoginException in734// the future.735methods[mIndex].invoke(moduleStack[i].module, initArgs);736}737738// find the requested method in the LoginModule739for (mIndex = 0; mIndex < methods.length; mIndex++) {740if (methods[mIndex].getName().equals(methodName)) {741break;742}743}744745// set up the arguments to be passed to the LoginModule method746Object[] args = { };747748// invoke the LoginModule method749//750// Throws ArrayIndexOutOfBoundsException if no such751// method defined. May improve to use LoginException in752// the future.753boolean status = ((Boolean)methods[mIndex].invoke754(moduleStack[i].module, args)).booleanValue();755756if (status == true) {757758// if SUFFICIENT, return if no prior REQUIRED errors759if (!methodName.equals(ABORT_METHOD) &&760!methodName.equals(LOGOUT_METHOD) &&761moduleStack[i].entry.getControlFlag() ==762AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT &&763firstRequiredError == null) {764765// clear state766clearState();767768if (debug != null)769debug.println(methodName + " SUFFICIENT success");770return;771}772773if (debug != null)774debug.println(methodName + " success");775success = true;776} else {777if (debug != null)778debug.println(methodName + " ignored");779}780781} catch (NoSuchMethodException nsme) {782MessageFormat form = new MessageFormat(ResourcesMgr.getString783("unable.to.instantiate.LoginModule.module.because.it.does.not.provide.a.no.argument.constructor"));784Object[] source = {moduleStack[i].entry.getLoginModuleName()};785throwException(null, new LoginException(form.format(source)));786} catch (InstantiationException ie) {787throwException(null, new LoginException(ResourcesMgr.getString788("unable.to.instantiate.LoginModule.") +789ie.getMessage()));790} catch (ClassNotFoundException cnfe) {791throwException(null, new LoginException(ResourcesMgr.getString792("unable.to.find.LoginModule.class.") +793cnfe.getMessage()));794} catch (IllegalAccessException iae) {795throwException(null, new LoginException(ResourcesMgr.getString796("unable.to.access.LoginModule.") +797iae.getMessage()));798} catch (InvocationTargetException ite) {799800// failure cases801802LoginException le;803804if (ite.getCause() instanceof PendingException &&805methodName.equals(LOGIN_METHOD)) {806807// XXX808//809// if a module's LOGIN_METHOD threw a PendingException810// then immediately throw it.811//812// when LoginContext is called again,813// the module that threw the exception is invoked first814// (the module list is not invoked from the start).815// previously thrown exception state is still present.816//817// it is assumed that the module which threw818// the exception can have its819// LOGIN_METHOD invoked twice in a row820// without any commit/abort in between.821//822// in all cases when LoginContext returns823// (either via natural return or by throwing an exception)824// we need to call clearState before returning.825// the only time that is not true is in this case -826// do not call throwException here.827828throw (PendingException)ite.getCause();829830} else if (ite.getCause() instanceof LoginException) {831832le = (LoginException)ite.getCause();833834} else if (ite.getCause() instanceof SecurityException) {835836// do not want privacy leak837// (e.g., sensitive file path in exception msg)838839le = new LoginException("Security Exception");840le.initCause(new SecurityException());841if (debug != null) {842debug.println843("original security exception with detail msg " +844"replaced by new exception with empty detail msg");845debug.println("original security exception: " +846ite.getCause().toString());847}848} else {849850// capture an unexpected LoginModule exception851java.io.StringWriter sw = new java.io.StringWriter();852ite.getCause().printStackTrace853(new java.io.PrintWriter(sw));854sw.flush();855le = new LoginException(sw.toString());856}857858if (moduleStack[i].entry.getControlFlag() ==859AppConfigurationEntry.LoginModuleControlFlag.REQUISITE) {860861if (debug != null)862debug.println(methodName + " REQUISITE failure");863864// if REQUISITE, then immediately throw an exception865if (methodName.equals(ABORT_METHOD) ||866methodName.equals(LOGOUT_METHOD)) {867if (firstRequiredError == null)868firstRequiredError = le;869} else {870throwException(firstRequiredError, le);871}872873} else if (moduleStack[i].entry.getControlFlag() ==874AppConfigurationEntry.LoginModuleControlFlag.REQUIRED) {875876if (debug != null)877debug.println(methodName + " REQUIRED failure");878879// mark down that a REQUIRED module failed880if (firstRequiredError == null)881firstRequiredError = le;882883} else {884885if (debug != null)886debug.println(methodName + " OPTIONAL failure");887888// mark down that an OPTIONAL module failed889if (firstError == null)890firstError = le;891}892}893}894895// we went thru all the LoginModules.896if (firstRequiredError != null) {897// a REQUIRED module failed -- return the error898throwException(firstRequiredError, null);899} else if (success == false && firstError != null) {900// no module succeeded -- return the first error901throwException(firstError, null);902} else if (success == false) {903// no module succeeded -- all modules were IGNORED904throwException(new LoginException905(ResourcesMgr.getString("Login.Failure.all.modules.ignored")),906null);907} else {908// success909910clearState();911return;912}913}914915/**916* Wrap the caller-specified CallbackHandler in our own917* and invoke it within a privileged block, constrained by918* the caller's AccessControlContext.919*/920private static class SecureCallbackHandler implements CallbackHandler {921922private final java.security.AccessControlContext acc;923private final CallbackHandler ch;924925SecureCallbackHandler(java.security.AccessControlContext acc,926CallbackHandler ch) {927this.acc = acc;928this.ch = ch;929}930931public void handle(final Callback[] callbacks)932throws java.io.IOException, UnsupportedCallbackException {933try {934java.security.AccessController.doPrivileged935(new java.security.PrivilegedExceptionAction<Void>() {936public Void run() throws java.io.IOException,937UnsupportedCallbackException {938ch.handle(callbacks);939return null;940}941}, acc);942} catch (java.security.PrivilegedActionException pae) {943if (pae.getException() instanceof java.io.IOException) {944throw (java.io.IOException)pae.getException();945} else {946throw (UnsupportedCallbackException)pae.getException();947}948}949}950}951952/**953* LoginModule information -954* incapsulates Configuration info and actual module instances955*/956private static class ModuleInfo {957AppConfigurationEntry entry;958Object module;959960ModuleInfo(AppConfigurationEntry newEntry, Object newModule) {961this.entry = newEntry;962this.module = newModule;963}964}965}966967968