AMLoginModule.java revision 5b9e6d4a0eba36a50745ce2f68b4da88dda4ca46
/**
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2005 Sun Microsystems Inc. All Rights Reserved
*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at opensso/legal/CDDLv1.0.txt.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* $Id: AMLoginModule.java,v 1.22 2009/11/21 01:11:56 222713 Exp $
*
*/
/*
* Portions Copyrighted 2010-2015 ForgeRock AS.
*/
/**
* An abstract class which implements JAAS LoginModule, it provides
* methods to access OpenAM services and the module
* xml configuration.
* <p>
* Because it is an abstract class, Login Module writers must subclass
* and implement init(), process(), getPrincipal() methods.
* <p>
* The Callback[] for the Login Module is dynamically generated based
* on the xml module configuration. The module configuration file name
* must be the same as the name of the class (no package name) and have the
* extension .xml.
* <p>
* Here is a sample module configuration file:
* <pre>
* <ModuleProperties moduleClass="LDAP" version="1.0" >
* <Callbacks length="2" order="1" timeout="60" header="LDAP
* Authentication" >
* <NameCallback>
* <Prompt> Enter UserId </Prompt>
* </NameCallback>
* <PasswordCallback echoPassword="false" >
* <Prompt> Enter Password </Prompt>
* </PasswordCallback>
* </Callbacks>
* <Callbacks length="3" order="2" timeout="120" header="Password
* Expiring Please Change" >
* <PasswordCallback echoPassword="false" >
* <Prompt> Enter Current Password </Prompt>
* </PasswordCallback>
* <PasswordCallback echoPassword="false" >
* <Prompt> Enter New Password </Prompt>
* </PasswordCallback>
* <PasswordCallback echoPassword="false" >
* <Prompt> Confirm New Password </Prompt>
* </PasswordCallback>
* </Callbacks>
* </ModuleProperties>
* </pre>
* Each Callbacks Element corresponds to one login state.
* When an authentication process is invoked, there will be Callback[]
* generated from user's Login Module for each state. All login state
* starts with 1, then module controls the login process, and decides what's
* the next state to go in the process() method.
* <p>
* In the sample module configuration shown above, state one has
* three Callbacks, Callback[0] is for module information, Callback[1] is
* for user ID, Callback[2] is for user password. When the user fills in the
* Callbacks, those Callback[] will be sent to the process() method, where
* the module writer gets the submitted Callbacks, validates them and returns.
* If user's password is expiring, the module writer will set the next
* state to 2. State two has four Callbacks to request user to change
* password. The process() routine is again
* called after user submits the Callback[]. If the module writer throws an
* LoginException, an 'authentication failed' page will be sent to the user.
* If no exception is thrown, the user will be redirected to their default
* page.
* <p>
* The optional 'timeout' attribute in each state is used to ensure that the
* user responds in a timely manner. If the time between sending the Callbacks
* and getting response is greater than the timeout, a timeout page will be
* sent.
* <p>
* There are also optional 'html' and 'image' attribute in each state. The
* 'html' attribute allows the module writer to use a custom HTML
* page for the Login UI. The 'image' attribute allows the writer to display
* a custom background image on each page.
* <p>
* When multiple states are available to the user, the Callback array from a
* previous state may be retrieved by using the <code>getCallbak(int)</code>
* methods. The underlying login module keeps the Callback[] from the previous
* states until the login process is completed.
* <p>
* If a module writer need to substitute dynamic text in next state, the writer
* could use the <code>getCallback()</code> method to get the Callback[] for the
* next state, modify the output text or prompt, then call
* <code>replaceCallback()</code> to update the Callback array. This allows a
* module writer to dynamically generate challenges, passwords or user IDs.
* <p>
* Each authentication session will create a new instance of your
* Login Module Java class. The reference to the class will be
* released once the authentication session has either succeeded
* or failed. It is important to note that any static data or
* reference to any static data in your Login module
* must be thread-safe.
* <p>
*
* For a complete sample, please refer to
* <install_root>/SUNWam/samples/authentication/providers
*
* @supported.api
*/
public abstract class AMLoginModule implements LoginModule {
// list which holds both presentation and credential callbacks
// list which holds only credential callbacks
// list which contains the original Callback list from AMModuleProperties
// class name
// if true, means this module does not hava any Callbacks defined, this
boolean noCallbacks = false;
// constant for empty Callback array
// state length for this module
private int stateLength = 0;
// resource bundle
// login state
/**
* Holds callback handler object passed in through initialize method
*/
/**
* Holds subject object passed in through initialize method
*/
/**
* Holds shared state map passed in through initialize method
*/
/**
* Holds options map passed in through initialize method
*/
// the authentication status
private boolean succeeded = false;
private boolean forceCallbacksRead = false;
//use Shared state by default disabled
private boolean isSharedState = false;
private boolean isStore = true;
// variable used in replaceHeader()
private String headerWithReplaceTag;
private boolean alreadyReplaced = false;
private int lastState = 0;
/**
* Holds handle to ResourceBundleCache to quickly get ResourceBundle for
* any Locale.
*/
protected static AMResourceBundleCache amCache =
protected final AuthenticationModuleEventAuditor auditor;
/**
* No argument constructor for {@link AMLoginModule}.
*/
public AMLoginModule() {
}
/**
* callbacks list. External callback contains all user defined
* Callbacks in the xml module configuration (property file),
* internal callback contains the external callbacks plus the
* PagePropertiesCallback. Note here, although
* instance they pointed are actually same instance
* @param index indicates state of callback
* @param original original array of callback to be cloned
* @return Callback[] returns cloned callback
* @exception AuthLoginException if callback can not be cloned
*/
throws AuthLoginException {
// check if there is any callbacks in original
// this is the error case where there is no Callbacks
// defined for a state
}
// Callback array which hold the cloned Callbacks
// List which contains the external callbacks only
// iterate through Callback array, and copy them one by one
// if it is an external Callback, add to the extCallback list
for (int i = 0; i < len; i++) {
if (original[i] instanceof HiddenValueCallback) {
copy[i] = new HiddenValueCallback(
} else {
copy[i] = new HiddenValueCallback(
}
if (debug.messageEnabled()) {
}
} else if (original[i] instanceof NameCallback) {
copy[i] = new NameCallback(
} else {
copy[i] = new NameCallback(
}
if (debug.messageEnabled()) {
}
} else if (original[i] instanceof PasswordCallback) {
copy[i] = new PasswordCallback(
if (debug.messageEnabled()) {
}
} else if (original[i] instanceof ScriptTextOutputCallback) {
copy[i] = new ScriptTextOutputCallback(
if (debug.messageEnabled()) {
}
} else if (original[i] instanceof TextOutputCallback) {
copy[i] = new TextOutputCallback(
if (debug.messageEnabled()) {
}
} else if (original[i] instanceof PagePropertiesCallback) {
// PagePropertiesCallback, no need to add to external callbacks
copy[i] = new PagePropertiesCallback(
if (debug.messageEnabled()) {
}
} else if (original[i] instanceof ChoiceCallback) {
} else {
}
}
if (debug.messageEnabled()) {
}
} else if (original[i] instanceof ConfirmationCallback) {
// no prompt
// no options
copy[i] = new ConfirmationCallback(
temp.getDefaultOption());
} else {
copy[i] = new ConfirmationCallback(
temp.getDefaultOption());
}
} else {
// has prompt
// no options
copy[i] = new ConfirmationCallback(
temp.getDefaultOption());
} else {
copy[i] = new ConfirmationCallback(
temp.getDefaultOption());
}
}
if (debug.messageEnabled()) {
}
} else if (original[i] instanceof TextInputCallback) {
copy[i] = new TextInputCallback(
if (debug.messageEnabled()) {
}
} else if (original[i] instanceof HttpCallback) {
hc.getNegotiationCode());
} else if (original[i] instanceof RedirectCallback) {
} else {
}
// more callbacks need to be handled here if ...
}
// construct external Callback[]
if (!extCallbacks.isEmpty()) {
int i = 0;
}
}
return ext;
}
/**
* Returns an administration SSOToken for use the OpenAM APIs.
*
* <I>NB:</I>This is not the SSOToken that represents the user, if you wish
* and <code>getUserSessionProperty</code> method respectively.
*
* @return An administrative <code>SSOToken</code>.
* @exception AuthLoginException if the authentication SSO session
* is null.
* @supported.api
*/
}
return sess;
}
/**
* Returns a Callback array for a specific state.
* <p>
* This method can be used to retrieve Callback[] for any state. All
* previous submitted Callback[] information are kept until the login
* process is completed.
* @param index order of state
* @return Callback array for this state, return 0-length Callback array
* if there is no Callback defined for this state
* @throws AuthLoginException if unable to read the callbacks
* @supported.api
*/
return getCallback(index, false);
}
/**
* Return a Callback array for a specific state.
* <p>
* This method can be used to retrieve Callback[] for any state. All
* previous submitted Callback[] information are kept until the login
* process is completed.
* @param index order of state
* @param fetchOrig boolean indicating even if the callbacks for this
* state have been previously retrieved, get the original callbacks
* from AMModuleProperties, if set to "true".
* @return Callback array for this state, return 0-length Callback array
* if there is no Callback defined for this state
* @throws AuthLoginException if unable to read the callbacks
* @supported.api
*/
throws AuthLoginException
{
// This method will be called by customer module, so it will
// return Callback[] from external callback List
// check if there is no callbacks defined for this module
return EMPTY_CALLBACK;
}
return EMPTY_CALLBACK;
}
if (debug.messageEnabled()) {
}
}
// get Callback[] for this page
// use index-1 as order since page index starts with 1
if (index > stateLength) {
// invalid login state
}
}
// callbacks has not been retrieved for this index yet
// need to get it from AMModuleProperties
// since the Callbacks could not be shared by different instances
// we need to create clone copy here
}
protected void forceCallbacksInit () throws AuthLoginException {
// get the callbacks for this class;
// we got file whose size is zero, this is the case for
noCallbacks = true;
return;
}
if (debug.messageEnabled()) {
}
for (int i = 0; i < stateLength; i++) {
}
}
}
/**
* Replace Callback object for a specific state.
* @param state Order of login state
* @param index Index of Callback in the Callback array to be replaced
* for the specified state. Here index starts with 0, i.e. 0 means the
* first Callback in the Callback[], 1 means the second callback.
* @param callback Callback instance to be replaced
* @exception AuthLoginException if state or index is out of
* bound, or callback instance is null.
* @supported.api
*/
throws AuthLoginException {
if (debug.messageEnabled()) {
}
// check state length
if (state > stateLength) {
}
// check callback length for the state
}
// check callback instance
}
// replace callback in external & internal Callback array
// in internal, first Callback is always PagePropertiesCallback
// so add one here for the index
}
/**
* Replace page header for a specific state.
* @param state Order of login state
* @param header header messages to be replaced
* @throws AuthLoginException if state is out of bound.
*/
throws AuthLoginException {
if (debug.messageEnabled()) {
header);
}
alreadyReplaced = false;
}
// check state length
if (state > stateLength) {
}
// check callback length for the state
null);
}
// in internal, first Callback is always PagePropertiesCallback
// retrieve header with REPLACE tag
if ( !(alreadyReplaced) ) {
}
// replace string
if (idx != -1) {
alreadyReplaced = true;
}else{
}
}
}
/**
* Allows you to set the info text for a specific callback. Info Text is shown
* under the element in the Login page. It is used in the membership module to
* implement in-line feedback.
*
* @param state state in which the Callback[] to be reset
* @param callback the callback to associate the info text
* @param infoText the infotext for the callback
* @supported.api
*/
throws AuthLoginException {
if (debug.messageEnabled()) {
}
// check state length
if (state > stateLength) {
}
// check callback length for the state
}
// in internal, first Callback is always PagePropertiesCallback
// substitute string
}
}
/**
* Clears the info text for a given callback state
*
* @param state The state to clear all infotexts
* @throws AuthLoginException Invalid state
* @supported.api
*/
public void clearInfoText(int state)
throws AuthLoginException {
if (debug.messageEnabled()) {
}
// check state length
if (state > stateLength) {
}
// check callback length for the state
}
// in internal, first Callback is always PagePropertiesCallback
// clear info text
}
}
/**
* Use this method to replace the header text from the XML file with new
* text. This method can be used multiple times on the same state replacing
* text with new text each time. Useful for modules that control their own
* error handling.
*
* @param state state state in which the Callback[] to be reset
* @param header The text of the header to be replaced
* @throws AuthLoginException if state is out of bounds
* @supported.api
*/
throws AuthLoginException {
if (debug.messageEnabled()) {
header);
}
// check state length
if (state > stateLength) {
}
// check callback length for the state
null);
}
// in internal, first Callback is always PagePropertiesCallback
// substitute string
}
}
/**
* Reset a Callback instance to the original Callback for the specified
* state and the specified index. This will override change to the Callback
* instance by the <code>replaceCallback()</code> method.
* @param state state in which the Callback[] to be reset
* @param index index order of the Callback in the Callback[], index starts
* with 0, i.e. 0 means first callback instance, 1 means
* the second callback instance.
* @throws AuthLoginException if state or index is out of bound.
* @supported.api
*/
throws AuthLoginException {
if (debug.messageEnabled()) {
}
// check state length
if (state > stateLength) {
}
// check callback length for the state
}
// get the Callback from AMModuleProperties
// add one to index here since first one is the PagePropertiesCallback
if (callback instanceof NameCallback) {
newCallback = new NameCallback(
} else if (callback instanceof PasswordCallback) {
newCallback = new PasswordCallback(
} else if (callback instanceof ChoiceCallback) {
newCallback = new ChoiceCallback(
} else {
// should never come here since only above three will be supported
}
if (debug.messageEnabled()) {
}
// set external & internal callback instance
}
/**
* Implements initialize() method in JAAS LoginModule class.
* <p>
* The purpose of this method is to initialize Login Module,
* it will call the init() method implemented by user's Login
* Module to do initialization.
* <p>
* This is a final method.
* @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 - state shared with other configured LoginModules.
* @param options - options specified in the login Configuration for this
* particular LoginModule.
*/
this.handler = callbackHandler;
this.sharedState = sharedState;
// get class name
// get module properties file path
loginState = getLoginState();
// get resource bundle
if (debug.messageEnabled()) {
}
).booleanValue();
).booleanValue();
"tryFirstPass");
if (debug.messageEnabled()) {
" is set to " + sharedStateBehaviorPattern);
}
// Check for composite Advice
if (compositeAdvice != null) {
if (debug.messageEnabled()) {
+ "Adding Composite Advice " + compositeAdvice);
}
}
// call customer init method
}
/**
* Initialize this LoginModule.
* <p>
* This is an abstract method, must be implemented by user's Login Module
* to initialize this LoginModule with the relevant information. If this
* LoginModule does not understand any of the data stored in sharedState
* or options parameters, they can be ignored.
* @param subject - the Subject to be authenticated.
* @param sharedState - state shared with other configured LoginModules.
* @param options - options specified in the login Configuration for this
* particular LoginModule. It contains all the global and organization
* attribute configuration for this module. The key of the map is the
* attribute name (e.g. <code>iplanet-am-auth-ldap-server</code>) as
* String, the value is the value of the corresponding attribute as Set.
* @supported.api
*/
/**
* Abstract method must be implemented by each login module to
* control the flow of the login process.
* <p>
* This method takes an array of sbumitted
* Callback, process them and decide the order of next state to go.
* Return -1 if the login is successful, return 0 if the
* LoginModule should be ignored.
* @param callbacks Callback[] for this Login state
* @param state Order of state. State order starts with 1.
* @return order of next state. return -1 if authentication
* is successful, return 0 if the LoginModule should be ignored.
* @exception LoginException if login fails.
* @supported.api
*/
throws LoginException;
/**
* Abstract method must be implemeted by each login module to
* get the user Principal
* @return Principal
* @supported.api
*/
/**
* This method should be overridden by each login module
* to destroy dispensable state fields.
*
* @supported.api
*/
public void destroyModuleState(){};
/**
* This method should be overridden by each login module
* to do some garbage collection work after the module
* process is done. Typically those class wide global variables
* that will not be used again until a logout call should be nullified.
*/
public void nullifyUsedVars() {};
/**
* Wrapper for process() to utilize AuthLoginException.
* @param callbacks associated with authentication
* @param state of callbacks
* @return state of auth login
* @exception AuthLoginException if login fails.
*/
throws AuthLoginException {
try {
if (callbacks[i] instanceof NameCallback) {
try {
getRequestOrg());
} catch (IdRepoException idRepoExp) {
//Print message and let Auth proceed.
"AMLoginModule.wrapProcess: Cannot get "+
"username from idrepo. ", idRepoExp);
}
}
}
}
}
} catch (InvalidPasswordException e) {
setFailureID(e.getTokenId());
throw e;
} catch (AuthLoginException e) {
throw e;
} catch (LoginException e) {
throw new AuthLoginException(e);
} catch (RuntimeException re) {
throw re;
}
}
private void setFailureState() {
}
/**
* Returns true if a module in authentication chain has already done, either
* succeeded or failed.
*
* @return true if a module in authentication chain has already done, either
* succeeded or failed.
*/
private boolean moduleHasDone() {
}
/**
* Implements login() method in JAAS LoginModule class.
* <p>
* This method is responsible for retrieving corresponding Callback[] for
* current state, send as requirement to user, get the submitted Callback[],
* call the process() method. The process() method will decide the next
* action based on those submitted Callback[].
* <p>
* This method is final.
* @return <code>true</code> if the authentication succeeded, or
* <code>false</code> if this LoginModule should be ignored.
* @throws AuthLoginException - if the authentication fails
*/
public final boolean login() throws AuthLoginException {
if (moduleHasDone()) {
return true;
} else {
return false;
}
} else {
if (debug.messageEnabled()) {
+ currentState);
}
}
// make one getCallback call to populate first state
// this will set the noCallbacks variable
getCallback(1);
}
// if this module does not define any Callbacks (such as Cert),
// pass control right to module, then check return code from module
if (noCallbacks) {
// check login status
succeeded = true;
return true;
// index = 0;
succeeded = false;
return false;
} else {
succeeded = false;
cleanup();
}
}
}
try {
boolean needToExit = false;
// starting from first page
//currentState = 1;
if (debug.messageEnabled()) {
}
if (isSharedState) {
isSharedState = false;
continue;
}
// get current set of callbacks
// check if this is an error state, if so, throw exception
// to terminate login process
if (callback.getErrorState()) {
// this is an error state
// this is the case which no error template is
// defined, only exception message in header
throw new MessageLoginException(errorMessage);
} else {
// send error template
//setLoginFailureURL(template);
throw new AuthLoginException(errorMessage);
}
}
// call handler to handle the internal callbacks
// Get the page state from the PagePropertiesCallback
//Set the current page state in PagePropertiesCallback
if (debug.messageEnabled()) {
}
}
// Get the last submitted callbacks to auth module and submit
// those callbacks to do DataStore authentication if the incoming
// user is special / internal user and auth module is other than
// "DataStore" and "Application" auth modules.
if (!authenticateToDatastore(lastCallbacks)) {
needToExit = true;
break;
}
}
// send external callback and send to module for processing
if (debug.messageEnabled()) {
}
}
if (needToExit) {
}
// check login status
succeeded = true;
return true;
} else {
// currentState = 0;
succeeded = false;
return false;
}
} catch (IOException e) {
} else {
} throw new AuthLoginException(e);
} catch (UnsupportedCallbackException e) {
throw new AuthLoginException(e);
}
}
/**
* Returns authentication level that has been set for the module
*
* @return authentication level of this authentication session
* @supported.api
*/
public int getAuthLevel() {
// get login state for this authentication session
if (loginState == null) {
loginState = getLoginState();
if (loginState == null) {
return 0;
}
}
return loginState.getAuthLevel();
}
/**
* Sets the <code>AuthLevel</code> for this session.
* The authentication level being set cannot be downgraded
* below that set by the module configuration.
*
* @param auth_level authentication level string to be set
* @return <code>true</code> if setting is successful,<code>false</code>
* otherwise
* @supported.api
*/
public boolean setAuthLevel(int auth_level) {
// get login state for this authentication session
if (loginState == null) {
loginState = getLoginState();
if (loginState == null) {
// may be should throw AuthLoginException here
return false;
}
}
return true;
}
/**
* Returns the current state in the authentication process.
*
* @return the current state in the authentication process.
* @supported.api
*/
public int getCurrentState() {
return currentState;
}
/**
* Returns the <code>HttpServletRequest</code> object that
* initiated the call to this module.
*
* @return <code>HttpServletRequest</code> for this request, returns null
* if the <code>HttpServletRequest</code> object could not be
* obtained.
* @supported.api
*/
public HttpServletRequest getHttpServletRequest() {
// get login state for this authentication session
if (loginState == null) {
loginState = getLoginState();
if (loginState == null) {
return null;
}
}
return loginState.getHttpServletRequest();
}
/**
* Returns the authentication <code>LoginState</code>
* @param methodName Name of the required methd in
* <code>LoginState</code> object
* @return <code>com.sun.identity.authentication.service.LoginState</code>
* for this authentication method.
* @throws AuthLoginException if fails to get the Login state
*/
if (loginState == null) {
loginState = getLoginState();
if (loginState == null) {
new Object[]{methodName});
}
}
return loginState;
}
/**
* Returns the Login <code>Locale</code> for this session
* @return <code>Locale</code> used for localizing text
*/
try {
} catch (AuthLoginException ex) {
}
}
/*
* Returns the Login State object
* @return com.sun.identity.authentication.service.LoginState
*/
try {
return null;
}
} catch (Exception e) {
return null;
}
}
/**
* Returns the <code>HttpServletResponse</code> object for the servlet
* request that initiated the call to this module. The servlet response
* object will be the response to the <code>HttpServletRequest</code>
* received by the authentication module.
*
* @return <code>HttpServletResponse</code> for this request, returns null
* if the <code>HttpServletResponse</code> object could not be obtained.
* @supported.api
*/
public HttpServletResponse getHttpServletResponse() {
// get login state for this authentication session
if (loginState == null) {
loginState = getLoginState();
if (loginState == null) {
return null;
}
}
return loginState.getHttpServletResponse();
}
/**
* Returns the CallbackHandler object for the module. This method
* will be used internally.
*
* @return CallbackHandler for this request, returns null if the
* CallbackHandler object could not be obtained.
*/
public CallbackHandler getCallbackHandler() {
return handler;
}
/**
* Returns the locale for this authentication session.
*
* @return <code>java.util.Locale</code> locale for this authentication
* session.
* @throws AuthLoginException if problem in accessing the
locale.
* @supported.api
*/
// get login state for this authentication session
}
/**
* Returns the number of authentication states for this
* login module.
*
* @return the number of authentication states for this login module.
* @supported.api
*/
public int getNumberOfStates() {
return stateLength;
}
/**
* Returns the organization DN for this authentication session.
*
* @return organization DN.
* @supported.api
*/
public String getRequestOrg() {
// get login state for this authentication session
if (loginState == null) {
loginState = getLoginState();
if (loginState == null) {
return null;
}
}
return loginState.getOrgDN();
}
/**
* Returns a unique key for this authentication session.
* This key will be unique throughout an entire Web browser session.
*
* @return null is unable to get the key,
* @supported.api
*/
public String getSessionId() {
// get login state for this authentication session
if (loginState == null) {
loginState = getLoginState();
if (loginState == null) {
return null;
}
}
/*
InternalSession sess = loginState.getSession();
if (sess != null) {
return sess.getID().toString();
} else {
return null;
}
*/
}
/**
* Returns the organization attributes for specified organization.
*
* @param orgDN Requested organization DN.
* in the organization.
* @throws AuthLoginException if cannot get organization profile.
* @supported.api
*/
// get login state for this authentication session
}
try {
if (debug.messageEnabled()) {
}
throw new AuthLoginException(ex);
}
return orgMap;
}
/**
* Returns service template attributes defined for the specified
* organization.
*
* @param orgDN Organization DN.
* @param serviceName Requested service name.
* organization service template.
* @throws AuthLoginException if cannot get organization service
* template.
* @supported.api
*/
throws AuthLoginException {
// get login state for this authentication session
"getOrgServiceTemplate(String, String)").getOrgDN();
}
try {
}
throw new AuthLoginException(ex);
}
return orgMap;
}
/**
* Checks if dynamic profile creation is enabled.
*
* @return <code>true</code> if dynamic profile creation is enabled.
*/
public boolean isDynamicProfileCreationEnabled() {
// get login state for this authentication session
if (loginState == null) {
loginState = getLoginState();
if (loginState == null) {
return false;
}
}
return loginState.isDynamicProfileCreationEnabled();
}
/**
* Returns service configuration attributes.
* @param name Requested service name.
* the service configuration.
* @throws AuthLoginException if error in accessing the service schema.
*
* @supported.api
*/
try {
}
}
}
}
return retMap;
throw new AuthLoginException(ex);
}
}
/**
* Returns the user profile for the user specified. This
* method may only be called in the validate() method.
*
* @param userDN distinguished name os user.
* @return <code>AMUser</code> object for the user's distinguished name.
* @throws AuthLoginException if it fails to get the user profile for
* <code>userDN</code>.
* @deprecated This method has been deprecated. Please use the
* IdRepo API's to get the AMIdentity object for the user. More
* information on how to use the Identity Repository APIs is
* available in the "Customizing Identity Data Storage" chapter
* of the OpenAM Developer's Guide.
*
* @supported.api
*/
try {
throw new AuthLoginException(ex);
}
return user;
}
/**
* Returns the property from the user session. If the session is being force
* upgraded then set on the old session otherwise set on the current session.
*
* @param name The property name.
* @return The property value.
* @throws AuthLoginException if the user session is invalid.
*
* @supported.api
*/
throws AuthLoginException {
} else {
}
} else {
return null;
}
}
/**
* Sets a property in the user session. If the session is being force
* upgraded then set on the old session otherwise set on the current session.
*
* @param name The property name.
* @param value The property value.
* @throws AuthLoginException if the user session is invalid.
*
* @supported.api
*/
throws AuthLoginException {
} else {
}
} else {
new Object[]{" setUserSessionProperty()"});
}
}
/**
* Returns a set of user IDs generated from the class defined
* in the Core Authentication Service. Returns null if the
* attribute <code>iplanet-am-auth-username-generator-enabled</code> is
* set to false.
*
* @param attributes the keys in the <code>Map</code> contains the
* attribute names and their corresponding values in
* the <code>Map</code> is a <code>Set</code> that
* contains the values for the attribute
* @param num the maximum number of returned user IDs; 0 means there
* is no limit
* @return a set of auto-generated user IDs
* @throws AuthLoginException if the class instantiation failed
*
* @supported.api
*/
throws AuthLoginException {
boolean enabled = getLoginState(
"getNewUserIDs(Map, int)").isUserIDGeneratorEnabled();
if (!enabled) {
return null;
}
"getNewUserIDs(Map, int)").getUserIDGeneratorClassName();
// if className is null or empty, use the default user ID
// generator class name
}
try {
// instantiate the Java class
} catch (Exception e) {
className, e);
return null;
}
}
/**
* Sets the the login failure URL for the user. This method does not
* change the URL in the user's profile. When the user authenticates
* failed, this URL will be used by the authentication for the
* redirect.
*
* @param url URL to go when authentication failed.
* @throws AuthLoginException if unable to set the URL.
*
* @supported.api
*/
}
/**
* Sets the error template for the module
* @param templateName the error template for the module
* @throws AuthLoginException when unable to set the template
*/
throws AuthLoginException {
}
/**
* Sets the the login successful URL for the user. This method does not
* change the URL in the user's profile. When the user authenticates
* successfully, this URL will be used by the authentication for the
* redirect.
*
* @param url <code>URL</code> to go when authentication is successful.
* @throws AuthLoginException if unable to set the URL.
* @supported.api
*/
}
/**
* Sets the user organization. This method should only be called when the
* user authenticates successfully. It allows the user authentication
* module to decide in which domain the user profile should be created.
*
* @param orgDN The organization DN.
* @throws AuthLoginException
*/
/* TODO
if (orgDN.indexOf("=") == -1) {
throw new AuthLoginException(bundleName, "invalidDN",
new Object[]{orgDN});
}
getLoginState("setOrg()").setOrg(orgDN);
*/
return;
}
/**
* Checks if a Callback is required to have input.
* @param state Order of state.
* @param index Order of the Callback in the Callback[], the index.
* starts with 0.
* @return <code>true</code> if the callback corresponding to the number
* in the specified state is required to have value,
* <code>false</code> otherwise
* @supported.api
*/
// check state
if (state > stateLength) {
// invalid state, return false now
return false;
}
// get internal callbacks for the state
// no callbacks defined for this state, return false
return false;
}
// check first Callback
if (callback instanceof PagePropertiesCallback) {
return false;
} else {
return true;
} else {
return false;
}
}
} else {
return false;
}
}
/**
* Returns the info text associated with a specific callback
*
* @param state The state to fetch the info text
* @param index The callback to fetch the info text
* @return The info text
* @supported.api
*/
// check state
if (state > stateLength) {
// invalid state, return empty string now
return EMPTY_STRING;
}
// get internal callbacks for the state
// no callbacks defined for this state, return empty string
return EMPTY_STRING;
}
// check first Callback
if (callback instanceof PagePropertiesCallback) {
return EMPTY_STRING;
} else {
}
} else {
return EMPTY_STRING;
}
}
/**
* Returns the attribute name for the specified callback in the
* specified login state.
*
* @param state Order of state
* @param index Order of the Callback in the Callback[], the index
* starts with 0.
* @return Name of the attribute, empty string will be returned
* if the attribute is not defined.
* @supported.api
*/
// check state
if (state > stateLength) {
// invalid state, return empty string now
return EMPTY_STRING;
}
// get internal callbacks for the state
// no callbacks defined for this state, return empty string
return EMPTY_STRING;
}
// check first Callback
if (callback instanceof PagePropertiesCallback) {
return EMPTY_STRING;
} else {
}
} else {
return EMPTY_STRING;
}
}
/**
* Aborts the authentication process.
* <p>
* This JAAS LoginModule method must be implemented by user's module.
* <p>
* This method is called if the overall authentication
* failed. (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL
* LoginModules did not succeed).
* If this LoginModule's own authentication attempt succeeded (checked by
* retrieving the private state saved by the login method), then this
* method cleans up any state that was originally saved.
*
* @return <code>true</code> if this method succeeded,<code>false</code>
* if this LoginModule should be ignored.
* @throws AuthLoginException if the abort fails
* @see javax.security.auth.spi.LoginModule#abort
*/
public final boolean abort() throws AuthLoginException {
if (succeeded == false) {
return false;
} else {
logout();
}
return true;
}
/**
* Commit the authentication process (phase 2).
* <p>
* This JAAS LoginModule method must be implemented by user's module.
* <p>
* This method is called if the 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 login method), then this
* method associates relevant Principals and Credentials with the Subject
* located in the LoginModule. If this LoginModule's own authentication
* originally saved.
*
* @return <code>true</code> if this method succeeded, or <code>false</code>
* if this <code>LoginModule</code> should be ignored.
* @throws AuthLoginException if the commit fails
* @see javax.security.auth.spi.LoginModule#commit
*/
public final boolean commit() throws AuthLoginException {
principal = getPrincipal();
if (debug.messageEnabled()) {
"AMLoginModule.commit():Succeed,principal=" + principal);
}
return false;
}
cleanup();
return true;
}
/**
* Logs out a Subject.
* <p>
* This JAAS LoginModule method must be implemented by user's module.
* <p>
* Principals and Credentials.
*
* @return <code>true</code> if this method succeeded, or <code>false</code>
* if this LoginModule should be ignored.
* @throws AuthLoginException if the logout fails
* @see javax.security.auth.spi.LoginModule#logout
*/
public final boolean logout() throws AuthLoginException {
// logging out
}
succeeded = false;
cleanup();
return true;
}
/**
* Sets the <code>userID</code> of user who failed authentication.
* This <code>userID</code> will be used to log failed authentication in
* the OpenSSO error logs.
*
* @param userID user name of user who failed authentication.
* @supported.api
*/
// get login state for this authentication session
return;
}
if (loginState == null) {
loginState = getLoginState();
if (loginState == null) {
// may be should throw AuthLoginException here
return;
}
}
return ;
}
/**
* Sets a Map of attribute value pairs to be used when the authentication
* service is configured to dynamically create a user.
*
* @param attributeValuePairs A map containing the attributes
* and its values. The key is the attribute name and the value
* is a Set of values.
*
* @supported.api
*/
// get login state for this authentication session
if (loginState == null) {
loginState = getLoginState();
if (loginState == null) {
return;
}
}
return;
}
/**
* Validates the given user name by using validation plugin if exists
* else it checks invalid characters in the source string.
*
* @param userName source string which should be validated.
* @param regEx the pattern for which to search.
* @throws UserNamePasswordValidationException if user name is invalid.
* @supported.api
*/
throws UserNamePasswordValidationException {
try {
getRequestOrg());
throw new UserNamePasswordValidationException(bundleName,
"invalidChars", null);
}
}
} catch (AMException ame) {
if (debug.messageEnabled()) {
}
throw new UserNamePasswordValidationException(ame);
"unKnown Exception occured during username validation");
throw new UserNamePasswordValidationException(ex);
}
}
/**
* Sets the moduleName of successful LoginModule.
* This moduleName will be populated in the session
* property "AuthType"
* @param moduleName name of module
*/
// get login state for this authentication session
if (loginState == null) {
loginState = getLoginState();
if (loginState == null) {
return;
}
}
if (debug.messageEnabled()) {
}
}
}
/**
* Checks if valid user exists.
*
* @param userDN the distinguished name of the user.
* @return <code>true</code> if user exists,<code>false</code>otherwise
*/
// TODO - IdRepo does not have an equivalent of this
// this method is mainly called to validate DSAME Users
// which are going to be processed differently.
boolean isValidUser = false;
try {
} catch (AuthException e) {
}
return isValidUser;
}
/**
* Checks if distinguished user name is a super admin.
*
* @param userDN the distinguished name of the user.
* @return <code>true</code> if distinguished user name is a super admin.
*/
if (debug.messageEnabled()) {
}
return isSuperAdmin;
}
/**
* Validate password for the distinguished user, this will use validation
* plugin if exists to validate password
*
* @param userPassword source string which should be validated.
* @throws UserNamePasswordValidationException if user password is invalid.
*
* @supported.api
*/
throws UserNamePasswordValidationException {
try {
if (debug.messageEnabled()) {
}
} else {
if (debug.messageEnabled()) {
}
}
} catch (AMException ame) {
if (debug.messageEnabled()) {
}
throw new UserNamePasswordValidationException(ame);
if (debug.messageEnabled()) {
}
throw new UserNamePasswordValidationException(ex);
}
}
/*
* this method instantiates and returns plugin object
*/
private AMUserPasswordValidation getUPValidationInstance() {
try {
}
else {
}
if (debug.messageEnabled()) {
}
return null;
}
return userPasswordInstance;
} catch (ClassNotFoundException ce) {
if (debug.messageEnabled()) {
}
return null;
} catch (Exception e) {
if (debug.messageEnabled()) {
}
return null;
}
}
/*
* this method gets plugin classname from adminstration service for the org
*/
try {
if (cachedValue != null) {
return cachedValue;
}
if (debug.messageEnabled()) {
}
return className;
return null;
}
}
/*
* this method gets plugin classname from adminstration service
*/
if (cachedValue != null) {
return cachedValue;
}
if (debug.messageEnabled()) {
}
return className;
}
/**
* Sets the moduleName of failed login module
* @param moduleName - module name of the failed module
*/
// get login state for this authentication session
if (loginState == null) {
loginState = getLoginState();
if (loginState == null) {
return;
}
}
if (debug.messageEnabled()) {
}
}
/**
* Returns JAAS shared state user key.
*
* @return user key.
*/
public String getUserKey() {
return ISAuthConstants.SHARED_STATE_USERNAME;
}
/**
* Returns JAAS shared state password key.
*
* @return password key
*/
return ISAuthConstants.SHARED_STATE_PASSWORD;
}
// cleanup method for Auth constants
private void cleanup() {
if (sharedState !=null) {
}
sharedState = null;
}
/**
* Stores user name into shared state map.
* This method should be called after successful authentication by each individual module
* if a username was supplied by that module.
*
* @param username user name.
*/
}
}
/**
* Stores password into shared state map.
* This method may be called after successful authentication by each individual module.
*
* @param password user's password.
*/
}
}
/**
* Stores user name and password into shared state map.
* This method should be called after successful authentication by each individual module
* if both a username and a password were supplied in that module.
*
* @param user user name.
* @param passwd user password.
*/
}
/**
* Checks if shared state enabled for the module.
*
* @return <code>true</code> if shared state enabled for the module.
*/
public boolean isSharedStateEnabled() {
return isSharedState;
}
/**
* Sets flag to force read call backs in auth chain process.
* @param val - value to force reading call backs
*/
public void setForceCallbacksRead(boolean val) {
}
/**
* This method returns use first pass enabled or not
* @return return true if use first pass is enabled for the module
*/
public boolean isUseFirstPassEnabled() {
return (sharedStateBehaviorPattern != null) &&
}
/**
* Returns <code>AMIdentityRepostiory</code> handle for an organization.
*
* @param orgDN the organization name.
* @return <code>AMIdentityRepostiory</code> object
*/
}
/**
* Creates <code>AMIdentity</code> in the repository.
*
* @param userName name of user to be created.
* @param userAttributes Map of default attributes.
* @param userRoles Set of default roles.
* @throws IdRepoException
* @throws SSOException
*/
public void createIdentity(
) throws IdRepoException, SSOException {
if (loginState == null) {
loginState = getLoginState();
if (loginState == null) {
return ;
}
}
return;
}
/**
* Get the number of failed login attempts for a user when account locking
* is enabled.
* @return number of failed attempts, -1 id account locking is not enabled.
* @throws AuthenticationException if the user name passed in is not valid
* or null, or for any other error condition.
* @supported.api
*/
if (loginState == null) {
loginState = getLoginState();
if (loginState == null) {
null);
}
}
try {
if (!isAccountLockout.isLockoutEnabled()) {
return -1;
} else {
if (debug.messageEnabled()) {
+"lockout is enabled");
}
}
if (debug.messageEnabled()) {
+"returned:" +failCount);
}
return failCount;
}
}
}
/**
* Get the maximum number failed login attempts permitted for a user
* before when their account is locked out.
*
* @return the maximum number of failed attempts
* @supported.api
*/
public int getMaximumFailCount()
throws AuthenticationException {
if (loginState == null) {
loginState = getLoginState();
if (loginState == null) {
null);
}
}
return loginState.getLoginFailureLockoutCount();
}
/**
* Increments the fail count for the given user.
*
* @throws AuthenticationException if the user name passed in is not valid
* or null, or for any other error condition.
* @supported.api
*/
throws AuthenticationException {
if (loginState == null) {
loginState = getLoginState();
if (loginState == null) {
null);
}
}
}
/**
* Returns true if the named account is locked out, false otherwise.
*
* @throws AuthenticationException if the user name passed in is not valid
* or null, or for any other error condition.
* @supported.api
*/
throws AuthenticationException {
if (loginState == null) {
loginState = getLoginState();
if (loginState == null) {
null);
}
}
}
return accountLocked;
}
/* returns the normalized DN */
}
}
return normalizedDN;
}
/**
* Authenticates to the datastore using idRepo API
*
* @param callbacks Array of last submitted callbacks to the
* authentication module
* @return <code>true</code> if success. <code>false</code> if failure
* @throws <code> AuthLoginException </code>
*/
throws AuthLoginException {
boolean retval = false;
boolean needToCheck = false;
if (callbacks[i] instanceof NameCallback) {
if (debug.messageEnabled()){
+ " user is : " + userName);
}
userName.toLowerCase())) {
needToCheck = true;
} else {
break;
}
} else if (callbacks[i] instanceof PasswordCallback) {
}
}
if (needToCheck == false) {
return true;
}
if (debug.messageEnabled()){
+ "Authenticating Internal user to configuration store");
}
"PasswordPrompt",false);
try {
getRequestOrg());
if (debug.messageEnabled()){
" IDRepo authentication successful");
}
} catch (IdRepoException idrepoExp) {
if (debug.messageEnabled()){
+ "IdRepo Exception : ", idrepoExp);
}
} catch (InvalidPasswordException ipe) {
}
return retval;
}
/**
* Returns true if the user identified by the supplied username has reached
* their session quota.<br>
* <i>NB</i>The existing session count is exclusive of any session created
* as part of the running authentication process
*
* @param userName the username of the user who's session quota will be checked
* @return true if the user session quota is reached, false otherwise
* @supported.api
*/
int sessionCount = -1;
int sessionQuota = -1;
return false;
}
try {
// Get the universal ID
loginState.getOrgDN());
if (debug.messageEnabled()) {
}
} else {
+ "univId is null , amIdUser is " + amIdUser);
return false;
}
+ "Exception : ", ex);
}
return (sessionCount >= sessionQuota);
}
return quota;
}
try {
}
"IDRepo interfaces, => Use the default " +
"value from the dynamic schema instead.", ex);
}
return quota;
}
/**
* Returns the set of SSOTokens for a specified user
*
* @param userName The username to be used to query the sessions
* @return The set of SSOTokens for the user's current sessions, returns null on error
* @supported.api
*/
return null;
}
try {
// Get the universal ID
}
if (debug.messageEnabled()) {
}
} else {
+ "univId is null , amIdUser is " + amIdUser);
return null;
}
+ "Exception : ", ex);
}
return sessions;
}
/**
* Provides the "Alias Search Attribute Name" list from the Authentication
* Service for the realm. If these attributes are not configured it falls
* back to the User Naming Attribute for the realm
* @return a set containing the attribute names configured
*/
final Map<String, Set<String>> orgSvc = getOrgServiceTemplate(getRequestOrg(), ISAuthConstants.AUTH_SERVICE_NAME);
if (debug.messageEnabled()) {
debug.message("AMLoginModule.getUserAliasList: from " + ISAuthConstants.AUTH_ALIAS_ATTR + ": "+ aliasAttrNames);
}
if (aliasAttrNames.isEmpty()) {
if (debug.messageEnabled()) {
+ aliasAttrNames);
}
}
return aliasAttrNames;
}
/**
* Returns the principals authenticated in the current authentication process or an empty set if login state is
* unavailable or no authenticated principals are present.
*
* @return a set of authenticated principals.
*/
if (loginState == null) {
loginState = getLoginState();
}
if (loginState == null) {
if (debug.messageEnabled()) {
}
return Collections.emptySet();
}
return loginState.getAuthenticatedPrincipals();
}
/**
* Supply the additional detail to be logged with this module's completion event. Subclasses can override this
* method to add more specific detail.
*
* @return The audit entry detail.
*/
protected AuthenticationAuditEntry getAuditEntryDetail() {
if (isNotEmpty(ip)) {
}
}
return entryDetail;
}
}