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-2014 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, String[] params, boolean pCookie, Map envMap, 844 String locale, HttpServletRequest req, HttpServletResponse res) throws AuthLoginException { 845 try { 846 String xmlString; 847 // remote auth 848 StringBuilder request = new StringBuilder(100); 849 String authHandle = getAuthHandle(); 850 if (ssoTokenID != null && "0".equals(authHandle)) { 851 if (authDebug.messageEnabled()) { 852 authDebug.message("AuthContext.runRemoteLogin: Found SSOTokenID " + ssoTokenID); 853 } 854 authHandle = ssoTokenID; 855 } 856 857 request.append(MessageFormat.format(AuthXMLTags.XML_REQUEST_PREFIX, authHandle)); 858 if (appSSOToken != null) { 859 request.append(AuthXMLTags.APPSSOTOKEN_BEGIN); 860 request.append(appSSOToken.getTokenID().toString()); 861 request.append(AuthXMLTags.APPSSOTOKEN_END); 862 } 863 request.append(AuthXMLTags.LOGIN_BEGIN); 864 865 if (!useOldStyleRemoteAuthentication) { 866 request.append(AuthXMLTags.SPACE) 867 .append(AuthXMLTags.ORG_NAME_ATTR) 868 .append(AuthXMLTags.EQUAL) 869 .append(AuthXMLTags.QUOTE) 870 .append(XMLUtils.escapeSpecialCharacters(organizationName)) 871 .append(AuthXMLTags.QUOTE); 872 if (hostName != null) { 873 request.append(AuthXMLTags.SPACE) 874 .append(AuthXMLTags.HOST_NAME_ATTR) 875 .append(AuthXMLTags.EQUAL) 876 .append(AuthXMLTags.QUOTE) 877 .append(XMLUtils.escapeSpecialCharacters(hostName)) 878 .append(AuthXMLTags.QUOTE); 879 } 880 if (locale != null && !locale.isEmpty()) { 881 request.append(AuthXMLTags.SPACE) 882 .append(AuthXMLTags.LOCALE) 883 .append(AuthXMLTags.EQUAL) 884 .append(AuthXMLTags.QUOTE) 885 .append(XMLUtils.escapeSpecialCharacters(locale)) 886 .append(AuthXMLTags.QUOTE); 887 } 888 if (forceAuth) { 889 request.append(AuthXMLTags.SPACE) 890 .append(AuthXMLTags.FORCE_AUTH_ATTR) 891 .append(AuthXMLTags.EQUAL) 892 .append(AuthXMLTags.QUOTE) 893 .append("true") 894 .append(AuthXMLTags.QUOTE); 895 } 896 } 897 request.append(AuthXMLTags.ELEMENT_END); 898 899 if (indexType != null) { 900 request.append(AuthXMLTags.INDEX_TYPE_PAIR_BEGIN) 901 .append(AuthXMLTags.SPACE) 902 .append(AuthXMLTags.INDEX_TYPE) 903 .append(AuthXMLTags.EQUAL) 904 .append(AuthXMLTags.QUOTE); 905 906 if (indexType == IndexType.USER) { 907 request.append(AuthXMLTags.INDEX_TYPE_USER_ATTR); 908 } else if (indexType == IndexType.ROLE) { 909 request.append(AuthXMLTags.INDEX_TYPE_ROLE_ATTR); 910 } else if (indexType == IndexType.SERVICE) { 911 request.append(AuthXMLTags.INDEX_TYPE_SVC_ATTR); 912 } else if (indexType == IndexType.MODULE_INSTANCE) { 913 request.append(AuthXMLTags.INDEX_TYPE_MODULE_ATTR); 914 } else if (indexType == IndexType.LEVEL) { 915 request.append(AuthXMLTags.INDEX_TYPE_LEVEL_ATTR); 916 } else if (indexType == IndexType.COMPOSITE_ADVICE) { 917 request.append(AuthXMLTags.INDEX_TYPE_COMPOSITE_ADVICE_ATTR); 918 } else if (indexType == IndexType.RESOURCE) { 919 request.append(AuthXMLTags.INDEX_TYPE_RESOURCE); 920 } 921 request.append(AuthXMLTags.QUOTE) 922 .append(AuthXMLTags.ELEMENT_END) 923 .append(AuthXMLTags.INDEX_NAME_BEGIN) 924 .append(XMLUtils.escapeSpecialCharacters(indexName)) 925 .append(AuthXMLTags.INDEX_NAME_END) 926 .append(AuthXMLTags.INDEX_TYPE_PAIR_END); 927 } 928 929 if (locale != null && locale.length() > 0) { 930 request.append(AuthXMLTags.LOCALE_BEGIN); 931 request.append(XMLUtils.escapeSpecialCharacters(locale)); 932 request.append(AuthXMLTags.LOCALE_END); 933 } 934 935 if (params != null) { 936 StringBuilder paramString = new StringBuilder(); 937 for (int i = 0; i < params.length; i++) { 938 if (i != 0 ) { 939 paramString.append(ISAuthConstants.PIPE_SEPARATOR); 940 } 941 paramString.append(XMLUtils.escapeSpecialCharacters(params[i])); 942 } 943 request.append(AuthXMLTags.PARAMS_BEGIN) 944 .append(paramString.toString()) 945 .append(AuthXMLTags.PARAMS_END); 946 } 947 if (envMap != null && !envMap.isEmpty()) { 948 StringBuilder envString = new StringBuilder(); 949 for (Map.Entry<String, Set<String>> entry : ((Map<String, Set<String>>) envMap).entrySet()) { 950 // convert Map to XMLString as follows: 951 // <EnvValue>keyname|value1|value2|...</EnvValue> 952 String keyName = entry.getKey(); 953 Set<String> values = entry.getValue(); 954 if (values != null && !values.isEmpty()) { 955 envString.append(AuthXMLTags.ENV_AV_BEGIN) 956 .append(AuthClientUtils.escapePipe(XMLUtils.escapeSpecialCharacters(keyName))); 957 for (String value : values) { 958 envString.append(ISAuthConstants.PIPE_SEPARATOR) 959 .append(AuthClientUtils.escapePipe(XMLUtils.escapeSpecialCharacters(value))); 960 } 961 envString.append(AuthXMLTags.ENV_AV_END); 962 } 963 } 964 request.append(AuthXMLTags.ENV_BEGIN) 965 .append(envString.toString()) 966 .append(AuthXMLTags.ENV_END); 967 } 968 request.append(AuthXMLTags.LOGIN_END); 969 970 if (includeReqRes) { 971 request.append(AuthXMLTags.REMOTE_REQUEST_RESPONSE_START) 972 .append(AuthXMLTags.HTTP_SERVLET_REQUEST_START); 973 String encObj = ""; 974 975 if (req != null) { 976 try { 977 encObj = AuthXMLUtils.serializeToString(new RemoteHttpServletRequest(req)); 978 } catch (IOException ioe) { 979 authDebug.error("AuthXMLUtils::runRemoteLogin Unable to serailize http request", ioe); 980 } 981 982 if (authDebug.messageEnabled()) { 983 authDebug.message("req=" + new RemoteHttpServletRequest(req).toString()); 984 } 985 986 request.append(encObj); 987 } 988 989 request.append(AuthXMLTags.HTTP_SERVLET_REQUEST_END); 990 request.append(AuthXMLTags.HTTP_SERVLET_RESPONSE_START); 991 992 if (res != null) { 993 encObj = ""; 994 995 try { 996 encObj = AuthXMLUtils.serializeToString(new RemoteHttpServletResponse(res)); 997 } catch (IOException ioe) { 998 authDebug.error("AuthXMLUtils::runRemoteLogin Unable to serailize http response", ioe); 999 } 1000 1001 if (authDebug.messageEnabled()) { 1002 authDebug.message("res=" + res); 1003 } 1004 1005 request.append(encObj); 1006 } 1007 1008 request.append(AuthXMLTags.HTTP_SERVLET_RESPONSE_END) 1009 .append(AuthXMLTags.REMOTE_REQUEST_RESPONSE_END); 1010 } else { 1011 if (authDebug.messageEnabled()) { 1012 authDebug.message("Not including req/res " + includeReqRes); 1013 } 1014 } 1015 1016 request.append(AuthXMLTags.XML_REQUEST_SUFFIX); 1017 xmlString = request.toString(); 1018 1019 // process the request, which will check for exceptions 1020 // and also get the authentication handle ID 1021 receivedDocument = processRequest(xmlString); 1022 1023 // Check set the login status 1024 checkAndSetLoginStatus(); 1025 1026 // if the app token was refreshed, retry remote login 1027 if (loginException != null && 1028 loginException.getErrorCode().equals(AMAuthErrorCode.REMOTE_AUTH_INVALID_SSO_TOKEN) && 1029 retryRunLogin > 0) { 1030 retryRunLogin--; 1031 1032 if (authDebug.messageEnabled()) { 1033 authDebug.message("Run remote login failed due to expired app token, retying"); 1034 } 1035 1036 // reset as we are starting again 1037 loginStatus = Status.IN_PROGRESS; 1038 runRemoteLogin(indexType, indexName, params, pCookie, envMap, locale, req, res); 1039 } 1040 } catch (AuthLoginException le) { 1041 // Login has failed 1042 loginStatus = Status.FAILED; 1043 loginException = le; 1044 } 1045 } 1046 1047 private void runRemoteOldAuthContext() throws AuthLoginException { 1048 try { 1049 StringBuilder request = new StringBuilder(100); 1050 String[] objs = { "0" }; 1051 if (ssoTokenID != null) { 1052 objs[0] = ssoTokenID; 1053 } 1054 request.append(MessageFormat.format( 1055 AuthXMLTags.XML_REQUEST_PREFIX, (Object[])objs)) 1056 .append(AuthXMLTags.NEW_AUTHCONTEXT_BEGIN) 1057 .append(AuthXMLTags.SPACE) 1058 .append(AuthXMLTags.ORG_NAME_ATTR) 1059 .append(AuthXMLTags.EQUAL) 1060 .append(AuthXMLTags.QUOTE) 1061 .append(XMLUtils.escapeSpecialCharacters(organizationName)) 1062 .append(AuthXMLTags.QUOTE) 1063 .append(AuthXMLTags.ELEMENT_END) 1064 .append(AuthXMLTags.NEW_AUTHCONTEXT_END) 1065 .append(AuthXMLTags.XML_REQUEST_SUFFIX); 1066 // process the request, which will check for exceptions 1067 // and also get the authentication handle ID 1068 receivedDocument = processRequest(request.toString()); 1069 1070 // Check set the login status 1071 checkAndSetLoginStatus(); 1072 } catch (AuthLoginException le) { 1073 // Login has failed 1074 loginStatus = Status.FAILED; 1075 loginException = le; 1076 } 1077 } 1078 1079 /** 1080 * Returns the set of Principals or Subject the user has been 1081 * authenticated as. 1082 * This should be invoked only after successful authentication. 1083 * 1084 * @return <code>Subject</code> for the authenticated User. 1085 * If the authentication fails or the authentication is in process, 1086 * this will return <code>null</code>. 1087 * 1088 * @supported.api 1089 */ 1090 public Subject getSubject() { 1091 if (localFlag) { 1092 if (!acLocal.getStatus().equals(Status.SUCCESS)) { 1093 return (null); 1094 } 1095 return (acLocal.getSubject()); 1096 } else { 1097 if (!loginStatus.equals(Status.SUCCESS)) { 1098 return (null); 1099 } 1100 return (getSubject(receivedDocument)); 1101 } 1102 } 1103 1104 /** 1105 * Returns a <code>Map</code> object that 1106 * that contains cookies set by AM server 1107 * 1108 * @return a <code>Map</code> of cookie name and 1109 * <code>Cookie</code> object. 1110 */ 1111 public Map getCookieTable() { 1112 return cookieTable; 1113 } 1114 1115 /** 1116 * Returns <code>true</code> if the login process requires more 1117 * information from the user to complete the authentication. 1118 * <p> 1119 * NOTE: This method has to be called as a condition of a 1120 * <code>while</code> loop in order to complete the authentication process 1121 * and get the correct <code>Status</code> after submitting the 1122 * requirements. 1123 * 1124 * @return <code>true</code> if more credentials are required from the user. 1125 * 1126 * @supported.api 1127 */ 1128 public boolean hasMoreRequirements() { 1129 if (localFlag) { 1130 return (acLocal.hasMoreRequirements(false)); 1131 } else { 1132 if ((!loginStatus.equals(Status.IN_PROGRESS)) || 1133 ((getCallbacks(receivedDocument, false)) == null)) { 1134 return (false); 1135 } 1136 return (true); 1137 } 1138 } 1139 1140 /** 1141 * Returns <code>true</code> if the login process requires more information 1142 * from the user to complete the authentication. 1143 * 1144 * NOTE: This method has to be called as a condition of a <ode>while</code> 1145 * loop in order to complete the authentication process and get the correct 1146 * <code>Status</code> after submitting the requirements. 1147 * 1148 * @param noFilter flag indicates whether to filter 1149 * <code>PagePropertiesCallback</code> or not. Value 1150 * <code>true</code> will not filter 1151 * <code>PagePropertiesCallback</code>. 1152 * @return <code>true</code> if more credentials are required from the user. 1153 * 1154 * @supported.api 1155 */ 1156 public boolean hasMoreRequirements(boolean noFilter) { 1157 if (localFlag) { 1158 return (acLocal.hasMoreRequirements(noFilter)); 1159 } else { 1160 if ((!loginStatus.equals(Status.IN_PROGRESS)) || 1161 ((getCallbacks(receivedDocument, noFilter)) == null)) { 1162 return (false); 1163 } 1164 return (true); 1165 } 1166 } 1167 1168 /** 1169 * Returns an array of <code>Callback</code> objects that must be populated 1170 * by the user and returned back. These objects are requested by the 1171 * authentication plug-ins, and these are usually displayed to the user. 1172 * The user then provides the requested information for it to be 1173 * authenticated. 1174 * 1175 * @return an array of <code>Callback</code> objects requesting credentials 1176 * from user 1177 * 1178 * @supported.api 1179 */ 1180 public Callback[] getRequirements() { 1181 if (localFlag) { 1182 if (!acLocal.getStatus().equals(Status.IN_PROGRESS)) { 1183 return (null); 1184 } 1185 return (acLocal.getRequirements(false)); 1186 } else { 1187 if (!loginStatus.equals(Status.IN_PROGRESS)) { 1188 return (null); 1189 } 1190 return (getCallbacks(receivedDocument, false)); 1191 } 1192 } 1193 1194 /** 1195 * Returns an array of <code>Callback</code> objects that 1196 * must be populated by the user and returned back. 1197 * These objects are requested by the authentication plug-ins, 1198 * and these are usually displayed to the user. The user then provides 1199 * the requested information for it to be authenticated. 1200 * 1201 * @param noFilter boolean flag indicating whether to filter 1202 * <code>PagePropertiesCallback</code> or not. Value <code>true</code> will 1203 * not filter <code>PagePropertiesCallback</code>. 1204 * 1205 * @return an array of <code>Callback</code> objects requesting credentials 1206 * from user 1207 * 1208 * @supported.api 1209 */ 1210 public Callback[] getRequirements(boolean noFilter) { 1211 if (localFlag) { 1212 if (!acLocal.getStatus().equals(Status.IN_PROGRESS)) { 1213 return (null); 1214 } 1215 return (acLocal.getRequirements(noFilter)); 1216 } else { 1217 if (!loginStatus.equals(Status.IN_PROGRESS)) { 1218 return (null); 1219 } 1220 return (getCallbacks(receivedDocument, noFilter)); 1221 } 1222 } 1223 1224 /** 1225 * Fetches the remote request from the context 1226 * 1227 * @return The Http Servlet Request 1228 */ 1229 public HttpServletRequest getRemoteRequest() { 1230 return remoteRequest; 1231 } 1232 1233 /** 1234 * Fetches the remote response from the context 1235 * 1236 * @return The Http Servlet Response 1237 */ 1238 public HttpServletResponse getRemoteResponse() { 1239 return remoteResponse; 1240 } 1241 1242 /** 1243 * Submits the populated <code>Callback</code> objects to the 1244 * authentication plug-in modules. Called after <code>getRequirements</code> 1245 * method and obtaining user's response to these requests. 1246 * 1247 * @param info Array of <code>Callback</code> objects. 1248 * 1249 * @supported.api 1250 */ 1251 public void submitRequirements(Callback[] info) { 1252 submitRequirements(info, null, null); 1253 } 1254 1255 public void submitRequirements(Callback[] info, HttpServletRequest request, 1256 HttpServletResponse response) { 1257 if (authDebug.messageEnabled()) { 1258 authDebug.message("submitRequirements with Callbacks : " + info); 1259 } 1260 1261 if (localFlag) { 1262 // Check if we are still in login session 1263 if (!acLocal.getStatus().equals(Status.IN_PROGRESS)) { 1264 return; 1265 } 1266 acLocal.submitRequirements(info); 1267 if (acLocal.getStatus().equals(Status.SUCCESS)) { 1268 onSuccessLocal(); 1269 } 1270 return; 1271 } else { 1272 // Check if we are still in login session 1273 if (!loginStatus.equals(Status.IN_PROGRESS)) { 1274 return; 1275 } 1276 1277 // Construct the XML 1278 try { 1279 StringBuilder xml = new StringBuilder(100); 1280 String[] authHandles = new String[1]; 1281 authHandles[0] = getAuthenticationHandle(receivedDocument); 1282 xml.append(MessageFormat.format( 1283 AuthXMLTags.XML_REQUEST_PREFIX,(Object[])authHandles)); 1284 if (appSSOToken != null) { 1285 xml.append(AuthXMLTags.APPSSOTOKEN_BEGIN); 1286 xml.append(appSSOToken.getTokenID().toString()). 1287 append(AuthXMLTags.APPSSOTOKEN_END); 1288 } 1289 xml.append(AuthXMLTags.SUBMIT_REQS_BEGIN) 1290 .append(AuthXMLUtils.getXMLForCallbacks(info)); 1291 1292 if (clientLocale != null) { 1293 String localeStr = clientLocale.toString(); 1294 if ((localeStr != null) && (localeStr.length() > 0)) { 1295 xml.append(AuthXMLTags.LOCALE_BEGIN) 1296 .append(XMLUtils.escapeSpecialCharacters(localeStr)) 1297 .append(AuthXMLTags.LOCALE_END); 1298 } 1299 } 1300 1301 xml.append(AuthXMLTags.SUBMIT_REQS_END); 1302 1303 if (includeReqRes) { 1304 // serialized request and response objects 1305 xml.append(AuthXMLTags.REMOTE_REQUEST_RESPONSE_START) 1306 .append(AuthXMLTags.HTTP_SERVLET_REQUEST_START); 1307 String encObj = ""; 1308 1309 if (request != null) { 1310 try { 1311 encObj = AuthXMLUtils.serializeToString(new RemoteHttpServletRequest(request)); 1312 } catch (IOException ioe) { 1313 authDebug.error("AuthXMLUtils::runRemoteLogin Unable to serailize http request", ioe); 1314 } 1315 1316 if (authDebug.messageEnabled()) { 1317 authDebug.message("req=" + request); 1318 } 1319 1320 xml.append(encObj); 1321 } 1322 1323 xml.append(AuthXMLTags.HTTP_SERVLET_REQUEST_END); 1324 xml.append(AuthXMLTags.HTTP_SERVLET_RESPONSE_START); 1325 1326 if (response != null) { 1327 encObj = ""; 1328 1329 try { 1330 encObj = AuthXMLUtils.serializeToString(new RemoteHttpServletResponse(response)); 1331 } catch (IOException ioe) { 1332 authDebug.error("AuthXMLUtils::runRemoteLogin Unable to serailize http response", ioe); 1333 } 1334 1335 if (authDebug.messageEnabled()) { 1336 authDebug.message("res=" + response); 1337 } 1338 1339 xml.append(encObj); 1340 } 1341 1342 xml.append(AuthXMLTags.HTTP_SERVLET_RESPONSE_END) 1343 .append(AuthXMLTags.REMOTE_REQUEST_RESPONSE_END); 1344 } 1345 xml.append(AuthXMLTags.XML_REQUEST_SUFFIX); 1346 1347 // Send the request to be processes 1348 receivedDocument = processRequest(xml.toString()); 1349 1350 // Check set the login status 1351 checkAndSetLoginStatus(); 1352 } catch (AuthLoginException le) { 1353 // Login has failed 1354 loginStatus = Status.FAILED; 1355 loginException = le; 1356 } 1357 } 1358 } 1359 1360 /** 1361 * Logs out the user and also invalidates the single sign on token 1362 * associated with this <code>AuthContext</code>. 1363 * 1364 * @throws AuthLoginException if an error occurred during logout. 1365 * 1366 * @supported.api 1367 */ 1368 public void logout() throws AuthLoginException { 1369 if (localFlag) { 1370 acLocal.logout(); 1371 return; 1372 } 1373 1374 // Construct the XML 1375 try { 1376 StringBuilder xml = new StringBuilder(100); 1377 String[] authHandles = new String[1]; 1378 authHandles[0] = getAuthenticationHandle(receivedDocument); 1379 xml.append(MessageFormat.format(AuthXMLTags.XML_REQUEST_PREFIX, 1380 (Object[])authHandles)); 1381 if (appSSOToken != null) { 1382 xml.append(AuthXMLTags.APPSSOTOKEN_BEGIN); 1383 xml.append(appSSOToken.getTokenID().toString()). 1384 append(AuthXMLTags.APPSSOTOKEN_END); 1385 } 1386 xml.append(AuthXMLTags.LOGOUT_BEGIN) 1387 .append(AuthXMLTags.LOGOUT_END) 1388 .append(AuthXMLTags.XML_REQUEST_SUFFIX); 1389 1390 // Send the request to be processes 1391 receivedDocument = processRequest(xml.toString()); 1392 1393 // Check set the login status 1394 checkAndSetLoginStatus(); 1395 } catch (AuthLoginException le) { 1396 // Login has failed 1397 loginStatus = Status.FAILED; 1398 loginException = le; 1399 } 1400 } 1401 1402 /** 1403 * Logs out the user and also invalidates the single sign on token 1404 * associated with this <code>AuthContext</code>. 1405 * 1406 * This method causes the logout to happen on the server and the 1407 * correct SPI hooks to be called. 1408 * 1409 * @throws AuthLoginException if an error occurred during logout. 1410 * 1411 * @supported.api 1412 */ 1413 public void logoutUsingTokenID() 1414 throws AuthLoginException { 1415 if (localFlag) { 1416 return; 1417 } 1418 1419 if (ssoToken != null) { 1420 try { 1421 organizationName = ssoToken.getProperty( 1422 ISAuthConstants.ORGANIZATION); 1423 ssoTokenID = ssoToken.getTokenID().toString(); 1424 authURL = Session.getSession( 1425 new SessionID(ssoTokenID)).getSessionServiceURL(); 1426 } catch (Exception e) { 1427 throw new AuthLoginException(e); 1428 } 1429 } 1430 1431 if (authURL != null) { 1432 authServiceURL = getAuthServiceURL(authURL.getProtocol(), 1433 authURL.getHost(), Integer.toString(authURL.getPort()), 1434 authURL.getPath()); 1435 } 1436 1437 1438 // Construct the XML 1439 try { 1440 StringBuilder xml = new StringBuilder(100); 1441 String[] authHandles = new String[1]; 1442 authHandles[0] = ssoToken.getTokenID().toString(); 1443 xml.append(MessageFormat.format(AuthXMLTags.XML_REQUEST_PREFIX, 1444 (Object[]) authHandles)); 1445 if (appSSOToken != null) { 1446 xml.append(AuthXMLTags.APPSSOTOKEN_BEGIN); 1447 xml.append(appSSOToken.getTokenID().toString()). 1448 append(AuthXMLTags.APPSSOTOKEN_END); 1449 } 1450 xml.append(AuthXMLTags.LOGOUT_BEGIN) 1451 .append(AuthXMLTags.LOGOUT_END) 1452 .append(AuthXMLTags.XML_REQUEST_SUFFIX); 1453 1454 // Send the request to be processes 1455 receivedDocument = processRequest(xml.toString()); 1456 1457 // Check set the login status 1458 checkAndSetLoginStatus(); 1459 } catch (AuthLoginException le) { 1460 // Login has failed 1461 loginStatus = Status.FAILED; 1462 loginException = le; 1463 } 1464 } 1465 1466 /** 1467 * Returns login exception, if any, during the authentication process. 1468 * Typically set when the login fails. 1469 * 1470 * @return login exception. 1471 * @supported.api 1472 */ 1473 public AuthLoginException getLoginException() { 1474 if (localFlag) { 1475 return (acLocal.getLoginException()); 1476 } else { 1477 return (loginException); 1478 } 1479 } 1480 1481 /** 1482 * Returns the Single-Sign-On (SSO) Token for the authenticated 1483 * user. If the user has not successfully authenticated 1484 * <code>Exception</code> will be thrown. 1485 * <p> 1486 * Single sign token can be used as the authenticated token. 1487 * 1488 * @return Single-Sign-On token for the valid user after successful 1489 * authentication. 1490 * @throws L10NMessageImpl if the user is not authenticated or an error is 1491 * encountered in retrieving the user's single sign on token. 1492 * @supported.api 1493 */ 1494 public SSOToken getSSOToken() throws L10NMessageImpl { 1495 if (localFlag) { 1496 if (!acLocal.getStatus().equals(Status.SUCCESS)) { 1497 throw new L10NMessageImpl( 1498 amAuthContext, "statusNotSuccess", null); 1499 } 1500 return (acLocal.getSSOToken()); 1501 } else { 1502 // Get the loginStatus node 1503 if (!loginStatus.equals(Status.SUCCESS)) { 1504 throw new L10NMessageImpl( 1505 amAuthContext, "statusNotSuccess", null); 1506 } 1507 Node loginStatusNode = XMLUtils.getRootNode(receivedDocument, 1508 AuthXMLTags.LOGIN_STATUS); 1509 if (loginStatusNode == null) { 1510 throw new L10NMessageImpl(amAuthContext, "noStatusNode", null); 1511 } 1512 1513 String ssoTokenIDTmp = XMLUtils.getNodeAttributeValue(loginStatusNode, 1514 AuthXMLTags.SSOTOKEN); 1515 try { 1516 return new com.iplanet.sso.providers.dpro.SSOProviderImpl(). 1517 createSSOToken(ssoTokenIDTmp, true); 1518 } catch (SSOException ssoe) { 1519 throw new L10NMessageImpl( 1520 amAuthContext, "createSSOTokenError", null); 1521 } 1522 } 1523 } 1524 1525 /** 1526 * Returns the current status of the authentication process as 1527 * <code>AuthContext.Status</code>. 1528 * 1529 * @return <code>Status</code> of the authentication process. 1530 * 1531 * @supported.api 1532 */ 1533 public Status getStatus() { 1534 if (localFlag) { 1535 return (acLocal.getStatus()); 1536 } else { 1537 return (loginStatus); 1538 } 1539 } 1540 1541 /** 1542 * Returns the current Auth Identifier of the authentication 1543 * process as String Session ID. 1544 * 1545 * @return Auth Identifier of the authentication process. 1546 */ 1547 public String getAuthIdentifier() { 1548 if (localFlag) { 1549 return (acLocal.getAuthIdentifier()); 1550 } else { 1551 return (getAuthHandle()); 1552 } 1553 } 1554 1555 /** 1556 * Returns the Successful Login URL for the authenticated user. 1557 * 1558 * @return the Successful Login URL for the authenticated user. 1559 * @throws Exception if it fails to get url for auth success 1560 */ 1561 public String getSuccessURL() throws Exception { 1562 if (localFlag) { 1563 if (!acLocal.getStatus().equals(Status.SUCCESS)) { 1564 throw new 1565 L10NMessageImpl(amAuthContext, "statusNotSuccess", null); 1566 } 1567 return (acLocal.getSuccessURL()); 1568 } else { 1569 // Get the loginStatus node 1570 if (!loginStatus.equals(Status.SUCCESS)) { 1571 throw new 1572 L10NMessageImpl(amAuthContext, "statusNotSuccess", null); 1573 } 1574 Node loginStatusNode = XMLUtils.getRootNode(receivedDocument, 1575 AuthXMLTags.LOGIN_STATUS); 1576 if (loginStatusNode == null) { 1577 throw new L10NMessageImpl(amAuthContext, "noStatusNode", null); 1578 } 1579 return (XMLUtils.getNodeAttributeValue(loginStatusNode, 1580 AuthXMLTags.SUCCESS_URL)); 1581 } 1582 } 1583 1584 /** 1585 * Returns the Failure Login URL for the authenticating user. 1586 * 1587 * @return the Failure Login URL for the authenticating user 1588 * @throws Exception if it fails to get url for auth failure 1589 */ 1590 public String getFailureURL() throws Exception { 1591 if (localFlag) { 1592 return (acLocal.getFailureURL()); 1593 } else { 1594 // Get the loginStatus node 1595 Node loginStatusNode = XMLUtils.getRootNode(receivedDocument, 1596 AuthXMLTags.LOGIN_STATUS); 1597 if (loginStatusNode == null) { 1598 throw new L10NMessageImpl(amAuthContext, "noStatusNode", null); 1599 } 1600 return (XMLUtils.getNodeAttributeValue(loginStatusNode, 1601 AuthXMLTags.FAILURE_URL)); 1602 } 1603 } 1604 1605 /** 1606 * Resets this instance of <code>AuthContext</code> object, so that a new 1607 * login process can be initiated. A new authentication process can started 1608 * using any one of the <code>login</code> methods. 1609 */ 1610 public void reset() { 1611 loginStatus = Status.NOT_STARTED; 1612 //organizationName = null; 1613 //receivedDocument = null; 1614 //loginException = null; 1615 } 1616 1617 /** 1618 * Returns the the organization name that was set during the 1619 * <code>AuthContext</code> constructor. 1620 * 1621 * @return Organization name in the <code>AuthContext</code>. 1622 * 1623 * @supported.api 1624 */ 1625 public String getOrganizationName() { 1626 return (this.organizationName); 1627 } 1628 1629 /** 1630 * 1631 * Returns authentication module/s instances (or plugins) configured 1632 * for a organization, or sub-organization name that was set during the 1633 * <code>AuthContext</code> constructor. 1634 * 1635 * @return Set of Module instance names. 1636 * 1637 * @supported.api 1638 */ 1639 public Set getModuleInstanceNames() { 1640 if (authURL != null) { 1641 authServiceURL = getAuthServiceURL( 1642 authURL.getProtocol(), 1643 authURL.getHost(), 1644 Integer.toString(authURL.getPort()), 1645 authURL.getPath()); 1646 } 1647 if (!localFlag) { 1648 setLocalFlag(authServiceURL); 1649 } 1650 if (localFlag) { 1651 return (acLocal.getModuleInstanceNames()); 1652 } else { 1653 if (authServiceURL == null) { 1654 try { 1655 authServiceURL = getAuthServiceURL(server_proto, 1656 server_host, server_port, server_uri); 1657 } catch (Exception e) { 1658 return Collections.EMPTY_SET; 1659 } 1660 } 1661 sendQueryInformation(AuthXMLTags.MODULE_INSTANCE); 1662 1663 //Receive data 1664 Node queryResultNode = XMLUtils.getRootNode(receivedDocument, 1665 AuthXMLTags.QUERY_RESULT); 1666 if (queryResultNode == null) { 1667 return (null); 1668 } 1669 1670 // Iteratate through moduleInstanceNames 1671 HashSet moduleInstanceNames = new HashSet(); 1672 NodeList childNodes = queryResultNode.getChildNodes(); 1673 if ( childNodes != null ) { 1674 for (int i = 0; i < childNodes.getLength(); i++) { 1675 Node childNode = childNodes.item(i); 1676 String moduleName = XMLUtils.getValueOfValueNode(childNode); 1677 moduleInstanceNames.add(moduleName); 1678 } 1679 } 1680 return (moduleInstanceNames); 1681 } 1682 } 1683 1684 /** 1685 * Terminates an ongoing <code>login</code> call that has not yet completed. 1686 * 1687 * @exception AuthLoginException if an error occurred during abort. 1688 * 1689 * @supported.api 1690 */ 1691 public void abort() throws AuthLoginException { 1692 if (localFlag) { 1693 acLocal.abort(); 1694 return; 1695 } 1696 1697 // Construct the XML 1698 try { 1699 StringBuilder xml = new StringBuilder(100); 1700 String[] authHandles = new String[1]; 1701 authHandles[0] = getAuthenticationHandle(receivedDocument); 1702 xml.append(MessageFormat.format(AuthXMLTags.XML_REQUEST_PREFIX, 1703 (Object[])authHandles)); 1704 if (appSSOToken != null) { 1705 xml.append(AuthXMLTags.APPSSOTOKEN_BEGIN); 1706 xml.append(appSSOToken.getTokenID().toString()). 1707 append(AuthXMLTags.APPSSOTOKEN_END); 1708 } 1709 xml.append(AuthXMLTags.ABORT_BEGIN) 1710 .append(AuthXMLTags.ABORT_END) 1711 .append(AuthXMLTags.XML_REQUEST_SUFFIX); 1712 1713 // Send the request to be processes 1714 receivedDocument = processRequest(xml.toString()); 1715 1716 // Check set the login status 1717 checkAndSetLoginStatus(); 1718 } catch (AuthLoginException le) { 1719 // Login has failed 1720 loginStatus = Status.FAILED; 1721 loginException = le; 1722 } 1723 } 1724 1725 /** 1726 * Sets the password for the certificate database. 1727 * It is required to call only once to initialize certificate database if 1728 * the password is not set in the password file (specified as 1729 * the value for <code>com.iplanet.am.admin.cli.certdb.passfile</code> 1730 * in <code>AMConfig.properties</code>). If both are set, this method will 1731 * overwrite the value in certificate password file. 1732 * 1733 * @param password Password for the certificate database. 1734 * 1735 * @supported.api 1736 */ 1737 public static void setCertDBPassword(String password) { 1738 try { 1739 if (usingJSSEHandler) { 1740 Class pcbClass = (Class) Class.forName(JSSE_PASSWORD_CALLBACK); 1741 Object passwdCallback = (Object) pcbClass.newInstance(); 1742 Method method = 1743 pcbClass.getMethod("setPassword", new Class[] { String.class }); 1744 KeyStore keystore = (KeyStore)method.invoke( 1745 passwdCallback, new Object[] { password }); 1746 } else { 1747 Class initializer = Class.forName(JSS_PASSWORD_UTIL); 1748 Constructor initializerConstructor = initializer.getConstructor( 1749 new Class[] { String.class }); 1750 initializerConstructor.newInstance(new Object[] { password }); 1751 } 1752 } catch (Exception e) { 1753 e.printStackTrace(); 1754 authDebug.message("Error in setCertDBPassword : " + e.getMessage()); 1755 } 1756 } 1757 1758 1759 /** 1760 * Returns the error template. 1761 * 1762 * @return error template. 1763 */ 1764 public String getErrorTemplate() { 1765 if (localFlag) { 1766 return (acLocal.getErrorTemplate()); 1767 } else { 1768 if (receivedDocument == null) { 1769 //something went terribly wrong, let's return with internal error template 1770 return AuthClientUtils.getErrorTemplate(AMAuthErrorCode.AUTH_ERROR); 1771 } 1772 String errTemplate = ""; 1773 Node exceptionNode = XMLUtils.getRootNode(receivedDocument, 1774 AuthXMLTags.EXCEPTION); 1775 if (exceptionNode != null) { 1776 errTemplate = XMLUtils.getNodeAttributeValue(exceptionNode, 1777 AuthXMLTags.TEMPLATE_NAME); 1778 } 1779 return errTemplate; 1780 } 1781 } 1782 1783 /** 1784 * Returns the error message. 1785 * 1786 * @return error message. 1787 */ 1788 public String getErrorMessage() { 1789 if (localFlag) { 1790 return (acLocal.getErrorMessage()); 1791 } else { 1792 if (receivedDocument == null) { 1793 //something went terribly wrong, let's return with internal error message 1794 return AuthClientUtils.getErrorMessage(AMAuthErrorCode.AUTH_ERROR); 1795 } 1796 String errMessage = null; 1797 Node exceptionNode = XMLUtils.getRootNode(receivedDocument, 1798 AuthXMLTags.EXCEPTION); 1799 if (exceptionNode != null) { 1800 errMessage = XMLUtils.getNodeAttributeValue(exceptionNode, 1801 AuthXMLTags.MESSAGE); 1802 } 1803 return errMessage; 1804 } 1805 } 1806 1807 /** 1808 * Returns error code. 1809 * 1810 * @return error code with white space trimmed 1811 */ 1812 public String getErrorCode() { 1813 if (localFlag) { 1814 return (acLocal.getErrorCode()); 1815 } else { 1816 if (receivedDocument == null) { 1817 //something went terribly wrong 1818 return AMAuthErrorCode.AUTH_ERROR; 1819 } 1820 String errCode = ""; 1821 Node exceptionNode = XMLUtils.getRootNode(receivedDocument, 1822 AuthXMLTags.EXCEPTION); 1823 1824 if (exceptionNode != null) { 1825 errCode = XMLUtils.getNodeAttributeValue(exceptionNode, 1826 AuthXMLTags.ERROR_CODE); 1827 } 1828 1829 if (errCode != null) { 1830 return errCode.trim(); 1831 } else { 1832 return errCode; 1833 } 1834 } 1835 } 1836 1837 /** 1838 * Sets the client's hostname or IP address.This could be used 1839 * by the policy component to restrict access to resources. 1840 * This method is ineffective if the "Remote Auth Security" option under 1841 * the global configuration of Core Authentication Service is not enabled. 1842 * This method must be called before calling <code>login</code> method. 1843 * If it is called after calling <code>login</code> then 1844 * it is ineffective. 1845 * 1846 * @param hostname hostname or ip address 1847 * 1848 * @supported.api 1849 */ 1850 public void setClientHostName(String hostname) { 1851 this.hostName = hostname; 1852 } 1853 1854 /** 1855 * Returns the client's hostname or IP address as set by 1856 * setClientHostName 1857 * 1858 * @return hostname/IP address 1859 * 1860 * @supported.api 1861 */ 1862 public String getClientHostName() { 1863 return (hostName); 1864 } 1865 1866 /** 1867 * Sets locale based on user locale preferemce. 1868 * 1869 * @param loc locale preference of user 1870 */ 1871 public void setLocale (java.util.Locale loc) { 1872 clientLocale = loc; 1873 } 1874 1875 /** 1876 * Returns locale preference set in AuthConext 1877 * @return - user prefered locale. 1878 */ 1879 1880 public java.util.Locale getLocale () { 1881 return clientLocale; 1882 } 1883 1884 private AuthLoginException checkException(){ 1885 AuthLoginException exception = null; 1886 String error = getErrorCode(); 1887 1888 // if the app token is invalid, refresh the token 1889 if (error != null && error.equals(AMAuthErrorCode.REMOTE_AUTH_INVALID_SSO_TOKEN)) { 1890 appSSOToken = getAppSSOToken(true); 1891 } 1892 1893 if (error != null && error.length() != 0){ 1894 exception = new AuthLoginException("amAuth", error, null); 1895 } else { 1896 error = getErrorMessage(); 1897 if (error != null && error.length() != 0) { 1898 exception = new AuthLoginException(error); 1899 } 1900 } 1901 return exception; 1902 } 1903 1904 protected void checkAndSetLoginStatus(){ 1905 1906 Node loginStatusNode = XMLUtils.getRootNode( 1907 receivedDocument, AuthXMLTags.LOGIN_STATUS); 1908 if (loginStatusNode == null) { 1909 loginException = checkException(); 1910 1911 if (includeReqRes) { 1912 remoteRequest = AuthXMLUtils.getRemoteRequest( 1913 XMLUtils.getRootNode(receivedDocument, AuthXMLTags.REMOTE_REQUEST_RESPONSE)); 1914 remoteResponse = AuthXMLUtils.getRemoteResponse( 1915 XMLUtils.getRootNode(receivedDocument, AuthXMLTags.REMOTE_REQUEST_RESPONSE)); 1916 } 1917 } else { 1918 //since there was no error, we should reset the loginException, to handle the case when the first auth 1919 //server was not available. 1920 loginException = null; 1921 // Get the status attribute 1922 String status = XMLUtils.getNodeAttributeValue( 1923 loginStatusNode, AuthXMLTags.STATUS); 1924 if (status != null) { 1925 if (status.equals(Status.SUCCESS.toString())) { 1926 loginStatus = Status.SUCCESS; 1927 } else if (status.equals(Status.FAILED.toString())) { 1928 loginStatus = Status.FAILED; 1929 loginException = checkException(); 1930 } else if (status.equals(Status.COMPLETED.toString())) { 1931 loginStatus = Status.COMPLETED; 1932 } else if (status.equals(Status.IN_PROGRESS.toString())) { 1933 loginStatus = Status.IN_PROGRESS; 1934 } else if (status.equals(Status.RESET.toString())) { 1935 loginStatus = Status.RESET; 1936 } 1937 } 1938 1939 if (includeReqRes) { 1940 remoteRequest = AuthXMLUtils.getRemoteRequest( 1941 XMLUtils.getRootNode(receivedDocument, AuthXMLTags.REMOTE_REQUEST_RESPONSE)); 1942 remoteResponse = AuthXMLUtils.getRemoteResponse( 1943 XMLUtils.getRootNode(receivedDocument, AuthXMLTags.REMOTE_REQUEST_RESPONSE)); 1944 } 1945 1946 if (authDebug.messageEnabled()) { 1947 authDebug.message("LoginStatus : " + loginStatus); 1948 } 1949 } 1950 } 1951 1952 protected void sendQueryInformation(String reqInfo) { 1953 // Construct the XML 1954 try { 1955 StringBuilder xml = new StringBuilder(100); 1956 String[] authHandles = new String[1]; 1957 authHandles[0] = getAuthHandle(); 1958 1959 xml.append(MessageFormat.format(AuthXMLTags.XML_REQUEST_PREFIX, 1960 (Object[])authHandles)); 1961 if (appSSOToken != null) { 1962 xml.append(AuthXMLTags.APPSSOTOKEN_BEGIN); 1963 xml.append(appSSOToken.getTokenID().toString()). 1964 append(AuthXMLTags.APPSSOTOKEN_END); 1965 } 1966 xml.append(AuthXMLTags.QUERY_INFO_BEGIN) 1967 .append(AuthXMLTags.SPACE) 1968 .append(AuthXMLTags.REQUESTED_INFO) 1969 .append(AuthXMLTags.EQUAL) 1970 .append(AuthXMLTags.QUOTE) 1971 .append(reqInfo) 1972 .append(AuthXMLTags.QUOTE); 1973 1974 if (authHandles[0].equals("0")) { 1975 xml.append(AuthXMLTags.SPACE) 1976 .append(AuthXMLTags.ORG_NAME_ATTR) 1977 .append(AuthXMLTags.EQUAL) 1978 .append(AuthXMLTags.QUOTE) 1979 .append(XMLUtils.escapeSpecialCharacters(organizationName)) 1980 .append(AuthXMLTags.QUOTE); 1981 } 1982 1983 xml.append(AuthXMLTags.ELEMENT_END) 1984 .append(AuthXMLTags.QUERY_INFO_END) 1985 .append(AuthXMLTags.XML_REQUEST_SUFFIX); 1986 1987 // Send the request to be processes 1988 receivedDocument = processRequest(xml.toString()); 1989 1990 // Check set the login status 1991 checkAndSetLoginStatus(); 1992 } catch (AuthLoginException le) { 1993 // Login has failed 1994 loginStatus = Status.FAILED; 1995 loginException = le; 1996 } 1997 } 1998 1999 private void setLocalFlag(URL url) { 2000 try { 2001 String urlStr = url.getProtocol() + "://" + url.getHost() + ":" 2002 + Integer.toString(url.getPort()); 2003 2004 if (authDebug.messageEnabled()) { 2005 authDebug.message("in setLocalFlag(), url : " + urlStr); 2006 authDebug.message("AuthContext.localAuthServiceID : " + 2007 localAuthServiceID); 2008 } 2009 2010 if ((localAuthServiceID != null) && 2011 (urlStr.equalsIgnoreCase(localAuthServiceID)) 2012 ) { 2013 localFlag = true; 2014 } 2015 } catch (Exception e) { 2016 authDebug.error("AuthContext::setLocalFlag:: " + e); 2017 } 2018 } 2019 2020 protected Document processRequest(String xmlRequest) 2021 throws AuthLoginException { 2022 Document doc = null; 2023 2024 try { 2025 Request request = new Request(xmlRequest); 2026 RequestSet set = new RequestSet(AuthXMLTags.AUTH_SERVICE); 2027 set.addRequest(request); 2028 2029 URL url = authServiceURL; 2030 2031 if (url.getProtocol().equals("https") && (nickName != null)) { 2032 Class[] paramtype = {String.class}; 2033 Object[] param = {nickName}; 2034 String protHandler = protHandlerPkg + ".https.Handler"; 2035 Constructor construct = 2036 Class.forName(protHandler).getConstructor(paramtype); 2037 URLStreamHandler handler = 2038 (URLStreamHandler)construct.newInstance(param); 2039 url = new URL(url.getProtocol(), url.getHost(), url.getPort(), 2040 url.getFile(), handler); 2041 } 2042 2043 if (authDebug.messageEnabled()) { 2044 authDebug.message("Service URL : " + url.toString()); 2045 } 2046 2047 Vector responses = PLLClient.send(url, set, cookieTable); 2048 2049 if ((responses.isEmpty()) || (responses.size() != 1)) { 2050 throw new L10NMessageImpl(amAuthContext, "responseError", null); 2051 } 2052 2053 Response res = (Response) responses.elementAt(0); 2054 String responseStr = (String)res.getContent(); 2055 2056 doc = XMLUtils.getXMLDocument( 2057 new ByteArrayInputStream(responseStr.getBytes("UTF-8"))); 2058 } catch (Exception e) { 2059 authDebug.message("error in getting service url", e); 2060 throw new AuthLoginException(amAuthContext, "xmlProcessError", 2061 null, e); 2062 } 2063 return (doc); 2064 } 2065 2066 protected static void checkForException(Document document) 2067 throws AuthLoginException { 2068 Node exceptionNode = XMLUtils.getRootNode( 2069 document, AuthXMLTags.EXCEPTION); 2070 2071 if (exceptionNode != null) { 2072 throw (new AuthLoginException(XMLUtils.getNodeAttributeValue( 2073 exceptionNode, AuthXMLTags.MESSAGE))); 2074 } 2075 } 2076 2077 protected String getAuthenticationHandle(Document document) 2078 throws AuthLoginException { 2079 Node responseNode = XMLUtils.getRootNode( 2080 document, AuthXMLTags.RESPONSE); 2081 if (responseNode == null) { 2082 throw new AuthLoginException(amAuthContext, "responseError", null); 2083 } 2084 2085 String authID = XMLUtils.getNodeAttributeValue( 2086 responseNode, AuthXMLTags.AUTH_ID_HANDLE); 2087 return (authID); 2088 } 2089 2090 protected static Callback[] getCallbacks( 2091 Document document, 2092 boolean noFilter) { 2093 return (AuthXMLUtils.getCallbacks(XMLUtils.getRootNode(document, 2094 AuthXMLTags.CALLBACKS), noFilter)); 2095 } 2096 2097 protected static Subject getSubject(Document document) { 2098 Node loginStatusNode = XMLUtils.getRootNode(document, 2099 AuthXMLTags.LOGIN_STATUS); 2100 2101 if (loginStatusNode == null) { 2102 return (null); 2103 } 2104 2105 Node subjectNode = XMLUtils.getChildNode(loginStatusNode, 2106 AuthXMLTags.SUBJECT); 2107 2108 if (subjectNode == null) { 2109 return (null); 2110 } 2111 2112 String subject = XMLUtils.getValueOfValueNode(subjectNode); 2113 try { 2114 Subject sSubject = AuthXMLUtils.getDeSerializedSubject(subject); 2115 2116 if (authDebug.messageEnabled()) { 2117 authDebug.message("Deserialized subject : " 2118 + sSubject.toString()); 2119 } 2120 return sSubject; 2121 } catch (Exception e) { 2122 authDebug.message("get Deserialized subject error : " , e); 2123 return null; 2124 } 2125 2126 } 2127 2128 protected static String getXMLforSubject(Subject subject) { 2129 if (subject == null) { 2130 return (""); 2131 } 2132 StringBuilder request = new StringBuilder(100); 2133 request.append(AuthXMLTags.SUBJECT_BEGIN); 2134 String serializeSubject = AuthXMLUtils.getSerializedSubject(subject); 2135 request.append(serializeSubject); 2136 request.append(AuthXMLTags.SUBJECT_END); 2137 return (request.toString()); 2138 } 2139 2140 /** 2141 * Returns the account lockout message. This can be either a dynamic 2142 * message indicating the number of tries left or the the account 2143 * deactivated message. 2144 * 2145 * @return account lockout message. 2146 */ 2147 public String getLockoutMsg() { 2148 String lockoutMsg = null; 2149 if (localFlag) { 2150 lockoutMsg = acLocal.getLockoutMsg(); 2151 } else { 2152 // Account Lockout Warning Check by scanning the error 2153 // message in the exception thrown by the server 2154 lockoutMsg = getErrorMessage(); 2155 if((lockoutMsg == null) || 2156 (lockoutMsg.indexOf("Account lockout") == -1)){ 2157 lockoutMsg = ""; 2158 } 2159 } 2160 return lockoutMsg; 2161 } 2162 2163 /** 2164 * Returns <code>true</code> if account is lock out. 2165 * 2166 * @return <code>true</code> if account is lock out. 2167 */ 2168 public boolean isLockedOut() { 2169 boolean isLockedOut = false; 2170 if (localFlag) { 2171 isLockedOut = acLocal.isLockedOut(); 2172 } else { 2173 // TBD 2174 } 2175 2176 return isLockedOut; 2177 } 2178 2179 /** 2180 * The class <code>Status</code> defines the possible 2181 * authentication states during the login process. 2182 * 2183 * @supported.all.api 2184 */ 2185 public static class Status extends Object { 2186 2187 private String status; 2188 2189 /** 2190 * The <code>NOT_STARTED</code> status indicates that the login process 2191 * has not yet started. Basically, it means that the method 2192 * <code>login</code> has not been called. 2193 */ 2194 public static final Status NOT_STARTED = new Status("not_started"); 2195 2196 /** 2197 * The <code>IN_PROGRESS</code> status indicates that the login process 2198 * is in progress. Basically, it means that the <code>login</code> 2199 * method has been called and that this object is waiting for the user 2200 * to send authentication information. 2201 */ 2202 public static final Status IN_PROGRESS = new Status("in_progress"); 2203 2204 /** 2205 * 2206 * The <code>SUCCESS</code> indicates that the login process has 2207 * succeeded. 2208 */ 2209 public static final Status SUCCESS = new Status("success"); 2210 2211 /** 2212 * The <code>FAILED</code> indicates that the login process has failed. 2213 */ 2214 public static final Status FAILED = new Status("failed"); 2215 2216 /** 2217 * 2218 * The <code>COMPLETED</code> indicates that the user has been 2219 * successfully logged out. 2220 */ 2221 public static final Status COMPLETED = new Status("completed"); 2222 2223 /** 2224 * The <code>RESET</code> indicates that the login process has been 2225 * reset or re-initialized. 2226 */ 2227 public static final Status RESET = new Status("reset"); 2228 2229 /** 2230 * The <code>ORG_MISMATCH</code> indicates that the framework 2231 * <code>org</code> and the <code>org</code> required by the user do 2232 * not match. 2233 */ 2234 public static final Status ORG_MISMATCH = new Status("org_mismatch"); 2235 2236 2237 private Status() { 2238 // do nothing 2239 } 2240 2241 private Status(String s) { 2242 status = s; 2243 } 2244 2245 /** 2246 * Returns the string representation of the authentication status. 2247 * 2248 * @return String representation of authentication status. 2249 */ 2250 public String toString() { 2251 return (status); 2252 } 2253 2254 /** 2255 * Checks if two authentication status objects are equal. 2256 * 2257 * @param authStatus Reference object with which to compare. 2258 * @return <code>true</code> if the objects are same. 2259 */ 2260 public boolean equals(Object authStatus) { 2261 if (authStatus instanceof Status) { 2262 Status s = (Status) authStatus; 2263 return (s.status.equalsIgnoreCase(status)); 2264 } 2265 return (false); 2266 } 2267 } 2268 2269 /** 2270 * The class <code>IndexType</code> defines the possible kinds of "objects" 2271 * or "resources" for which an authentication can be performed. 2272 * 2273 * @supported.all.api 2274 */ 2275 public static class IndexType extends Object { 2276 2277 private String index; 2278 2279 /** 2280 * The <code>USER</code> index type indicates that the index name given 2281 * corresponds to a user. 2282 */ 2283 public static final IndexType USER = new IndexType("user"); 2284 2285 /** 2286 * The <code>ROLE</code> index type indicates that the index name given 2287 * corresponds to a role. 2288 */ 2289 public static final IndexType ROLE = new IndexType("role"); 2290 2291 /** 2292 * 2293 * The <code>SERVICE</code> index type indicates that the index name 2294 * given corresponds to a service (or application). 2295 */ 2296 public static final IndexType SERVICE = new IndexType("service"); 2297 2298 /** 2299 * The <code>LEVEL</code> index type indicates that the index name 2300 * given corresponds to a given authentication level. 2301 */ 2302 public static final IndexType LEVEL = new IndexType("level"); 2303 2304 /** 2305 * The <code>MODULE_INSTANCE</code> index type indicates that the index 2306 * name given corresponds to one of the authentication modules. 2307 */ 2308 public static final IndexType MODULE_INSTANCE = 2309 new IndexType("module_instance"); 2310 2311 /** 2312 * The <code>RESOURCE</code> index type indicates that the index 2313 * name given corresponds to a given policy protected resource URL. 2314 */ 2315 public static final IndexType RESOURCE = 2316 new IndexType("resource"); 2317 2318 /** 2319 * The <code>COMPOSITE_ADVICE</code> index type indicates that the 2320 * index name given corresponds to string in the form of XML 2321 * representing different Policy Authentication conditions, example 2322 * <code>AuthSchemeCondition</code>, <code>AuthLevelCondition</code>, 2323 * etc. 2324 */ 2325 public static final IndexType COMPOSITE_ADVICE = 2326 new IndexType("composite_advice"); 2327 2328 private IndexType() { 2329 // do nothing 2330 } 2331 2332 private IndexType(String s) { 2333 index = s; 2334 } 2335 2336 /** 2337 * Returns the string representation of the index type. 2338 * 2339 * @return String representation of index type. 2340 */ 2341 public String toString() { 2342 return (index); 2343 } 2344 2345 /** 2346 * Checks if two index type objects are equal. 2347 * 2348 * @param indexType Reference object with which to compare. 2349 * 2350 * @return <code>true</code> if the objects are same. 2351 */ 2352 public boolean equals(Object indexType) { 2353 if (indexType instanceof IndexType) { 2354 IndexType s = (IndexType) indexType; 2355 return (s.index.equalsIgnoreCase(index)); 2356 } 2357 return (false); 2358 } 2359 } 2360 2361 private String getAuthHandle() { 2362 String handle = null; 2363 2364 if (receivedDocument != null) { 2365 try { 2366 handle = getAuthenticationHandle(receivedDocument); 2367 } catch (Exception e) { 2368 // do nothing 2369 } 2370 } 2371 if ( handle == null ) { 2372 handle = "0"; 2373 } 2374 return handle; 2375 } 2376 2377 private static URL getAuthServiceURL( 2378 String protocol, 2379 String host, 2380 String port, 2381 String uri 2382 ) { 2383 URL authservice = null; 2384 try { 2385 authservice = WebtopNaming.getServiceURL(AuthXMLTags.AUTH_SERVICE, 2386 protocol, host, port, uri); 2387 } catch (Exception e) { 2388 authDebug.error("Failed to obtain auth service url from server: " + 2389 protocol + "://" + host + ":" + port); 2390 } 2391 return authservice; 2392 } 2393 2394 private void onSuccessLocal() { 2395 if (localSessionChecked) { 2396 return; 2397 } 2398 SSOToken currToken = acLocal.getSSOToken(); 2399 com.iplanet.dpro.session.service.InternalSession oldSess 2400 = acLocal.getLoginState().getOldSession(); 2401 if (oldSess != null) { 2402 if (forceAuth) { 2403 try { 2404 SSOTokenManager.getInstance(). 2405 destroyToken(currToken); 2406 } catch (SSOException ssoExp) { 2407 authDebug.error("AuthContext.onSuccessLocal: ", 2408 ssoExp); 2409 2410 } 2411 acLocal.getLoginState().setSession(oldSess); 2412 acLocal.getLoginState().setForceAuth(false); 2413 ssoToken = acLocal.getSSOToken(); 2414 ssoTokenID = ssoToken.getTokenID().toString(); 2415 2416 } else { 2417 com.iplanet.dpro.session.service.SessionService. 2418 getSessionService().destroyInternalSession 2419 (oldSess.getID()); 2420 } 2421 } 2422 localSessionChecked = true; 2423 } 2424 2425 /** 2426 * Returns the application sso token. Can perform a check to ensure that 2427 * the app token is still valid (requires a session refresh call to OpenAM) 2428 * 2429 * @param refresh true if we should check with OpenAM if the app token is valid 2430 * @return a valid application's sso token. 2431 */ 2432 private SSOToken getAppSSOToken(boolean refresh) { 2433 SSOToken appToken = null; 2434 2435 try { 2436 appToken = (SSOToken) AccessController.doPrivileged( 2437 AdminTokenAction.getInstance()); 2438 } catch (AMSecurityPropertiesException aspe) { 2439 if (authDebug.messageEnabled()) { 2440 authDebug.message("AuthContext::getAppSSOToken: " + 2441 "unable to get app ssotoken " + aspe.getMessage()); 2442 } 2443 } 2444 2445 if (refresh) { 2446 // ensure the token is valid 2447 try { 2448 SSOTokenManager ssoTokenManager = SSOTokenManager.getInstance(); 2449 ssoTokenManager.refreshSession(appToken); 2450 2451 if (!ssoTokenManager.isValidToken(appToken)) { 2452 if (authDebug.messageEnabled()) { 2453 authDebug.message("AuthContext.getAppSSOToken(): " + 2454 "App SSOToken is invalid, retrying"); 2455 } 2456 2457 try { 2458 appToken = (SSOToken) AccessController.doPrivileged( 2459 AdminTokenAction.getInstance()); 2460 } catch (AMSecurityPropertiesException aspe) { 2461 if (authDebug.messageEnabled()) { 2462 authDebug.message("AuthContext::getAppSSOToken: " + 2463 "unable to get app ssotoken " + aspe.getMessage()); 2464 } 2465 } 2466 } 2467 } catch (SSOException ssoe) { 2468 if (authDebug.messageEnabled()) { 2469 authDebug.message("AuthContext.getAppSSOToken(): " + 2470 "unable to refresh app token: " + ssoe.getL10NMessage()); 2471 } 2472 2473 try { 2474 appToken = (SSOToken) AccessController.doPrivileged( 2475 AdminTokenAction.getInstance()); 2476 } catch (AMSecurityPropertiesException aspe) { 2477 if (authDebug.errorEnabled()) { 2478 authDebug.error("AuthContext::getAppSSOToken: " + 2479 "unable to get app ssotoken " + aspe.getMessage()); 2480 } 2481 } 2482 } 2483 } 2484 2485 if (authDebug.messageEnabled()) { 2486 if (appToken == null) { 2487 authDebug.message("Null App SSO Token"); 2488 } else { 2489 authDebug.message("Obtained App Token= " + appToken.getTokenID().toString()); 2490 } 2491 } 2492 2493 return appToken; 2494 } 2495 2496 public AuthContextLocal getAuthContextLocal() { 2497 return acLocal; 2498 } 2499}
Copyright © 2010-2017, ForgeRock All Rights Reserved.