001/** 002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 003 * 004 * Copyright (c) 2005 Sun Microsystems Inc. All Rights Reserved 005 * 006 * The contents of this file are subject to the terms 007 * of the Common Development and Distribution License 008 * (the License). You may not use this file except in 009 * compliance with the License. 010 * 011 * You can obtain a copy of the License at 012 * https://opensso.dev.java.net/public/CDDLv1.0.html or 013 * opensso/legal/CDDLv1.0.txt 014 * See the License for the specific language governing 015 * permission and limitations under the License. 016 * 017 * When distributing Covered Code, include this CDDL 018 * Header Notice in each file and include the License file 019 * at opensso/legal/CDDLv1.0.txt. 020 * If applicable, add the following below the CDDL Header, 021 * with the fields enclosed by brackets [] replaced by 022 * your own identifying information: 023 * "Portions Copyrighted [year] [name of copyright owner]" 024 * 025 * $Id: AMLoginModule.java,v 1.22 2009/11/21 01:11:56 222713 Exp $ 026 * 027 * Portions Copyrighted 2010-2017 ForgeRock AS. 028 */ 029 030package com.sun.identity.authentication.spi; 031 032import static org.forgerock.openam.audit.AuditConstants.EntriesInfoFieldKey.*; 033import static org.forgerock.openam.utils.StringUtils.*; 034import static com.sun.identity.authentication.util.ISAuthConstants.*; 035 036import com.iplanet.am.sdk.AMException; 037import com.iplanet.am.sdk.AMUser; 038import com.iplanet.am.sdk.AMUserPasswordValidation; 039import com.iplanet.am.util.Misc; 040import com.iplanet.dpro.session.service.InternalSession; 041import com.iplanet.dpro.session.service.SessionConstraint; 042import com.iplanet.dpro.session.service.SessionCount; 043import com.iplanet.sso.SSOException; 044import com.iplanet.sso.SSOToken; 045import com.iplanet.sso.SSOTokenManager; 046import com.sun.identity.authentication.AuthContext; 047import com.sun.identity.authentication.audit.AuthenticationModuleEventAuditor; 048import com.sun.identity.authentication.callbacks.HiddenValueCallback; 049import com.sun.identity.authentication.callbacks.ScriptTextOutputCallback; 050import com.sun.identity.authentication.config.AMAuthConfigUtils; 051import com.sun.identity.authentication.service.AMAuthErrorCode; 052import com.sun.identity.authentication.service.AuthD; 053import com.sun.identity.authentication.service.AuthException; 054import com.sun.identity.authentication.service.LoginState; 055import com.sun.identity.authentication.service.LoginStateCallback; 056import com.sun.identity.authentication.util.ISAuthConstants; 057import com.sun.identity.authentication.util.ISValidation; 058import com.sun.identity.common.AccountLockoutInfo; 059import com.sun.identity.common.AdministrationServiceListener; 060import com.sun.identity.common.DNUtils; 061import com.sun.identity.common.ISAccountLockout; 062import com.sun.identity.idm.AMIdentity; 063import com.sun.identity.idm.AMIdentityRepository; 064import com.sun.identity.idm.IdRepoException; 065import com.sun.identity.idm.IdType; 066import com.sun.identity.idm.IdUtils; 067import com.sun.identity.shared.Constants; 068import com.sun.identity.shared.datastruct.CollectionHelper; 069import com.sun.identity.shared.debug.Debug; 070import com.sun.identity.shared.locale.AMResourceBundleCache; 071import com.sun.identity.sm.OrganizationConfigManager; 072import com.sun.identity.sm.ServiceSchema; 073import com.sun.identity.sm.ServiceSchemaManager; 074import org.forgerock.guice.core.InjectorHolder; 075import org.forgerock.openam.audit.AuditConstants; 076import org.forgerock.openam.audit.model.AuthenticationAuditEntry; 077import org.forgerock.openam.authentication.callbacks.PollingWaitCallback; 078import org.forgerock.openam.ldap.LDAPUtils; 079 080import javax.security.auth.Subject; 081import javax.security.auth.callback.Callback; 082import javax.security.auth.callback.CallbackHandler; 083import javax.security.auth.callback.ChoiceCallback; 084import javax.security.auth.callback.ConfirmationCallback; 085import javax.security.auth.callback.NameCallback; 086import javax.security.auth.callback.PasswordCallback; 087import javax.security.auth.callback.TextInputCallback; 088import javax.security.auth.callback.TextOutputCallback; 089import javax.security.auth.callback.UnsupportedCallbackException; 090import javax.security.auth.login.LoginException; 091import javax.security.auth.spi.LoginModule; 092import javax.servlet.http.HttpServletRequest; 093import javax.servlet.http.HttpServletResponse; 094import java.io.IOException; 095import java.security.Principal; 096import java.util.ArrayList; 097import java.util.Collections; 098import java.util.HashMap; 099import java.util.HashSet; 100import java.util.Iterator; 101import java.util.List; 102import java.util.Map; 103import java.util.ResourceBundle; 104import java.util.Set; 105 106/** 107 * An abstract class which implements JAAS LoginModule, it provides 108 * methods to access OpenAM services and the module 109 * xml configuration. 110 * <p> 111 * Because it is an abstract class, Login Module writers must subclass 112 * and implement init(), process(), getPrincipal() methods. 113 * <p> 114 * The Callback[] for the Login Module is dynamically generated based 115 * on the xml module configuration. The module configuration file name 116 * must be the same as the name of the class (no package name) and have the 117 * extension .xml. 118 * <p> 119 * Here is a sample module configuration file: 120 * <pre> 121 * <ModuleProperties moduleClass="LDAP" version="1.0" > 122 * <Callbacks length="2" order="1" timeout="60" header="LDAP 123 * Authentication" > 124 * <NameCallback> 125 * <Prompt> Enter UserId </Prompt> 126 * </NameCallback> 127 * <PasswordCallback echoPassword="false" > 128 * <Prompt> Enter Password </Prompt> 129 * </PasswordCallback> 130 * </Callbacks> 131 * <Callbacks length="3" order="2" timeout="120" header="Password 132 * Expiring Please Change" > 133 * <PasswordCallback echoPassword="false" > 134 * <Prompt> Enter Current Password </Prompt> 135 * </PasswordCallback> 136 * <PasswordCallback echoPassword="false" > 137 * <Prompt> Enter New Password </Prompt> 138 * </PasswordCallback> 139 * <PasswordCallback echoPassword="false" > 140 * <Prompt> Confirm New Password </Prompt> 141 * </PasswordCallback> 142 * </Callbacks> 143 * </ModuleProperties> 144 * </pre> 145 * Each Callbacks Element corresponds to one login state. 146 * When an authentication process is invoked, there will be Callback[] 147 * generated from user's Login Module for each state. All login state 148 * starts with 1, then module controls the login process, and decides what's 149 * the next state to go in the process() method. 150 * <p> 151 * In the sample module configuration shown above, state one has 152 * three Callbacks, Callback[0] is for module information, Callback[1] is 153 * for user ID, Callback[2] is for user password. When the user fills in the 154 * Callbacks, those Callback[] will be sent to the process() method, where 155 * the module writer gets the submitted Callbacks, validates them and returns. 156 * If user's password is expiring, the module writer will set the next 157 * state to 2. State two has four Callbacks to request user to change 158 * password. The process() routine is again 159 * called after user submits the Callback[]. If the module writer throws an 160 * LoginException, an 'authentication failed' page will be sent to the user. 161 * If no exception is thrown, the user will be redirected to their default 162 * page. 163 * <p> 164 * The optional 'timeout' attribute in each state is used to ensure that the 165 * user responds in a timely manner. If the time between sending the Callbacks 166 * and getting response is greater than the timeout, a timeout page will be 167 * sent. 168 * <p> 169 * There are also optional 'html' and 'image' attribute in each state. The 170 * 'html' attribute allows the module writer to use a custom HTML 171 * page for the Login UI. The 'image' attribute allows the writer to display 172 * a custom background image on each page. 173 * <p> 174 * When multiple states are available to the user, the Callback array from a 175 * previous state may be retrieved by using the <code>getCallbak(int)</code> 176 * methods. The underlying login module keeps the Callback[] from the previous 177 * states until the login process is completed. 178 * <p> 179 * If a module writer need to substitute dynamic text in next state, the writer 180 * could use the <code>getCallback()</code> method to get the Callback[] for the 181 * next state, modify the output text or prompt, then call 182 * <code>replaceCallback()</code> to update the Callback array. This allows a 183 * module writer to dynamically generate challenges, passwords or user IDs. 184 * <p> 185 * Each authentication session will create a new instance of your 186 * Login Module Java class. The reference to the class will be 187 * released once the authentication session has either succeeded 188 * or failed. It is important to note that any static data or 189 * reference to any static data in your Login module 190 * must be thread-safe. 191 * <p> 192 * AMLoginModule will call <code>setAuthLevel()</code> method when authentication 193 * has succeeded for each Login Module. The authentication level can be defined in 194 * Login Module's service schema and the attribute name must conform to 195 * <code>forgerock-am-auth-<Login Module Name>--auth-level<code>. 196 * <p> 197 * Here is a sample module schema for authentication level: 198 * <pre> 199 * <AttributeSchema name="forgerock-am-auth-adaptive-auth-level" 200 * cosQualifier="default" 201 * type="single" 202 * syntax="number" 203 * i18nKey="a500" 204 * order="100" 205 * resourceName="authenticationLevel"> 206 * <DefaultValues> 207 * <Value>0</Value> 208 * </DefaultValues> 209 * </AttributeSchema> 210 * </pre> 211 * The final authentication level for a user's session is calculated to be the highest 212 * authentication level of any authentication module that passed. 213 *<p> 214 * For a complete sample, please refer to 215 * <install_root>/SUNWam/samples/authentication/providers 216 * 217 * @supported.api 218 */ 219public abstract class AMLoginModule implements LoginModule { 220 // list which holds both presentation and credential callbacks 221 List internal = null; 222 // list which holds only credential callbacks 223 List external = null; 224 // list which contains the original Callback list from AMModuleProperties 225 List origList = null; 226 // class name 227 private String fileName = null; 228 // if true, means this module does not hava any Callbacks defined, this 229 // is the case for anonymous/cert, which have a size 0 config file 230 boolean noCallbacks = false; 231 232 // constant for empty Callback array 233 private static Callback[] EMPTY_CALLBACK = new Callback[0]; 234 235 // state length for this module 236 private int stateLength = 0; 237 238 // resource bundle 239 private ResourceBundle bundle = null; 240 241 // login state 242 private LoginState loginState =null; 243 244 /** 245 * Holds callback handler object passed in through initialize method 246 */ 247 private CallbackHandler handler = null; 248 /** 249 * Holds subject object passed in through initialize method 250 */ 251 private Subject subject = null; 252 /** 253 * Holds shared state map passed in through initialize method 254 */ 255 private Map sharedState = null; 256 /** 257 * Holds options map passed in through initialize method 258 */ 259 private Map options = null; 260 261 private static Debug debug = Debug.getInstance("amLoginModule"); 262 263 private int currentState = ISAuthConstants.LOGIN_START; 264 265 private final String EMPTY_STRING = ""; 266 private String moduleName = null; 267 private String moduleClass = null; 268 private static final String bundleName = "amAuth"; 269 private static AuthD ad = AuthD.getAuth(); 270 private Principal principal = null; 271 // the authentication status 272 private boolean succeeded = false; 273 274 private boolean forceCallbacksRead = false; 275 276 //use Shared state by default disabled 277 private boolean isSharedState = false; 278 private boolean isStore = true; 279 private String sharedStateBehaviorPattern = ""; 280 281 // variable used in replaceHeader() 282 private String headerWithReplaceTag; 283 private boolean alreadyReplaced = false; 284 private int lastState = 0; 285 286 /** 287 * Holds handle to ResourceBundleCache to quickly get ResourceBundle for 288 * any Locale. 289 */ 290 protected static AMResourceBundleCache amCache = 291 AMResourceBundleCache.getInstance(); 292 293 protected final AuthenticationModuleEventAuditor auditor; 294 295 /** 296 * No argument constructor for {@link AMLoginModule}. 297 */ 298 public AMLoginModule() { 299 auditor = InjectorHolder.getInstance(AuthenticationModuleEventAuditor.class); 300 } 301 302 /** 303 * Clone Callback[], and save it in the internal/external 304 * callbacks list. External callback contains all user defined 305 * Callbacks in the xml module configuration (property file), 306 * internal callback contains the external callbacks plus the 307 * PagePropertiesCallback. Note here, although 308 * Callback[] in internal/external are different, the Callback 309 * instance they pointed are actually same instance 310 * @param index indicates state of callback 311 * @param original original array of callback to be cloned 312 * @return Callback[] returns cloned callback 313 * @exception AuthLoginException if callback can not be cloned 314 */ 315 private Callback[] cloneCallbacks(int index, Callback[] original) 316 throws AuthLoginException { 317 // check if there is any callbacks in original 318 if (original == null || original.length == 0) { 319 // this is the error case where there is no Callbacks 320 // defined for a state 321 debug.error("cloneCallbacks, no callbacks in state " + (index+1)); 322 throw new AuthLoginException(bundleName, "noCallbackState", 323 new Object[]{new Integer(index + 1)}); 324 } 325 326 int len = original.length; 327 // Callback array which hold the cloned Callbacks 328 Callback[] copy = new Callback[len]; 329 // List which contains the external callbacks only 330 List extCallbacks = new ArrayList(); 331 332 // iterate through Callback array, and copy them one by one 333 // if it is an external Callback, add to the extCallback list 334 for (int i = 0; i < len; i++) { 335 if (original[i] instanceof HiddenValueCallback) { 336 final HiddenValueCallback hiddenValueCallback = (HiddenValueCallback) original[i]; 337 String defaultValue = hiddenValueCallback.getDefaultValue(); 338 if (defaultValue != null && defaultValue.length() != 0) { 339 copy[i] = new HiddenValueCallback( 340 hiddenValueCallback.getId(), defaultValue); 341 } else { 342 copy[i] = new HiddenValueCallback( 343 hiddenValueCallback.getId()); 344 } 345 extCallbacks.add(copy[i]); 346 if (debug.messageEnabled()) { 347 debug.message("clone #" + i + " is HiddenValueCallback"); 348 } 349 } else if (original[i] instanceof NameCallback) { 350 String dftName = ((NameCallback) original[i]).getDefaultName(); 351 if (dftName != null && dftName.length() != 0) { 352 copy[i] = new NameCallback( 353 ((NameCallback) original[i]).getPrompt(), dftName); 354 } else { 355 copy[i] = new NameCallback( 356 ((NameCallback) original[i]).getPrompt()); 357 } 358 extCallbacks.add(copy[i]); 359 if (debug.messageEnabled()) { 360 debug.message("clone #" + i + " is NameCallback"); 361 } 362 } else if (original[i] instanceof PasswordCallback) { 363 copy[i] = new PasswordCallback( 364 ((PasswordCallback) original[i]).getPrompt(), 365 ((PasswordCallback) original[i]).isEchoOn()); 366 extCallbacks.add(copy[i]); 367 if (debug.messageEnabled()) { 368 debug.message("clone #" + i + " is PasswordCallback"); 369 } 370 } else if (original[i] instanceof ScriptTextOutputCallback) { 371 copy[i] = new ScriptTextOutputCallback( 372 ((TextOutputCallback) original[i]).getMessage()); 373 extCallbacks.add(copy[i]); 374 if (debug.messageEnabled()) { 375 debug.message("clone #" + i + " is ScriptTextOutputCallback"); 376 } 377 } else if (original[i] instanceof TextOutputCallback) { 378 copy[i] = new TextOutputCallback( 379 ((TextOutputCallback) original[i]).getMessageType(), 380 ((TextOutputCallback) original[i]).getMessage()); 381 extCallbacks.add(copy[i]); 382 if (debug.messageEnabled()) { 383 debug.message("clone #" + i + " is TextOutputCallback"); 384 } 385 } else if (original[i] instanceof PagePropertiesCallback) { 386 // PagePropertiesCallback, no need to add to external callbacks 387 copy[i] = new PagePropertiesCallback( 388 ((PagePropertiesCallback) original[i]).getModuleName(), 389 ((PagePropertiesCallback) original[i]).getHeader(), 390 ((PagePropertiesCallback) original[i]).getImage(), 391 ((PagePropertiesCallback) original[i]).getTimeOutValue(), 392 ((PagePropertiesCallback) original[i]).getTemplateName(), 393 ((PagePropertiesCallback) original[i]).getErrorState(), 394 ((PagePropertiesCallback) original[i]).getPageState()); 395 ((PagePropertiesCallback) copy[i]).setRequire( 396 ((PagePropertiesCallback) original[i]).getRequire()); 397 ((PagePropertiesCallback) copy[i]).setAttribute( 398 ((PagePropertiesCallback) original[i]).getAttribute()); 399 ((PagePropertiesCallback) copy[i]).setInfoText( 400 ((PagePropertiesCallback) original[i]).getInfoText()); 401 if (debug.messageEnabled()) { 402 debug.message("clone #" + i + " is PagePropertiesCallback"); 403 } 404 } else if (original[i] instanceof ChoiceCallback) { 405 406 ChoiceCallback originalChoiceCallback = (ChoiceCallback) original[i]; 407 408 ChoiceCallback clone = new ChoiceCallback( 409 originalChoiceCallback.getPrompt(), 410 originalChoiceCallback.getChoices(), 411 originalChoiceCallback.getDefaultChoice(), 412 originalChoiceCallback.allowMultipleSelections()); 413 414 if (originalChoiceCallback.getSelectedIndexes() != null 415 && originalChoiceCallback.getSelectedIndexes().length > 0) { 416 if (originalChoiceCallback.allowMultipleSelections()) { 417 clone.setSelectedIndexes(originalChoiceCallback.getSelectedIndexes()); 418 } else { 419 clone.setSelectedIndex(originalChoiceCallback.getSelectedIndexes()[0]); 420 } 421 } 422 423 copy[i] = clone; 424 extCallbacks.add(copy[i]); 425 if (debug.messageEnabled()) { 426 debug.message("clone #" + i + " is ChoiceCallback"); 427 } 428 } else if (original[i] instanceof ConfirmationCallback) { 429 ConfirmationCallback temp = (ConfirmationCallback) original[i]; 430 String prompt = temp.getPrompt(); 431 String[] options = temp.getOptions(); 432 if (prompt == null) { 433 // no prompt 434 if (options == null) { 435 // no options 436 copy[i] = new ConfirmationCallback( 437 temp.getMessageType(), 438 temp.getOptionType(), 439 temp.getDefaultOption()); 440 } else { 441 copy[i] = new ConfirmationCallback( 442 temp.getMessageType(), 443 options, 444 temp.getDefaultOption()); 445 } 446 } else { 447 // has prompt 448 if (options == null) { 449 // no options 450 copy[i] = new ConfirmationCallback( 451 prompt, 452 temp.getMessageType(), 453 temp.getOptionType(), 454 temp.getDefaultOption()); 455 } else { 456 copy[i] = new ConfirmationCallback( 457 prompt, 458 temp.getMessageType(), 459 options, 460 temp.getDefaultOption()); 461 } 462 } 463 extCallbacks.add(copy[i]); 464 if (debug.messageEnabled()) { 465 debug.message("clone #" + i + " is ConfirmationCallback"); 466 } 467 } else if (original[i] instanceof TextInputCallback) { 468 copy[i] = new TextInputCallback( 469 ((TextInputCallback) original[i]).getPrompt()); 470 extCallbacks.add(copy[i]); 471 if (debug.messageEnabled()) { 472 debug.message("clone #" + i + " is TextInputCallback"); 473 } 474 } else if (original[i] instanceof HttpCallback) { 475 HttpCallback hc = (HttpCallback) original[i]; 476 copy[i] = new HttpCallback(hc.getAuthorizationHeader(), 477 hc.getNegotiationHeaderName(), 478 hc.getNegotiationHeaderValue(), 479 hc.getNegotiationCode()); 480 extCallbacks.add(copy[i]); 481 } else if (original[i] instanceof RedirectCallback) { 482 RedirectCallback rc = (RedirectCallback) original[i]; 483 copy[i] = new RedirectCallback(rc.getRedirectUrl(), 484 rc.getRedirectData(), 485 rc.getMethod(), 486 rc.getStatusParameter(), 487 rc.getRedirectBackUrlCookieName()); 488 extCallbacks.add(copy[i]); 489 } else if (original[i] instanceof PollingWaitCallback) { 490 PollingWaitCallback pollingWaitCallback = (PollingWaitCallback) original[i]; 491 copy[i] = PollingWaitCallback.makeCallback().asCopyOf(pollingWaitCallback).build(); 492 extCallbacks.add(copy[i]); 493 494 } else { 495 debug.error("unknown callback " + original[i]); 496 } 497 // more callbacks need to be handled here if ... 498 } 499 500 // construct external Callback[] 501 Callback[] ext = new Callback[extCallbacks.size()]; 502 if (!extCallbacks.isEmpty()) { 503 Iterator it = extCallbacks.iterator(); 504 int i = 0; 505 while (it.hasNext()) { 506 ext[i++] = (Callback) it.next(); 507 } 508 } 509 510 // set external/internal callbacks 511 internal.set(index, copy); 512 external.set(index, ext); 513 514 return ext; 515 } 516 517 /** 518 * Returns an administration SSOToken for use the OpenAM APIs. 519 * 520 * <I>NB:</I>This is not the SSOToken that represents the user, if you wish 521 * to set/get user session properties use the <code>setUserSessionProperty</code> 522 * and <code>getUserSessionProperty</code> method respectively. 523 * 524 * @return An administrative <code>SSOToken</code>. 525 * @exception AuthLoginException if the authentication SSO session 526 * is null. 527 * @supported.api 528 */ 529 public SSOToken getSSOSession() throws AuthLoginException { 530 SSOToken sess = AuthD.getAuth().getSSOAuthSession(); 531 if (sess == null) { 532 throw new AuthLoginException(bundleName, "nullSess", null); 533 } 534 return sess; 535 } 536 537 /** 538 * Returns a Callback array for a specific state. 539 * <p> 540 * This method can be used to retrieve Callback[] for any state. All 541 * previous submitted Callback[] information are kept until the login 542 * process is completed. 543 * @param index order of state 544 * @return Callback array for this state, return 0-length Callback array 545 * if there is no Callback defined for this state 546 * @throws AuthLoginException if unable to read the callbacks 547 * @supported.api 548 */ 549 public Callback[] getCallback(int index) throws AuthLoginException { 550 return getCallback(index, false); 551 } 552 553 /** 554 * Return a Callback array for a specific state. 555 * <p> 556 * This method can be used to retrieve Callback[] for any state. All 557 * previous submitted Callback[] information are kept until the login 558 * process is completed. 559 * @param index order of state 560 * @param fetchOrig boolean indicating even if the callbacks for this 561 * state have been previously retrieved, get the original callbacks 562 * from AMModuleProperties, if set to "true". 563 * @return Callback array for this state, return 0-length Callback array 564 * if there is no Callback defined for this state 565 * @throws AuthLoginException if unable to read the callbacks 566 * @supported.api 567 */ 568 public Callback[] getCallback(int index, boolean fetchOrig) 569 throws AuthLoginException 570 { 571 // This method will be called by customer module, so it will 572 // return Callback[] from external callback List 573 // check if there is no callbacks defined for this module 574 if (noCallbacks || ( (isSharedState) && (!forceCallbacksRead) )) { 575 return EMPTY_CALLBACK; 576 } 577 578 if ((internal == null) || ( fetchOrig )) { 579 forceCallbacksInit(); 580 if (origList == null || origList.isEmpty()) { 581 return EMPTY_CALLBACK; 582 } 583 584 if (debug.messageEnabled()) { 585 debug.message("callback size for state " + index + "=" + 586 stateLength); 587 } 588 } 589 590 // get Callback[] for this page 591 // use index-1 as order since page index starts with 1 592 if (index > stateLength) { 593 // invalid login state 594 debug.error("getCallback, state " + index + " > " + stateLength); 595 throw new AuthLoginException(bundleName, "invalidState", 596 new Object[]{new Integer(index)}); 597 } 598 Object temp = external.get(index-1); 599 if (temp != null) { 600 return (Callback[]) temp; 601 } 602 603 // callbacks has not been retrieved for this index yet 604 // need to get it from AMModuleProperties 605 // since the Callbacks could not be shared by different instances 606 // we need to create clone copy here 607 return cloneCallbacks(index-1, (Callback[]) origList.get(index-1)); 608 } 609 610 protected void forceCallbacksInit () throws AuthLoginException { 611 if (internal == null) { 612 // get the callbacks for this class; 613 origList = AMModuleProperties.getModuleProperties(fileName); 614 if (origList == null || origList.isEmpty()) { 615 // we got file whose size is zero, this is the case for 616 // Cert/Anonymous based authentication 617 noCallbacks = true; 618 return; 619 } 620 // instantiate internal/external according to module callback size 621 stateLength = origList.size(); 622 internal = new ArrayList(); 623 external = new ArrayList(); 624 if (debug.messageEnabled()) { 625 debug.message("callback stateLength in file = " + stateLength); 626 } 627 for (int i = 0; i < stateLength; i++) { 628 internal.add(null); 629 external.add(null); 630 } 631 } 632 } 633 634 /** 635 * Replace Callback object for a specific state. 636 * @param state Order of login state 637 * @param index Index of Callback in the Callback array to be replaced 638 * for the specified state. Here index starts with 0, i.e. 0 means the 639 * first Callback in the Callback[], 1 means the second callback. 640 * @param callback Callback instance to be replaced 641 * @exception AuthLoginException if state or index is out of 642 * bound, or callback instance is null. 643 * @supported.api 644 */ 645 public void replaceCallback(int state, int index, Callback callback) 646 throws AuthLoginException { 647 if (debug.messageEnabled()) { 648 debug.message("ReplaceCallback : state=" + state + ", index=" + 649 index + ", callback=" + callback); 650 } 651 // check state length 652 if (state > stateLength) { 653 throw new AuthLoginException(bundleName, "invalidState", 654 new Object[]{new Integer(state)}); 655 } 656 // check callback length for the state 657 Callback[] ext = getCallback(state); 658 if (index < 0 || index >= ext.length) { 659 throw new AuthLoginException(bundleName, "invalidCallbackIndex", 660 new Object[]{new Integer(index)}); 661 } 662 // check callback instance 663 if (callback == null) { 664 throw new AuthLoginException(bundleName, "nullCallback", null); 665 } 666 667 // replace callback in external & internal Callback array 668 ext[index] = callback; 669 // in internal, first Callback is always PagePropertiesCallback 670 // so add one here for the index 671 ((Callback[]) internal.get(state-1))[index + 1] = callback; 672 } 673 674 /** 675 * Replace page header for a specific state. 676 * @param state Order of login state 677 * @param header header messages to be replaced 678 * @throws AuthLoginException if state is out of bound. 679 */ 680 public void replaceHeader(int state, String header) 681 throws AuthLoginException { 682 if (debug.messageEnabled()) { 683 debug.message("ReplaceHeader : state=" + state + ", header=" + 684 header); 685 } 686 687 if (lastState != state) { 688 alreadyReplaced = false; 689 } 690 lastState = state; 691 692 // check state length 693 if (state > stateLength) { 694 throw new AuthLoginException(bundleName, "invalidState", 695 new Object[]{new Integer(state)}); 696 } 697 // check callback length for the state 698 Callback[] ext = getCallback(state, true); 699 if (ext.length<=0) { 700 throw new AuthLoginException(bundleName, "invalidCallbackIndex", 701 null); 702 } 703 704 // in internal, first Callback is always PagePropertiesCallback 705 if ((header!=null)&&(header.length() != 0)) { 706 PagePropertiesCallback pc = 707 (PagePropertiesCallback)((Callback[]) internal.get(state-1))[0]; 708 // retrieve header with REPLACE tag 709 if ( !(alreadyReplaced) ) { 710 headerWithReplaceTag = pc.getHeader(); 711 } 712 // replace string 713 int idx = headerWithReplaceTag.indexOf("#REPLACE#"); 714 if (idx != -1) { 715 String newHeader = headerWithReplaceTag.substring(0, idx) + header; 716 pc.setHeader(newHeader); 717 alreadyReplaced = true; 718 }else{ 719 String newHeader = headerWithReplaceTag.substring(0, 720 headerWithReplaceTag.indexOf("<BR></BR>")) + "<BR></BR>" + header; 721 pc.setHeader(newHeader); 722 } 723 } 724 } 725 726 /** 727 * Allows you to set the info text for a specific callback. Info Text is shown 728 * under the element in the Login page. It is used in the membership module to 729 * implement in-line feedback. 730 * 731 * @param state state in which the Callback[] to be reset 732 * @param callback the callback to associate the info text 733 * @param infoText the infotext for the callback 734 * @throws AuthLoginException if state/callback is out of bounds 735 * @supported.api 736 */ 737 public void substituteInfoText(int state, int callback, String infoText) 738 throws AuthLoginException { 739 if (debug.messageEnabled()) { 740 debug.message("setInfoText : state=" + state + ", infoText=" + infoText); 741 } 742 743 // check state length 744 if (state > stateLength) { 745 throw new AuthLoginException(bundleName, "invalidState", 746 new Object[]{new Integer(state)}); 747 } 748 749 // check callback length for the state 750 Callback[] ext = getCallback(state); 751 if (ext.length<=0) { 752 throw new AuthLoginException(bundleName, "invalidCallbackIndex", null); 753 } 754 755 // in internal, first Callback is always PagePropertiesCallback 756 if ((infoText != null) && (infoText.length() != 0)) { 757 PagePropertiesCallback pagePropertiesCallback = 758 (PagePropertiesCallback)((Callback[]) internal.get(state - 1))[0]; 759 760 List<String> infoTexts = pagePropertiesCallback.getInfoText(); 761 infoTexts.set(callback, infoText); 762 pagePropertiesCallback.setInfoText(infoTexts); 763 } 764 } 765 766 /** 767 * Clears the info text for a given callback state 768 * 769 * @param state The state to clear all infotexts 770 * @throws AuthLoginException Invalid state 771 * @supported.api 772 */ 773 public void clearInfoText(int state) 774 throws AuthLoginException { 775 if (debug.messageEnabled()) { 776 debug.message("clearInfoText : state=" + state); 777 } 778 779 // check state length 780 if (state > stateLength) { 781 throw new AuthLoginException(bundleName, "invalidState", 782 new Object[]{new Integer(state)}); 783 } 784 785 // check callback length for the state 786 Callback[] ext = getCallback(state); 787 if (ext.length<=0) { 788 throw new AuthLoginException(bundleName, "invalidCallbackIndex", null); 789 } 790 791 // in internal, first Callback is always PagePropertiesCallback 792 PagePropertiesCallback pc = 793 (PagePropertiesCallback)((Callback[]) internal.get(state - 1))[0]; 794 795 // clear info text 796 List<String> infoTexts = pc.getInfoText(); 797 798 for (int i = 0; i < infoTexts.size(); i++) { 799 infoTexts.set(i, EMPTY_STRING); 800 } 801 802 pc.setInfoText(infoTexts); 803 } 804 805 /** 806 * Use this method to replace the header text from the XML file with new 807 * text. This method can be used multiple times on the same state replacing 808 * text with new text each time. Useful for modules that control their own 809 * error handling. 810 * 811 * @param state state state in which the Callback[] to be reset 812 * @param header The text of the header to be replaced 813 * @throws AuthLoginException if state is out of bounds 814 * @supported.api 815 */ 816 public void substituteHeader(int state, String header) 817 throws AuthLoginException { 818 if (debug.messageEnabled()) { 819 debug.message("substituteHeader : state=" + state + ", header=" + 820 header); 821 } 822 // check state length 823 if (state > stateLength) { 824 throw new AuthLoginException(bundleName, "invalidState", 825 new Object[]{new Integer(state)}); 826 } 827 // check callback length for the state 828 Callback[] ext = getCallback(state); 829 if (ext.length<=0) { 830 throw new AuthLoginException(bundleName, "invalidCallbackIndex", 831 null); 832 } 833 834 // in internal, first Callback is always PagePropertiesCallback 835 if ((header!=null)&&(header.length() != 0)) { 836 PagePropertiesCallback pc = 837 (PagePropertiesCallback)((Callback[]) internal.get(state-1))[0]; 838 839 // substitute string 840 pc.setHeader(header); 841 } 842 } 843 844 /** 845 * Reset a Callback instance to the original Callback for the specified 846 * state and the specified index. This will override change to the Callback 847 * instance by the <code>replaceCallback()</code> method. 848 * @param state state in which the Callback[] to be reset 849 * @param index index order of the Callback in the Callback[], index starts 850 * with 0, i.e. 0 means first callback instance, 1 means 851 * the second callback instance. 852 * @throws AuthLoginException if state or index is out of bound. 853 * @supported.api 854 */ 855 public void resetCallback(int state, int index) 856 throws AuthLoginException { 857 if (debug.messageEnabled()) { 858 debug.message("resetCallback: state=" + state + ",index=" + index); 859 } 860 // check state length 861 if (state > stateLength) { 862 throw new AuthLoginException(bundleName, "invalidState", 863 new Object[]{new Integer(state)}); 864 } 865 // check callback length for the state 866 Callback[] ext = getCallback(state); 867 if (index < 0 || index >= ext.length) { 868 throw new AuthLoginException(bundleName, "invalidCallbackIndex", 869 new Object[]{new Integer(index)}); 870 } 871 872 // get the Callback from AMModuleProperties 873 // add one to index here since first one is the PagePropertiesCallback 874 Callback callback = ((Callback[]) origList.get(state-1))[index+1]; 875 Callback newCallback = null; 876 if (callback instanceof NameCallback) { 877 newCallback = new NameCallback( 878 ((NameCallback) callback).getPrompt()); 879 } else if (callback instanceof PasswordCallback) { 880 newCallback = new PasswordCallback( 881 ((PasswordCallback) callback).getPrompt(), 882 ((PasswordCallback) callback).isEchoOn()); 883 } else if (callback instanceof ChoiceCallback) { 884 int selection = ((ChoiceCallback) callback).getDefaultChoice(); 885 newCallback = new ChoiceCallback( 886 ((ChoiceCallback) callback).getPrompt(), 887 ((ChoiceCallback) callback).getChoices(), 888 selection, 889 ((ChoiceCallback) callback).allowMultipleSelections()); 890 } else { 891 // should never come here since only above three will be supported 892 debug.error("Unsupported call back instance " + callback); 893 throw new AuthLoginException(bundleName, "unknownCallback", null); 894 } 895 896 if (debug.messageEnabled()) { 897 debug.message("original=" + callback + ",new=" + newCallback); 898 } 899 900 // set external & internal callback instance 901 ((Callback[]) internal.get(state-1))[index+1] = newCallback; 902 ((Callback[]) external.get(state-1))[index] = newCallback; 903 } 904 905 /** 906 * Implements initialize() method in JAAS LoginModule class. 907 * <p> 908 * The purpose of this method is to initialize Login Module, 909 * it will call the init() method implemented by user's Login 910 * Module to do initialization. 911 * <p> 912 * This is a final method. 913 * @param subject - the Subject to be authenticated. 914 * @param callbackHandler - a CallbackHandler for communicating with the 915 * end user (prompting for usernames and passwords, for example). 916 * @param sharedState - state shared with other configured LoginModules. 917 * @param options - options specified in the login Configuration for this 918 * particular LoginModule. 919 */ 920 public final void initialize(Subject subject, 921 CallbackHandler callbackHandler, 922 java.util.Map sharedState, 923 java.util.Map options) { 924 this.subject = subject; 925 this.handler = callbackHandler; 926 this.sharedState = sharedState; 927 this.options = options; 928 // get class name 929 String className = this.getClass().getName(); 930 int index = className.lastIndexOf("."); 931 moduleClass = className.substring(index + 1); 932 moduleName = (String) options.get(ISAuthConstants. 933 MODULE_INSTANCE_NAME); 934 935 // get module properties file path 936 937 loginState = getLoginState(); 938 939 fileName = loginState.getFileName(moduleClass+ ".xml"); 940 loginState.setSharedState(sharedState); 941 942 // get resource bundle 943 944 bundle = amCache.getResBundle(bundleName, getLoginLocale()); 945 946 if (debug.messageEnabled()) { 947 debug.message("AMLoginModule resbundle locale="+getLoginLocale()); 948 debug.message("Login, class = " + className + 949 ", module=" + moduleName + ", file=" + fileName); 950 } 951 isSharedState = Boolean.valueOf(CollectionHelper.getMapAttr( 952 options, ISAuthConstants.SHARED_STATE_ENABLED, "false") 953 ).booleanValue(); 954 955 isStore = Boolean.valueOf(CollectionHelper.getMapAttr( 956 options, ISAuthConstants.STORE_SHARED_STATE_ENABLED, "true") 957 ).booleanValue(); 958 959 sharedStateBehaviorPattern = Misc.getMapAttr(options, 960 ISAuthConstants.SHARED_STATE_BEHAVIOR_PATTERN, 961 "tryFirstPass"); 962 963 if (debug.messageEnabled()) { 964 debug.message("AMLoginModule" + 965 ISAuthConstants.SHARED_STATE_BEHAVIOR_PATTERN + 966 " is set to " + sharedStateBehaviorPattern); 967 } 968 969 // Check for composite Advice 970 String compositeAdvice = loginState.getCompositeAdvice(); 971 if (compositeAdvice != null) { 972 if (debug.messageEnabled()) { 973 debug.message("AMLoginModule.initialize: " 974 + "Adding Composite Advice " + compositeAdvice); 975 } 976 sharedState.put(ISAuthConstants.COMPOSITE_ADVICE_XML, 977 compositeAdvice); 978 } 979 // call customer init method 980 init(subject, sharedState, options); 981 } 982 983 /** 984 * Initialize this LoginModule. 985 * <p> 986 * This is an abstract method, must be implemented by user's Login Module 987 * to initialize this LoginModule with the relevant information. If this 988 * LoginModule does not understand any of the data stored in sharedState 989 * or options parameters, they can be ignored. 990 * @param subject - the Subject to be authenticated. 991 * @param sharedState - state shared with other configured LoginModules. 992 * @param options - options specified in the login Configuration for this 993 * particular LoginModule. It contains all the global and organization 994 * attribute configuration for this module. The key of the map is the 995 * attribute name (e.g. <code>iplanet-am-auth-ldap-server</code>) as 996 * String, the value is the value of the corresponding attribute as Set. 997 * @supported.api 998 */ 999 abstract public void init(Subject subject, 1000 java.util.Map sharedState, 1001 java.util.Map options); 1002 1003 /** 1004 * Abstract method must be implemented by each login module to 1005 * control the flow of the login process. 1006 * <p> 1007 * This method takes an array of sbumitted 1008 * Callback, process them and decide the order of next state to go. 1009 * Return -1 if the login is successful, return 0 if the 1010 * LoginModule should be ignored. 1011 * @param callbacks Callback[] for this Login state 1012 * @param state Order of state. State order starts with 1. 1013 * @return order of next state. return -1 if authentication 1014 * is successful, return 0 if the LoginModule should be ignored. 1015 * @exception LoginException if login fails. 1016 * @supported.api 1017 */ 1018 abstract public int process(Callback[] callbacks, int state) 1019 throws LoginException; 1020 1021 /** 1022 * Abstract method must be implemeted by each login module to 1023 * get the user Principal 1024 * @return Principal 1025 * @supported.api 1026 */ 1027 abstract public java.security.Principal getPrincipal(); 1028 1029 /** 1030 * This method should be overridden by each login module 1031 * to destroy dispensable state fields. 1032 * 1033 * @supported.api 1034 */ 1035 public void destroyModuleState(){}; 1036 1037 /** 1038 * This method should be overridden by each login module 1039 * to do some garbage collection work after the module 1040 * process is done. Typically those class wide global variables 1041 * that will not be used again until a logout call should be nullified. 1042 */ 1043 public void nullifyUsedVars() {}; 1044 1045 /** 1046 * Wrapper for process() to utilize AuthLoginException. 1047 * @param callbacks associated with authentication 1048 * @param state of callbacks 1049 * @return state of auth login 1050 * @exception AuthLoginException if login fails. 1051 */ 1052 private int wrapProcess(Callback[] callbacks, int state) 1053 throws AuthLoginException { 1054 try { 1055 if (callbacks != null) { 1056 for (int i = 0; i < callbacks.length; i++) { 1057 if (callbacks[i] instanceof NameCallback) { 1058 String newUser = null; 1059 try { 1060 newUser = IdUtils.getIdentityName( 1061 ((NameCallback) callbacks[i]).getName(), 1062 getRequestOrg()); 1063 } catch (IdRepoException idRepoExp) { 1064 //Print message and let Auth proceed. 1065 debug.message( 1066 "AMLoginModule.wrapProcess: Cannot get "+ 1067 "username from idrepo. ", idRepoExp); 1068 } 1069 if (newUser != null) { 1070 ((NameCallback) callbacks[i]).setName(newUser); 1071 } 1072 } 1073 } 1074 } 1075 return process(callbacks, state); 1076 } catch (InvalidPasswordException e) { 1077 setFailureReason(AMAuthErrorCode.AUTH_INVALID_PASSWORD); 1078 setFailureID(e.getTokenId()); 1079 setFailureState(); 1080 throw e; 1081 } catch (AuthLoginException e) { 1082 setFailureReason(e.getErrorCode()); 1083 setFailureState(); 1084 throw e; 1085 } catch (LoginException e) { 1086 setFailureState(); 1087 throw new AuthLoginException(e); 1088 } catch (RuntimeException re) { 1089 setFailureState(); 1090 throw re; 1091 } 1092 } 1093 1094 /** 1095 * Sets the <code>errorCode</code> for failed authentication 1096 * 1097 * @param errorCode reason for failed authentication. 1098 */ 1099 private void setFailureReason(String errorCode) { 1100 // get login state for this authentication session 1101 if (errorCode == null) { 1102 return; 1103 } 1104 if (loginState == null) { 1105 loginState = getLoginState(); 1106 if (loginState == null) { 1107 return; 1108 } 1109 } 1110 loginState.setErrorCode(errorCode); 1111 return ; 1112 } 1113 1114 private void setFailureState() { 1115 currentState = ISAuthConstants.LOGIN_IGNORE; 1116 setFailureModuleName(moduleName); 1117 } 1118 1119 /** 1120 * Returns true if a module in authentication chain has already done, either 1121 * succeeded or failed. 1122 * 1123 * @return true if a module in authentication chain has already done, either 1124 * succeeded or failed. 1125 */ 1126 private boolean moduleHasDone() { 1127 return (currentState == ISAuthConstants.LOGIN_SUCCEED) || 1128 (currentState == ISAuthConstants.LOGIN_IGNORE); 1129 } 1130 1131 /** 1132 * Implements login() method in JAAS LoginModule class. 1133 * <p> 1134 * This method is responsible for retrieving corresponding Callback[] for 1135 * current state, send as requirement to user, get the submitted Callback[], 1136 * call the process() method. The process() method will decide the next 1137 * action based on those submitted Callback[]. 1138 * <p> 1139 * This method is final. 1140 * @return <code>true</code> if the authentication succeeded, or 1141 * <code>false</code> if this LoginModule should be ignored. 1142 * @throws AuthLoginException - if the authentication fails 1143 */ 1144 public final boolean login() throws AuthLoginException { 1145 if (moduleHasDone()) { 1146 debug.message("This module has already done."); 1147 return ISAuthConstants.LOGIN_SUCCEED == currentState; 1148 } else { 1149 if (debug.messageEnabled()) { 1150 debug.message("This module is not done yet. CurrentState: {}", currentState); 1151 } 1152 } 1153 1154 // make one getCallback call to populate first state 1155 // this will set the noCallbacks variable 1156 if (internal == null) { 1157 getCallback(1); 1158 } 1159 // if this module does not define any Callbacks (such as Cert), 1160 // pass control right to module, then check return code from module 1161 if (noCallbacks) { 1162 currentState = wrapProcess(EMPTY_CALLBACK, 1); 1163 // check login status 1164 switch (currentState) { 1165 case LOGIN_SUCCEED: 1166 setSuccessModuleName(moduleName); 1167 succeeded = true; 1168 setModuleAuthLevel(); 1169 nullifyUsedVars(); 1170 return true; 1171 case LOGIN_IGNORE: 1172 setFailureModuleName(moduleName); 1173 succeeded = false; 1174 destroyModuleState(); 1175 principal = null; 1176 return false; 1177 default: 1178 setFailureModuleName(moduleName); 1179 succeeded = false; 1180 cleanup(); 1181 throw new AuthLoginException(bundleName, "invalidCode", new Object[]{new Integer(currentState)}); 1182 } 1183 } 1184 1185 if (handler == null) { 1186 debug.error("Handler is null"); 1187 throw new AuthLoginException(bundleName, "nullHandler", null); 1188 } 1189 try { 1190 Callback[] lastCallbacks = null; 1191 boolean needToExit = false; 1192 1193 // starting from first page 1194 //currentState = 1; 1195 while (currentState != ISAuthConstants.LOGIN_SUCCEED && 1196 currentState != ISAuthConstants.LOGIN_IGNORE) { 1197 if (debug.messageEnabled()) { 1198 debug.message("Login, state = " + currentState); 1199 } 1200 if (isSharedState) { 1201 currentState = wrapProcess(EMPTY_CALLBACK, 1); 1202 isSharedState = false; 1203 continue; 1204 } 1205 // get current set of callbacks 1206 getCallback(currentState); 1207 // check if this is an error state, if so, throw exception 1208 // to terminate login process 1209 Callback[] cbks = ((Callback[]) internal.get(currentState-1)); 1210 PagePropertiesCallback callback = 1211 (PagePropertiesCallback) cbks[0]; 1212 1213 if (callback.getErrorState()) { 1214 // this is an error state 1215 setFailureModuleName(moduleName); 1216 String template = callback.getTemplateName(); 1217 String errorMessage = callback.getHeader(); 1218 if (template == null || template.length() == 0) { 1219 // this is the case which no error template is 1220 // defined, only exception message in header 1221 throw new MessageLoginException(errorMessage); 1222 } else { 1223 // send error template 1224 //setLoginFailureURL(template); 1225 setModuleErrorTemplate(template); 1226 throw new AuthLoginException(errorMessage); 1227 } 1228 } 1229 // call handler to handle the internal callbacks 1230 handler.handle(cbks); 1231 1232 // Get the page state from the PagePropertiesCallback 1233 Callback[] cbksPrev= ((Callback[])internal.get(currentState-1)); 1234 1235 PagePropertiesCallback callbackPrev = 1236 (PagePropertiesCallback) cbksPrev[0]; 1237 String pageState = callbackPrev.getPageState(); 1238 if ((pageState != null) && 1239 (pageState.length() != 0) && 1240 (!pageState.equals(Integer.toString(currentState)))) { 1241 int loginPage = Integer.parseInt(pageState); 1242 1243 //Set the current page state in PagePropertiesCallback 1244 callbackPrev.setPageState(Integer.toString(currentState)); 1245 1246 currentState = loginPage; 1247 if (debug.messageEnabled()) { 1248 debug.message("currentState from UI " + currentState); 1249 } 1250 } 1251 1252 // Get the last submitted callbacks to auth module and submit 1253 // those callbacks to do DataStore authentication if the incoming 1254 // user is special / internal user and auth module is other than 1255 // "DataStore" and "Application" auth modules. 1256 lastCallbacks = (Callback[])external.get(currentState-1); 1257 if ((!moduleClass.equalsIgnoreCase("DataStore")) && 1258 (!moduleClass.equalsIgnoreCase("Application"))) { 1259 try { 1260 if (!authenticateToDatastore(lastCallbacks)) { 1261 needToExit = true; 1262 break; 1263 } 1264 } catch (AuthLoginException e) { 1265 //Set the failure state here before throwing - to reflect the datastore auth failing 1266 setFailureReason(e.getErrorCode()); 1267 setFailureState(); 1268 throw e; 1269 } 1270 } 1271 1272 // send external callback and send to module for processing 1273 currentState = wrapProcess((Callback[]) 1274 external.get(currentState-1), currentState); 1275 1276 if (debug.messageEnabled()) { 1277 debug.message("Login NEXT State : " + currentState); 1278 } 1279 } 1280 1281 if (needToExit) { 1282 nullifyUsedVars(); 1283 setFailureState(); 1284 throw new AuthLoginException(AMAuthErrorCode.AUTH_MODULE_DENIED); 1285 } 1286 1287 // check login status 1288 if (currentState == ISAuthConstants.LOGIN_SUCCEED) { 1289 setSuccessModuleName(moduleName); 1290 succeeded = true; 1291 setModuleAuthLevel(); 1292 nullifyUsedVars(); 1293 return true; 1294 } else { 1295 // currentState = 0; 1296 setFailureModuleName(moduleName); 1297 succeeded = false; 1298 destroyModuleState(); 1299 principal = null; 1300 return false; 1301 } 1302 } catch (IOException e) { 1303 setFailureModuleName(moduleName); 1304 if (e.getMessage().equals(AMAuthErrorCode.AUTH_TIMEOUT)) { 1305 debug.message("login timed out ", e); 1306 } else { 1307 debug.message("login ", e); 1308 } throw new AuthLoginException(e); 1309 } catch (UnsupportedCallbackException e) { 1310 setFailureModuleName(moduleName); 1311 debug.message("Login", e); 1312 throw new AuthLoginException(e); 1313 } 1314 } 1315 1316 /** 1317 * Returns authentication level that has been set for the module 1318 * 1319 * @return authentication level of this authentication session 1320 * @supported.api 1321 */ 1322 public int getAuthLevel() { 1323 // get login state for this authentication session 1324 if (loginState == null) { 1325 loginState = getLoginState(); 1326 if (loginState == null) { 1327 return 0; 1328 } 1329 } 1330 return loginState.getAuthLevel(); 1331 } 1332 1333 /** 1334 * Sets the <code>AuthLevel</code> for this session. 1335 * The authentication level being set cannot be downgraded 1336 * below that set by the module configuration. 1337 * 1338 * @param auth_level authentication level string to be set 1339 * @return <code>true</code> if setting is successful,<code>false</code> 1340 * otherwise 1341 * @supported.api 1342 */ 1343 public boolean setAuthLevel(int auth_level) { 1344 // get login state for this authentication session 1345 if (loginState == null) { 1346 loginState = getLoginState(); 1347 if (loginState == null) { 1348 // may be should throw AuthLoginException here 1349 debug.error("Unable to set auth level : " + auth_level); 1350 return false; 1351 } 1352 } 1353 loginState.setModuleAuthLevel(auth_level); 1354 return true; 1355 } 1356 1357 private void setModuleAuthLevel() { 1358 String authLevelAttribute = AMAuthConfigUtils.getAuthLevelAttribute(options, moduleName); 1359 if (authLevelAttribute != null) { 1360 String authLevel = CollectionHelper.getMapAttr(options, authLevelAttribute); 1361 if (authLevel != null) { 1362 try { 1363 setAuthLevel(Integer.parseInt(authLevel)); 1364 } catch (Exception e) { 1365 debug.error("Unable to set auth level {} for {}", moduleName, authLevel, e); 1366 } 1367 } 1368 } 1369 } 1370 1371 /** 1372 * Returns the current state in the authentication process. 1373 * 1374 * @return the current state in the authentication process. 1375 * @supported.api 1376 */ 1377 public int getCurrentState() { 1378 return currentState; 1379 } 1380 1381 /** 1382 * Returns the <code>HttpServletRequest</code> object that 1383 * initiated the call to this module. 1384 * 1385 * @return <code>HttpServletRequest</code> for this request, returns null 1386 * if the <code>HttpServletRequest</code> object could not be 1387 * obtained. 1388 * @supported.api 1389 */ 1390 public HttpServletRequest getHttpServletRequest() { 1391 // get login state for this authentication session 1392 if (loginState == null) { 1393 loginState = getLoginState(); 1394 if (loginState == null) { 1395 return null; 1396 } 1397 } 1398 return loginState.getHttpServletRequest(); 1399 } 1400 1401 /** 1402 * Returns the authentication <code>LoginState</code> 1403 * @param methodName Name of the required methd in 1404 * <code>LoginState</code> object 1405 * @return <code>com.sun.identity.authentication.service.LoginState</code> 1406 * for this authentication method. 1407 * @throws AuthLoginException if fails to get the Login state 1408 */ 1409 protected com.sun.identity.authentication.service.LoginState getLoginState( 1410 String methodName) throws AuthLoginException { 1411 if (loginState == null) { 1412 loginState = getLoginState(); 1413 if (loginState == null) { 1414 throw new AuthLoginException(bundleName, "wrongCall", 1415 new Object[]{methodName}); 1416 } 1417 } 1418 return loginState; 1419 } 1420 1421 /** 1422 * Returns the Login <code>Locale</code> for this session 1423 * @return <code>Locale</code> used for localizing text 1424 */ 1425 protected java.util.Locale getLoginLocale() { 1426 try { 1427 String loc = getLocale(); 1428 return com.sun.identity.shared.locale.Locale.getLocale(loc); 1429 } catch (AuthLoginException ex) { 1430 debug.message("unable to determine loginlocale ", ex); 1431 return java.util.Locale.ENGLISH; 1432 } 1433 } 1434 1435 /* 1436 * Returns the Login State object 1437 * @return com.sun.identity.authentication.service.LoginState 1438 */ 1439 private com.sun.identity.authentication.service.LoginState getLoginState() { 1440 Callback[] callbacks = new Callback[1]; 1441 try { 1442 callbacks[0] = new LoginStateCallback(); 1443 if (handler == null) { 1444 return null; 1445 } 1446 handler.handle(callbacks); 1447 return ((LoginStateCallback) callbacks[0]).getLoginState(); 1448 } catch (Exception e) { 1449 debug.message("Error.." ,e ); 1450 return null; 1451 } 1452 } 1453 1454 /** 1455 * Returns the <code>HttpServletResponse</code> object for the servlet 1456 * request that initiated the call to this module. The servlet response 1457 * object will be the response to the <code>HttpServletRequest</code> 1458 * received by the authentication module. 1459 * 1460 * @return <code>HttpServletResponse</code> for this request, returns null 1461 * if the <code>HttpServletResponse</code> object could not be obtained. 1462 * @supported.api 1463 */ 1464 public HttpServletResponse getHttpServletResponse() { 1465 // get login state for this authentication session 1466 if (loginState == null) { 1467 loginState = getLoginState(); 1468 if (loginState == null) { 1469 return null; 1470 } 1471 } 1472 return loginState.getHttpServletResponse(); 1473 } 1474 1475 /** 1476 * Returns the CallbackHandler object for the module. This method 1477 * will be used internally. 1478 * 1479 * @return CallbackHandler for this request, returns null if the 1480 * CallbackHandler object could not be obtained. 1481 */ 1482 public CallbackHandler getCallbackHandler() { 1483 return handler; 1484 } 1485 1486 /** 1487 * Returns the locale for this authentication session. 1488 * 1489 * @return <code>java.util.Locale</code> locale for this authentication 1490 * session. 1491 * @throws AuthLoginException if problem in accessing the 1492 locale. 1493 * @supported.api 1494 */ 1495 public String getLocale() throws AuthLoginException { 1496 // get login state for this authentication session 1497 return getLoginState("getLocale()").getLocale(); 1498 } 1499 1500 /** 1501 * Returns the number of authentication states for this 1502 * login module. 1503 * 1504 * @return the number of authentication states for this login module. 1505 * @supported.api 1506 */ 1507 public int getNumberOfStates() { 1508 return stateLength; 1509 } 1510 1511 /** 1512 * Returns the organization DN for this authentication session. 1513 * 1514 * @return organization DN. 1515 * @supported.api 1516 */ 1517 public String getRequestOrg() { 1518 // get login state for this authentication session 1519 if (loginState == null) { 1520 loginState = getLoginState(); 1521 if (loginState == null) { 1522 return null; 1523 } 1524 } 1525 return loginState.getOrgDN(); 1526 } 1527 1528 /** 1529 * Returns a unique key for this authentication session. 1530 * This key will be unique throughout an entire Web browser session. 1531 * 1532 * @return null is unable to get the key, 1533 * @supported.api 1534 */ 1535 public String getSessionId() { 1536 // get login state for this authentication session 1537 if (loginState == null) { 1538 loginState = getLoginState(); 1539 if (loginState == null) { 1540 return null; 1541 } 1542 } 1543 return loginState.getSid().toString(); 1544/* 1545 InternalSession sess = loginState.getSession(); 1546 if (sess != null) { 1547 return sess.getID().toString(); 1548 } else { 1549 return null; 1550 } 1551*/ 1552 } 1553 1554 /** 1555 * Returns the organization attributes for specified organization. 1556 * 1557 * @param orgDN Requested organization DN. 1558 * @return Map that contains all attribute key/value pairs defined 1559 * in the organization. 1560 * @throws AuthLoginException if cannot get organization profile. 1561 * @supported.api 1562 */ 1563 public Map getOrgProfile(String orgDN) throws AuthLoginException { 1564 Map orgMap = null; 1565 if (orgDN == null || orgDN.length() == 0) { 1566 // get login state for this authentication session 1567 orgDN = getLoginState("getOrgProfile(String)").getOrgDN(); 1568 } 1569 1570 try { 1571 OrganizationConfigManager orgConfigMgr = 1572 AuthD.getAuth().getOrgConfigManager(orgDN); 1573 orgMap = orgConfigMgr.getAttributes( 1574 ISAuthConstants.IDREPO_SVC_NAME); 1575 if (debug.messageEnabled()) { 1576 debug.message("orgMap is : " + orgMap); 1577 } 1578 } catch (Exception ex) { 1579 debug.message("getOrgProfile", ex); 1580 throw new AuthLoginException(ex); 1581 } 1582 return orgMap; 1583 } 1584 1585 /** 1586 * Returns service template attributes defined for the specified 1587 * organization. 1588 * 1589 * @param orgDN Organization DN. 1590 * @param serviceName Requested service name. 1591 * @return Map that contains all attribute key/value pairs defined in the 1592 * organization service template. 1593 * @throws AuthLoginException if cannot get organization service 1594 * template. 1595 * @supported.api 1596 */ 1597 public Map getOrgServiceTemplate(String orgDN, String serviceName) 1598 throws AuthLoginException { 1599 Map orgMap = null; 1600 if (orgDN == null || orgDN.length() == 0) { 1601 // get login state for this authentication session 1602 orgDN = getLoginState( 1603 "getOrgServiceTemplate(String, String)").getOrgDN(); 1604 } 1605 try { 1606 OrganizationConfigManager orgConfigMgr = 1607 AuthD.getAuth().getOrgConfigManager(orgDN); 1608 orgMap = orgConfigMgr.getServiceConfig(serviceName).getAttributes(); 1609 } 1610 catch (Exception ex) { 1611 debug.message("getOrgServiceTemplate", ex); 1612 throw new AuthLoginException(ex); 1613 } 1614 return orgMap; 1615 } 1616 1617 /** 1618 * Checks if dynamic profile creation is enabled. 1619 * 1620 * @return <code>true</code> if dynamic profile creation is enabled. 1621 */ 1622 public boolean isDynamicProfileCreationEnabled() { 1623 // get login state for this authentication session 1624 if (loginState == null) { 1625 loginState = getLoginState(); 1626 if (loginState == null) { 1627 return false; 1628 } 1629 } 1630 return loginState.isDynamicProfileCreationEnabled(); 1631 } 1632 1633 /** 1634 * Returns service configuration attributes. 1635 * @param name Requested service name. 1636 * @return Map that contains all attribute key/value pairs defined in 1637 * the service configuration. 1638 * @throws AuthLoginException if error in accessing the service schema. 1639 * 1640 * @supported.api 1641 */ 1642 public Map getServiceConfig(String name) throws AuthLoginException { 1643 try { 1644 ServiceSchemaManager scm = new ServiceSchemaManager(name, 1645 AuthD.getAuth().getSSOAuthSession()); 1646 ServiceSchema sc = scm.getGlobalSchema(); 1647 HashMap retMap = new HashMap(); 1648 if (sc != null) { 1649 retMap.putAll(sc.getAttributeDefaults()); 1650 } 1651 1652 sc = scm.getOrganizationSchema(); 1653 if (sc != null) { 1654 retMap.putAll(sc.getAttributeDefaults()); 1655 } 1656 1657 sc = scm.getUserSchema(); 1658 if (sc != null) { 1659 retMap.putAll(sc.getAttributeDefaults()); 1660 } 1661 1662 sc = scm.getPolicySchema(); 1663 if (sc != null) { 1664 retMap.putAll(sc.getAttributeDefaults()); 1665 } 1666 1667 return retMap; 1668 } catch (Exception ex) { 1669 debug.message("getServiceConfig", ex); 1670 throw new AuthLoginException(ex); 1671 } 1672 } 1673 1674 /** 1675 * Returns the user profile for the user specified. This 1676 * method may only be called in the validate() method. 1677 * 1678 * @param userDN distinguished name os user. 1679 * @return <code>AMUser</code> object for the user's distinguished name. 1680 * @throws AuthLoginException if it fails to get the user profile for 1681 * <code>userDN</code>. 1682 * @deprecated This method has been deprecated. Please use the 1683 * IdRepo API's to get the AMIdentity object for the user. More 1684 * information on how to use the Identity Repository APIs is 1685 * available in the "Customizing Identity Data Storage" chapter 1686 * of the OpenAM Developer's Guide. 1687 * 1688 * @supported.api 1689 */ 1690 public AMUser getUserProfile(String userDN) throws AuthLoginException{ 1691 AMUser user = null; 1692 try { 1693 user = AuthD.getAuth().getSDK().getUser(userDN); 1694 } catch (Exception ex) { 1695 debug.message("getUserProfile", ex); 1696 throw new AuthLoginException(ex); 1697 } 1698 return user; 1699 } 1700 1701 /** 1702 * Returns the property from the user session. If the session is being force 1703 * upgraded then set on the old session otherwise set on the current session. 1704 * 1705 * @param name The property name. 1706 * @return The property value. 1707 * @throws AuthLoginException if the user session is invalid. 1708 * 1709 * @supported.api 1710 */ 1711 public String getUserSessionProperty(String name) 1712 throws AuthLoginException { 1713 InternalSession sess = null; 1714 1715 if (getLoginState(null).isSessionUpgrade() && 1716 getLoginState(null).getForceFlag()) { 1717 sess = getLoginState(null).getOldSession(); 1718 } else { 1719 sess = getLoginState("getUserSessionProperty()").getSession(); 1720 } 1721 1722 if (sess != null) { 1723 return sess.getProperty(name); 1724 } else { 1725 return null; 1726 } 1727 } 1728 1729 /** 1730 * Sets a property in the user session. If the session is being force 1731 * upgraded then set on the old session otherwise set on the current session. 1732 * 1733 * @param name The property name. 1734 * @param value The property value. 1735 * @throws AuthLoginException if the user session is invalid. 1736 * 1737 * @supported.api 1738 */ 1739 public void setUserSessionProperty(String name, String value) 1740 throws AuthLoginException { 1741 InternalSession sess = null; 1742 1743 if (getLoginState(null).isSessionUpgrade() && 1744 getLoginState(null).getForceFlag()) { 1745 sess = getLoginState(null).getOldSession(); 1746 } else { 1747 sess = getLoginState("setUserSessionProperty()").getSession(); 1748 } 1749 1750 if (sess != null) { 1751 sess.putProperty(name, value); 1752 } else { 1753 throw new AuthLoginException(bundleName, "wrongCall", 1754 new Object[]{" setUserSessionProperty()"}); 1755 } 1756 } 1757 1758 /** 1759 * Returns a set of user IDs generated from the class defined 1760 * in the Core Authentication Service. Returns null if the 1761 * attribute <code>iplanet-am-auth-username-generator-enabled</code> is 1762 * set to false. 1763 * 1764 * @param attributes the keys in the <code>Map</code> contains the 1765 * attribute names and their corresponding values in 1766 * the <code>Map</code> is a <code>Set</code> that 1767 * contains the values for the attribute 1768 * @param num the maximum number of returned user IDs; 0 means there 1769 * is no limit 1770 * @return a set of auto-generated user IDs 1771 * @throws AuthLoginException if the class instantiation failed 1772 * 1773 * @supported.api 1774 */ 1775 public Set getNewUserIDs(Map attributes, int num) 1776 throws AuthLoginException { 1777 boolean enabled = getLoginState( 1778 "getNewUserIDs(Map, int)").isUserIDGeneratorEnabled(); 1779 1780 if (!enabled) { 1781 return null; 1782 } 1783 1784 String className = getLoginState( 1785 "getNewUserIDs(Map, int)").getUserIDGeneratorClassName(); 1786 String orgDN = getLoginState("getNewUserIDs(Map, int)").getOrgDN(); 1787 1788 // if className is null or empty, use the default user ID 1789 // generator class name 1790 if (className == null || className.length() == 0) { 1791 className = ISAuthConstants.DEFAULT_USERID_GENERATOR_CLASS; 1792 } 1793 1794 UserIDGenerator idGenerator = null; 1795 try { 1796 // instantiate the Java class 1797 Class theClass = Class.forName(className); 1798 idGenerator = (UserIDGenerator)theClass.newInstance(); 1799 1800 } catch (Exception e) { 1801 debug.message("getNewUserIDs(): unable to instantiate " + 1802 className, e); 1803 return null; 1804 } 1805 1806 return (idGenerator.generateUserIDs(orgDN, attributes, num)); 1807 } 1808 1809 /** 1810 * Sets the the login failure URL for the user. This method does not 1811 * change the URL in the user's profile. When the user authenticates 1812 * failed, this URL will be used by the authentication for the 1813 * redirect. 1814 * 1815 * @param url URL to go when authentication failed. 1816 * @throws AuthLoginException if unable to set the URL. 1817 * 1818 * @supported.api 1819 */ 1820 public void setLoginFailureURL(String url) throws AuthLoginException { 1821 getLoginState("setLoginFailureURL()").setFailureLoginURL(url); 1822 } 1823 1824 /** 1825 * Sets the error template for the module 1826 * @param templateName the error template for the module 1827 * @throws AuthLoginException when unable to set the template 1828 */ 1829 public void setModuleErrorTemplate(String templateName) 1830 throws AuthLoginException { 1831 getLoginState( 1832 "setModuleTemplate()").setModuleErrorTemplate(templateName); 1833 } 1834 1835 /** 1836 * Sets the the login successful URL for the user. This method does not 1837 * change the URL in the user's profile. When the user authenticates 1838 * successfully, this URL will be used by the authentication for the 1839 * redirect. 1840 * 1841 * @param url <code>URL</code> to go when authentication is successful. 1842 * @throws AuthLoginException if unable to set the URL. 1843 * @supported.api 1844 */ 1845 public void setLoginSuccessURL(String url) throws AuthLoginException { 1846 getLoginState("setLoginSuccessURL()").setSuccessLoginURL(url); 1847 } 1848 1849 /** 1850 * Sets the user organization. This method should only be called when the 1851 * user authenticates successfully. It allows the user authentication 1852 * module to decide in which domain the user profile should be created. 1853 * 1854 * @param orgDN The organization DN. 1855 * @throws AuthLoginException 1856 */ 1857 public void setOrg(String orgDN) throws AuthLoginException { 1858/* TODO 1859 if (orgDN.indexOf("=") == -1) { 1860 throw new AuthLoginException(bundleName, "invalidDN", 1861 new Object[]{orgDN}); 1862 } 1863 getLoginState("setOrg()").setOrg(orgDN); 1864 */ 1865 return; 1866 } 1867 1868 /** 1869 * Checks if a Callback is required to have input. 1870 * @param state Order of state. 1871 * @param index Order of the Callback in the Callback[], the index. 1872 * starts with 0. 1873 * @return <code>true</code> if the callback corresponding to the number 1874 * in the specified state is required to have value, 1875 * <code>false</code> otherwise 1876 * @supported.api 1877 */ 1878 public boolean isRequired(int state, int index) { 1879 // check state 1880 if (state > stateLength) { 1881 // invalid state, return false now 1882 return false; 1883 } 1884 // get internal callbacks for the state 1885 Callback[] callbacks = (Callback[]) internal.get(state - 1); 1886 if (callbacks == null || callbacks.length == 0) { 1887 // no callbacks defined for this state, return false 1888 return false; 1889 } 1890 // check first Callback 1891 Callback callback = callbacks[0]; 1892 if (callback instanceof PagePropertiesCallback) { 1893 List req = ((PagePropertiesCallback) callback).getRequire(); 1894 if (req == null || req.isEmpty() || index >= req.size()) { 1895 return false; 1896 } else { 1897 String tmp = (String) req.get(index); 1898 if (tmp.equalsIgnoreCase("true")) { 1899 return true; 1900 } else { 1901 return false; 1902 } 1903 } 1904 } else { 1905 return false; 1906 } 1907 } 1908 1909 /** 1910 * Returns the info text associated with a specific callback 1911 * 1912 * @param state The state to fetch the info text 1913 * @param index The callback to fetch the info text 1914 * @return The info text 1915 * @supported.api 1916 */ 1917 public String getInfoText(int state, int index) { 1918 // check state 1919 if (state > stateLength) { 1920 // invalid state, return empty string now 1921 return EMPTY_STRING; 1922 } 1923 // get internal callbacks for the state 1924 Callback[] callbacks = (Callback[]) internal.get(state - 1); 1925 if (callbacks == null || callbacks.length == 0) { 1926 // no callbacks defined for this state, return empty string 1927 return EMPTY_STRING; 1928 } 1929 // check first Callback 1930 Callback callback = callbacks[0]; 1931 if (callback instanceof PagePropertiesCallback) { 1932 List<String> infoText = ((PagePropertiesCallback) callback).getAttribute(); 1933 if (infoText == null || infoText.isEmpty() || index >= infoText.size()) { 1934 return EMPTY_STRING; 1935 } else { 1936 return infoText.get(index); 1937 } 1938 } else { 1939 return EMPTY_STRING; 1940 } 1941 } 1942 1943 /** 1944 * Returns the attribute name for the specified callback in the 1945 * specified login state. 1946 * 1947 * @param state Order of state 1948 * @param index Order of the Callback in the Callback[], the index 1949 * starts with 0. 1950 * @return Name of the attribute, empty string will be returned 1951 * if the attribute is not defined. 1952 * @supported.api 1953 */ 1954 public String getAttribute(int state, int index) { 1955 // check state 1956 if (state > stateLength) { 1957 // invalid state, return empty string now 1958 return EMPTY_STRING; 1959 } 1960 // get internal callbacks for the state 1961 Callback[] callbacks = (Callback[]) internal.get(state - 1); 1962 if (callbacks == null || callbacks.length == 0) { 1963 // no callbacks defined for this state, return empty string 1964 return EMPTY_STRING; 1965 } 1966 // check first Callback 1967 Callback callback = callbacks[0]; 1968 if (callback instanceof PagePropertiesCallback) { 1969 List req = ((PagePropertiesCallback) callback).getAttribute(); 1970 if (req == null || req.isEmpty() || index >= req.size()) { 1971 return EMPTY_STRING; 1972 } else { 1973 return (String) req.get(index); 1974 } 1975 } else { 1976 return EMPTY_STRING; 1977 } 1978 } 1979 1980 /** 1981 * Aborts the authentication process. 1982 * <p> 1983 * This JAAS LoginModule method must be implemented by user's module. 1984 * <p> 1985 * This method is called if the overall authentication 1986 * failed. (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL 1987 * LoginModules did not succeed). 1988 * If this LoginModule's own authentication attempt succeeded (checked by 1989 * retrieving the private state saved by the login method), then this 1990 * method cleans up any state that was originally saved. 1991 * 1992 * @return <code>true</code> if this method succeeded,<code>false</code> 1993 * if this LoginModule should be ignored. 1994 * @throws AuthLoginException if the abort fails 1995 * @see javax.security.auth.spi.LoginModule#abort 1996 */ 1997 public final boolean abort() throws AuthLoginException { 1998 debug.message("ABORT return.... false"); 1999 if (succeeded == false) { 2000 return false; 2001 } else { 2002 logout(); 2003 } 2004 return true; 2005 } 2006 2007 /** 2008 * Commit the authentication process (phase 2). 2009 * <p> 2010 * This JAAS LoginModule method must be implemented by user's module. 2011 * <p> 2012 * This method is called if the overall authentication 2013 * succeeded (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL 2014 * LoginModules succeeded). 2015 * <p> 2016 * If this LoginModule's own authentication attempt succeeded (checked by 2017 * retrieving the private state saved by the login method), then this 2018 * method associates relevant Principals and Credentials with the Subject 2019 * located in the LoginModule. If this LoginModule's own authentication 2020 * attempted failed, then this method removes/destroys any state that was 2021 * originally saved. 2022 * 2023 * @return <code>true</code> if this method succeeded, or <code>false</code> 2024 * if this <code>LoginModule</code> should be ignored. 2025 * @throws AuthLoginException if the commit fails 2026 * @see javax.security.auth.spi.LoginModule#commit 2027 */ 2028 public final boolean commit() throws AuthLoginException { 2029 principal = getPrincipal(); 2030 if (debug.messageEnabled()) { 2031 debug.message( 2032 "AMLoginModule.commit():Succeed,principal=" + principal); 2033 } 2034 if (succeeded == false || principal == null) { 2035 return false; 2036 } else if (!subject.getPrincipals().contains(principal)) { 2037 subject.getPrincipals().add(principal); 2038 debug.message("Done added user to principal"); 2039 } 2040 cleanup(); 2041 return true; 2042 } 2043 2044 /** 2045 * Logs out a Subject. 2046 * <p> 2047 * This JAAS LoginModule method must be implemented by user's module. 2048 * <p> 2049 * An implementation of this method might remove/destroy a Subject's 2050 * Principals and Credentials. 2051 * 2052 * @return <code>true</code> if this method succeeded, or <code>false</code> 2053 * if this LoginModule should be ignored. 2054 * @throws AuthLoginException if the logout fails 2055 * @see javax.security.auth.spi.LoginModule#logout 2056 */ 2057 public final boolean logout() throws AuthLoginException { 2058 // logging out 2059 if (subject.getPrincipals().contains(principal)) { 2060 subject.getPrincipals().remove(principal); 2061 } 2062 succeeded = false; 2063 cleanup(); 2064 return true; 2065 } 2066 2067 /** 2068 * Sets the <code>userID</code> of user who failed authentication. 2069 * This <code>userID</code> will be used to log failed authentication in 2070 * the OpenSSO error logs. 2071 * 2072 * @param userID user name of user who failed authentication. 2073 * @supported.api 2074 */ 2075 public void setFailureID(String userID) { 2076 // get login state for this authentication session 2077 if (userID == null) { 2078 return; 2079 } 2080 debug.message("setFailureID : " + userID); 2081 if (loginState == null) { 2082 loginState = getLoginState(); 2083 if (loginState == null) { 2084 // may be should throw AuthLoginException here 2085 debug.error("Unable to set set userId : " + userID); 2086 return; 2087 } 2088 } 2089 loginState.setFailedUserId(userID); 2090 return ; 2091 } 2092 2093 /** 2094 * Sets a Map of attribute value pairs to be used when the authentication 2095 * service is configured to dynamically create a user. 2096 * 2097 * @param attributeValuePairs A map containing the attributes 2098 * and its values. The key is the attribute name and the value 2099 * is a Set of values. 2100 * 2101 * @supported.api 2102 */ 2103 public void setUserAttributes(Map attributeValuePairs) { 2104 // get login state for this authentication session 2105 if (loginState == null) { 2106 loginState = getLoginState(); 2107 if (loginState == null) { 2108 debug.error("Unable to set user attributes"); 2109 return; 2110 } 2111 } 2112 loginState.setUserCreationAttributes(attributeValuePairs); 2113 return; 2114 } 2115 2116 /** 2117 * Validates the given user name by using validation plugin if exists 2118 * else it checks invalid characters in the source string. 2119 * 2120 * @param userName source string which should be validated. 2121 * @param regEx the pattern for which to search. 2122 * @throws UserNamePasswordValidationException if user name is invalid. 2123 * @supported.api 2124 */ 2125 public void validateUserName(String userName, String regEx) 2126 throws UserNamePasswordValidationException { 2127 try { 2128 AMUserPasswordValidation plugin = getUPValidationInstance(); 2129 if (plugin != null) { 2130 debug.message("Validating username..."); 2131 Map envMap = new HashMap(2); 2132 envMap.put( 2133 com.sun.identity.shared.Constants.ORGANIZATION_NAME, 2134 getRequestOrg()); 2135 plugin.validateUserID(userName, envMap); 2136 } else if (regEx != null && (regEx.length() != 0)) { 2137 if (! (ISValidation.validate(userName, regEx, debug))) { 2138 throw new UserNamePasswordValidationException(bundleName, 2139 "invalidChars", null); 2140 } 2141 } 2142 } catch (AMException ame) { 2143 if (debug.messageEnabled()) { 2144 debug.message("User Name validation Failed" + ame.getMessage()); 2145 } 2146 throw new UserNamePasswordValidationException(ame); 2147 } catch (Exception ex) { 2148 debug.message( 2149 "unKnown Exception occured during username validation"); 2150 throw new UserNamePasswordValidationException(ex); 2151 } 2152 } 2153 2154 2155 /** 2156 * Sets the moduleName of successful LoginModule. 2157 * This moduleName will be populated in the session 2158 * property "AuthType" 2159 * @param moduleName name of module 2160 */ 2161 private void setSuccessModuleName(String moduleName) { 2162 // get login state for this authentication session 2163 if (loginState == null) { 2164 loginState = getLoginState(); 2165 if (loginState == null) { 2166 debug.error("Unable to set moduleName : " + moduleName); 2167 return; 2168 } 2169 } 2170 if (debug.messageEnabled()) { 2171 debug.message("SETTING Module name.... :" + moduleName); 2172 } 2173 loginState.setSuccessModuleName(moduleName); 2174 loginState.saveSharedStateAttributes(); 2175 java.security.Principal modulePrincipal = getPrincipal(); 2176 if (modulePrincipal != null && modulePrincipal.getName() != null) { 2177 loginState.saveAuthenticatedPrincipal(modulePrincipal.getName()); 2178 } 2179 2180 auditor.auditModuleSuccess(loginState, modulePrincipal, getAuditEntryDetail()); 2181 } 2182 2183 /** 2184 * Checks if valid user exists. 2185 * 2186 * @param userDN the distinguished name of the user. 2187 * @return <code>true</code> if user exists,<code>false</code>otherwise 2188 */ 2189 public boolean isValidUserEntry(String userDN) { 2190 // TODO - IdRepo does not have an equivalent of this 2191 // this method is mainly called to validate DSAME Users 2192 // which are going to be processed differently. 2193 2194 boolean isValidUser = false; 2195 try { 2196 isValidUser = 2197 (AuthD.getAuth().getIdentity(IdType.USER, userDN, "/") != null); 2198 } catch (AuthException e) { 2199 debug.message("User Valid :" + isValidUser); 2200 } 2201 return isValidUser; 2202 } 2203 2204 /** 2205 * Checks if distinguished user name is a super admin. 2206 * 2207 * @param userDN the distinguished name of the user. 2208 * @return <code>true</code> if distinguished user name is a super admin. 2209 */ 2210 public boolean isSuperAdmin(String userDN) { 2211 boolean isSuperAdmin = AuthD.getAuth().isSuperAdmin(userDN); 2212 if (debug.messageEnabled()) { 2213 debug.message("is SuperAdmin : " + isSuperAdmin); 2214 } 2215 return isSuperAdmin; 2216 } 2217 2218 /** 2219 * Validate password for the distinguished user, this will use validation 2220 * plugin if exists to validate password 2221 * 2222 * @param userPassword source string which should be validated. 2223 * @throws UserNamePasswordValidationException if user password is invalid. 2224 * 2225 * @supported.api 2226 */ 2227 public void validatePassword(String userPassword) 2228 throws UserNamePasswordValidationException { 2229 AMUserPasswordValidation plugin = getUPValidationInstance(); 2230 try { 2231 if (plugin != null) { 2232 if (debug.messageEnabled()) { 2233 debug.message("Validating password..."); 2234 } 2235 2236 plugin.validatePassword(userPassword); 2237 } else { 2238 if (debug.messageEnabled()) { 2239 debug.message("No plugin found"); 2240 } 2241 } 2242 } catch (AMException ame) { 2243 if (debug.messageEnabled()) { 2244 debug.message("Password validation Failed " + ame.getMessage()); 2245 } 2246 2247 throw new UserNamePasswordValidationException(ame); 2248 } catch (Exception ex) { 2249 if (debug.messageEnabled()) { 2250 debug.message("Unknown Exception occured during password validation"); 2251 } 2252 2253 throw new UserNamePasswordValidationException(ex); 2254 } 2255 } 2256 2257 /* 2258 * this method instantiates and returns plugin object 2259 */ 2260 private AMUserPasswordValidation getUPValidationInstance() { 2261 2262 try { 2263 String className ; 2264 String orgDN = getRequestOrg(); 2265 if (orgDN != null){ 2266 className = getOrgPluginClassName(orgDN); 2267 } 2268 else { 2269 className = getPluginClassName(); 2270 } 2271 2272 if (debug.messageEnabled()) { 2273 debug.message("UserPasswordValidation Class Name is : " + 2274 className); 2275 } 2276 if ( (className == null) || (className.length() == 0)) { 2277 return null; 2278 } 2279 2280 AMUserPasswordValidation userPasswordInstance = 2281 (AMUserPasswordValidation) 2282 (Class.forName(className).newInstance()); 2283 return userPasswordInstance; 2284 } catch (ClassNotFoundException ce) { 2285 if (debug.messageEnabled()) { 2286 debug.message("Class not Found :", ce); 2287 } 2288 return null; 2289 } catch (Exception e) { 2290 if (debug.messageEnabled()) { 2291 debug.message("Error: ", e); 2292 } 2293 return null; 2294 } 2295 } 2296 2297 /* 2298 * this method gets plugin classname from adminstration service for the org 2299 */ 2300 private String getOrgPluginClassName(String orgDN) { 2301 try { 2302 String cachedValue = AdministrationServiceListener. 2303 getOrgPluginNameFromCache(orgDN); 2304 if (cachedValue != null) { 2305 return cachedValue; 2306 } 2307 Map config = 2308 getOrgServiceTemplate(orgDN,ISAuthConstants.ADMINISTRATION_SERVICE); 2309 String className = 2310 Misc.getServerMapAttr(config, 2311 ISAuthConstants.USERID_PASSWORD_VALIDATION_CLASS); 2312 if (debug.messageEnabled()) { 2313 debug.message("Org Plugin Class: " + className); 2314 } 2315 AdministrationServiceListener.setOrgPluginNameInCache( 2316 orgDN, className); 2317 return className; 2318 } catch (Exception ee) { 2319 debug.message("Error while getting UserPasswordValidationClass " ,ee ); 2320 return null; 2321 } 2322 } 2323 2324 /* 2325 * this method gets plugin classname from adminstration service 2326 */ 2327 private String getPluginClassName() throws AuthLoginException { 2328 String cachedValue = AdministrationServiceListener. 2329 getGlobalPluginNameFromCache(); 2330 if (cachedValue != null) { 2331 return cachedValue; 2332 } 2333 Map config = getServiceConfig(ISAuthConstants.ADMINISTRATION_SERVICE); 2334 String className = 2335 CollectionHelper.getServerMapAttr( 2336 config, ISAuthConstants.USERID_PASSWORD_VALIDATION_CLASS); 2337 if (debug.messageEnabled()) { 2338 debug.message("Plugin Class: " + className); 2339 } 2340 AdministrationServiceListener.setGlobalPluginNameInCache( 2341 className); 2342 return className; 2343 } 2344 2345 /** 2346 * Sets the moduleName of failed login module 2347 * @param moduleName - module name of the failed module 2348 */ 2349 2350 private void setFailureModuleName(String moduleName) { 2351 // get login state for this authentication session 2352 if (loginState == null) { 2353 loginState = getLoginState(); 2354 if (loginState == null) { 2355 debug.error("Unable to set moduleName : " + moduleName); 2356 return; 2357 } 2358 } 2359 if (debug.messageEnabled()) { 2360 debug.message("SETTING Failure Module name.... :" + moduleName); 2361 } 2362 loginState.setFailureModuleName(moduleName); 2363 loginState.saveSharedStateAttributes(); 2364 2365 auditor.auditModuleFailure(loginState, getPrincipal(), getAuditEntryDetail()); 2366 } 2367 2368 /** 2369 * Returns JAAS shared state user key. 2370 * 2371 * @return user key. 2372 */ 2373 public String getUserKey() { 2374 return ISAuthConstants.SHARED_STATE_USERNAME; 2375 } 2376 2377 /** 2378 * Returns JAAS shared state password key. 2379 * 2380 * @return password key 2381 */ 2382 public String getPwdKey() { 2383 return ISAuthConstants.SHARED_STATE_PASSWORD; 2384 } 2385 2386 // cleanup method for Auth constants 2387 private void cleanup() { 2388 principal = null; 2389 if (sharedState !=null) { 2390 sharedState.remove(ISAuthConstants.SHARED_STATE_USERNAME); 2391 sharedState.remove(ISAuthConstants.SHARED_STATE_PASSWORD); 2392 } 2393 sharedState = null; 2394 destroyModuleState(); 2395 } 2396 2397 /** 2398 * Stores user name into shared state map. 2399 * This method should be called after successful authentication by each individual module 2400 * if a username was supplied by that module. 2401 * 2402 * @param username user name. 2403 */ 2404 public void storeUsername(String username) { 2405 if (isStore && sharedState != null) { 2406 sharedState.put(getUserKey(), username); 2407 } 2408 } 2409 2410 /** 2411 * Stores password into shared state map. 2412 * This method may be called after successful authentication by each individual module. 2413 * 2414 * @param password user's password. 2415 */ 2416 private void storePassword(String password) { 2417 if (isStore && sharedState != null) { 2418 sharedState.put(getPwdKey(), password); 2419 } 2420 } 2421 2422 /** 2423 * Stores user name and password into shared state map. 2424 * This method should be called after successful authentication by each individual module 2425 * if both a username and a password were supplied in that module. 2426 * 2427 * @param user user name. 2428 * @param passwd user password. 2429 */ 2430 public void storeUsernamePasswd(String user, String passwd) { 2431 storeUsername(user); 2432 storePassword(passwd); 2433 } 2434 2435 /** 2436 * Checks if shared state enabled for the module. 2437 * 2438 * @return <code>true</code> if shared state enabled for the module. 2439 */ 2440 public boolean isSharedStateEnabled() { 2441 return isSharedState; 2442 } 2443 2444 /** 2445 * Sets flag to force read call backs in auth chain process. 2446 * @param val - value to force reading call backs 2447 */ 2448 public void setForceCallbacksRead(boolean val) { 2449 forceCallbacksRead = val; 2450 } 2451 2452 /** 2453 * This method returns use first pass enabled or not 2454 * @return return true if use first pass is enabled for the module 2455 */ 2456 public boolean isUseFirstPassEnabled() { 2457 return (sharedStateBehaviorPattern != null) && 2458 sharedStateBehaviorPattern.equals("useFirstPass"); 2459 } 2460 2461 /** 2462 * Returns <code>AMIdentityRepostiory</code> handle for an organization. 2463 * 2464 * @param orgDN the organization name. 2465 * @return <code>AMIdentityRepostiory</code> object 2466 */ 2467 public AMIdentityRepository getAMIdentityRepository(String orgDN) { 2468 return AuthD.getAuth().getAMIdentityRepository(orgDN); 2469 } 2470 2471 /** 2472 * Creates <code>AMIdentity</code> in the repository. 2473 * 2474 * @param userName name of user to be created. 2475 * @param userAttributes Map of default attributes. 2476 * @param userRoles Set of default roles. 2477 * @throws IdRepoException 2478 * @throws SSOException 2479 */ 2480 public void createIdentity( 2481 String userName, 2482 Map userAttributes, 2483 Set userRoles 2484 ) throws IdRepoException, SSOException { 2485 if (loginState == null) { 2486 loginState = getLoginState(); 2487 if (loginState == null) { 2488 debug.error("Unable to create Identity: " + userName); 2489 return ; 2490 } 2491 } 2492 loginState.createUserIdentity(userName,userAttributes,userRoles); 2493 return; 2494 } 2495 2496 /** 2497 * Get the number of failed login attempts for a user when account locking 2498 * is enabled. 2499 * @return number of failed attempts, -1 means account locking is not enabled. 2500 * @throws AuthenticationException if the user name passed in is not valid 2501 * or null, or for any other error condition. 2502 * @supported.api 2503 */ 2504 public int getFailCount(AMIdentity amIdUser) throws AuthenticationException { 2505 if (loginState == null) { 2506 loginState = getLoginState(); 2507 if (loginState == null) { 2508 throw new AuthenticationException(bundleName, "nullLoginState", null); 2509 } 2510 } 2511 ISAccountLockout isAccountLockout = new ISAccountLockout(loginState, bundleName); 2512 2513 try { 2514 debug.message("Failure lockout mode enabled: {}", isAccountLockout.isLockoutEnabled()); 2515 if (isAccountLockout.isLockoutEnabled()) { 2516 AccountLockoutInfo acInfo = isAccountLockout.getAcInfo(amIdUser); 2517 int failCount = acInfo.getFailCount(); 2518 debug.message("AMLoginModule.getFailCount:failCount returned: {}", failCount); 2519 return failCount; 2520 } else { 2521 return -1; 2522 } 2523 } catch (Exception ex) { 2524 debug.error("AMLoginModule.getFailCount:Error", ex); 2525 throw new AuthenticationException(ex.getMessage()); 2526 } 2527 } 2528 2529 /** 2530 * Get the maximum number failed login attempts permitted for a user 2531 * before when their account is locked out. 2532 * 2533 * @return the maximum number of failed attempts 2534 * @supported.api 2535 */ 2536 public int getMaximumFailCount() 2537 throws AuthenticationException { 2538 if (loginState == null) { 2539 loginState = getLoginState(); 2540 2541 if (loginState == null) { 2542 throw new AuthenticationException(bundleName, "nullLoginState", 2543 null); 2544 } 2545 } 2546 2547 return loginState.getLoginFailureLockoutCount(); 2548 } 2549 2550 /** 2551 * Increments the fail count for the given user. 2552 * 2553 * @throws AuthenticationException if the user name passed in is not valid 2554 * or null, or for any other error condition. 2555 * @supported.api 2556 */ 2557 public void incrementFailCount(String userName) 2558 throws AuthenticationException { 2559 if (loginState == null) { 2560 loginState = getLoginState(); 2561 2562 if (loginState == null) { 2563 throw new AuthenticationException(bundleName, "nullLoginState", 2564 null); 2565 } 2566 } 2567 2568 loginState.incrementFailCount(userName); 2569 } 2570 2571 /** 2572 * Returns true if the named account is locked out, false otherwise. 2573 * 2574 * @throws AuthenticationException if the user name passed in is not valid 2575 * or null, or for any other error condition. 2576 * @supported.api 2577 */ 2578 public boolean isAccountLocked(String userName) 2579 throws AuthenticationException { 2580 if (loginState == null) { 2581 loginState = getLoginState(); 2582 2583 if (loginState == null) { 2584 throw new AuthenticationException(bundleName, "nullLoginState", 2585 null); 2586 } 2587 } 2588 2589 boolean accountLocked = loginState.isAccountLocked(userName); 2590 2591 if (ad.debug.messageEnabled()) { 2592 ad.debug.message("isAccountLocked for user=" + userName + " :" + accountLocked); 2593 } 2594 2595 return accountLocked; 2596 } 2597 2598 /* returns the normalized DN */ 2599 private String normalizeDN(String userDN) { 2600 String normalizedDN = userDN; 2601 if ((userDN != null) && LDAPUtils.isDN(userDN)) { 2602 normalizedDN = DNUtils.normalizeDN(userDN); 2603 } 2604 if (ad.debug.messageEnabled()) { 2605 ad.debug.message("Original DN is:" + userDN); 2606 ad.debug.message("Normalized DN is:" + normalizedDN); 2607 } 2608 return normalizedDN; 2609 } 2610 2611 /** 2612 * Authenticates to the datastore using idRepo API 2613 * 2614 * @param callbacks Array of last submitted callbacks to the 2615 * authentication module 2616 * @return <code>true</code> if success. <code>false</code> if failure 2617 * @throws <code> AuthLoginException </code> 2618 */ 2619 private boolean authenticateToDatastore(Callback[] callbacks) 2620 throws AuthLoginException { 2621 boolean retval = false; 2622 boolean needToCheck = false; 2623 Callback[] idrepoCallbacks = new Callback[2]; 2624 String userName = null; 2625 char[] password = null; 2626 2627 for (int i = 0; i < callbacks.length; i++) { 2628 if (callbacks[i] instanceof NameCallback) { 2629 NameCallback nc = (NameCallback) callbacks[i]; 2630 userName = nc.getName(); 2631 if (debug.messageEnabled()){ 2632 debug.message("AMLoginModule.authenticateToDatastore:: " 2633 + " user is : " + userName); 2634 debug.message("AMLoginModule.authenticateToDatastore:: " 2635 + " Internal users : " + LoginState.INTERNAL_USERS); 2636 } 2637 2638 if (LoginState.INTERNAL_USERS.contains( 2639 userName.toLowerCase())) { 2640 needToCheck = true; 2641 } else { 2642 break; 2643 } 2644 2645 } else if (callbacks[i] instanceof PasswordCallback) { 2646 PasswordCallback pc = (PasswordCallback) callbacks[i]; 2647 password = pc.getPassword(); 2648 } 2649 } 2650 if (needToCheck == false) { 2651 return true; 2652 } 2653 2654 if (debug.messageEnabled()){ 2655 debug.message("AMLoginModule.authenticateToDatastore:: " 2656 + "Authenticating Internal user to configuration store"); 2657 } 2658 NameCallback nameCallback = new NameCallback("NamePrompt"); 2659 nameCallback.setName(userName); 2660 idrepoCallbacks[0] = nameCallback; 2661 PasswordCallback passwordCallback = new PasswordCallback( 2662 "PasswordPrompt",false); 2663 passwordCallback.setPassword(password); 2664 idrepoCallbacks[1] = passwordCallback; 2665 try { 2666 AMIdentityRepository idrepo = getAMIdentityRepository( 2667 getRequestOrg()); 2668 retval = idrepo.authenticate(idrepoCallbacks); 2669 if (debug.messageEnabled()){ 2670 debug.message("AMLoginModule.authenticateToDatastore:: " + 2671 " IDRepo authentication successful"); 2672 } 2673 } catch (IdRepoException idrepoExp) { 2674 if (debug.messageEnabled()){ 2675 debug.message("AMLoginModule.authenticateToDatastore:: " 2676 + "IdRepo Exception : ", idrepoExp); 2677 } 2678 } catch (InvalidPasswordException ipe) { 2679 throw new AuthLoginException(AMAuthErrorCode.AUTH_MODULE_DENIED); 2680 } 2681 return retval; 2682 2683 } 2684 2685 /** 2686 * Returns true if the user identified by the supplied username has reached 2687 * their session quota.<br> 2688 * <i>NB</i>The existing session count is exclusive of any session created 2689 * as part of the running authentication process 2690 * 2691 * @param userName the username of the user who's session quota will be checked 2692 * @return true if the user session quota is reached, false otherwise 2693 * @supported.api 2694 */ 2695 public boolean isSessionQuotaReached(String userName) { 2696 int sessionCount = -1; 2697 int sessionQuota = -1; 2698 2699 if (userName == null || userName.equals(Constants.EMPTY)) { 2700 debug.error("AMLoginModule.isSessionQuotaReached :: called with null username"); 2701 return false; 2702 } 2703 2704 try { 2705 // Get the universal ID 2706 AMIdentity amIdUser = ad.getIdentity(IdType.USER, userName, 2707 loginState.getOrgDN()); 2708 2709 String univId = IdUtils.getUniversalId(amIdUser); 2710 2711 if (univId != null) { 2712 sessionQuota = getSessionQuota(amIdUser); 2713 sessionCount = SessionCount.getAllSessionsByUUID(univId).size(); 2714 2715 if (debug.messageEnabled()) { 2716 debug.message("AMLoginModule.isSessionQuotaReached :: univId= " 2717 + univId + " - Session Quota Reached = " + (sessionCount >= sessionQuota)); 2718 } 2719 } else { 2720 debug.error("AMLoginModule.isSessionQuotaReached :: " 2721 + "univId is null , amIdUser is " + amIdUser); 2722 return false; 2723 } 2724 } catch (Exception ex) { 2725 debug.error("AMLoginModule.getSessionQuotaLevel:: " 2726 + "Exception : ", ex); 2727 } 2728 2729 return (sessionCount >= sessionQuota); 2730 } 2731 2732 private int getSessionQuota(AMIdentity iden) { 2733 int quota = SessionConstraint.getDefaultSessionQuota(); 2734 2735 if (iden == null) { 2736 debug.error("AMLoginModule.getSessionQuota :: AMIdentity is null, returning default quota"); 2737 return quota; 2738 } 2739 2740 try { 2741 Map serviceAttrs = 2742 iden.getServiceAttributesAscending("iPlanetAMSessionService"); 2743 2744 Set s = (Set)serviceAttrs.get("iplanet-am-session-quota-limit"); 2745 Iterator attrs = s.iterator(); 2746 if (attrs.hasNext()) { 2747 String attr = (String) attrs.next(); 2748 quota = (Integer.valueOf(attr)).intValue(); 2749 } 2750 } catch (Exception ex) { 2751 debug.error("Failed to get the session quota via the "+ 2752 "IDRepo interfaces, => Use the default " + 2753 "value from the dynamic schema instead.", ex); 2754 } 2755 2756 return quota; 2757 } 2758 2759 2760 /** 2761 * Returns the set of SSOTokens for a specified user 2762 * 2763 * @param userName The username to be used to query the sessions 2764 * @return The set of SSOTokens for the user's current sessions, returns null on error 2765 * @supported.api 2766 */ 2767 public Set<SSOToken> getUserSessions(String userName) { 2768 Set<SSOToken> sessions = new HashSet<SSOToken>(); 2769 2770 if (userName == null || userName.equals(Constants.EMPTY)) { 2771 debug.error("AMLoginModule.getUserSessions :: called with null username"); 2772 return null; 2773 } 2774 2775 try { 2776 // Get the universal ID 2777 AMIdentity amIdUser = ad.getIdentity(IdType.USER, userName, loginState.getOrgDN()); 2778 2779 String univId = IdUtils.getUniversalId(amIdUser); 2780 2781 if (univId != null) { 2782 Map<String, String> currentSessions = SessionCount.getAllSessionsByUUID(univId); 2783 SSOTokenManager manager = SSOTokenManager.getInstance(); 2784 2785 for (String tokenID : currentSessions.keySet()) { 2786 sessions.add(manager.createSSOToken(tokenID)); 2787 } 2788 2789 if (debug.messageEnabled()) { 2790 debug.message("AMLoginModule.getUserSessions :: univId= " 2791 + univId + " - found sessions = " + sessions); 2792 } 2793 } else { 2794 debug.error("AMLoginModule.getUserSessions :: " 2795 + "univId is null , amIdUser is " + amIdUser); 2796 return null; 2797 } 2798 } catch (Exception ex) { 2799 debug.error("AMLoginModule.getUserSessions:: " 2800 + "Exception : ", ex); 2801 } 2802 2803 return sessions; 2804 } 2805 2806 /** 2807 * Provides the "Alias Search Attribute Name" list from the Authentication 2808 * Service for the realm. If these attributes are not configured it falls 2809 * back to the User Naming Attribute for the realm 2810 * @return a set containing the attribute names configured 2811 */ 2812 protected Set<String> getUserAliasList() throws AuthLoginException { 2813 final Map<String, Set<String>> orgSvc = getOrgServiceTemplate(getRequestOrg(), ISAuthConstants.AUTH_SERVICE_NAME); 2814 Set<String> aliasAttrNames = orgSvc.get(ISAuthConstants.AUTH_ALIAS_ATTR); 2815 if (debug.messageEnabled()) { 2816 debug.message("AMLoginModule.getUserAliasList: from " + ISAuthConstants.AUTH_ALIAS_ATTR + ": "+ aliasAttrNames); 2817 } 2818 if (aliasAttrNames.isEmpty()) { 2819 aliasAttrNames = orgSvc.get(ISAuthConstants.AUTH_NAMING_ATTR); 2820 if (debug.messageEnabled()) { 2821 debug.message("AMLoginModule.getUserAliasList: from " + ISAuthConstants.AUTH_NAMING_ATTR +": " 2822 + aliasAttrNames); 2823 } 2824 } 2825 return aliasAttrNames; 2826 } 2827 2828 /** 2829 * Returns the principals authenticated in the current authentication process or an empty set if login state is 2830 * unavailable or no authenticated principals are present. 2831 * 2832 * @return a set of authenticated principals. 2833 */ 2834 protected Set<String> getAuthenticatedPrincipals() { 2835 if (loginState == null) { 2836 loginState = getLoginState(); 2837 } 2838 if (loginState == null) { 2839 if (debug.messageEnabled()) { 2840 debug.message("AMLoginModule.getAuthenticatedPrincipals: ubable to get loginState"); 2841 } 2842 return Collections.emptySet(); 2843 } 2844 return loginState.getAuthenticatedPrincipals(); 2845 } 2846 2847 /** 2848 * Supply the additional detail to be logged with this module's completion event. Subclasses can override this 2849 * method to add more specific detail. 2850 * 2851 * @return The audit entry detail. 2852 */ 2853 protected AuthenticationAuditEntry getAuditEntryDetail() { 2854 AuthenticationAuditEntry entryDetail = new AuthenticationAuditEntry(); 2855 entryDetail.setModuleId(moduleName); 2856 2857 String ip = loginState.getClient(); 2858 if (isNotEmpty(ip)) { 2859 entryDetail.addInfo(IP_ADDRESS, ip); 2860 } 2861 AuthContext.IndexType indexType = loginState.getIndexType(); 2862 if (indexType != null) { 2863 entryDetail.addInfo(AUTH_INDEX, indexType.toString()); 2864 } 2865 entryDetail.addInfo(AuditConstants.EntriesInfoFieldKey.AUTH_LEVEL, String.valueOf(getAuthLevel())); 2866 entryDetail.addInfo(MODULE_CLASS, moduleClass); 2867 2868 return entryDetail; 2869 } 2870}