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: AuthContext.java,v 1.25 2009/11/21 01:12:59 qcheng Exp $ 026 * 027 */ 028 029/** 030 * Portions Copyrighted 2010-2013 ForgeRock AS 031 */ 032package com.sun.identity.authentication; 033 034import com.iplanet.am.util.SystemProperties; 035import com.iplanet.dpro.session.Session; 036import com.iplanet.dpro.session.SessionID; 037import com.iplanet.services.comm.client.PLLClient; 038import com.iplanet.services.comm.share.Request; 039import com.iplanet.services.comm.share.RequestSet; 040import com.iplanet.services.comm.share.Response; 041import com.iplanet.services.naming.WebtopNaming; 042import com.iplanet.sso.SSOException; 043import com.iplanet.sso.SSOToken; 044import com.iplanet.sso.SSOTokenManager; 045import com.sun.identity.authentication.client.AuthClientUtils; 046import com.sun.identity.authentication.server.AuthContextLocal; 047import com.sun.identity.authentication.service.AMAuthErrorCode; 048import com.sun.identity.authentication.service.AuthException; 049import com.sun.identity.authentication.service.LoginState; 050import com.sun.identity.authentication.share.AuthXMLTags; 051import com.sun.identity.authentication.share.AuthXMLUtils; 052import com.sun.identity.authentication.spi.AuthLoginException; 053import com.sun.identity.authentication.util.ISAuthConstants; 054import com.sun.identity.security.AdminTokenAction; 055import com.sun.identity.security.AMSecurityPropertiesException; 056import com.sun.identity.shared.Constants; 057import com.sun.identity.shared.debug.Debug; 058import com.sun.identity.shared.locale.L10NMessageImpl; 059import com.sun.identity.shared.xml.XMLUtils; 060import java.io.ByteArrayInputStream; 061import java.io.IOException; 062import java.lang.reflect.Constructor; 063import java.lang.reflect.Method; 064import java.net.URL; 065import java.net.URLStreamHandler; 066import java.security.AccessController; 067import java.security.KeyStore; 068import java.text.MessageFormat; 069import java.util.Collections; 070import java.util.Enumeration; 071import java.util.HashMap; 072import java.util.HashSet; 073import java.util.Hashtable; 074import java.util.Iterator; 075import java.util.Map; 076import java.util.ResourceBundle; 077import java.util.Set; 078import java.util.Vector; 079import javax.security.auth.Subject; 080import javax.security.auth.callback.Callback; 081import javax.servlet.http.HttpServletRequest; 082import javax.servlet.http.HttpServletResponse; 083import org.forgerock.openam.authentication.service.protocol.RemoteHttpServletRequest; 084import org.forgerock.openam.authentication.service.protocol.RemoteHttpServletResponse; 085import org.w3c.dom.Document; 086import org.w3c.dom.Node; 087import org.w3c.dom.NodeList; 088 089/** 090 * The <code>AuthContext</code> provides the implementation for 091 * authenticating users. 092 * <p> 093 * A typical caller instantiates this class and starts the login process. 094 * The caller then obtains an array of <code>Callback</code> objects, 095 * which contains the information required by the authentication plug-in 096 * module. The caller requests information from the user. On receiving 097 * the information from the user, the caller submits the same to this class. 098 * While more information is required, the above process continues until all 099 * the information required by the plug-ins/authentication modules, has 100 * been supplied. The caller then checks if the user has successfully 101 * been authenticated. If successfully authenticated, the caller can 102 * then get the <code>Subject</code> and <code>SSOToken</code> for the user; 103 * if not successfully authenticated, the caller obtains the 104 * <code>AuthLoginException</code>. 105 * <p> 106 * The implementation supports authenticating users either locally 107 * i.e., in process with all authentication modules configured or remotely 108 * to an authentication service/framework. (See documentation to configure 109 * in either of the modes). 110 * 111 * @supported.api 112 */ 113public class AuthContext extends Object implements java.io.Serializable { 114 115 private java.util.Locale clientLocale = null; 116 117 private String server_proto = 118 SystemProperties.get(Constants.AM_SERVER_PROTOCOL); 119 private String server_host = 120 SystemProperties.get(Constants.AM_SERVER_HOST); 121 private String server_port = 122 SystemProperties.get(Constants.AM_SERVER_PORT); 123 private String server_uri = 124 SystemProperties.get(Constants.AM_SERVICES_DEPLOYMENT_DESCRIPTOR); 125 private boolean includeReqRes = 126 SystemProperties.getAsBoolean(Constants.REMOTEAUTH_INCLUDE_REQRES); 127 128 private static final String amAuthContext = "amAuthContext"; 129 130 private static final String JSS_PASSWORD_UTIL = 131 "com.sun.identity.authentication.util.JSSPasswordUtil"; 132 133 private static final String JSSE_PASSWORD_CALLBACK = 134 "com.sun.identity.security.keystore.AMCallbackHandler"; 135 136 static String protHandlerPkg = 137 System.getProperty(Constants.PROTOCOL_HANDLER, Constants.JSSE_HANDLER); 138 139 static boolean usingJSSEHandler = 140 protHandlerPkg.equals(Constants.JSSE_HANDLER); 141 142 // Debug & I18N class 143 protected static Debug authDebug = Debug.getInstance(amAuthContext); 144 protected static ResourceBundle bundle = 145 com.sun.identity.shared.locale.Locale.getInstallResourceBundle(amAuthContext); 146 147 Status loginStatus = Status.IN_PROGRESS; 148 String organizationName = ""; 149 Document receivedDocument; 150 AuthLoginException loginException = null; 151 152 String hostName = null; 153 private boolean forceAuth = false; 154 private boolean localSessionChecked = false; 155 String nickName = null; 156 private URL authURL = null; 157 private URL authServiceURL = null; 158 private SSOToken ssoToken = null; 159 private String ssoTokenID = null; 160 private static SSOToken appSSOToken = null; 161 com.sun.identity.authentication.server.AuthContextLocal acLocal = null; 162 private final static int DEFAULT_RETRY_COUNT = 1; 163 private int retryRunLogin = DEFAULT_RETRY_COUNT; 164 165 /** 166 * Variables for checking auth service is running local 167 */ 168 public boolean localFlag = false; 169 /** 170 * Variables for local AuthService identifier 171 */ 172 public static String localAuthServiceID; 173 174 // Variable to check if 6.3 style remote AuthN has to be performed 175 static boolean useOldStyleRemoteAuthentication; 176 static boolean useNewStyleRemoteAuthentication; 177 178 // this cookieTable is used to keep all the cookies retrieved from the 179 // the PLL layer and replay them in subsequent auth requests, mainly for 180 // persistence purpose. 181 private HashMap cookieTable = new HashMap(); 182 183 private HttpServletRequest remoteRequest = null; 184 private HttpServletResponse remoteResponse = null; 185 186 /** 187 * Constructs an instance of <code>AuthContext</code> for a given 188 * organization name or sub organization name. This organization or 189 * sub-organization name must be either "/" separated 190 * ( where it starts with "/" ) , DN , Domain name or DNS Alias Name. 191 * <p> 192 * Caller would then use <code>login</code> to start the 193 * authentication process and use <code>getRequirements()</code> and 194 * <code>submitRequirements()</code> to pass the credentials 195 * needed for authentication by the plugin authentication modules. 196 * The method <code>getStatus()</code> returns the 197 * authentication status. 198 * 199 * @param orgName Name of the user's organization. 200 * @throws AuthLoginException if <code>AuthContext</code> creation fails. 201 * This exception is kept for backward compatibility only. 202 * 203 * @supported.api 204 */ 205 public AuthContext(String orgName) throws AuthLoginException { 206 organizationName = orgName; 207 } 208 209 /** 210 * Constructs an instance of <code>AuthContext</code> for a given 211 * organization name, or sub organization name and the OpenSSO 212 * URL. 213 * This organization or sub-organization name must be either "/" separated 214 * ( where it starts with "/" ) , DN , Domain name or DNS Alias Name. 215 * And the <code>url</code> should specify the OpenSSO protocol, 216 * host name, port to talk to. 217 * for example : <code>http://daye.red.iplanet.com:58080</code> 218 * 219 * Caller would then use <code>login</code> to start the 220 * authentication process and use <code>getRequirements()</code> and 221 * <code>submitRequirements()</code> to pass the credentials 222 * needed for authentication by the plugin authentication modules. 223 * The method <code>getStatus()</code> returns the 224 * authentication status. 225 * 226 * @param orgName name of the user's organization 227 * @param url URL of the OpenSSO to talk to 228 * @throws AuthLoginException if <code>AuthContext</code> creation fails. 229 * This exception is kept for backward compatibility only. 230 * 231 * @supported.api 232 */ 233 public AuthContext(String orgName, URL url) throws AuthLoginException { 234 organizationName = orgName; 235 authURL = url; 236 } 237 238 /** 239 * Constructs an instance of <code>AuthContext</code> for a given 240 * organization name, or sub organization name and a nick name 241 * for the certificate to be used in SSL handshake if client authentication 242 * is turn on in the server side. 243 * This organization or sub-organization name must be either "/" separated 244 * ( where it starts with "/" ) , DN , Domain name or DNS Alias Name. 245 * 246 * This constructor would be mainly used for the Certificate based 247 * authentication. If the certificate database contains multiple matching 248 * certificates for SSL, this constructor must be called in order for the 249 * desired certificate to be used for the Certificate based authentication. 250 * 251 * Caller would then use <code>login</code> to start the 252 * authentication process and use <code>getRequirements()</code> and 253 * <code>submitRequirements()</code> to pass the credentials 254 * needed for authentication by the plugin authentication modules. 255 * The method <code>getStatus()</code> returns the 256 * authentication status. 257 * 258 * @param orgName name of the user's organization 259 * @param nickName nick name for the certificate to be used 260 * @throws AuthLoginException if <code>AuthContext</code> creation fails. 261 * This exception is kept for backward compatibility only. 262 * 263 * @supported.api 264 */ 265 public AuthContext(String orgName, String nickName) 266 throws AuthLoginException { 267 organizationName = orgName; 268 this.nickName = nickName; 269 } 270 271 /** 272 * Constructs an instance of <code>AuthContext</code> for a given 273 * organization name, or sub organization name, a nick name 274 * for the certificate to be used in SSL handshake if client authentication 275 * is turn on in the server side and the OpenSSO URL. 276 * This organization or sub-organization name must be either "/" separated 277 * ( where it starts with "/" ) , DN , Domain name or a DNS Alias Name. 278 * And the <code>url</code> should specify the OpenSSO protocol, 279 * host name, port to talk to. 280 * for example : <code>http://daye.red.iplanet.com:58080</code> 281 * This constructor would be mainly used for the Certificate based 282 * authentication. If the certificate database contains multiple matching 283 * certificates for SSL, this constructor must be called in order for the 284 * desired certificate to be used for the Certificate based authentication. 285 * 286 * Caller would then use <code>login</code> to start the 287 * authentication process and use <code>getRequirements()</code> and 288 * <code>submitRequirements()</code> to pass the credentials 289 * needed for authentication by the plugin authentication modules. 290 * The method <code>getStatus()</code> returns the 291 * authentication status. 292 * 293 * @param orgName name of the user's organization 294 * @param nickName nick name for the certificate to be used 295 * @param url URL of the OpenSSO to talk to 296 * @throws AuthLoginException if <code>AuthContext</code> creation fails. 297 * This exception is kept for backward compatibility only. 298 * 299 * @supported.api 300 */ 301 public AuthContext(String orgName, String nickName, URL url) 302 throws AuthLoginException { 303 organizationName = orgName; 304 this.nickName = nickName; 305 authURL = url; 306 } 307 308 /** 309 * Constructs an instance of <code>AuthContext</code> for a given 310 * organization name, or sub organization name contained in the 311 * single sign on token. 312 * 313 * This constructor should be called for re-authentication of an 314 * authenticated user. single sign on token is the authenticated resource's 315 * Single-Sign-On Token. If the session properties based on 316 * the login method used matches those in the user's new 317 * authenticated session then session upgrade will be done. 318 * A new session containing properties from both old single sign on token 319 * and new session shall be returned and old session will be 320 * destroyed if authentication passes. 321 * 322 * Caller would then use <code>login</code> to start the 323 * authentication process and use <code>getRequirements()</code> and 324 * <code>submitRequirements()</code> to pass the credentials 325 * needed for authentication by the plugin authentication modules. 326 * The method <code>getStatus()</code> returns the 327 * authentication status. 328 * 329 * @param ssoToken single sign on token representing the resource's previous 330 * authenticated session. 331 * @throws AuthLoginException if <code>AuthContext</code> creation fails. 332 * This exception is kept for backward compatibility only. 333 * 334 * @supported.api 335 */ 336 public AuthContext(SSOToken ssoToken) throws AuthLoginException { 337 this.ssoToken = ssoToken; 338 } 339 340 /** 341 * Constructs an instance of <code>AuthContext</code> for a given 342 * organization name, or sub organization name contained in the 343 * single sign on token. 344 * 345 * This constructor should be called for re-authentication of an 346 * authenticated user. single sign on token is the authenticated resource's 347 * Single-Sign-On Token. If the session properties based on 348 * the login method used matches those in the user's new 349 * authenticated session then session upgrade will be done. 350 * If forceAuth flag is <code>true</code> then the existing session 351 * is used and no new session is created otherwise this constructor 352 * behaves same as the constructor with no forceAuth flag. 353 * 354 * Caller would then use <code>login</code> to start the 355 * authentication process and use <code>getRequirements()</code> and 356 * <code>submitRequirements()</code> to pass the credentials 357 * needed for authentication by the plugin authentication modules. 358 * The method <code>getStatus()</code> returns the 359 * authentication status. 360 * 361 * @param ssoToken single sign on token representing the resource's 362 * previous authenticated session. 363 * @param forceAuth indicates that authentication preocess has to be 364 * restarted and given single sign on token will be used and new 365 * session will not be created. 366 * @throws AuthLoginException if <code>AuthContext</code> creation fails. 367 * This exception is kept for backward compatibility only. 368 * 369 * @supported.api 370 */ 371 public AuthContext(SSOToken ssoToken, boolean forceAuth) throws 372 AuthLoginException { 373 this.ssoToken = ssoToken; 374 this.forceAuth = forceAuth; 375 } 376 377 /** 378 * Starts the login process for the given <code>AuthContext</code> object. 379 * 380 * @exception AuthLoginException if an error occurred during login. 381 * 382 * @supported.api 383 */ 384 public void login() throws AuthLoginException { 385 login(null, null, null, false, null, null, null); 386 } 387 388 /** 389 * Starts the login process for the given <code>AuthContext</code> object. 390 * 391 * @param request The HttpServletRequest that was sent to start the authentication process. 392 * @param response The corresponding HttpServletResponse for the HttpServletRequest. 393 * @throws AuthLoginException If an error occurred during login. 394 * 395 * @supported.api 396 */ 397 public void login(HttpServletRequest request, HttpServletResponse response) throws AuthLoginException { 398 login(null, null, null, null, request, response); 399 } 400 401 /** 402 * Starts the login process for the given <code>AuthContext</code> object 403 * identified by the index type and index name. The <code>IndexType</code> 404 * defines the possible kinds of "objects" or "resources" for which an 405 * authentication can be performed. Currently supported index types are 406 * users, roles, services (or application), levels, resources and 407 * mechanism/authentication modules. 408 * 409 * @param type Authentication index type. 410 * @param indexName Authentication index name. 411 * @exception AuthLoginException if an error occurred during login. 412 * 413 * @supported.api 414 */ 415 public void login(IndexType type, String indexName) 416 throws AuthLoginException { 417 login(type, indexName, null, false, null, null, null); 418 } 419 420 /** 421 * Starts the login process for the given <code>AuthContext</code> object 422 * identified by the index type and index name. 423 * The <code>IndexType</code> defines the possible kinds of "objects" 424 * or "resources" for which an authentication can 425 * be performed. Currently supported index types are 426 * users, roles, services (or application), levels, resources and mechanism. 427 * The <code>pCookieMode</code> indicates that a persistent cookie exists 428 * for this request. 429 * 430 * @param type authentication index type. 431 * @param indexName authentication index name. 432 * @param pCookieMode <code>true</code> if persistent Cookie exists. 433 * @exception AuthLoginException if an error occurred during login 434 */ 435 public void login(IndexType type, String indexName, boolean pCookieMode) 436 throws AuthLoginException { 437 login(type, indexName, null, pCookieMode, null, null, null); 438 } 439 440 /** 441 * Starts the login process for the given <code>AuthContext</code> object 442 * identified by the index type and index name. 443 * The <code>IndexType</code> defines the possible kinds of "objects" 444 * or "resources" for which an authentication can 445 * be performed. Currently supported index types are 446 * users, roles, services (or application), levels, resources and mechanism. 447 * It allows the caller to pass in the desired locale for this request. 448 * 449 * @param type authentication index type 450 * @param indexName authentication index name 451 * @param locale locale setting 452 * 453 * @exception AuthLoginException if an error occurred during login 454 */ 455 public void login(IndexType type, String indexName, String locale) 456 throws AuthLoginException { 457 login(type, indexName, null, false, null, locale); 458 } 459 460 /** 461 * Starts the login process for the given <code>AuthContext</code> object 462 * identified by the index type and index name and also completes 463 * the login process by submitting the given User credentials 464 * in the form of Callbacks. 465 * The <code>IndexType</code> defines the possible kinds of "objects" 466 * or "resources" for which an authentication can 467 * be performed. Currently supported index types are 468 * users, roles, services (or application), levels, resources and mechanism. 469 * <p> 470 * NOTE : This is a simplified wrapper method to eliminate multi-step calls 471 * to 'login' and submit credentials. This method is useful and will work 472 * only for those authentication modules which require only one set of 473 * callbacks or one page. This method can not be used to authenticate to 474 * authentication modules which require user interaction or multiple pages. 475 * 476 * @param type Authentication index type. 477 * @param indexName Authentication index name. 478 * @param userInfo User information/credentials in the form of array of 479 * <code>Callback</code> objects. The <code>Callback</code> objects 480 * array must be in the same order as defined in the authentication 481 * module properties file, otherwise authentication module code will 482 * not work. 483 * @return single-sign-on token for the valid user after successful 484 * authentication. 485 * @exception AuthLoginException if an error occurred during login. 486 */ 487 public SSOToken login(IndexType type, String indexName, Callback[] userInfo) 488 throws AuthLoginException { 489 login(type, indexName, null, false, null, null, null); 490 491 SSOToken ssoToken = null; 492 Callback[] callbacks = null; 493 494 while (hasMoreRequirements()) { 495 callbacks = getRequirements(); 496 497 if (callbacks != null) { 498 try { 499 submitRequirements(userInfo); 500 } catch (Exception e) { 501 if (authDebug.messageEnabled()) { 502 authDebug.message( 503 "Error: submitRequirements with userInfo : " 504 + e.getMessage()); 505 } 506 throw new AuthLoginException(e); 507 } 508 } 509 } 510 try { 511 if (getStatus() == AuthContext.Status.SUCCESS) { 512 ssoToken = getSSOToken(); 513 } 514 } catch (Exception e) { 515 if (authDebug.messageEnabled()) { 516 authDebug.message("Error: getSSOToken : " + e.getMessage()); 517 } 518 throw new AuthLoginException(e); 519 } 520 return ssoToken; 521 } 522 523 /** 524 * Starts the login process for the given <code>AuthContext</code> object 525 * identified by the index type and index name with default parameters. 526 * The <code>IndexType</code> defines the possible kinds of "objects" 527 * or "resources" for which an authentication can be performed. Currently 528 * supported index types are users, roles, services (or application), 529 * levels, resources and mechanism/authentication modules. 530 * 531 * @param indexType authentication index type. 532 * @param indexName authentication index name. 533 * @param params contains the default values for the callbacks. The order 534 * of this array matches the callbacks order for this login process. 535 * value for the <code>PasswordCallback</code> is also in String 536 * format, it will be converted to <code>char[]</code> when it is 537 * set to the callback. Internal processing for this string array 538 * uses <code>|</code> as separator. Hence <code>|</code> should not 539 * be used in these default values. Currently only 540 * <code>NameCallback</code> and <code>PasswordCallback</code> are 541 * supported. 542 * @exception AuthLoginException if an error occurred during login. 543 * 544 * @supported.api 545 */ 546 public void login(IndexType indexType, String indexName, String[] params) 547 throws AuthLoginException { 548 login(indexType, indexName, params, false, null, null, null); 549 } 550 551 public void login(IndexType indexType, 552 String indexName, 553 String[] params, 554 HttpServletRequest request, 555 HttpServletResponse response) 556 throws AuthLoginException { 557 login(indexType, indexName, params, false, null, request, response); 558 } 559 560 /** 561 * Starts the login process for the given <code>AuthContext</code> object 562 * identified by the index type and index name with certain parameters 563 * and environment map. 564 * The <code>IndexType</code> defines the possible kinds of "objects" 565 * or "resources" for which an authentication can be performed. Currently 566 * supported index types are users, roles, services (or application), 567 * levels, modules and resources. 568 * 569 * @param indexType authentication index type. 570 * @param indexName authentication index name. 571 * @param params contains the default values for the callbacks. The order 572 * of this array matches the callbacks order for this login process. 573 * value for the <code>PasswordCallback</code> is also in String 574 * format, it will be converted to <code>char[]</code> when it is 575 * set to the callback. Internal processing for this string array 576 * uses <code>|</code> as separator. Hence <code>|</code> should not 577 * be used in these default values. Currently only 578 * <code>NameCallback</code> and <code>PasswordCallback</code> are 579 * supported. 580 * @param envMap contains the environment key/value pairs. Key is a String 581 * object indicating the property name, value is a Set of String 582 * values for the property. Currenty this parameter only applicable 583 * when the indexTye is <code>AuthContext.IndexType.RESOURCE</code>. 584 * @exception AuthLoginException if an error occurred during login. 585 * 586 * @supported.api 587 */ 588 public void login(IndexType indexType, String indexName, 589 String[] params, Map envMap) 590 throws AuthLoginException { 591 login(indexType, indexName, params, false, envMap, null, null); 592 } 593 594 public void login(IndexType indexType, 595 String indexName, 596 String[] params, 597 Map envMap, 598 HttpServletRequest request, 599 HttpServletResponse response) 600 throws AuthLoginException { 601 login(indexType, indexName, params, false, envMap, request, response); 602 } 603 604 private void login( 605 IndexType indexType, 606 String indexName, 607 String[] params, 608 boolean pCookie, 609 Map envMap, 610 HttpServletRequest request, 611 HttpServletResponse response 612 ) throws AuthLoginException { 613 if (clientLocale == null) { 614 login(indexType, indexName, params, pCookie, envMap, null, request, response); 615 } else { 616 String localeStr = clientLocale.toString(); 617 login(indexType, indexName, params, pCookie, envMap, localeStr, request, response); 618 } 619 } 620 621 private void login( 622 IndexType indexType, 623 String indexName, 624 String[] params, 625 boolean pCookie, 626 Map envMap, 627 String locale 628 ) throws AuthLoginException { 629 login(indexType, indexName, params, false, envMap, locale, null, null); 630 } 631 632 private void login( 633 IndexType indexType, 634 String indexName, 635 String[] params, 636 boolean pCookie, 637 Map envMap, 638 String locale, 639 HttpServletRequest request, 640 HttpServletResponse response 641 ) throws AuthLoginException { 642 if (ssoToken != null) { 643 try { 644 organizationName = ssoToken.getProperty( 645 ISAuthConstants.ORGANIZATION); 646 ssoTokenID = ssoToken.getTokenID().toString(); 647 authURL = Session.getSession( 648 new SessionID(ssoTokenID)).getSessionServiceURL(); 649 } catch (Exception e) { 650 throw new AuthLoginException(e); 651 } 652 } 653 654 if (authURL != null) { 655 authServiceURL = getAuthServiceURL(authURL.getProtocol(), 656 authURL.getHost(), Integer.toString(authURL.getPort()), 657 authURL.getPath()); 658 } 659 660 AuthLoginException authException = null; 661 try { 662 if (authServiceURL == null) { 663 authServiceURL = getAuthServiceURL( server_proto, 664 server_host, server_port, server_uri); 665 } 666 if (authServiceURL != null) { 667 if (authDebug.messageEnabled()) { 668 authDebug.message("AuthContext.login : runLogin against " 669 + authServiceURL); 670 } 671 runLogin(indexType, indexName, params, pCookie, envMap, locale, 672 request, response); 673 return; 674 } 675 } catch (AuthLoginException e) { 676 authException = e; 677 authDebug.error("Failed to login to " + authServiceURL); 678 } catch (Exception e) { 679 authDebug.error("Failed to login to " + authServiceURL 680 + ": " + e.getMessage(),e); 681 } 682 683 if (authURL == null) { 684 // failover when authURL is not specified 685 Vector serviceURLs = null; 686 try { 687 serviceURLs = WebtopNaming.getServiceAllURLs( 688 AuthXMLTags.AUTH_SERVICE); 689 } catch (Exception e) { 690 throw new AuthLoginException(amAuthContext, "loginError", 691 new Object[]{e.getMessage()}); 692 } 693 694 if (authDebug.messageEnabled()) { 695 authDebug.message("Org Name : " + organizationName); 696 authDebug.message("ssoTokenID: " + ssoTokenID); 697 authDebug.message("serviceURLs: " + serviceURLs); 698 } 699 700 if (serviceURLs != null) { 701 serviceURLs.remove(authServiceURL); 702 for (Enumeration e = serviceURLs.elements(); 703 e.hasMoreElements(); ) { 704 authServiceURL = (URL)e.nextElement(); 705 try { 706 runLogin(indexType, indexName, params, pCookie, 707 envMap, locale, request, response); 708 return; 709 } catch (AuthLoginException ex) { 710 authException = ex; 711 authDebug.error("Failed to login in failover with " + 712 authServiceURL + ": " + ex.getMessage()); 713 } 714 } 715 } 716 } 717 authDebug.error("Authentication failed."); 718 if (authException != null) { 719 throw authException; 720 } else { 721 throw new AuthLoginException(amAuthContext, "loginError",null); 722 } 723 } 724 725 726 private void runLogin( 727 IndexType indexType, 728 String indexName, 729 String[] params, 730 boolean pCookie, 731 Map envMap, 732 String locale, 733 HttpServletRequest request, 734 HttpServletResponse response 735 ) throws AuthLoginException { 736 if (!localFlag) { 737 setLocalFlag(authServiceURL); 738 } 739 740 if (appSSOToken == null) { 741 if (!((indexType == IndexType.MODULE_INSTANCE) && 742 (indexName.equals("Application")))){ 743 appSSOToken = getAppSSOToken(false); 744 } 745 } 746 747 if (localFlag) { 748 try { 749 if (ssoTokenID == null) { 750 acLocal = com.sun.identity.authentication.service.AuthUtils. 751 getAuthContext(organizationName); 752 } else { 753 if (authDebug.messageEnabled()) { 754 authDebug.message("AuthContext.runLogin: " 755 + "ForceAuth = "+forceAuth); 756 } 757 acLocal = com.sun.identity.authentication.service.AuthUtils. 758 getAuthContext(organizationName, ssoTokenID, false, 759 null, null, null, forceAuth); 760 } 761 LoginState loginState = acLocal.getLoginState(); 762 /* 763 * Set both the HttpRequest and HttpResponse on the login state so they are accessible by the Auth 764 * Modules. 765 */ 766 if (request != null) { 767 loginState.setHttpServletRequest(request); 768 Hashtable hashtable = AuthClientUtils.parseRequestParameters(request); 769 loginState.setParamHash(hashtable); 770 } 771 if (response != null) { 772 loginState.setHttpServletResponse(response); 773 } 774 if (hostName != null) { 775 acLocal.getLoginState().setClient(hostName); 776 } 777 acLocal.login(indexType, indexName, pCookie, envMap, locale); 778 } catch (AuthException e) { 779 throw new AuthLoginException(e); 780 } 781 if (acLocal.getStatus().equals(Status.SUCCESS)) { 782 onSuccessLocal(); 783 } 784 return; 785 } 786 787 // Check if 7.0 RR stype protocol needs to be used 788 // This will setup NewAuthContext and authHandles 789 if (useOldStyleRemoteAuthentication) { 790 runRemoteOldAuthContext(); 791 if (loginException != null) { 792 throw loginException; 793 } 794 } 795 // Run Login 796 runRemoteLogin(indexType, indexName, params, pCookie, envMap, locale, 797 request, response); 798 // reset the retry count 799 retryRunLogin = DEFAULT_RETRY_COUNT; 800 801 if (authDebug.messageEnabled()) { 802 authDebug.message("useNewStyleRemoteAuthentication : " 803 + useNewStyleRemoteAuthentication); 804 authDebug.message("useOldStyleRemoteAuthentication : " 805 + useOldStyleRemoteAuthentication); 806 authDebug.message("receivedDocument : " + receivedDocument); 807 authDebug.message("loginException : " + loginException); 808 } 809 810 // If "Login" fails and we have not set 6.3, 7.0 RR style protocol 811 // the server could be either 6.3 or 7.0 RR. Hence try "NewAuthContext" 812 // and then "Login" 813 if (!useNewStyleRemoteAuthentication && 814 !useOldStyleRemoteAuthentication && 815 (receivedDocument == null || 816 (getAuthenticationHandle(receivedDocument)).equals("null")) && 817 loginException != null) { 818 if (authDebug.messageEnabled()) { 819 authDebug.message("AuthContext: trying 6.3 style remote " + 820 "AuthN and setting the flag to use 6.3 style"); 821 } 822 useOldStyleRemoteAuthentication = true; 823 // Server could be either 6.3 or 7.0 RR, try old style 824 // Construct the Request XML with New AuthContext parameters 825 loginException = null; // Reset loginException 826 runRemoteOldAuthContext(); 827 if (loginException != null) { 828 throw loginException; 829 } 830 // Re-try login process with AuthIdentifier 831 runRemoteLogin(indexType, indexName, params, pCookie, 832 envMap, locale, request, response); 833 // reset the retry count 834 retryRunLogin = DEFAULT_RETRY_COUNT; 835 } else if (!useNewStyleRemoteAuthentication) { 836 useNewStyleRemoteAuthentication = true; 837 } 838 if (loginException != null) { 839 throw loginException; 840 } 841 } 842 843 private void runRemoteLogin(IndexType indexType, String indexName, 844 String[] params, boolean pCookie, Map envMap, String locale, 845 HttpServletRequest req, HttpServletResponse res) 846 throws AuthLoginException { 847 try { 848 String xmlString = null; 849 // remote auth 850 StringBuilder request = new StringBuilder(100); 851 String[] authHandles = new String[1]; 852 authHandles[0] = getAuthHandle(); 853 if ((ssoTokenID != null) && (authHandles[0].equals("0"))) { 854 if (authDebug.messageEnabled()) { 855 authDebug.message("AuthContext.runRemoteLogin: Found" 856 + " SSOTokenID " + ssoTokenID); 857 } 858 authHandles[0] = ssoTokenID; 859 } 860 861 request.append(MessageFormat.format( 862 AuthXMLTags.XML_REQUEST_PREFIX, (Object[])authHandles)); 863 if (appSSOToken != null) { 864 request.append(AuthXMLTags.APPSSOTOKEN_BEGIN); 865 request.append(appSSOToken.getTokenID().toString()). 866 append(AuthXMLTags.APPSSOTOKEN_END); 867 } 868 request.append(AuthXMLTags.LOGIN_BEGIN); 869 870 if (!useOldStyleRemoteAuthentication) { 871 request.append(AuthXMLTags.SPACE) 872 .append(AuthXMLTags.ORG_NAME_ATTR) 873 .append(AuthXMLTags.EQUAL) 874 .append(AuthXMLTags.QUOTE) 875 .append(XMLUtils.escapeSpecialCharacters(organizationName)) 876 .append(AuthXMLTags.QUOTE); 877 if (hostName != null) { 878 request.append(AuthXMLTags.SPACE) 879 .append(AuthXMLTags.HOST_NAME_ATTR) 880 .append(AuthXMLTags.EQUAL) 881 .append(AuthXMLTags.QUOTE) 882 .append(XMLUtils.escapeSpecialCharacters(hostName)) 883 .append(AuthXMLTags.QUOTE); 884 } 885 if ((locale != null) && (locale.length() > 0)) { 886 request.append(AuthXMLTags.SPACE) 887 .append(AuthXMLTags.LOCALE) 888 .append(AuthXMLTags.EQUAL) 889 .append(AuthXMLTags.QUOTE) 890 .append(XMLUtils.escapeSpecialCharacters(locale)) 891 .append(AuthXMLTags.QUOTE); 892 } 893 if (forceAuth) { 894 request.append(AuthXMLTags.SPACE) 895 .append(AuthXMLTags.FORCE_AUTH_ATTR) 896 .append(AuthXMLTags.EQUAL) 897 .append(AuthXMLTags.QUOTE) 898 .append("true") 899 .append(AuthXMLTags.QUOTE); 900 } 901 } 902 request.append(AuthXMLTags.ELEMENT_END); 903 904 if (indexType != null) { 905 request.append(AuthXMLTags.INDEX_TYPE_PAIR_BEGIN) 906 .append(AuthXMLTags.SPACE) 907 .append(AuthXMLTags.INDEX_TYPE) 908 .append(AuthXMLTags.EQUAL) 909 .append(AuthXMLTags.QUOTE); 910 911 if (indexType == IndexType.USER) { 912 request.append(AuthXMLTags.INDEX_TYPE_USER_ATTR); 913 } else if (indexType == IndexType.ROLE) { 914 request.append(AuthXMLTags.INDEX_TYPE_ROLE_ATTR); 915 } else if (indexType == IndexType.SERVICE) { 916 request.append(AuthXMLTags.INDEX_TYPE_SVC_ATTR); 917 } else if (indexType == IndexType.MODULE_INSTANCE) { 918 request.append(AuthXMLTags.INDEX_TYPE_MODULE_ATTR); 919 } else if (indexType == IndexType.LEVEL) { 920 request.append(AuthXMLTags.INDEX_TYPE_LEVEL_ATTR); 921 } else if (indexType == IndexType.COMPOSITE_ADVICE) { 922 request.append( 923 AuthXMLTags.INDEX_TYPE_COMPOSITE_ADVICE_ATTR); 924 } else if (indexType == IndexType.RESOURCE) { 925 request.append(AuthXMLTags.INDEX_TYPE_RESOURCE); 926 } 927 request.append(AuthXMLTags.QUOTE) 928 .append(AuthXMLTags.ELEMENT_END) 929 .append(AuthXMLTags.INDEX_NAME_BEGIN) 930 .append(indexName) 931 .append(AuthXMLTags.INDEX_NAME_END) 932 .append(AuthXMLTags.INDEX_TYPE_PAIR_END); 933 } 934 935 if (locale != null && locale.length() > 0) { 936 request.append(AuthXMLTags.LOCALE_BEGIN); 937 request.append(locale); 938 request.append(AuthXMLTags.LOCALE_END); 939 } 940 941 if (params != null) { 942 StringBuilder paramString = new StringBuilder(); 943 for (int i = 0; i < params.length; i++) { 944 if (i != 0 ) { 945 paramString.append(ISAuthConstants.PIPE_SEPARATOR); 946 } 947 paramString.append(params[i]); 948 } 949 request.append(AuthXMLTags.PARAMS_BEGIN) 950 .append(paramString.toString()) 951 .append(AuthXMLTags.PARAMS_END); 952 } 953 if ((envMap != null) && !envMap.isEmpty()) { 954 StringBuilder envString = new StringBuilder(); 955 Iterator keys = envMap.keySet().iterator(); 956 while (keys.hasNext()) { 957 // convert Map to XMLString as follows: 958 // <EnvValue>keyname|value1|value2|...</EnvValue> 959 String keyName = (String) keys.next(); 960 Set values = (Set) envMap.get(keyName); 961 if ((values != null) && !values.isEmpty()) { 962 envString.append(AuthXMLTags.ENV_AV_BEGIN).append( 963 AuthClientUtils.escapePipe(keyName)); 964 Iterator iter = values.iterator(); 965 while (iter.hasNext()) { 966 envString.append(ISAuthConstants.PIPE_SEPARATOR) 967 .append(AuthClientUtils.escapePipe( 968 XMLUtils.escapeSpecialCharacters( 969 (String) iter.next()))); 970 } 971 envString.append(AuthXMLTags.ENV_AV_END); 972 } 973 } 974 request.append(AuthXMLTags.ENV_BEGIN) 975 .append(envString.toString()) 976 .append(AuthXMLTags.ENV_END); 977 } 978 request.append(AuthXMLTags.LOGIN_END); 979 980 if (includeReqRes) { 981 request.append(AuthXMLTags.REMOTE_REQUEST_RESPONSE_START) 982 .append(AuthXMLTags.HTTP_SERVLET_REQUEST_START); 983 String encObj = ""; 984 985 if (req != null) { 986 try { 987 encObj = AuthXMLUtils.serializeToString(new RemoteHttpServletRequest(req)); 988 } catch (IOException ioe) { 989 authDebug.error("AuthXMLUtils::runRemoteLogin Unable to serailize http request", ioe); 990 } 991 992 if (authDebug.messageEnabled()) { 993 authDebug.message("req=" + new RemoteHttpServletRequest(req).toString()); 994 } 995 996 request.append(encObj); 997 } 998 999 request.append(AuthXMLTags.HTTP_SERVLET_REQUEST_END); 1000 request.append(AuthXMLTags.HTTP_SERVLET_RESPONSE_START); 1001 1002 if (res != null) { 1003 encObj = ""; 1004 1005 try { 1006 encObj = AuthXMLUtils.serializeToString(new RemoteHttpServletResponse(res)); 1007 } catch (IOException ioe) { 1008 authDebug.error("AuthXMLUtils::runRemoteLogin Unable to serailize http response", ioe); 1009 } 1010 1011 if (authDebug.messageEnabled()) { 1012 authDebug.message("res=" + res); 1013 } 1014 1015 request.append(encObj); 1016 } 1017 1018 request.append(AuthXMLTags.HTTP_SERVLET_RESPONSE_END) 1019 .append(AuthXMLTags.REMOTE_REQUEST_RESPONSE_END); 1020 } else { 1021 if (authDebug.messageEnabled()) { 1022 authDebug.message("Not including req/res " + includeReqRes); 1023 } 1024 } 1025 1026 request.append(AuthXMLTags.XML_REQUEST_SUFFIX); 1027 xmlString = request.toString(); 1028 1029 // process the request, which will check for exceptions 1030 // and also get the authentication handle ID 1031 receivedDocument = processRequest(xmlString); 1032 1033 // Check set the login status 1034 checkAndSetLoginStatus(); 1035 1036 // if the app token was refreshed, retry remote login 1037 if (loginException != null && 1038 loginException.getErrorCode().equals(AMAuthErrorCode.REMOTE_AUTH_INVALID_SSO_TOKEN) && 1039 retryRunLogin > 0) { 1040 retryRunLogin--; 1041 1042 if (authDebug.messageEnabled()) { 1043 authDebug.message("Run remote login failed due to expired app token, retying"); 1044 } 1045 1046 // reset as we are starting again 1047 loginStatus = Status.IN_PROGRESS; 1048 runRemoteLogin(indexType, indexName, params, pCookie, envMap, locale, req, res); 1049 } 1050 } catch (AuthLoginException le) { 1051 // Login has failed 1052 loginStatus = Status.FAILED; 1053 loginException = le; 1054 } 1055 } 1056 1057 private void runRemoteOldAuthContext() throws AuthLoginException { 1058 try { 1059 StringBuilder request = new StringBuilder(100); 1060 String[] objs = { "0" }; 1061 if (ssoTokenID != null) { 1062 objs[0] = ssoTokenID; 1063 } 1064 request.append(MessageFormat.format( 1065 AuthXMLTags.XML_REQUEST_PREFIX, (Object[])objs)) 1066 .append(AuthXMLTags.NEW_AUTHCONTEXT_BEGIN) 1067 .append(AuthXMLTags.SPACE) 1068 .append(AuthXMLTags.ORG_NAME_ATTR) 1069 .append(AuthXMLTags.EQUAL) 1070 .append(AuthXMLTags.QUOTE) 1071 .append(XMLUtils.escapeSpecialCharacters(organizationName)) 1072 .append(AuthXMLTags.QUOTE) 1073 .append(AuthXMLTags.ELEMENT_END) 1074 .append(AuthXMLTags.NEW_AUTHCONTEXT_END) 1075 .append(AuthXMLTags.XML_REQUEST_SUFFIX); 1076 // process the request, which will check for exceptions 1077 // and also get the authentication handle ID 1078 receivedDocument = processRequest(request.toString()); 1079 1080 // Check set the login status 1081 checkAndSetLoginStatus(); 1082 } catch (AuthLoginException le) { 1083 // Login has failed 1084 loginStatus = Status.FAILED; 1085 loginException = le; 1086 } 1087 } 1088 1089 /** 1090 * Returns the set of Principals or Subject the user has been 1091 * authenticated as. 1092 * This should be invoked only after successful authentication. 1093 * 1094 * @return <code>Subject</code> for the authenticated User. 1095 * If the authentication fails or the authentication is in process, 1096 * this will return <code>null</code>. 1097 * 1098 * @supported.api 1099 */ 1100 public Subject getSubject() { 1101 if (localFlag) { 1102 if (!acLocal.getStatus().equals(Status.SUCCESS)) { 1103 return (null); 1104 } 1105 return (acLocal.getSubject()); 1106 } else { 1107 if (!loginStatus.equals(Status.SUCCESS)) { 1108 return (null); 1109 } 1110 return (getSubject(receivedDocument)); 1111 } 1112 } 1113 1114 /** 1115 * Returns a <code>Map</code> object that 1116 * that contains cookies set by AM server 1117 * 1118 * @return a <code>Map</code> of cookie name and 1119 * <code>Cookie</code> object. 1120 */ 1121 public Map getCookieTable() { 1122 return cookieTable; 1123 } 1124 1125 /** 1126 * Returns <code>true</code> if the login process requires more 1127 * information from the user to complete the authentication. 1128 * <p> 1129 * NOTE: This method has to be called as a condition of a 1130 * <code>while</code> loop in order to complete the authentication process 1131 * and get the correct <code>Status</code> after submitting the 1132 * requirements. 1133 * 1134 * @return <code>true</code> if more credentials are required from the user. 1135 * 1136 * @supported.api 1137 */ 1138 public boolean hasMoreRequirements() { 1139 if (localFlag) { 1140 return (acLocal.hasMoreRequirements(false)); 1141 } else { 1142 if ((!loginStatus.equals(Status.IN_PROGRESS)) || 1143 ((getCallbacks(receivedDocument, false)) == null)) { 1144 return (false); 1145 } 1146 return (true); 1147 } 1148 } 1149 1150 /** 1151 * Returns <code>true</code> if the login process requires more information 1152 * from the user to complete the authentication. 1153 * 1154 * NOTE: This method has to be called as a condition of a <ode>while</code> 1155 * loop in order to complete the authentication process and get the correct 1156 * <code>Status</code> after submitting the requirements. 1157 * 1158 * @param noFilter flag indicates whether to filter 1159 * <code>PagePropertiesCallback</code> or not. Value 1160 * <code>true</code> will not filter 1161 * <code>PagePropertiesCallback</code>. 1162 * @return <code>true</code> if more credentials are required from the user. 1163 * 1164 * @supported.api 1165 */ 1166 public boolean hasMoreRequirements(boolean noFilter) { 1167 if (localFlag) { 1168 return (acLocal.hasMoreRequirements(noFilter)); 1169 } else { 1170 if ((!loginStatus.equals(Status.IN_PROGRESS)) || 1171 ((getCallbacks(receivedDocument, noFilter)) == null)) { 1172 return (false); 1173 } 1174 return (true); 1175 } 1176 } 1177 1178 /** 1179 * Returns an array of <code>Callback</code> objects that must be populated 1180 * by the user and returned back. These objects are requested by the 1181 * authentication plug-ins, and these are usually displayed to the user. 1182 * The user then provides the requested information for it to be 1183 * authenticated. 1184 * 1185 * @return an array of <code>Callback</code> objects requesting credentials 1186 * from user 1187 * 1188 * @supported.api 1189 */ 1190 public Callback[] getRequirements() { 1191 if (localFlag) { 1192 if (!acLocal.getStatus().equals(Status.IN_PROGRESS)) { 1193 return (null); 1194 } 1195 return (acLocal.getRequirements(false)); 1196 } else { 1197 if (!loginStatus.equals(Status.IN_PROGRESS)) { 1198 return (null); 1199 } 1200 return (getCallbacks(receivedDocument, false)); 1201 } 1202 } 1203 1204 /** 1205 * Returns an array of <code>Callback</code> objects that 1206 * must be populated by the user and returned back. 1207 * These objects are requested by the authentication plug-ins, 1208 * and these are usually displayed to the user. The user then provides 1209 * the requested information for it to be authenticated. 1210 * 1211 * @param noFilter boolean flag indicating whether to filter 1212 * <code>PagePropertiesCallback</code> or not. Value <code>true</code> will 1213 * not filter <code>PagePropertiesCallback</code>. 1214 * 1215 * @return an array of <code>Callback</code> objects requesting credentials 1216 * from user 1217 * 1218 * @supported.api 1219 */ 1220 public Callback[] getRequirements(boolean noFilter) { 1221 if (localFlag) { 1222 if (!acLocal.getStatus().equals(Status.IN_PROGRESS)) { 1223 return (null); 1224 } 1225 return (acLocal.getRequirements(noFilter)); 1226 } else { 1227 if (!loginStatus.equals(Status.IN_PROGRESS)) { 1228 return (null); 1229 } 1230 return (getCallbacks(receivedDocument, noFilter)); 1231 } 1232 } 1233 1234 /** 1235 * Fetches the remote request from the context 1236 * 1237 * @return The Http Servlet Request 1238 */ 1239 public HttpServletRequest getRemoteRequest() { 1240 return remoteRequest; 1241 } 1242 1243 /** 1244 * Fetches the remote response from the context 1245 * 1246 * @return The Http Servlet Response 1247 */ 1248 public HttpServletResponse getRemoteResponse() { 1249 return remoteResponse; 1250 } 1251 1252 /** 1253 * Submits the populated <code>Callback</code> objects to the 1254 * authentication plug-in modules. Called after <code>getRequirements</code> 1255 * method and obtaining user's response to these requests. 1256 * 1257 * @param info Array of <code>Callback</code> objects. 1258 * 1259 * @supported.api 1260 */ 1261 public void submitRequirements(Callback[] info) { 1262 submitRequirements(info, null, null); 1263 } 1264 1265 public void submitRequirements(Callback[] info, HttpServletRequest request, 1266 HttpServletResponse response) { 1267 if (authDebug.messageEnabled()) { 1268 authDebug.message("submitRequirements with Callbacks : " + info); 1269 } 1270 1271 if (localFlag) { 1272 // Check if we are still in login session 1273 if (!acLocal.getStatus().equals(Status.IN_PROGRESS)) { 1274 return; 1275 } 1276 acLocal.submitRequirements(info); 1277 if (acLocal.getStatus().equals(Status.SUCCESS)) { 1278 onSuccessLocal(); 1279 } 1280 return; 1281 } else { 1282 // Check if we are still in login session 1283 if (!loginStatus.equals(Status.IN_PROGRESS)) { 1284 return; 1285 } 1286 1287 // Construct the XML 1288 try { 1289 StringBuilder xml = new StringBuilder(100); 1290 String[] authHandles = new String[1]; 1291 authHandles[0] = getAuthenticationHandle(receivedDocument); 1292 xml.append(MessageFormat.format( 1293 AuthXMLTags.XML_REQUEST_PREFIX,(Object[])authHandles)); 1294 if (appSSOToken != null) { 1295 xml.append(AuthXMLTags.APPSSOTOKEN_BEGIN); 1296 xml.append(appSSOToken.getTokenID().toString()). 1297 append(AuthXMLTags.APPSSOTOKEN_END); 1298 } 1299 xml.append(AuthXMLTags.SUBMIT_REQS_BEGIN) 1300 .append(AuthXMLUtils.getXMLForCallbacks(info)); 1301 1302 if (clientLocale != null) { 1303 String localeStr = clientLocale.toString(); 1304 if ((localeStr != null) && (localeStr.length() > 0)) { 1305 xml.append(AuthXMLTags.LOCALE_BEGIN) 1306 .append(XMLUtils.escapeSpecialCharacters(localeStr)) 1307 .append(AuthXMLTags.LOCALE_END); 1308 } 1309 } 1310 1311 xml.append(AuthXMLTags.SUBMIT_REQS_END); 1312 1313 if (includeReqRes) { 1314 // serialized request and response objects 1315 xml.append(AuthXMLTags.REMOTE_REQUEST_RESPONSE_START) 1316 .append(AuthXMLTags.HTTP_SERVLET_REQUEST_START); 1317 String encObj = ""; 1318 1319 if (request != null) { 1320 try { 1321 encObj = AuthXMLUtils.serializeToString(new RemoteHttpServletRequest(request)); 1322 } catch (IOException ioe) { 1323 authDebug.error("AuthXMLUtils::runRemoteLogin Unable to serailize http request", ioe); 1324 } 1325 1326 if (authDebug.messageEnabled()) { 1327 authDebug.message("req=" + request); 1328 } 1329 1330 xml.append(encObj); 1331 } 1332 1333 xml.append(AuthXMLTags.HTTP_SERVLET_REQUEST_END); 1334 xml.append(AuthXMLTags.HTTP_SERVLET_RESPONSE_START); 1335 1336 if (response != null) { 1337 encObj = ""; 1338 1339 try { 1340 encObj = AuthXMLUtils.serializeToString(new RemoteHttpServletResponse(response)); 1341 } catch (IOException ioe) { 1342 authDebug.error("AuthXMLUtils::runRemoteLogin Unable to serailize http response", ioe); 1343 } 1344 1345 if (authDebug.messageEnabled()) { 1346 authDebug.message("res=" + response); 1347 } 1348 1349 xml.append(encObj); 1350 } 1351 1352 xml.append(AuthXMLTags.HTTP_SERVLET_RESPONSE_END) 1353 .append(AuthXMLTags.REMOTE_REQUEST_RESPONSE_END); 1354 } 1355 xml.append(AuthXMLTags.XML_REQUEST_SUFFIX); 1356 1357 // Send the request to be processes 1358 receivedDocument = processRequest(xml.toString()); 1359 1360 // Check set the login status 1361 checkAndSetLoginStatus(); 1362 } catch (AuthLoginException le) { 1363 // Login has failed 1364 loginStatus = Status.FAILED; 1365 loginException = le; 1366 } 1367 } 1368 } 1369 1370 /** 1371 * Logs out the user and also invalidates the single sign on token 1372 * associated with this <code>AuthContext</code>. 1373 * 1374 * @throws AuthLoginException if an error occurred during logout. 1375 * 1376 * @supported.api 1377 */ 1378 public void logout() throws AuthLoginException { 1379 if (localFlag) { 1380 acLocal.logout(); 1381 return; 1382 } 1383 1384 // Construct the XML 1385 try { 1386 StringBuilder xml = new StringBuilder(100); 1387 String[] authHandles = new String[1]; 1388 authHandles[0] = getAuthenticationHandle(receivedDocument); 1389 xml.append(MessageFormat.format(AuthXMLTags.XML_REQUEST_PREFIX, 1390 (Object[])authHandles)); 1391 if (appSSOToken != null) { 1392 xml.append(AuthXMLTags.APPSSOTOKEN_BEGIN); 1393 xml.append(appSSOToken.getTokenID().toString()). 1394 append(AuthXMLTags.APPSSOTOKEN_END); 1395 } 1396 xml.append(AuthXMLTags.LOGOUT_BEGIN) 1397 .append(AuthXMLTags.LOGOUT_END) 1398 .append(AuthXMLTags.XML_REQUEST_SUFFIX); 1399 1400 // Send the request to be processes 1401 receivedDocument = processRequest(xml.toString()); 1402 1403 // Check set the login status 1404 checkAndSetLoginStatus(); 1405 } catch (AuthLoginException le) { 1406 // Login has failed 1407 loginStatus = Status.FAILED; 1408 loginException = le; 1409 } 1410 } 1411 1412 /** 1413 * Logs out the user and also invalidates the single sign on token 1414 * associated with this <code>AuthContext</code>. 1415 * 1416 * This method causes the logout to happen on the server and the 1417 * correct SPI hooks to be called. 1418 * 1419 * @throws AuthLoginException if an error occurred during logout. 1420 * 1421 * @supported.api 1422 */ 1423 public void logoutUsingTokenID() 1424 throws AuthLoginException { 1425 if (localFlag) { 1426 return; 1427 } 1428 1429 if (ssoToken != null) { 1430 try { 1431 organizationName = ssoToken.getProperty( 1432 ISAuthConstants.ORGANIZATION); 1433 ssoTokenID = ssoToken.getTokenID().toString(); 1434 authURL = Session.getSession( 1435 new SessionID(ssoTokenID)).getSessionServiceURL(); 1436 } catch (Exception e) { 1437 throw new AuthLoginException(e); 1438 } 1439 } 1440 1441 if (authURL != null) { 1442 authServiceURL = getAuthServiceURL(authURL.getProtocol(), 1443 authURL.getHost(), Integer.toString(authURL.getPort()), 1444 authURL.getPath()); 1445 } 1446 1447 1448 // Construct the XML 1449 try { 1450 StringBuilder xml = new StringBuilder(100); 1451 String[] authHandles = new String[1]; 1452 authHandles[0] = ssoToken.getTokenID().toString(); 1453 xml.append(MessageFormat.format(AuthXMLTags.XML_REQUEST_PREFIX, 1454 (Object[]) authHandles)); 1455 if (appSSOToken != null) { 1456 xml.append(AuthXMLTags.APPSSOTOKEN_BEGIN); 1457 xml.append(appSSOToken.getTokenID().toString()). 1458 append(AuthXMLTags.APPSSOTOKEN_END); 1459 } 1460 xml.append(AuthXMLTags.LOGOUT_BEGIN) 1461 .append(AuthXMLTags.LOGOUT_END) 1462 .append(AuthXMLTags.XML_REQUEST_SUFFIX); 1463 1464 // Send the request to be processes 1465 receivedDocument = processRequest(xml.toString()); 1466 1467 // Check set the login status 1468 checkAndSetLoginStatus(); 1469 } catch (AuthLoginException le) { 1470 // Login has failed 1471 loginStatus = Status.FAILED; 1472 loginException = le; 1473 } 1474 } 1475 1476 /** 1477 * Returns login exception, if any, during the authentication process. 1478 * Typically set when the login fails. 1479 * 1480 * @return login exception. 1481 * @supported.api 1482 */ 1483 public AuthLoginException getLoginException() { 1484 if (localFlag) { 1485 return (acLocal.getLoginException()); 1486 } else { 1487 return (loginException); 1488 } 1489 } 1490 1491 /** 1492 * Returns the Single-Sign-On (SSO) Token for the authenticated 1493 * user. If the user has not successfully authenticated 1494 * <code>Exception</code> will be thrown. 1495 * <p> 1496 * Single sign token can be used as the authenticated token. 1497 * 1498 * @return Single-Sign-On token for the valid user after successful 1499 * authentication. 1500 * @throws L10NMessageImpl if the user is not authenticated or an error is 1501 * encountered in retrieving the user's single sign on token. 1502 * @supported.api 1503 */ 1504 public SSOToken getSSOToken() throws L10NMessageImpl { 1505 if (localFlag) { 1506 if (!acLocal.getStatus().equals(Status.SUCCESS)) { 1507 throw new L10NMessageImpl( 1508 amAuthContext, "statusNotSuccess", null); 1509 } 1510 return (acLocal.getSSOToken()); 1511 } else { 1512 // Get the loginStatus node 1513 if (!loginStatus.equals(Status.SUCCESS)) { 1514 throw new L10NMessageImpl( 1515 amAuthContext, "statusNotSuccess", null); 1516 } 1517 Node loginStatusNode = XMLUtils.getRootNode(receivedDocument, 1518 AuthXMLTags.LOGIN_STATUS); 1519 if (loginStatusNode == null) { 1520 throw new L10NMessageImpl(amAuthContext, "noStatusNode", null); 1521 } 1522 1523 String ssoTokenIDTmp = XMLUtils.getNodeAttributeValue(loginStatusNode, 1524 AuthXMLTags.SSOTOKEN); 1525 try { 1526 return new com.iplanet.sso.providers.dpro.SSOProviderImpl(). 1527 createSSOToken(ssoTokenIDTmp, true); 1528 } catch (SSOException ssoe) { 1529 throw new L10NMessageImpl( 1530 amAuthContext, "createSSOTokenError", null); 1531 } 1532 } 1533 } 1534 1535 /** 1536 * Returns the current status of the authentication process as 1537 * <code>AuthContext.Status</code>. 1538 * 1539 * @return <code>Status</code> of the authentication process. 1540 * 1541 * @supported.api 1542 */ 1543 public Status getStatus() { 1544 if (localFlag) { 1545 return (acLocal.getStatus()); 1546 } else { 1547 return (loginStatus); 1548 } 1549 } 1550 1551 /** 1552 * Returns the current Auth Identifier of the authentication 1553 * process as String Session ID. 1554 * 1555 * @return Auth Identifier of the authentication process. 1556 */ 1557 public String getAuthIdentifier() { 1558 if (localFlag) { 1559 return (acLocal.getAuthIdentifier()); 1560 } else { 1561 return (getAuthHandle()); 1562 } 1563 } 1564 1565 /** 1566 * Returns the Successful Login URL for the authenticated user. 1567 * 1568 * @return the Successful Login URL for the authenticated user. 1569 * @throws Exception if it fails to get url for auth success 1570 */ 1571 public String getSuccessURL() throws Exception { 1572 if (localFlag) { 1573 if (!acLocal.getStatus().equals(Status.SUCCESS)) { 1574 throw new 1575 L10NMessageImpl(amAuthContext, "statusNotSuccess", null); 1576 } 1577 return (acLocal.getSuccessURL()); 1578 } else { 1579 // Get the loginStatus node 1580 if (!loginStatus.equals(Status.SUCCESS)) { 1581 throw new 1582 L10NMessageImpl(amAuthContext, "statusNotSuccess", null); 1583 } 1584 Node loginStatusNode = XMLUtils.getRootNode(receivedDocument, 1585 AuthXMLTags.LOGIN_STATUS); 1586 if (loginStatusNode == null) { 1587 throw new L10NMessageImpl(amAuthContext, "noStatusNode", null); 1588 } 1589 return (XMLUtils.getNodeAttributeValue(loginStatusNode, 1590 AuthXMLTags.SUCCESS_URL)); 1591 } 1592 } 1593 1594 /** 1595 * Returns the Failure Login URL for the authenticating user. 1596 * 1597 * @return the Failure Login URL for the authenticating user 1598 * @throws Exception if it fails to get url for auth failure 1599 */ 1600 public String getFailureURL() throws Exception { 1601 if (localFlag) { 1602 return (acLocal.getFailureURL()); 1603 } else { 1604 // Get the loginStatus node 1605 Node loginStatusNode = XMLUtils.getRootNode(receivedDocument, 1606 AuthXMLTags.LOGIN_STATUS); 1607 if (loginStatusNode == null) { 1608 throw new L10NMessageImpl(amAuthContext, "noStatusNode", null); 1609 } 1610 return (XMLUtils.getNodeAttributeValue(loginStatusNode, 1611 AuthXMLTags.FAILURE_URL)); 1612 } 1613 } 1614 1615 /** 1616 * Resets this instance of <code>AuthContext</code> object, so that a new 1617 * login process can be initiated. A new authentication process can started 1618 * using any one of the <code>login</code> methods. 1619 */ 1620 public void reset() { 1621 loginStatus = Status.NOT_STARTED; 1622 //organizationName = null; 1623 //receivedDocument = null; 1624 //loginException = null; 1625 } 1626 1627 /** 1628 * Returns the the organization name that was set during the 1629 * <code>AuthContext</code> constructor. 1630 * 1631 * @return Organization name in the <code>AuthContext</code>. 1632 * 1633 * @supported.api 1634 */ 1635 public String getOrganizationName() { 1636 return (this.organizationName); 1637 } 1638 1639 /** 1640 * 1641 * Returns authentication module/s instances (or plugins) configured 1642 * for a organization, or sub-organization name that was set during the 1643 * <code>AuthContext</code> constructor. 1644 * 1645 * @return Set of Module instance names. 1646 * 1647 * @supported.api 1648 */ 1649 public Set getModuleInstanceNames() { 1650 if (authURL != null) { 1651 authServiceURL = getAuthServiceURL( 1652 authURL.getProtocol(), 1653 authURL.getHost(), 1654 Integer.toString(authURL.getPort()), 1655 authURL.getPath()); 1656 } 1657 if (!localFlag) { 1658 setLocalFlag(authServiceURL); 1659 } 1660 if (localFlag) { 1661 return (acLocal.getModuleInstanceNames()); 1662 } else { 1663 if (authServiceURL == null) { 1664 try { 1665 authServiceURL = getAuthServiceURL(server_proto, 1666 server_host, server_port, server_uri); 1667 } catch (Exception e) { 1668 return Collections.EMPTY_SET; 1669 } 1670 } 1671 sendQueryInformation(AuthXMLTags.MODULE_INSTANCE); 1672 1673 //Receive data 1674 Node queryResultNode = XMLUtils.getRootNode(receivedDocument, 1675 AuthXMLTags.QUERY_RESULT); 1676 if (queryResultNode == null) { 1677 return (null); 1678 } 1679 1680 // Iteratate through moduleInstanceNames 1681 HashSet moduleInstanceNames = new HashSet(); 1682 NodeList childNodes = queryResultNode.getChildNodes(); 1683 if ( childNodes != null ) { 1684 for (int i = 0; i < childNodes.getLength(); i++) { 1685 Node childNode = childNodes.item(i); 1686 String moduleName = XMLUtils.getValueOfValueNode(childNode); 1687 moduleInstanceNames.add(moduleName); 1688 } 1689 } 1690 return (moduleInstanceNames); 1691 } 1692 } 1693 1694 /** 1695 * Terminates an ongoing <code>login</code> call that has not yet completed. 1696 * 1697 * @exception AuthLoginException if an error occurred during abort. 1698 * 1699 * @supported.api 1700 */ 1701 public void abort() throws AuthLoginException { 1702 if (localFlag) { 1703 acLocal.abort(); 1704 return; 1705 } 1706 1707 // Construct the XML 1708 try { 1709 StringBuilder xml = new StringBuilder(100); 1710 String[] authHandles = new String[1]; 1711 authHandles[0] = getAuthenticationHandle(receivedDocument); 1712 xml.append(MessageFormat.format(AuthXMLTags.XML_REQUEST_PREFIX, 1713 (Object[])authHandles)); 1714 if (appSSOToken != null) { 1715 xml.append(AuthXMLTags.APPSSOTOKEN_BEGIN); 1716 xml.append(appSSOToken.getTokenID().toString()). 1717 append(AuthXMLTags.APPSSOTOKEN_END); 1718 } 1719 xml.append(AuthXMLTags.ABORT_BEGIN) 1720 .append(AuthXMLTags.ABORT_END) 1721 .append(AuthXMLTags.XML_REQUEST_SUFFIX); 1722 1723 // Send the request to be processes 1724 receivedDocument = processRequest(xml.toString()); 1725 1726 // Check set the login status 1727 checkAndSetLoginStatus(); 1728 } catch (AuthLoginException le) { 1729 // Login has failed 1730 loginStatus = Status.FAILED; 1731 loginException = le; 1732 } 1733 } 1734 1735 /** 1736 * Sets the password for the certificate database. 1737 * It is required to call only once to initialize certificate database if 1738 * the password is not set in the password file (specified as 1739 * the value for <code>com.iplanet.am.admin.cli.certdb.passfile</code> 1740 * in <code>AMConfig.properties</code>). If both are set, this method will 1741 * overwrite the value in certificate password file. 1742 * 1743 * @param password Password for the certificate database. 1744 * 1745 * @supported.api 1746 */ 1747 public static void setCertDBPassword(String password) { 1748 try { 1749 if (usingJSSEHandler) { 1750 Class pcbClass = (Class) Class.forName(JSSE_PASSWORD_CALLBACK); 1751 Object passwdCallback = (Object) pcbClass.newInstance(); 1752 Method method = 1753 pcbClass.getMethod("setPassword", new Class[] { String.class }); 1754 KeyStore keystore = (KeyStore)method.invoke( 1755 passwdCallback, new Object[] { password }); 1756 } else { 1757 Class initializer = Class.forName(JSS_PASSWORD_UTIL); 1758 Constructor initializerConstructor = initializer.getConstructor( 1759 new Class[] { String.class }); 1760 initializerConstructor.newInstance(new Object[] { password }); 1761 } 1762 } catch (Exception e) { 1763 e.printStackTrace(); 1764 authDebug.message("Error in setCertDBPassword : " + e.getMessage()); 1765 } 1766 } 1767 1768 1769 /** 1770 * Returns the error template. 1771 * 1772 * @return error template. 1773 */ 1774 public String getErrorTemplate() { 1775 if (localFlag) { 1776 return (acLocal.getErrorTemplate()); 1777 } else { 1778 if (receivedDocument == null) { 1779 //something went terribly wrong, let's return with internal error template 1780 return AuthClientUtils.getErrorTemplate(AMAuthErrorCode.AUTH_ERROR); 1781 } 1782 String errTemplate = ""; 1783 Node exceptionNode = XMLUtils.getRootNode(receivedDocument, 1784 AuthXMLTags.EXCEPTION); 1785 if (exceptionNode != null) { 1786 errTemplate = XMLUtils.getNodeAttributeValue(exceptionNode, 1787 AuthXMLTags.TEMPLATE_NAME); 1788 } 1789 return errTemplate; 1790 } 1791 } 1792 1793 /** 1794 * Returns the error message. 1795 * 1796 * @return error message. 1797 */ 1798 public String getErrorMessage() { 1799 if (localFlag) { 1800 return (acLocal.getErrorMessage()); 1801 } else { 1802 if (receivedDocument == null) { 1803 //something went terribly wrong, let's return with internal error message 1804 return AuthClientUtils.getErrorMessage(AMAuthErrorCode.AUTH_ERROR); 1805 } 1806 String errMessage = null; 1807 Node exceptionNode = XMLUtils.getRootNode(receivedDocument, 1808 AuthXMLTags.EXCEPTION); 1809 if (exceptionNode != null) { 1810 errMessage = XMLUtils.getNodeAttributeValue(exceptionNode, 1811 AuthXMLTags.MESSAGE); 1812 } 1813 return errMessage; 1814 } 1815 } 1816 1817 /** 1818 * Returns error code. 1819 * 1820 * @return error code with white space trimmed 1821 */ 1822 public String getErrorCode() { 1823 if (localFlag) { 1824 return (acLocal.getErrorCode()); 1825 } else { 1826 if (receivedDocument == null) { 1827 //something went terribly wrong 1828 return AMAuthErrorCode.AUTH_ERROR; 1829 } 1830 String errCode = ""; 1831 Node exceptionNode = XMLUtils.getRootNode(receivedDocument, 1832 AuthXMLTags.EXCEPTION); 1833 1834 if (exceptionNode != null) { 1835 errCode = XMLUtils.getNodeAttributeValue(exceptionNode, 1836 AuthXMLTags.ERROR_CODE); 1837 } 1838 1839 if (errCode != null) { 1840 return errCode.trim(); 1841 } else { 1842 return errCode; 1843 } 1844 } 1845 } 1846 1847 /** 1848 * Sets the client's hostname or IP address.This could be used 1849 * by the policy component to restrict access to resources. 1850 * This method is ineffective if the "Remote Auth Security" option under 1851 * the global configuration of Core Authentication Service is not enabled. 1852 * This method must be called before calling <code>login</code> method. 1853 * If it is called after calling <code>login</code> then 1854 * it is ineffective. 1855 * 1856 * @param hostname hostname or ip address 1857 * 1858 * @supported.api 1859 */ 1860 public void setClientHostName(String hostname) { 1861 this.hostName = hostname; 1862 } 1863 1864 /** 1865 * Returns the client's hostname or IP address as set by 1866 * setClientHostName 1867 * 1868 * @return hostname/IP address 1869 * 1870 * @supported.api 1871 */ 1872 public String getClientHostName() { 1873 return (hostName); 1874 } 1875 1876 /** 1877 * Sets locale based on user locale preferemce. 1878 * 1879 * @param loc locale preference of user 1880 */ 1881 public void setLocale (java.util.Locale loc) { 1882 clientLocale = loc; 1883 } 1884 1885 /** 1886 * Returns locale preference set in AuthConext 1887 * @return - user prefered locale. 1888 */ 1889 1890 public java.util.Locale getLocale () { 1891 return clientLocale; 1892 } 1893 1894 private AuthLoginException checkException(){ 1895 AuthLoginException exception = null; 1896 String error = getErrorCode(); 1897 1898 // if the app token is invalid, refresh the token 1899 if (error != null && error.equals(AMAuthErrorCode.REMOTE_AUTH_INVALID_SSO_TOKEN)) { 1900 appSSOToken = getAppSSOToken(true); 1901 } 1902 1903 if (error != null && error.length() != 0){ 1904 exception = new AuthLoginException("amAuth", error, null); 1905 } else { 1906 error = getErrorMessage(); 1907 if (error != null && error.length() != 0) { 1908 exception = new AuthLoginException(error); 1909 } 1910 } 1911 return exception; 1912 } 1913 1914 protected void checkAndSetLoginStatus(){ 1915 1916 Node loginStatusNode = XMLUtils.getRootNode( 1917 receivedDocument, AuthXMLTags.LOGIN_STATUS); 1918 if (loginStatusNode == null) { 1919 loginException = checkException(); 1920 1921 if (includeReqRes) { 1922 remoteRequest = AuthXMLUtils.getRemoteRequest( 1923 XMLUtils.getRootNode(receivedDocument, AuthXMLTags.REMOTE_REQUEST_RESPONSE)); 1924 remoteResponse = AuthXMLUtils.getRemoteResponse( 1925 XMLUtils.getRootNode(receivedDocument, AuthXMLTags.REMOTE_REQUEST_RESPONSE)); 1926 } 1927 } else { 1928 // Get the status attribute 1929 String status = XMLUtils.getNodeAttributeValue( 1930 loginStatusNode, AuthXMLTags.STATUS); 1931 if (status != null) { 1932 if (status.equals(Status.SUCCESS.toString())) { 1933 loginStatus = Status.SUCCESS; 1934 } else if (status.equals(Status.FAILED.toString())) { 1935 loginStatus = Status.FAILED; 1936 loginException = checkException(); 1937 } else if (status.equals(Status.COMPLETED.toString())) { 1938 loginStatus = Status.COMPLETED; 1939 } else if (status.equals(Status.IN_PROGRESS.toString())) { 1940 loginStatus = Status.IN_PROGRESS; 1941 } else if (status.equals(Status.RESET.toString())) { 1942 loginStatus = Status.RESET; 1943 } 1944 } 1945 1946 if (includeReqRes) { 1947 remoteRequest = AuthXMLUtils.getRemoteRequest( 1948 XMLUtils.getRootNode(receivedDocument, AuthXMLTags.REMOTE_REQUEST_RESPONSE)); 1949 remoteResponse = AuthXMLUtils.getRemoteResponse( 1950 XMLUtils.getRootNode(receivedDocument, AuthXMLTags.REMOTE_REQUEST_RESPONSE)); 1951 } 1952 1953 if (authDebug.messageEnabled()) { 1954 authDebug.message("LoginStatus : " + loginStatus); 1955 } 1956 } 1957 } 1958 1959 protected void sendQueryInformation(String reqInfo) { 1960 // Construct the XML 1961 try { 1962 StringBuilder xml = new StringBuilder(100); 1963 String[] authHandles = new String[1]; 1964 authHandles[0] = getAuthHandle(); 1965 1966 xml.append(MessageFormat.format(AuthXMLTags.XML_REQUEST_PREFIX, 1967 (Object[])authHandles)); 1968 if (appSSOToken != null) { 1969 xml.append(AuthXMLTags.APPSSOTOKEN_BEGIN); 1970 xml.append(appSSOToken.getTokenID().toString()). 1971 append(AuthXMLTags.APPSSOTOKEN_END); 1972 } 1973 xml.append(AuthXMLTags.QUERY_INFO_BEGIN) 1974 .append(AuthXMLTags.SPACE) 1975 .append(AuthXMLTags.REQUESTED_INFO) 1976 .append(AuthXMLTags.EQUAL) 1977 .append(AuthXMLTags.QUOTE) 1978 .append(reqInfo) 1979 .append(AuthXMLTags.QUOTE); 1980 1981 if (authHandles[0].equals("0")) { 1982 xml.append(AuthXMLTags.SPACE) 1983 .append(AuthXMLTags.ORG_NAME_ATTR) 1984 .append(AuthXMLTags.EQUAL) 1985 .append(AuthXMLTags.QUOTE) 1986 .append(XMLUtils.escapeSpecialCharacters(organizationName)) 1987 .append(AuthXMLTags.QUOTE); 1988 } 1989 1990 xml.append(AuthXMLTags.ELEMENT_END) 1991 .append(AuthXMLTags.QUERY_INFO_END) 1992 .append(AuthXMLTags.XML_REQUEST_SUFFIX); 1993 1994 // Send the request to be processes 1995 receivedDocument = processRequest(xml.toString()); 1996 1997 // Check set the login status 1998 checkAndSetLoginStatus(); 1999 } catch (AuthLoginException le) { 2000 // Login has failed 2001 loginStatus = Status.FAILED; 2002 loginException = le; 2003 } 2004 } 2005 2006 private void setLocalFlag(URL url) { 2007 try { 2008 String urlStr = url.getProtocol() + "://" + url.getHost() + ":" 2009 + Integer.toString(url.getPort()); 2010 2011 if (authDebug.messageEnabled()) { 2012 authDebug.message("in setLocalFlag(), url : " + urlStr); 2013 authDebug.message("AuthContext.localAuthServiceID : " + 2014 localAuthServiceID); 2015 } 2016 2017 if ((localAuthServiceID != null) && 2018 (urlStr.equalsIgnoreCase(localAuthServiceID)) 2019 ) { 2020 localFlag = true; 2021 } 2022 } catch (Exception e) { 2023 authDebug.error("AuthContext::setLocalFlag:: " + e); 2024 } 2025 } 2026 2027 protected Document processRequest(String xmlRequest) 2028 throws AuthLoginException { 2029 Document doc = null; 2030 2031 try { 2032 Request request = new Request(xmlRequest); 2033 RequestSet set = new RequestSet(AuthXMLTags.AUTH_SERVICE); 2034 set.addRequest(request); 2035 2036 URL url = authServiceURL; 2037 2038 if (url.getProtocol().equals("https") && (nickName != null)) { 2039 Class[] paramtype = {String.class}; 2040 Object[] param = {nickName}; 2041 String protHandler = protHandlerPkg + ".https.Handler"; 2042 Constructor construct = 2043 Class.forName(protHandler).getConstructor(paramtype); 2044 URLStreamHandler handler = 2045 (URLStreamHandler)construct.newInstance(param); 2046 url = new URL(url.getProtocol(), url.getHost(), url.getPort(), 2047 url.getFile(), handler); 2048 } 2049 2050 if (authDebug.messageEnabled()) { 2051 authDebug.message("Service URL : " + url.toString()); 2052 } 2053 2054 Vector responses = PLLClient.send(url, set, cookieTable); 2055 2056 if ((responses.isEmpty()) || (responses.size() != 1)) { 2057 throw new L10NMessageImpl(amAuthContext, "responseError", null); 2058 } 2059 2060 Response res = (Response) responses.elementAt(0); 2061 String responseStr = (String)res.getContent(); 2062 2063 doc = XMLUtils.getXMLDocument( 2064 new ByteArrayInputStream(responseStr.getBytes("UTF-8"))); 2065 } catch (Exception e) { 2066 authDebug.message("error in getting service url", e); 2067 throw new AuthLoginException(amAuthContext, "xmlProcessError", 2068 null, e); 2069 } 2070 return (doc); 2071 } 2072 2073 protected static void checkForException(Document document) 2074 throws AuthLoginException { 2075 Node exceptionNode = XMLUtils.getRootNode( 2076 document, AuthXMLTags.EXCEPTION); 2077 2078 if (exceptionNode != null) { 2079 throw (new AuthLoginException(XMLUtils.getNodeAttributeValue( 2080 exceptionNode, AuthXMLTags.MESSAGE))); 2081 } 2082 } 2083 2084 protected String getAuthenticationHandle(Document document) 2085 throws AuthLoginException { 2086 Node responseNode = XMLUtils.getRootNode( 2087 document, AuthXMLTags.RESPONSE); 2088 if (responseNode == null) { 2089 throw new AuthLoginException(amAuthContext, "responseError", null); 2090 } 2091 2092 String authID = XMLUtils.getNodeAttributeValue( 2093 responseNode, AuthXMLTags.AUTH_ID_HANDLE); 2094 return (authID); 2095 } 2096 2097 protected static Callback[] getCallbacks( 2098 Document document, 2099 boolean noFilter) { 2100 return (AuthXMLUtils.getCallbacks(XMLUtils.getRootNode(document, 2101 AuthXMLTags.CALLBACKS), noFilter)); 2102 } 2103 2104 protected static Subject getSubject(Document document) { 2105 Node loginStatusNode = XMLUtils.getRootNode(document, 2106 AuthXMLTags.LOGIN_STATUS); 2107 2108 if (loginStatusNode == null) { 2109 return (null); 2110 } 2111 2112 Node subjectNode = XMLUtils.getChildNode(loginStatusNode, 2113 AuthXMLTags.SUBJECT); 2114 2115 if (subjectNode == null) { 2116 return (null); 2117 } 2118 2119 String subject = XMLUtils.getValueOfValueNode(subjectNode); 2120 try { 2121 Subject sSubject = AuthXMLUtils.getDeSerializedSubject(subject); 2122 2123 if (authDebug.messageEnabled()) { 2124 authDebug.message("Deserialized subject : " 2125 + sSubject.toString()); 2126 } 2127 return sSubject; 2128 } catch (Exception e) { 2129 authDebug.message("get Deserialized subject error : " , e); 2130 return null; 2131 } 2132 2133 } 2134 2135 protected static String getXMLforSubject(Subject subject) { 2136 if (subject == null) { 2137 return (""); 2138 } 2139 StringBuilder request = new StringBuilder(100); 2140 request.append(AuthXMLTags.SUBJECT_BEGIN); 2141 String serializeSubject = AuthXMLUtils.getSerializedSubject(subject); 2142 request.append(serializeSubject); 2143 request.append(AuthXMLTags.SUBJECT_END); 2144 return (request.toString()); 2145 } 2146 2147 /** 2148 * Returns the account lockout message. This can be either a dynamic 2149 * message indicating the number of tries left or the the account 2150 * deactivated message. 2151 * 2152 * @return account lockout message. 2153 */ 2154 public String getLockoutMsg() { 2155 String lockoutMsg = null; 2156 if (localFlag) { 2157 lockoutMsg = acLocal.getLockoutMsg(); 2158 } else { 2159 // Account Lockout Warning Check by scanning the error 2160 // message in the exception thrown by the server 2161 lockoutMsg = getErrorMessage(); 2162 if((lockoutMsg == null) || 2163 (lockoutMsg.indexOf("Account lockout") == -1)){ 2164 lockoutMsg = ""; 2165 } 2166 } 2167 return lockoutMsg; 2168 } 2169 2170 /** 2171 * Returns <code>true</code> if account is lock out. 2172 * 2173 * @return <code>true</code> if account is lock out. 2174 */ 2175 public boolean isLockedOut() { 2176 boolean isLockedOut = false; 2177 if (localFlag) { 2178 isLockedOut = acLocal.isLockedOut(); 2179 } else { 2180 // TBD 2181 } 2182 2183 return isLockedOut; 2184 } 2185 2186 /** 2187 * The class <code>Status</code> defines the possible 2188 * authentication states during the login process. 2189 * 2190 * @supported.all.api 2191 */ 2192 public static class Status extends Object { 2193 2194 private String status; 2195 2196 /** 2197 * The <code>NOT_STARTED</code> status indicates that the login process 2198 * has not yet started. Basically, it means that the method 2199 * <code>login</code> has not been called. 2200 */ 2201 public static final Status NOT_STARTED = new Status("not_started"); 2202 2203 /** 2204 * The <code>IN_PROGRESS</code> status indicates that the login process 2205 * is in progress. Basically, it means that the <code>login</code> 2206 * method has been called and that this object is waiting for the user 2207 * to send authentication information. 2208 */ 2209 public static final Status IN_PROGRESS = new Status("in_progress"); 2210 2211 /** 2212 * 2213 * The <code>SUCCESS</code> indicates that the login process has 2214 * succeeded. 2215 */ 2216 public static final Status SUCCESS = new Status("success"); 2217 2218 /** 2219 * The <code>FAILED</code> indicates that the login process has failed. 2220 */ 2221 public static final Status FAILED = new Status("failed"); 2222 2223 /** 2224 * 2225 * The <code>COMPLETED</code> indicates that the user has been 2226 * successfully logged out. 2227 */ 2228 public static final Status COMPLETED = new Status("completed"); 2229 2230 /** 2231 * The <code>RESET</code> indicates that the login process has been 2232 * reset or re-initialized. 2233 */ 2234 public static final Status RESET = new Status("reset"); 2235 2236 /** 2237 * The <code>ORG_MISMATCH</code> indicates that the framework 2238 * <code>org</code> and the <code>org</code> required by the user do 2239 * not match. 2240 */ 2241 public static final Status ORG_MISMATCH = new Status("org_mismatch"); 2242 2243 2244 private Status() { 2245 // do nothing 2246 } 2247 2248 private Status(String s) { 2249 status = s; 2250 } 2251 2252 /** 2253 * Returns the string representation of the authentication status. 2254 * 2255 * @return String representation of authentication status. 2256 */ 2257 public String toString() { 2258 return (status); 2259 } 2260 2261 /** 2262 * Checks if two authentication status objects are equal. 2263 * 2264 * @param authStatus Reference object with which to compare. 2265 * @return <code>true</code> if the objects are same. 2266 */ 2267 public boolean equals(Object authStatus) { 2268 if (authStatus instanceof Status) { 2269 Status s = (Status) authStatus; 2270 return (s.status.equalsIgnoreCase(status)); 2271 } 2272 return (false); 2273 } 2274 } 2275 2276 /** 2277 * The class <code>IndexType</code> defines the possible kinds of "objects" 2278 * or "resources" for which an authentication can be performed. 2279 * 2280 * @supported.all.api 2281 */ 2282 public static class IndexType extends Object { 2283 2284 private String index; 2285 2286 /** 2287 * The <code>USER</code> index type indicates that the index name given 2288 * corresponds to a user. 2289 */ 2290 public static final IndexType USER = new IndexType("user"); 2291 2292 /** 2293 * The <code>ROLE</code> index type indicates that the index name given 2294 * corresponds to a role. 2295 */ 2296 public static final IndexType ROLE = new IndexType("role"); 2297 2298 /** 2299 * 2300 * The <code>SERVICE</code> index type indicates that the index name 2301 * given corresponds to a service (or application). 2302 */ 2303 public static final IndexType SERVICE = new IndexType("service"); 2304 2305 /** 2306 * The <code>LEVEL</code> index type indicates that the index name 2307 * given corresponds to a given authentication level. 2308 */ 2309 public static final IndexType LEVEL = new IndexType("level"); 2310 2311 /** 2312 * The <code>MODULE_INSTANCE</code> index type indicates that the index 2313 * name given corresponds to one of the authentication modules. 2314 */ 2315 public static final IndexType MODULE_INSTANCE = 2316 new IndexType("module_instance"); 2317 2318 /** 2319 * The <code>RESOURCE</code> index type indicates that the index 2320 * name given corresponds to a given policy protected resource URL. 2321 */ 2322 public static final IndexType RESOURCE = 2323 new IndexType("resource"); 2324 2325 /** 2326 * The <code>COMPOSITE_ADVICE</code> index type indicates that the 2327 * index name given corresponds to string in the form of XML 2328 * representing different Policy Authentication conditions, example 2329 * <code>AuthSchemeCondition</code>, <code>AuthLevelCondition</code>, 2330 * etc. 2331 */ 2332 public static final IndexType COMPOSITE_ADVICE = 2333 new IndexType("composite_advice"); 2334 2335 private IndexType() { 2336 // do nothing 2337 } 2338 2339 private IndexType(String s) { 2340 index = s; 2341 } 2342 2343 /** 2344 * Returns the string representation of the index type. 2345 * 2346 * @return String representation of index type. 2347 */ 2348 public String toString() { 2349 return (index); 2350 } 2351 2352 /** 2353 * Checks if two index type objects are equal. 2354 * 2355 * @param indexType Reference object with which to compare. 2356 * 2357 * @return <code>true</code> if the objects are same. 2358 */ 2359 public boolean equals(Object indexType) { 2360 if (indexType instanceof IndexType) { 2361 IndexType s = (IndexType) indexType; 2362 return (s.index.equalsIgnoreCase(index)); 2363 } 2364 return (false); 2365 } 2366 } 2367 2368 private String getAuthHandle() { 2369 String handle = null; 2370 2371 if (receivedDocument != null) { 2372 try { 2373 handle = getAuthenticationHandle(receivedDocument); 2374 } catch (Exception e) { 2375 // do nothing 2376 } 2377 } 2378 if ( handle == null ) { 2379 handle = "0"; 2380 } 2381 return handle; 2382 } 2383 2384 private static URL getAuthServiceURL( 2385 String protocol, 2386 String host, 2387 String port, 2388 String uri 2389 ) { 2390 URL authservice = null; 2391 try { 2392 authservice = WebtopNaming.getServiceURL(AuthXMLTags.AUTH_SERVICE, 2393 protocol, host, port, uri); 2394 } catch (Exception e) { 2395 authDebug.error("Failed to obtain auth service url from server: " + 2396 protocol + "://" + host + ":" + port); 2397 } 2398 return authservice; 2399 } 2400 2401 private void onSuccessLocal() { 2402 if (localSessionChecked) { 2403 return; 2404 } 2405 SSOToken currToken = acLocal.getSSOToken(); 2406 com.iplanet.dpro.session.service.InternalSession oldSess 2407 = acLocal.getLoginState().getOldSession(); 2408 if (oldSess != null) { 2409 if (forceAuth) { 2410 try { 2411 SSOTokenManager.getInstance(). 2412 destroyToken(currToken); 2413 } catch (SSOException ssoExp) { 2414 authDebug.error("AuthContext.onSuccessLocal: ", 2415 ssoExp); 2416 2417 } 2418 acLocal.getLoginState().setSession(oldSess); 2419 acLocal.getLoginState().setSid(oldSess 2420 .getID()); 2421 acLocal.getLoginState().setForceAuth(false); 2422 ssoToken = acLocal.getSSOToken(); 2423 ssoTokenID = ssoToken.getTokenID().toString(); 2424 2425 } else { 2426 com.iplanet.dpro.session.service.SessionService. 2427 getSessionService().destroyInternalSession 2428 (oldSess.getID()); 2429 } 2430 } 2431 localSessionChecked = true; 2432 } 2433 2434 /** 2435 * Returns the application sso token. Can perform a check to ensure that 2436 * the app token is still valid (requires a session refresh call to OpenAM) 2437 * 2438 * @param refresh true if we should check with OpenAM if the app token is valid 2439 * @return a valid application's sso token. 2440 */ 2441 private SSOToken getAppSSOToken(boolean refresh) { 2442 SSOToken appToken = null; 2443 2444 try { 2445 appToken = (SSOToken) AccessController.doPrivileged( 2446 AdminTokenAction.getInstance()); 2447 } catch (AMSecurityPropertiesException aspe) { 2448 if (authDebug.messageEnabled()) { 2449 authDebug.message("AuthContext::getAppSSOToken: " + 2450 "unable to get app ssotoken " + aspe.getMessage()); 2451 } 2452 } 2453 2454 if (refresh) { 2455 // ensure the token is valid 2456 try { 2457 SSOTokenManager ssoTokenManager = SSOTokenManager.getInstance(); 2458 ssoTokenManager.refreshSession(appToken); 2459 2460 if (!ssoTokenManager.isValidToken(appToken)) { 2461 if (authDebug.messageEnabled()) { 2462 authDebug.message("AuthContext.getAppSSOToken(): " + 2463 "App SSOToken is invalid, retrying"); 2464 } 2465 2466 try { 2467 appToken = (SSOToken) AccessController.doPrivileged( 2468 AdminTokenAction.getInstance()); 2469 } catch (AMSecurityPropertiesException aspe) { 2470 if (authDebug.messageEnabled()) { 2471 authDebug.message("AuthContext::getAppSSOToken: " + 2472 "unable to get app ssotoken " + aspe.getMessage()); 2473 } 2474 } 2475 } 2476 } catch (SSOException ssoe) { 2477 if (authDebug.messageEnabled()) { 2478 authDebug.message("AuthContext.getAppSSOToken(): " + 2479 "unable to refresh app token: " + ssoe.getL10NMessage()); 2480 } 2481 2482 try { 2483 appToken = (SSOToken) AccessController.doPrivileged( 2484 AdminTokenAction.getInstance()); 2485 } catch (AMSecurityPropertiesException aspe) { 2486 if (authDebug.errorEnabled()) { 2487 authDebug.error("AuthContext::getAppSSOToken: " + 2488 "unable to get app ssotoken " + aspe.getMessage()); 2489 } 2490 } 2491 } 2492 } 2493 2494 if (authDebug.messageEnabled()) { 2495 if (appToken == null) { 2496 authDebug.message("Null App SSO Token"); 2497 } else { 2498 authDebug.message("Obtained App Token= " + appToken.getTokenID().toString()); 2499 } 2500 } 2501 2502 return appToken; 2503 } 2504 2505 public AuthContextLocal getAuthContextLocal() { 2506 return acLocal; 2507 } 2508}