1 /**
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright (c) 2005 Sun Microsystems Inc. All Rights Reserved
5 *
6 * The contents of this file are subject to the terms
7 * of the Common Development and Distribution License
8 * (the License). You may not use this file except in
9 * compliance with the License.
10 *
11 * You can obtain a copy of the License at
12 * https://opensso.dev.java.net/public/CDDLv1.0.html or
13 * opensso/legal/CDDLv1.0.txt
14 * See the License for the specific language governing
15 * permission and limitations under the License.
16 *
17 * When distributing Covered Code, include this CDDL
18 * Header Notice in each file and include the License file
19 * at opensso/legal/CDDLv1.0.txt.
20 * If applicable, add the following below the CDDL Header,
21 * with the fields enclosed by brackets [] replaced by
22 * your own identifying information:
23 * "Portions Copyrighted [year] [name of copyright owner]"
24 *
25 * $Id: AuthContext.java,v 1.16 2008/08/19 19:08:47 veiming Exp $
26 *
27 */
28
29 package com.sun.identity.authentication;
30
31 import com.iplanet.am.util.SystemProperties;
32 import com.iplanet.dpro.session.Session;
33 import com.iplanet.dpro.session.SessionID;
34 import com.iplanet.services.comm.client.PLLClient;
35 import com.iplanet.services.comm.share.Request;
36 import com.iplanet.services.comm.share.RequestSet;
37 import com.iplanet.services.comm.share.Response;
38 import com.iplanet.services.naming.WebtopNaming;
39 import com.iplanet.sso.SSOException;
40 import com.iplanet.sso.SSOToken;
41 import com.iplanet.sso.SSOTokenManager;
42 import com.sun.identity.authentication.service.AuthException;
43 import com.sun.identity.authentication.share.AuthXMLTags;
44 import com.sun.identity.authentication.share.AuthXMLUtils;
45 import com.sun.identity.authentication.spi.AuthLoginException;
46 import com.sun.identity.authentication.util.ISAuthConstants;
47 import com.sun.identity.security.AdminTokenAction;
48 import com.sun.identity.security.AMSecurityPropertiesException;
49 import com.sun.identity.shared.Constants;
50 import com.sun.identity.shared.debug.Debug;
51 import com.sun.identity.shared.locale.L10NMessageImpl;
52 import com.sun.identity.shared.locale.Locale;
53 import com.sun.identity.shared.xml.XMLUtils;
54 import java.io.ByteArrayInputStream;
55 import java.lang.reflect.Constructor;
56 import java.lang.reflect.Method;
57 import java.net.URL;
58 import java.net.URLStreamHandler;
59 import java.security.AccessController;
60 import java.security.KeyStore;
61 import java.text.MessageFormat;
62 import java.util.Collections;
63 import java.util.Enumeration;
64 import java.util.HashMap;
65 import java.util.HashSet;
66 import java.util.Map;
67 import java.util.ResourceBundle;
68 import java.util.Set;
69 import java.util.Vector;
70 import javax.security.auth.Subject;
71 import javax.security.auth.callback.Callback;
72 import org.w3c.dom.Document;
73 import org.w3c.dom.Node;
74 import org.w3c.dom.NodeList;
75
76 /**
77 * The <code>AuthContext</code> provides the implementation for
78 * authenticating users.
79 * <p>
80 * A typical caller instantiates this class and starts the login process.
81 * The caller then obtains an array of <code>Callback</code> objects,
82 * which contains the information required by the authentication plug-in
83 * module. The caller requests information from the user. On receiving
84 * the information from the user, the caller submits the same to this class.
85 * While more information is required, the above process continues until all
86 * the information required by the plug-ins/authentication modules, has
87 * been supplied. The caller then checks if the user has successfully
88 * been authenticated. If successfully authenticated, the caller can
89 * then get the <code>Subject</code> and <code>SSOToken</code> for the user;
90 * if not successfully authenticated, the caller obtains the
91 * <code>AuthLoginException</code>.
92 * <p>
93 * The implementation supports authenticating users either locally
94 * i.e., in process with all authentication modules configured or remotely
95 * to an authentication service/framework. (See documentation to configure
96 * in either of the modes).
97 *
98 * @supported.api
99 */
100 public class AuthContext extends Object implements java.io.Serializable {
101 private String server_proto =
102 SystemProperties.get(Constants.AM_SERVER_PROTOCOL);
103 private String server_host =
104 SystemProperties.get(Constants.AM_SERVER_HOST);
105 private String server_port =
106 SystemProperties.get(Constants.AM_SERVER_PORT);
107 private String server_uri =
108 SystemProperties.get(Constants.AM_SERVICES_DEPLOYMENT_DESCRIPTOR);
109
110 private static final String amAuthContext = "amAuthContext";
111
112 private static final String JSS_PASSWORD_UTIL =
113 "com.sun.identity.authentication.util.JSSPasswordUtil";
114
115 private static final String JSSE_PASSWORD_CALLBACK =
116 "com.sun.identity.security.keystore.AMCallbackHandler";
117
118 static String protHandlerPkg =
119 System.getProperty(Constants.PROTOCOL_HANDLER, Constants.JSSE_HANDLER);
120
121 static boolean usingJSSEHandler =
122 protHandlerPkg.equals(Constants.JSSE_HANDLER);
123
124 // Debug & I18N class
125 protected static Debug authDebug = Debug.getInstance(amAuthContext);
126 protected static ResourceBundle bundle =
127 Locale.getInstallResourceBundle(amAuthContext);
128
129 Status loginStatus = Status.IN_PROGRESS;
130 String organizationName = "";
131 Document receivedDocument;
132 AuthLoginException loginException = null;
133
134 String hostName = null;
135 private boolean forceAuth = false;
136 private boolean localSessionChecked = false;
137 String nickName = null;
138 private URL authURL = null;
139 private URL authServiceURL = null;
140 private SSOToken ssoToken = null;
141 private String ssoTokenID = null;
142 private static SSOToken appSSOToken = null;
143 com.sun.identity.authentication.server.AuthContextLocal acLocal = null;
144
145 /**
146 * Variables for checking auth service is running local
147 */
148 public boolean localFlag = false;
149 /**
150 * Variables for local AuthService identifier
151 */
152 public static String localAuthServiceID;
153
154 // Variable to check if 6.3 style remote AuthN has to be performed
155 static boolean useOldStyleRemoteAuthentication;
156 static boolean useNewStyleRemoteAuthentication;
157
158 // this cookieTable is used to keep all the cookies retrieved from the
159 // the PLL layer and replay them in subsequent auth requests, mainly for
160 // persistence purpose.
161 private HashMap cookieTable = new HashMap();
162
163 /**
164 * Constructs an instance of <code>AuthContext</code> for a given
165 * organization name or sub organization name. This organization or
166 * sub-organization name must be either "/" separated
167 * ( where it starts with "/" ) , DN , Domain name or DNS Alias Name.
168 * <p>
169 * Caller would then use <code>login</code> to start the
170 * authentication process and use <code>getRequirements()</code> and
171 * <code>submitRequirements()</code> to pass the credentials
172 * needed for authentication by the plugin authentication modules.
173 * The method <code>getStatus()</code> returns the
174 * authentication status.
175 *
176 * @param orgName Name of the user's organization.
177 * @throws AuthLoginException if <code>AuthContext</code> creation fails.
178 * This exception is kept for backward compatibility only.
179 *
180 * @supported.api
181 */
182 public AuthContext(String orgName) throws AuthLoginException {
183 organizationName = orgName;
184 }
185
186 /**
187 * Constructs an instance of <code>AuthContext</code> for a given
188 * organization name, or sub organization name and the OpenSSO
189 * URL.
190 * This organization or sub-organization name must be either "/" separated
191 * ( where it starts with "/" ) , DN , Domain name or DNS Alias Name.
192 * And the <code>url</code> should specify the OpenSSO protocol,
193 * host name, port to talk to.
194 * for example : <code>http://daye.red.iplanet.com:58080</code>
195 *
196 * Caller would then use <code>login</code> to start the
197 * authentication process and use <code>getRequirements()</code> and
198 * <code>submitRequirements()</code> to pass the credentials
199 * needed for authentication by the plugin authentication modules.
200 * The method <code>getStatus()</code> returns the
201 * authentication status.
202 *
203 * @param orgName name of the user's organization
204 * @param url URL of the OpenSSO to talk to
205 * @throws AuthLoginException if <code>AuthContext</code> creation fails.
206 * This exception is kept for backward compatibility only.
207 *
208 * @supported.api
209 */
210 public AuthContext(String orgName, URL url) throws AuthLoginException {
211 organizationName = orgName;
212 authURL = url;
213 }
214
215 /**
216 * Constructs an instance of <code>AuthContext</code> for a given
217 * organization name, or sub organization name and a nick name
218 * for the certificate to be used in SSL handshake if client authentication
219 * is turn on in the server side.
220 * This organization or sub-organization name must be either "/" separated
221 * ( where it starts with "/" ) , DN , Domain name or DNS Alias Name.
222 *
223 * This constructor would be mainly used for the Certificate based
224 * authentication. If the certificate database contains multiple matching
225 * certificates for SSL, this constructor must be called in order for the
226 * desired certificate to be used for the Certificate based authentication.
227 *
228 * Caller would then use <code>login</code> to start the
229 * authentication process and use <code>getRequirements()</code> and
230 * <code>submitRequirements()</code> to pass the credentials
231 * needed for authentication by the plugin authentication modules.
232 * The method <code>getStatus()</code> returns the
233 * authentication status.
234 *
235 * @param orgName name of the user's organization
236 * @param nickName nick name for the certificate to be used
237 * @throws AuthLoginException if <code>AuthContext</code> creation fails.
238 * This exception is kept for backward compatibility only.
239 *
240 * @supported.api
241 */
242 public AuthContext(String orgName, String nickName)
243 throws AuthLoginException {
244 organizationName = orgName;
245 this.nickName = nickName;
246 }
247
248 /**
249 * Constructs an instance of <code>AuthContext</code> for a given
250 * organization name, or sub organization name, a nick name
251 * for the certificate to be used in SSL handshake if client authentication
252 * is turn on in the server side and the OpenSSO URL.
253 * This organization or sub-organization name must be either "/" separated
254 * ( where it starts with "/" ) , DN , Domain name or a DNS Alias Name.
255 * And the <code>url</code> should specify the OpenSSO protocol,
256 * host name, port to talk to.
257 * for example : <code>http://daye.red.iplanet.com:58080</code>
258 * This constructor would be mainly used for the Certificate based
259 * authentication. If the certificate database contains multiple matching
260 * certificates for SSL, this constructor must be called in order for the
261 * desired certificate to be used for the Certificate based authentication.
262 *
263 * Caller would then use <code>login</code> to start the
264 * authentication process and use <code>getRequirements()</code> and
265 * <code>submitRequirements()</code> to pass the credentials
266 * needed for authentication by the plugin authentication modules.
267 * The method <code>getStatus()</code> returns the
268 * authentication status.
269 *
270 * @param orgName name of the user's organization
271 * @param nickName nick name for the certificate to be used
272 * @param url URL of the OpenSSO to talk to
273 * @throws AuthLoginException if <code>AuthContext</code> creation fails.
274 * This exception is kept for backward compatibility only.
275 *
276 * @supported.api
277 */
278 public AuthContext(String orgName, String nickName, URL url)
279 throws AuthLoginException {
280 organizationName = orgName;
281 this.nickName = nickName;
282 authURL = url;
283 }
284
285 /**
286 * Constructs an instance of <code>AuthContext</code> for a given
287 * organization name, or sub organization name contained in the
288 * single sign on token.
289 *
290 * This constructor should be called for re-authentication of an
291 * authenticated user. single sign on token is the authenticated resource's
292 * Single-Sign-On Token. If the session properties based on
293 * the login method used matches those in the user's new
294 * authenticated session then session upgrade will be done.
295 * A new session containing properties from both old single sign on token
296 * and new session shall be returned and old session will be
297 * destroyed if authentication passes.
298 *
299 * Caller would then use <code>login</code> to start the
300 * authentication process and use <code>getRequirements()</code> and
301 * <code>submitRequirements()</code> to pass the credentials
302 * needed for authentication by the plugin authentication modules.
303 * The method <code>getStatus()</code> returns the
304 * authentication status.
305 *
306 * @param ssoToken single sign on token representing the resource's previous
307 * authenticated session.
308 * @throws AuthLoginException if <code>AuthContext</code> creation fails.
309 * This exception is kept for backward compatibility only.
310 *
311 * @supported.api
312 */
313 public AuthContext(SSOToken ssoToken) throws AuthLoginException {
314 this.ssoToken = ssoToken;
315 }
316
317 /**
318 * Constructs an instance of <code>AuthContext</code> for a given
319 * organization name, or sub organization name contained in the
320 * single sign on token.
321 *
322 * This constructor should be called for re-authentication of an
323 * authenticated user. single sign on token is the authenticated resource's
324 * Single-Sign-On Token. If the session properties based on
325 * the login method used matches those in the user's new
326 * authenticated session then session upgrade will be done.
327 * If forceAuth flag is <code>true</code> then the existing session
328 * is used and no new session is created otherwise this constructor
329 * behaves same as the constructor with no forceAuth flag.
330 *
331 * Caller would then use <code>login</code> to start the
332 * authentication process and use <code>getRequirements()</code> and
333 * <code>submitRequirements()</code> to pass the credentials
334 * needed for authentication by the plugin authentication modules.
335 * The method <code>getStatus()</code> returns the
336 * authentication status.
337 *
338 * @param ssoToken single sign on token representing the resource's
339 * previous authenticated session.
340 * @param forceAuth indicates that authentication preocess has to be
341 * restarted and given single sign on token will be used and new
342 * session will not be created.
343 * @throws AuthLoginException if <code>AuthContext</code> creation fails.
344 * This exception is kept for backward compatibility only.
345 *
346 * @supported.api
347 */
348 public AuthContext(SSOToken ssoToken, boolean forceAuth) throws
349 AuthLoginException {
350 this.ssoToken = ssoToken;
351 this.forceAuth = forceAuth;
352 }
353
354 /**
355 * Starts the login process for the given <code>AuthContext</code> object.
356 *
357 * @exception AuthLoginException if an error occurred during login.
358 *
359 * @supported.api
360 */
361 public void login() throws AuthLoginException {
362 login(null, null, null, false);
363 }
364
365 /**
366 * Starts the login process for the given <code>AuthContext</code> object
367 * identified by the index type and index name. The <code>IndexType</code>
368 * defines the possible kinds of "objects" or "resources" for which an
369 * authentication can be performed. Currently supported index types are
370 * users, roles, services (or application), levels and
371 * mechanism/authentication modules.
372 *
373 * @param type Authentication index type.
374 * @param indexName Authentication index name.
375 * @exception AuthLoginException if an error occurred during login.
376 *
377 * @supported.api
378 */
379 public void login(IndexType type, String indexName)
380 throws AuthLoginException {
381 login(type, indexName, null, false);
382 }
383
384 /**
385 * Starts the login process for the given <code>AuthContext</code> object
386 * identified by the index type and index name.
387 * The <code>IndexType</code> defines the possible kinds of "objects"
388 * or "resources" for which an authentication can
389 * be performed. Currently supported index types are
390 * users, roles, services (or application), levels and mechanism.
391 * The <code>pCookieMode</code> indicates that a persistent cookie exists
392 * for this request.
393 *
394 * @param type authentication index type.
395 * @param indexName authentication index name.
396 * @param pCookieMode <code>true</code> if persistent Cookie exists.
397 * @exception AuthLoginException if an error occurred during login
398 */
399 public void login(IndexType type, String indexName, boolean pCookieMode)
400 throws AuthLoginException {
401 login(type, indexName, null, pCookieMode);
402 }
403
404 /**
405 * Starts the login process for the given <code>AuthContext</code> object
406 * identified by the index type and index name.
407 * The <code>IndexType</code> defines the possible kinds of "objects"
408 * or "resources" for which an authentication can
409 * be performed. Currently supported index types are
410 * users, roles, services (or application), levels and mechanism.
411 * It allows the caller to pass in the desired locale for this request.
412 *
413 * @param type authentication index type
414 * @param indexName authentication index name
415 * @param locale locale setting
416 *
417 * @exception AuthLoginException if an error occurred during login
418 */
419 public void login(IndexType type, String indexName, String locale)
420 throws AuthLoginException {
421 login(type, indexName, null, false, locale);
422 }
423
424 /**
425 * Starts the login process for the given <code>AuthContext</code> object
426 * identified by the index type and index name and also completes
427 * the login process by submitting the given User credentials
428 * in the form of Callbacks.
429 * The <code>IndexType</code> defines the possible kinds of "objects"
430 * or "resources" for which an authentication can
431 * be performed. Currently supported index types are
432 * users, roles, services (or application), levels and mechanism.
433 * <p>
434 * NOTE : This is a simplified wrapper method to eliminate multi-step calls
435 * to 'login' and submit credentials. This method is useful and will work
436 * only for those authentication modules which require only one set of
437 * callbacks or one page. This method can not be used to authenticate to
438 * authentication modules which require user interaction or multiple pages.
439 *
440 * @param type Authentication index type.
441 * @param indexName Authentication index name.
442 * @param userInfo User information/credentials in the form of array of
443 * <code>Callback</code> objects. The <code>Callback</code> objects
444 * array must be in the same order as defined in the authentication
445 * module properties file, otherwise authentication module code will
446 * not work.
447 * @return single-sign-on token for the valid user after successful
448 * authentication.
449 * @exception AuthLoginException if an error occurred during login.
450 */
451 public SSOToken login(IndexType type, String indexName, Callback[] userInfo)
452 throws AuthLoginException {
453 login(type, indexName, null, false);
454
455 SSOToken ssoToken = null;
456 Callback[] callbacks = null;
457
458 while (hasMoreRequirements()) {
459 callbacks = getRequirements();
460
461 if (callbacks != null) {
462 try {
463 submitRequirements(userInfo);
464 } catch (Exception e) {
465 if (authDebug.messageEnabled()) {
466 authDebug.message(
467 "Error: submitRequirements with userInfo : "
468 + e.getMessage());
469 }
470 throw new AuthLoginException(e);
471 }
472 }
473 }
474 try {
475 if (getStatus() == AuthContext.Status.SUCCESS) {
476 ssoToken = getSSOToken();
477 }
478 } catch (Exception e) {
479 if (authDebug.messageEnabled()) {
480 authDebug.message("Error: getSSOToken : " + e.getMessage());
481 }
482 throw new AuthLoginException(e);
483 }
484 return ssoToken;
485 }
486
487 /**
488 * Starts the login process for the given <code>AuthContext</code> object
489 * identified by the index type and index name with default parameters.
490 * The <code>IndexType</code> defines the possible kinds of "objects"
491 * or "resources" for which an authentication can be performed. Currently
492 * supported index types are users, roles, services (or application),
493 * levels and mechanism/authentication modules.
494 *
495 * @param indexType authentication index type.
496 * @param indexName authentication index name.
497 * @param params contains the default values for the callbacks. The order
498 * of this array matches the callbacks order for this login process.
499 * value for the <code>PasswordCallback</code> is also in String
500 * format, it will be converted to <code>char[]</code> when it is
501 * set to the callback. Internal processing for this string array
502 * uses <code>|</code> as separator. Hence <code>|</code> should not
503 * be used in these default values. Currently only
504 * <code>NameCallback</code> and <code>PasswordCallback</code> are
505 * supported.
506 * @exception AuthLoginException if an error occurred during login.
507 *
508 * @supported.api
509 */
510 public void login(IndexType indexType, String indexName, String[] params)
511 throws AuthLoginException {
512 login(indexType, indexName, params, false);
513 }
514
515 private void login(
516 IndexType indexType,
517 String indexName,
518 String[] params,
519 boolean pCookie
520 ) throws AuthLoginException {
521 login(indexType, indexName, params, false, null);
522 }
523
524 private void login(
525 IndexType indexType,
526 String indexName,
527 String[] params,
528 boolean pCookie,
529 String locale
530 ) throws AuthLoginException {
531 if (ssoToken != null) {
532 try {
533 organizationName = ssoToken.getProperty(
534 ISAuthConstants.ORGANIZATION);
535 ssoTokenID = ssoToken.getTokenID().toString();
536 authURL = Session.getSession(
537 new SessionID(ssoTokenID)).getSessionServiceURL();
538 } catch (Exception e) {
539 throw new AuthLoginException(e);
540 }
541 }
542
543 if (authURL != null) {
544 authServiceURL = getAuthServiceURL(authURL.getProtocol(),
545 authURL.getHost(), Integer.toString(authURL.getPort()),
546 authURL.getPath());
547 }
548
549 AuthLoginException authException = null;
550 try {
551 if (authServiceURL == null) {
552 authServiceURL = getAuthServiceURL( server_proto,
553 server_host, server_port, server_uri);
554 }
555 if (authServiceURL != null) {
556 if (authDebug.messageEnabled()) {
557 authDebug.message("AuthContext.login : runLogin against "
558 + authServiceURL);
559 }
560 runLogin(indexType, indexName, params, pCookie, locale);
561 return;
562 }
563 } catch (AuthLoginException e) {
564 authException = e;
565 authDebug.error("Failed to login to " + authServiceURL);
566 } catch (Exception e) {
567 authDebug.error("Failed to login to " + authServiceURL
568 + ": " + e.getMessage(),e);
569 }
570
571 if (authURL == null) {
572 // failover when authURL is not specified
573 Vector serviceURLs = null;
574 try {
575 serviceURLs = WebtopNaming.getServiceAllURLs(
576 AuthXMLTags.AUTH_SERVICE);
577 } catch (Exception e) {
578 throw new AuthLoginException(amAuthContext, "loginError",
579 new Object[]{e.getMessage()});
580 }
581
582 if (authDebug.messageEnabled()) {
583 authDebug.message("Org Name : " + organizationName);
584 authDebug.message("ssoTokenID: " + ssoTokenID);
585 authDebug.message("serviceURLs: " + serviceURLs);
586 }
587
588 if (serviceURLs != null) {
589 serviceURLs.remove(authServiceURL);
590 for (Enumeration e = serviceURLs.elements();
591 e.hasMoreElements(); ) {
592 authServiceURL = (URL)e.nextElement();
593 try {
594 runLogin(indexType, indexName, params, pCookie, locale);
595 return;
596 } catch (AuthLoginException ex) {
597 authException = ex;
598 authDebug.error("Failed to login in failover with " +
599 authServiceURL + ": " + ex.getMessage());
600 }
601 }
602 }
603 }
604 authDebug.error("Authentication failed.");
605 if (authException != null) {
606 throw authException;
607 } else {
608 throw new AuthLoginException(amAuthContext, "loginError",null);
609 }
610 }
611
612
613 private void runLogin(
614 IndexType indexType,
615 String indexName,
616 String[] params,
617 boolean pCookie,
618 String locale
619 ) throws AuthLoginException {
620 if (!localFlag) {
621 setLocalFlag(authServiceURL);
622 }
623
624 if (appSSOToken == null) {
625 if (!((indexType == IndexType.MODULE_INSTANCE) &&
626 (indexName.equals("Application")))){
627 try {
628 appSSOToken = (SSOToken) AccessController.doPrivileged(
629 AdminTokenAction.getInstance());
630 } catch (AMSecurityPropertiesException propExp) {
631 // Ignore the Exception and continue without App SSO Token.
632 if (authDebug.messageEnabled()) {
633 authDebug.message("AuthContext.runLogin: "
634 + "Runtime Exception" + propExp.getMessage());
635 authDebug.message("AuthContext.runLogin: Not "
636 + "able to get appSSOToken, continuing without "
637 + "appSSOToken");
638 }
639 }
640 if (appSSOToken == null) {
641 authDebug.message("Null App SSO Token");
642 }
643 }
644 if (authDebug.messageEnabled()) {
645 authDebug.message("Obtained App Token= "+appSSOToken);
646 }
647 }
648
649 if (localFlag) {
650 try {
651 if (ssoTokenID == null) {
652 acLocal = com.sun.identity.authentication.service.AuthUtils.
653 getAuthContext(organizationName);
654 } else {
655 if (authDebug.messageEnabled()) {
656 authDebug.message("AuthContext.runLogin: "
657 + "ForceAuth = "+forceAuth);
658 }
659 acLocal = com.sun.identity.authentication.service.AuthUtils.
660 getAuthContext(organizationName, ssoTokenID, false,
661 null, null, null, forceAuth);
662 }
663 acLocal.login(indexType, indexName, pCookie, locale);
664 } catch (AuthException e) {
665 throw new AuthLoginException(e);
666 }
667 if (acLocal.getStatus().equals(Status.SUCCESS)) {
668 onSuccessLocal();
669 }
670 return;
671 }
672
673 // Check if 7.0 RR stype protocol needs to be used
674 // This will setup NewAuthContext and authHandles
675 if (useOldStyleRemoteAuthentication) {
676 runRemoteOldAuthContext();
677 if (loginException != null) {
678 throw loginException;
679 }
680 }
681 // Run Login
682 runRemoteLogin(indexType, indexName, params, pCookie, locale);
683
684 if (authDebug.messageEnabled()) {
685 authDebug.message("useNewStyleRemoteAuthentication : "
686 + useNewStyleRemoteAuthentication);
687 authDebug.message("useOldStyleRemoteAuthentication : "
688 + useOldStyleRemoteAuthentication);
689 authDebug.message("receivedDocument : " + receivedDocument);
690 authDebug.message("loginException : " + loginException);
691 }
692
693 // If "Login" fails and we have not set 6.3, 7.0 RR style protocol
694 // the server could be either 6.3 or 7.0 RR. Hence try "NewAuthContext"
695 // and then "Login"
696 if (!useNewStyleRemoteAuthentication &&
697 !useOldStyleRemoteAuthentication &&
698 (receivedDocument == null ||
699 (getAuthenticationHandle(receivedDocument)).equals("null")) &&
700 loginException != null) {
701 if (authDebug.messageEnabled()) {
702 authDebug.message("AuthContext: trying 6.3 style remote " +
703 "AuthN and setting the flag to use 6.3 style");
704 }
705 useOldStyleRemoteAuthentication = true;
706 // Server could be either 6.3 or 7.0 RR, try old style
707 // Construct the Request XML with New AuthContext parameters
708 loginException = null; // Reset loginException
709 runRemoteOldAuthContext();
710 if (loginException != null) {
711 throw loginException;
712 }
713 // Re-try login process with AuthIdentifier
714 runRemoteLogin(indexType, indexName, params, pCookie, locale);
715 } else if (!useNewStyleRemoteAuthentication) {
716 useNewStyleRemoteAuthentication = true;
717 }
718 if (loginException != null) {
719 throw loginException;
720 }
721 }
722
723 private void runRemoteLogin(IndexType indexType, String indexName,
724 String[] params, boolean pCookie, String locale)
725 throws AuthLoginException {
726 try {
727 String xmlString = null;
728 // remote auth
729 StringBuffer request = new StringBuffer(100);
730 String[] authHandles = new String[1];
731 authHandles[0] = getAuthHandle();
732 if ((ssoTokenID != null) && (authHandles[0].equals("0"))) {
733 if (authDebug.messageEnabled()) {
734 authDebug.message("AuthContext.runRemoteLogin: Found"
735 + " SSOTokenID " + ssoTokenID);
736 }
737 authHandles[0] = ssoTokenID;
738 }
739
740 request.append(MessageFormat.format(
741 AuthXMLTags.XML_REQUEST_PREFIX,authHandles));
742 if (appSSOToken != null) {
743 request.append(AuthXMLTags.APPSSOTOKEN_BEGIN);
744 request.append(appSSOToken.getTokenID().toString()).
745 append(AuthXMLTags.APPSSOTOKEN_END);
746 }
747 request.append(AuthXMLTags.LOGIN_BEGIN);
748
749 if (!useOldStyleRemoteAuthentication) {
750 request.append(AuthXMLTags.SPACE)
751 .append(AuthXMLTags.ORG_NAME_ATTR)
752 .append(AuthXMLTags.EQUAL)
753 .append(AuthXMLTags.QUOTE)
754 .append(XMLUtils.escapeSpecialCharacters(organizationName))
755 .append(AuthXMLTags.QUOTE);
756 if (hostName != null) {
757 request.append(AuthXMLTags.SPACE)
758 .append(AuthXMLTags.HOST_NAME_ATTR)
759 .append(AuthXMLTags.EQUAL)
760 .append(AuthXMLTags.QUOTE)
761 .append(XMLUtils.escapeSpecialCharacters(hostName))
762 .append(AuthXMLTags.QUOTE);
763 }
764 if (forceAuth) {
765 request.append(AuthXMLTags.SPACE)
766 .append(AuthXMLTags.FORCE_AUTH_ATTR)
767 .append(AuthXMLTags.EQUAL)
768 .append(AuthXMLTags.QUOTE)
769 .append("true")
770 .append(AuthXMLTags.QUOTE);
771 }
772 }
773 request.append(AuthXMLTags.ELEMENT_END);
774
775 if (indexType != null) {
776 request.append(AuthXMLTags.INDEX_TYPE_PAIR_BEGIN)
777 .append(AuthXMLTags.SPACE)
778 .append(AuthXMLTags.INDEX_TYPE)
779 .append(AuthXMLTags.EQUAL)
780 .append(AuthXMLTags.QUOTE);
781
782 if (indexType == IndexType.USER) {
783 request.append(AuthXMLTags.INDEX_TYPE_USER_ATTR);
784 } else if (indexType == IndexType.ROLE) {
785 request.append(AuthXMLTags.INDEX_TYPE_ROLE_ATTR);
786 } else if (indexType == IndexType.SERVICE) {
787 request.append(AuthXMLTags.INDEX_TYPE_SVC_ATTR);
788 } else if (indexType == IndexType.MODULE_INSTANCE) {
789 request.append(AuthXMLTags.INDEX_TYPE_MODULE_ATTR);
790 } else if (indexType == IndexType.LEVEL) {
791 request.append(AuthXMLTags.INDEX_TYPE_LEVEL_ATTR);
792 } else if (indexType == IndexType.COMPOSITE_ADVICE) {
793 request.append(
794 AuthXMLTags.INDEX_TYPE_COMPOSITE_ADVICE_ATTR);
795 }
796 request.append(AuthXMLTags.QUOTE)
797 .append(AuthXMLTags.ELEMENT_END)
798 .append(AuthXMLTags.INDEX_NAME_BEGIN)
799 .append(indexName)
800 .append(AuthXMLTags.INDEX_NAME_END)
801 .append(AuthXMLTags.INDEX_TYPE_PAIR_END);
802 }
803
804 if (locale != null && locale.length() > 0) {
805 request.append(AuthXMLTags.LOCALE_BEGIN);
806 request.append(locale);
807 request.append(AuthXMLTags.LOCALE_END);
808 }
809
810 if (params != null) {
811 StringBuffer paramString = new StringBuffer();
812 for (int i = 0; i < params.length; i++) {
813 if (i != 0 ) {
814 paramString.append(ISAuthConstants.PIPE_SEPARATOR);
815 }
816 paramString.append(params[i]);
817 }
818 request.append(AuthXMLTags.PARAMS_BEGIN)
819 .append(paramString.toString())
820 .append(AuthXMLTags.PARAMS_END);
821 }
822 request.append(AuthXMLTags.LOGIN_END)
823 .append(AuthXMLTags.XML_REQUEST_SUFFIX);
824 xmlString = request.toString();
825
826 // process the request, which will check for exceptions
827 // and also get the authentication handle ID
828 receivedDocument = processRequest(xmlString);
829
830 // Check set the login status
831 checkAndSetLoginStatus();
832 } catch (AuthLoginException le) {
833 // Login has failed
834 loginStatus = Status.FAILED;
835 loginException = le;
836 }
837 }
838
839 private void runRemoteOldAuthContext() throws AuthLoginException {
840 try {
841 StringBuffer request = new StringBuffer(100);
842 String[] objs = { "0" };
843 if (ssoTokenID != null) {
844 objs[0] = ssoTokenID;
845 }
846 request.append(MessageFormat.format(
847 AuthXMLTags.XML_REQUEST_PREFIX, (Object[])objs))
848 .append(AuthXMLTags.NEW_AUTHCONTEXT_BEGIN)
849 .append(AuthXMLTags.SPACE)
850 .append(AuthXMLTags.ORG_NAME_ATTR)
851 .append(AuthXMLTags.EQUAL)
852 .append(AuthXMLTags.QUOTE)
853 .append(XMLUtils.escapeSpecialCharacters(organizationName))
854 .append(AuthXMLTags.QUOTE)
855 .append(AuthXMLTags.ELEMENT_END)
856 .append(AuthXMLTags.NEW_AUTHCONTEXT_END)
857 .append(AuthXMLTags.XML_REQUEST_SUFFIX);
858 // process the request, which will check for exceptions
859 // and also get the authentication handle ID
860 receivedDocument = processRequest(request.toString());
861
862 // Check set the login status
863 checkAndSetLoginStatus();
864 } catch (AuthLoginException le) {
865 // Login has failed
866 loginStatus = Status.FAILED;
867 loginException = le;
868 }
869 }
870
871 /**
872 * Returns the set of Principals or Subject the user has been
873 * authenticated as.
874 * This should be invoked only after successful authentication.
875 *
876 * @return <code>Subject</code> for the authenticated User.
877 * If the authentication fails or the authentication is in process,
878 * this will return <code>null</code>.
879 *
880 * @supported.api
881 */
882 public Subject getSubject() {
883 if (localFlag) {
884 if (!acLocal.getStatus().equals(Status.SUCCESS)) {
885 return (null);
886 }
887 return (acLocal.getSubject());
888 } else {
889 if (!loginStatus.equals(Status.SUCCESS)) {
890 return (null);
891 }
892 return (getSubject(receivedDocument));
893 }
894 }
895
896 /**
897 * Returns a <code>Map</code> object that
898 * that contains cookies set by AM server
899 *
900 * @return a <code>Map</code> of cookie name and
901 * <code>Cookie</code> object.
902 */
903 public Map getCookieTable() {
904 return cookieTable;
905 }
906
907 /**
908 * Returns <code>true</code> if the login process requires more
909 * information from the user to complete the authentication.
910 * <p>
911 * NOTE: This method has to be called as a condition of a
912 * <code>while</code> loop in order to complete the authentication process
913 * and get the correct <code>Status</code> after submitting the
914 * requirements.
915 *
916 * @return <code>true</code> if more credentials are required from the user.
917 *
918 * @supported.api
919 */
920 public boolean hasMoreRequirements() {
921 if (localFlag) {
922 return (acLocal.hasMoreRequirements(false));
923 } else {
924 if ((!loginStatus.equals(Status.IN_PROGRESS)) ||
925 ((getCallbacks(receivedDocument, false)) == null)) {
926 return (false);
927 }
928 return (true);
929 }
930 }
931
932 /**
933 * Returns <code>true</code> if the login process requires more information
934 * from the user to complete the authentication.
935 *
936 * NOTE: This method has to be called as a condition of a <ode>while</code>
937 * loop in order to complete the authentication process and get the correct
938 * <code>Status</code> after submitting the requirements.
939 *
940 * @param noFilter flag indicates whether to filter
941 * <code>PagePropertiesCallback</code> or not. Value
942 * <code>true</code> will not filter
943 * <code>PagePropertiesCallback</code>.
944 * @return <code>true</code> if more credentials are required from the user.
945 *
946 * @supported.api
947 */
948 public boolean hasMoreRequirements(boolean noFilter) {
949 if (localFlag) {
950 return (acLocal.hasMoreRequirements(noFilter));
951 } else {
952 if ((!loginStatus.equals(Status.IN_PROGRESS)) ||
953 ((getCallbacks(receivedDocument, noFilter)) == null)) {
954 return (false);
955 }
956 return (true);
957 }
958 }
959
960 /**
961 * Returns an array of <code>Callback</code> objects that must be populated
962 * by the user and returned back. These objects are requested by the
963 * authentication plug-ins, and these are usually displayed to the user.
964 * The user then provides the requested information for it to be
965 * authenticated.
966 *
967 * @return an array of <code>Callback</code> objects requesting credentials
968 * from user
969 *
970 * @supported.api
971 */
972 public Callback[] getRequirements() {
973 if (localFlag) {
974 if (!acLocal.getStatus().equals(Status.IN_PROGRESS)) {
975 return (null);
976 }
977 return (acLocal.getRequirements(false));
978 } else {
979 if (!loginStatus.equals(Status.IN_PROGRESS)) {
980 return (null);
981 }
982 return (getCallbacks(receivedDocument, false));
983 }
984 }
985
986 /**
987 * Returns an array of <code>Callback</code> objects that
988 * must be populated by the user and returned back.
989 * These objects are requested by the authentication plug-ins,
990 * and these are usually displayed to the user. The user then provides
991 * the requested information for it to be authenticated.
992 *
993 * @param noFilter boolean flag indicating whether to filter
994 * <code>PagePropertiesCallback</code> or not. Value <code>true</code> will
995 * not filter <code>PagePropertiesCallback</code>.
996 *
997 * @return an array of <code>Callback</code> objects requesting credentials
998 * from user
999 *
1000 * @supported.api
1001 */
1002 public Callback[] getRequirements(boolean noFilter) {
1003 if (localFlag) {
1004 if (!acLocal.getStatus().equals(Status.IN_PROGRESS)) {
1005 return (null);
1006 }
1007 return (acLocal.getRequirements(noFilter));
1008 } else {
1009 if (!loginStatus.equals(Status.IN_PROGRESS)) {
1010 return (null);
1011 }
1012 return (getCallbacks(receivedDocument, noFilter));
1013 }
1014 }
1015
1016 /**
1017 * Submits the populated <code>Callback</code> objects to the
1018 * authentication plug-in modules. Called after <code>getRequirements</code>
1019 * method and obtaining user's response to these requests.
1020 *
1021 * @param info Array of <code>Callback</code> objects.
1022 *
1023 * @supported.api
1024 */
1025 public void submitRequirements(Callback[] info) {
1026 if (authDebug.messageEnabled()) {
1027 authDebug.message("submitRequirements with Callbacks : " + info);
1028 }
1029
1030 if (localFlag) {
1031 // Check if we are still in login session
1032 if (!acLocal.getStatus().equals(Status.IN_PROGRESS)) {
1033 return;
1034 }
1035 acLocal.submitRequirements(info);
1036 if (acLocal.getStatus().equals(Status.SUCCESS)) {
1037 onSuccessLocal();
1038 }
1039 return;
1040 } else {
1041 // Check if we are still in login session
1042 if (!loginStatus.equals(Status.IN_PROGRESS)) {
1043 return;
1044 }
1045
1046 // Construct the XML
1047 try {
1048 StringBuffer xml = new StringBuffer(100);
1049 String[] authHandles = new String[1];
1050 authHandles[0] = getAuthenticationHandle(receivedDocument);
1051 xml.append(MessageFormat.format(
1052 AuthXMLTags.XML_REQUEST_PREFIX,authHandles));
1053 if (appSSOToken != null) {
1054 xml.append(AuthXMLTags.APPSSOTOKEN_BEGIN);
1055 xml.append(appSSOToken.getTokenID().toString()).
1056 append(AuthXMLTags.APPSSOTOKEN_END);
1057 }
1058 xml.append(AuthXMLTags.SUBMIT_REQS_BEGIN)
1059 .append(AuthXMLUtils.getXMLForCallbacks(info))
1060 .append(AuthXMLTags.SUBMIT_REQS_END)
1061 .append(AuthXMLTags.XML_REQUEST_SUFFIX);
1062
1063 // Send the request to be processes
1064 receivedDocument = processRequest(xml.toString());
1065
1066 // Check set the login status
1067 checkAndSetLoginStatus();
1068 } catch (AuthLoginException le) {
1069 // Login has failed
1070 loginStatus = Status.FAILED;
1071 loginException = le;
1072 }
1073 }
1074 }
1075
1076 /**
1077 * Logs out the user and also invalidates the single sign on token
1078 * associated with this <code>AuthContext</code>.
1079 *
1080 * @throws AuthLoginException if an error occurred during logout.
1081 *
1082 * @supported.api
1083 */
1084 public void logout() throws AuthLoginException {
1085 if (localFlag) {
1086 acLocal.logout();
1087 return;
1088 }
1089
1090 // Construct the XML
1091 try {
1092 StringBuffer xml = new StringBuffer(100);
1093 String[] authHandles = new String[1];
1094 authHandles[0] = getAuthenticationHandle(receivedDocument);
1095 xml.append(MessageFormat.format(AuthXMLTags.XML_REQUEST_PREFIX,
1096 authHandles));
1097 if (appSSOToken != null) {
1098 xml.append(AuthXMLTags.APPSSOTOKEN_BEGIN);
1099 xml.append(appSSOToken.getTokenID().toString()).
1100 append(AuthXMLTags.APPSSOTOKEN_END);
1101 }
1102 xml.append(AuthXMLTags.LOGOUT_BEGIN)
1103 .append(AuthXMLTags.LOGOUT_END)
1104 .append(AuthXMLTags.XML_REQUEST_SUFFIX);
1105
1106 // Send the request to be processes
1107 receivedDocument = processRequest(xml.toString());
1108
1109 // Check set the login status
1110 checkAndSetLoginStatus();
1111 } catch (AuthLoginException le) {
1112 // Login has failed
1113 loginStatus = Status.FAILED;
1114 loginException = le;
1115 }
1116 }
1117
1118 /**
1119 * Returns login exception, if any, during the authentication process.
1120 * Typically set when the login fails.
1121 *
1122 * @return login exception.
1123 * @supported.api
1124 */
1125 public AuthLoginException getLoginException() {
1126 if (localFlag) {
1127 return (acLocal.getLoginException());
1128 } else {
1129 return (loginException);
1130 }
1131 }
1132
1133 /**
1134 * Returns the Single-Sign-On (SSO) Token for the authenticated
1135 * user. If the user has not successfully authenticated
1136 * <code>Exception</code> will be thrown.
1137 * <p>
1138 * Single sign token can be used as the authenticated token.
1139 *
1140 * @return Single-Sign-On token for the valid user after successful
1141 * authentication.
1142 * @throws Exception if the user is not authenticated or an error is
1143 * encountered in retrieving the user's single sign on token.
1144 * @supported.api
1145 */
1146 public SSOToken getSSOToken() throws Exception {
1147 if (localFlag) {
1148 if (!acLocal.getStatus().equals(Status.SUCCESS)) {
1149 throw new L10NMessageImpl(
1150 amAuthContext, "statusNotSuccess", null);
1151 }
1152 return (acLocal.getSSOToken());
1153 } else {
1154 // Get the loginStatus node
1155 if (!loginStatus.equals(Status.SUCCESS)) {
1156 throw new L10NMessageImpl(
1157 amAuthContext, "statusNotSuccess", null);
1158 }
1159 Node loginStatusNode = XMLUtils.getRootNode(receivedDocument,
1160 AuthXMLTags.LOGIN_STATUS);
1161 if (loginStatusNode == null) {
1162 throw new L10NMessageImpl(amAuthContext, "noStatusNode", null);
1163 }
1164
1165 String ssoTokenID = XMLUtils.getNodeAttributeValue(loginStatusNode,
1166 AuthXMLTags.SSOTOKEN);
1167 try {
1168 return (SSOTokenManager.getInstance().createSSOToken(
1169 ssoTokenID));
1170 } catch (SSOException ssoe) {
1171 throw new L10NMessageImpl(
1172 amAuthContext, "createSSOTokenError", null);
1173 }
1174 }
1175 }
1176
1177 /**
1178 * Returns the current status of the authentication process as
1179 * <code>AuthContext.Status</code>.
1180 *
1181 * @return <code>Status</code> of the authentication process.
1182 *
1183 * @supported.api
1184 */
1185 public Status getStatus() {
1186 if (localFlag) {
1187 return (acLocal.getStatus());
1188 } else {
1189 return (loginStatus);
1190 }
1191 }
1192
1193 /**
1194 * Returns the current Auth Identifier of the authentication
1195 * process as String Session ID.
1196 *
1197 * @return Auth Identifier of the authentication process.
1198 */
1199 public String getAuthIdentifier() {
1200 if (localFlag) {
1201 return (acLocal.getAuthIdentifier());
1202 } else {
1203 return (getAuthHandle());
1204 }
1205 }
1206
1207 /**
1208 * Returns the Successful Login URL for the authenticated user.
1209 *
1210 * @return the Successful Login URL for the authenticated user.
1211 * @throws Exception if it fails to get url for auth success
1212 */
1213 public String getSuccessURL() throws Exception {
1214 if (localFlag) {
1215 if (!acLocal.getStatus().equals(Status.SUCCESS)) {
1216 throw new
1217 L10NMessageImpl(amAuthContext, "statusNotSuccess", null);
1218 }
1219 return (acLocal.getSuccessURL());
1220 } else {
1221 // Get the loginStatus node
1222 if (!loginStatus.equals(Status.SUCCESS)) {
1223 throw new
1224 L10NMessageImpl(amAuthContext, "statusNotSuccess", null);
1225 }
1226 Node loginStatusNode = XMLUtils.getRootNode(receivedDocument,
1227 AuthXMLTags.LOGIN_STATUS);
1228 if (loginStatusNode == null) {
1229 throw new L10NMessageImpl(amAuthContext, "noStatusNode", null);
1230 }
1231 return (XMLUtils.getNodeAttributeValue(loginStatusNode,
1232 AuthXMLTags.SUCCESS_URL));
1233 }
1234 }
1235
1236 /**
1237 * Returns the Failure Login URL for the authenticating user.
1238 *
1239 * @return the Failure Login URL for the authenticating user
1240 * @throws Exception if it fails to get url for auth failure
1241 */
1242 public String getFailureURL() throws Exception {
1243 if (localFlag) {
1244 return (acLocal.getFailureURL());
1245 } else {
1246 // Get the loginStatus node
1247 Node loginStatusNode = XMLUtils.getRootNode(receivedDocument,
1248 AuthXMLTags.LOGIN_STATUS);
1249 if (loginStatusNode == null) {
1250 throw new L10NMessageImpl(amAuthContext, "noStatusNode", null);
1251 }
1252 return (XMLUtils.getNodeAttributeValue(loginStatusNode,
1253 AuthXMLTags.FAILURE_URL));
1254 }
1255 }
1256
1257 /**
1258 * Resets this instance of <code>AuthContext</code> object, so that a new
1259 * login process can be initiated. A new authentication process can started
1260 * using any one of the <code>login</code> methods.
1261 */
1262 public void reset() {
1263 loginStatus = Status.NOT_STARTED;
1264 //organizationName = null;
1265 //receivedDocument = null;
1266 //loginException = null;
1267 }
1268
1269 /**
1270 * Returns the the organization name that was set during the
1271 * <code>AuthContext</code> constructor.
1272 *
1273 * @return Organization name in the <code>AuthContext</code>.
1274 *
1275 * @supported.api
1276 */
1277 public String getOrganizationName() {
1278 return (this.organizationName);
1279 }
1280
1281 /**
1282 *
1283 * Returns authentication module/s instances (or plugins) configured
1284 * for a organization, or sub-organization name that was set during the
1285 * <code>AuthContext</code> constructor.
1286 *
1287 * @return Set of Module instance names.
1288 *
1289 * @supported.api
1290 */
1291 public Set getModuleInstanceNames() {
1292 if (authURL != null) {
1293 authServiceURL = getAuthServiceURL(
1294 authURL.getProtocol(),
1295 authURL.getHost(),
1296 Integer.toString(authURL.getPort()),
1297 authURL.getPath());
1298 }
1299 if (!localFlag) {
1300 setLocalFlag(authServiceURL);
1301 }
1302 if (localFlag) {
1303 return (acLocal.getModuleInstanceNames());
1304 } else {
1305 if (authServiceURL == null) {
1306 try {
1307 authServiceURL = getAuthServiceURL(server_proto,
1308 server_host, server_port, server_uri);
1309 } catch (Exception e) {
1310 return Collections.EMPTY_SET;
1311 }
1312 }
1313 sendQueryInformation(AuthXMLTags.MODULE_INSTANCE);
1314
1315 //Receive data
1316 Node queryResultNode = XMLUtils.getRootNode(receivedDocument,
1317 AuthXMLTags.QUERY_RESULT);
1318 if (queryResultNode == null) {
1319 return (null);
1320 }
1321
1322 // Iteratate through moduleInstanceNames
1323 HashSet moduleInstanceNames = new HashSet();
1324 NodeList childNodes = queryResultNode.getChildNodes();
1325 if ( childNodes != null ) {
1326 for (int i = 0; i < childNodes.getLength(); i++) {
1327 Node childNode = childNodes.item(i);
1328 String moduleName = XMLUtils.getValueOfValueNode(childNode);
1329 moduleInstanceNames.add(moduleName);
1330 }
1331 }
1332 return (moduleInstanceNames);
1333 }
1334 }
1335
1336 /**
1337 * Terminates an ongoing <code>login</code> call that has not yet completed.
1338 *
1339 * @exception AuthLoginException if an error occurred during abort.
1340 *
1341 * @supported.api
1342 */
1343 public void abort() throws AuthLoginException {
1344 if (localFlag) {
1345 acLocal.abort();
1346 return;
1347 }
1348
1349 // Construct the XML
1350 try {
1351 StringBuffer xml = new StringBuffer(100);
1352 String[] authHandles = new String[1];
1353 authHandles[0] = getAuthenticationHandle(receivedDocument);
1354 xml.append(MessageFormat.format(AuthXMLTags.XML_REQUEST_PREFIX,
1355 authHandles));
1356 if (appSSOToken != null) {
1357 xml.append(AuthXMLTags.APPSSOTOKEN_BEGIN);
1358 xml.append(appSSOToken.getTokenID().toString()).
1359 append(AuthXMLTags.APPSSOTOKEN_END);
1360 }
1361 xml.append(AuthXMLTags.ABORT_BEGIN)
1362 .append(AuthXMLTags.ABORT_END)
1363 .append(AuthXMLTags.XML_REQUEST_SUFFIX);
1364
1365 // Send the request to be processes
1366 receivedDocument = processRequest(xml.toString());
1367
1368 // Check set the login status
1369 checkAndSetLoginStatus();
1370 } catch (AuthLoginException le) {
1371 // Login has failed
1372 loginStatus = Status.FAILED;
1373 loginException = le;
1374 }
1375 }
1376
1377 /**
1378 * Sets the password for the certificate database.
1379 * It is required to call only once to initialize certificate database if
1380 * the password is not set in the password file (specified as
1381 * the value for <code>com.iplanet.am.admin.cli.certdb.passfile</code>
1382 * in <code>AMConfig.properties</code>). If both are set, this method will
1383 * overwrite the value in certificate password file.
1384 *
1385 * @param password Password for the certificate database.
1386 *
1387 * @supported.api
1388 */
1389 public static void setCertDBPassword(String password) {
1390 try {
1391 if (usingJSSEHandler) {
1392 Class pcbClass = (Class) Class.forName(JSSE_PASSWORD_CALLBACK);
1393 Object passwdCallback = (Object) pcbClass.newInstance();
1394 Method method =
1395 pcbClass.getMethod("setPassword", new Class[] { String.class });
1396 KeyStore keystore = (KeyStore)method.invoke(
1397 passwdCallback, new Object[] { password });
1398 } else {
1399 Class initializer = Class.forName(JSS_PASSWORD_UTIL);
1400 Constructor initializerConstructor = initializer.getConstructor(
1401 new Class[] { String.class });
1402 initializerConstructor.newInstance(new Object[] { password });
1403 }
1404 } catch (Exception e) {
1405 e.printStackTrace();
1406 authDebug.message("Error in setCertDBPassword : " + e.getMessage());
1407 }
1408 }
1409
1410
1411 /**
1412 * Returns the error template.
1413 *
1414 * @return error template.
1415 */
1416 public String getErrorTemplate() {
1417 if (localFlag) {
1418 return (acLocal.getErrorTemplate());
1419 } else {
1420 String errTemplate = "";
1421 Node exceptionNode = XMLUtils.getRootNode(receivedDocument,
1422 AuthXMLTags.EXCEPTION);
1423 if (exceptionNode != null) {
1424 errTemplate = XMLUtils.getNodeAttributeValue(exceptionNode,
1425 AuthXMLTags.TEMPLATE_NAME);
1426 }
1427 return errTemplate;
1428 }
1429 }
1430
1431 /**
1432 * Returns the error message.
1433 *
1434 * @return error message.
1435 */
1436 public String getErrorMessage() {
1437 if (localFlag) {
1438 return (acLocal.getErrorMessage());
1439 } else {
1440 String errMessage = null;
1441 Node exceptionNode = XMLUtils.getRootNode(receivedDocument,
1442 AuthXMLTags.EXCEPTION);
1443 if (exceptionNode != null) {
1444 errMessage = XMLUtils.getNodeAttributeValue(exceptionNode,
1445 AuthXMLTags.MESSAGE);
1446 }
1447 return errMessage;
1448 }
1449 }
1450
1451 /**
1452 * Returns error code.
1453 *
1454 * @return error code.
1455 */
1456 public String getErrorCode() {
1457 if (localFlag) {
1458 return (acLocal.getErrorCode());
1459 } else {
1460 String errCode = "";
1461 Node exceptionNode = XMLUtils.getRootNode(receivedDocument,
1462 AuthXMLTags.EXCEPTION);
1463 if (exceptionNode != null) {
1464 errCode = XMLUtils.getNodeAttributeValue(exceptionNode,
1465 AuthXMLTags.ERROR_CODE);
1466 }
1467 return errCode;
1468 }
1469 }
1470
1471 /**
1472 * Sets the client's hostname or IP address.This could be used
1473 * by the policy component to restrict access to resources.
1474 * This method must be called before calling <code>login</code> method.
1475 * If it is called after calling <code>login</code> then
1476 * it is ineffective.
1477 *
1478 * @param hostname hostname or ip address
1479 *
1480 * iPlanet-PUBLIC-METHOD
1481 */
1482 public void setClientHostName(String hostname) {
1483 this.hostName = hostname;
1484 }
1485
1486 /**
1487 * Returns the client's hostname or IP address as set by
1488 * setClientHostName
1489 *
1490 * @return hostname/IP address
1491 *
1492 * iPlanet-PUBLIC-METHOD
1493 */
1494 public String getClientHostName() {
1495 return (hostName);
1496 }
1497
1498
1499 private AuthLoginException checkException(){
1500 AuthLoginException exception = null;
1501 String error = getErrorCode();
1502 if (error != null && error.length() != 0){
1503 exception = new AuthLoginException("amAuth", error, null);
1504 } else {
1505 error = getErrorMessage();
1506 if (error != null && error.length() != 0) {
1507 exception = new AuthLoginException(error);
1508 }
1509 }
1510 return exception;
1511 }
1512
1513 protected void checkAndSetLoginStatus(){
1514
1515 Node loginStatusNode = XMLUtils.getRootNode(
1516 receivedDocument, AuthXMLTags.LOGIN_STATUS);
1517 if (loginStatusNode == null) {
1518 loginException = checkException();
1519 } else {
1520 // Get the status attribute
1521 String status = XMLUtils.getNodeAttributeValue(
1522 loginStatusNode, AuthXMLTags.STATUS);
1523 if (status != null) {
1524 if (status.equals("success")) {
1525 loginStatus = Status.SUCCESS;
1526 } else if (status.equals("failed")) {
1527 loginStatus = Status.FAILED;
1528 loginException = checkException();
1529 } else if (status.equals("completed")) {
1530 loginStatus = Status.COMPLETED;
1531 } else if (status.equals("in_progress")) {
1532 loginStatus = Status.IN_PROGRESS;
1533 }
1534 }
1535 if (authDebug.messageEnabled()) {
1536 authDebug.message("LoginStatus : " + loginStatus);
1537 }
1538 }
1539 }
1540
1541 protected void sendQueryInformation(String reqInfo) {
1542 // Construct the XML
1543 try {
1544 StringBuffer xml = new StringBuffer(100);
1545 String[] authHandles = new String[1];
1546 authHandles[0] = getAuthHandle();
1547
1548 xml.append(MessageFormat.format(AuthXMLTags.XML_REQUEST_PREFIX,
1549 authHandles));
1550 if (appSSOToken != null) {
1551 xml.append(AuthXMLTags.APPSSOTOKEN_BEGIN);
1552 xml.append(appSSOToken.getTokenID().toString()).
1553 append(AuthXMLTags.APPSSOTOKEN_END);
1554 }
1555 xml.append(AuthXMLTags.QUERY_INFO_BEGIN)
1556 .append(AuthXMLTags.SPACE)
1557 .append(AuthXMLTags.REQUESTED_INFO)
1558 .append(AuthXMLTags.EQUAL)
1559 .append(AuthXMLTags.QUOTE)
1560 .append(reqInfo)
1561 .append(AuthXMLTags.QUOTE);
1562
1563 if (authHandles[0].equals("0")) {
1564 xml.append(AuthXMLTags.SPACE)
1565 .append(AuthXMLTags.ORG_NAME_ATTR)
1566 .append(AuthXMLTags.EQUAL)
1567 .append(AuthXMLTags.QUOTE)
1568 .append(XMLUtils.escapeSpecialCharacters(organizationName))
1569 .append(AuthXMLTags.QUOTE);
1570 }
1571
1572 xml.append(AuthXMLTags.ELEMENT_END)
1573 .append(AuthXMLTags.QUERY_INFO_END)
1574 .append(AuthXMLTags.XML_REQUEST_SUFFIX);
1575
1576 // Send the request to be processes
1577 receivedDocument = processRequest(xml.toString());
1578
1579 // Check set the login status
1580 checkAndSetLoginStatus();
1581 } catch (AuthLoginException le) {
1582 // Login has failed
1583 loginStatus = Status.FAILED;
1584 loginException = le;
1585 }
1586 }
1587
1588 private void setLocalFlag(URL url) {
1589 try {
1590 String urlStr = url.getProtocol() + "://" + url.getHost() + ":"
1591 + Integer.toString(url.getPort());
1592
1593 if (authDebug.messageEnabled()) {
1594 authDebug.message("in setLocalFlag(), url : " + urlStr);
1595 authDebug.message("AuthContext.localAuthServiceID : " +
1596 localAuthServiceID);
1597 }
1598
1599 if ((localAuthServiceID != null) &&
1600 (urlStr.equalsIgnoreCase(localAuthServiceID))
1601 ) {
1602 localFlag = true;
1603 }
1604 } catch (Exception e) {
1605 authDebug.error("AuthContext::setLocalFlag:: " + e);
1606 }
1607 }
1608
1609 protected Document processRequest(String xmlRequest)
1610 throws AuthLoginException {
1611 // if (authDebug.messageEnabled()) {
1612 // Commented so that passwords will not be printed in
1613 // debug logs
1614 // authDebug.message("Sent XML data : " + xmlRequest);
1615 // }
1616 Document doc = null;
1617 try {
1618 Request request = new Request(xmlRequest);
1619 RequestSet set = new RequestSet(AuthXMLTags.AUTH_SERVICE);
1620 set.addRequest(request);
1621
1622 URL url = authServiceURL;
1623
1624 if (url.getProtocol().equals("https") && (nickName != null)) {
1625 Class[] paramtype = {String.class};
1626 Object[] param = {nickName};
1627 String protHandler = protHandlerPkg + ".https.Handler";
1628 Constructor construct =
1629 Class.forName(protHandler).getConstructor(paramtype);
1630 URLStreamHandler handler =
1631 (URLStreamHandler)construct.newInstance(param);
1632 url = new URL(url.getProtocol(), url.getHost(), url.getPort(),
1633 url.getFile(), handler);
1634 }
1635
1636 if (authDebug.messageEnabled()) {
1637 authDebug.message("Service URL : " + url.toString());
1638 }
1639
1640 Vector responses = PLLClient.send(url, set, cookieTable);
1641
1642 if ((responses.isEmpty()) || (responses.size() != 1)) {
1643 throw new L10NMessageImpl(amAuthContext, "responseError", null);
1644 }
1645
1646 Response res = (Response) responses.elementAt(0);
1647 String responseStr = (String)res.getContent();
1648
1649 if (authDebug.messageEnabled()) {
1650 authDebug.message("Received XML data : " + responseStr);
1651 }
1652
1653 doc = XMLUtils.getXMLDocument(
1654 new ByteArrayInputStream(responseStr.getBytes("UTF-8")));
1655 } catch (Exception e) {
1656 authDebug.message("error in getting service url", e);
1657 throw new AuthLoginException(amAuthContext, "xmlProcessError",
1658 null, e);
1659 }
1660 return (doc);
1661 }
1662
1663 protected static void checkForException(Document document)
1664 throws AuthLoginException {
1665 Node exceptionNode = XMLUtils.getRootNode(
1666 document, AuthXMLTags.EXCEPTION);
1667
1668 if (exceptionNode != null) {
1669 throw (new AuthLoginException(XMLUtils.getNodeAttributeValue(
1670 exceptionNode, AuthXMLTags.MESSAGE)));
1671 }
1672 }
1673
1674 protected String getAuthenticationHandle(Document document)
1675 throws AuthLoginException {
1676 Node responseNode = XMLUtils.getRootNode(
1677 document, AuthXMLTags.RESPONSE);
1678 if (responseNode == null) {
1679 throw new AuthLoginException(amAuthContext, "responseError", null);
1680 }
1681
1682 String authID = XMLUtils.getNodeAttributeValue(
1683 responseNode, AuthXMLTags.AUTH_ID_HANDLE);
1684 return (authID);
1685 }
1686
1687 protected static Callback[] getCallbacks(
1688 Document document,
1689 boolean noFilter) {
1690 return (AuthXMLUtils.getCallbacks(XMLUtils.getRootNode(document,
1691 AuthXMLTags.CALLBACKS), noFilter));
1692 }
1693
1694 protected static Subject getSubject(Document document) {
1695 Node loginStatusNode = XMLUtils.getRootNode(document,
1696 AuthXMLTags.LOGIN_STATUS);
1697
1698 if (loginStatusNode == null) {
1699 return (null);
1700 }
1701
1702 Node subjectNode = XMLUtils.getChildNode(loginStatusNode,
1703 AuthXMLTags.SUBJECT);
1704
1705 if (subjectNode == null) {
1706 return (null);
1707 }
1708
1709 String subject = XMLUtils.getValueOfValueNode(subjectNode);
1710 try {
1711 Subject sSubject = AuthXMLUtils.getDeSerializedSubject(subject);
1712
1713 if (authDebug.messageEnabled()) {
1714 authDebug.message("Deserialized subject : "
1715 + sSubject.toString());
1716 }
1717 return sSubject;
1718 } catch (Exception e) {
1719 authDebug.message("get Deserialized subject error : " , e);
1720 return null;
1721 }
1722
1723 }
1724
1725 protected static String getXMLforSubject(Subject subject) {
1726 if (subject == null) {
1727 return ("");
1728 }
1729 StringBuffer request = new StringBuffer(100);
1730 request.append(AuthXMLTags.SUBJECT_BEGIN);
1731 String serializeSubject = AuthXMLUtils.getSerializedSubject(subject);
1732 request.append(serializeSubject);
1733 request.append(AuthXMLTags.SUBJECT_END);
1734 return (request.toString());
1735 }
1736
1737 /**
1738 * Returns the account lockout message. This can be either a dynamic
1739 * message indicating the number of tries left or the the account
1740 * deactivated message.
1741 *
1742 * @return account lockout message.
1743 */
1744 public String getLockoutMsg() {
1745 String lockoutMsg = null;
1746 if (localFlag) {
1747 lockoutMsg = acLocal.getLockoutMsg();
1748 } else {
1749 // Account Lockout Warning Check by scanning the error
1750 // message in the exception thrown by the server
1751 lockoutMsg = getErrorMessage();
1752 if((lockoutMsg == null) ||
1753 (lockoutMsg.indexOf("Account lockout") == -1)){
1754 lockoutMsg = "";
1755 }
1756 }
1757 return lockoutMsg;
1758 }
1759
1760 /**
1761 * Returns <code>true</code> if account is lock out.
1762 *
1763 * @return <code>true</code> if account is lock out.
1764 */
1765 public boolean isLockedOut() {
1766 boolean isLockedOut = false;
1767 if (localFlag) {
1768 isLockedOut = acLocal.isLockedOut();
1769 } else {
1770 // TBD
1771 }
1772
1773 return isLockedOut;
1774 }
1775
1776 /**
1777 * The class <code>Status</code> defines the possible
1778 * authentication states during the login process.
1779 *
1780 * @supported.all.api
1781 */
1782 public static class Status extends Object {
1783
1784 private String status;
1785
1786 /**
1787 * The <code>NOT_STARTED</code> status indicates that the login process
1788 * has not yet started. Basically, it means that the method
1789 * <code>login</code> has not been called.
1790 */
1791 public static final Status NOT_STARTED = new Status("not_started");
1792
1793 /**
1794 * The <code>IN_PROGRESS</code> status indicates that the login process
1795 * is in progress. Basically, it means that the <code>login</code>
1796 * method has been called and that this object is waiting for the user
1797 * to send authentication information.
1798 */
1799 public static final Status IN_PROGRESS = new Status("in_progress");
1800
1801 /**
1802 *
1803 * The <code>SUCCESS</code> indicates that the login process has
1804 * succeeded.
1805 */
1806 public static final Status SUCCESS = new Status("success");
1807
1808 /**
1809 * The <code>FAILED</code> indicates that the login process has failed.
1810 */
1811 public static final Status FAILED = new Status("failed");
1812
1813 /**
1814 *
1815 * The <code>COMPLETED</code> indicates that the user has been
1816 * successfully logged out.
1817 */
1818 public static final Status COMPLETED = new Status("completed");
1819
1820 /**
1821 * The <code>RESET</code> indicates that the login process has been
1822 * reset or re-initialized.
1823 */
1824 public static final Status RESET = new Status("reset");
1825
1826 /**
1827 * The <code>ORG_MISMATCH</code> indicates that the framework
1828 * <code>org</code> and the <code>org</code> required by the user do
1829 * not match.
1830 */
1831 public static final Status ORG_MISMATCH = new Status("org_mismatch");
1832
1833
1834 private Status() {
1835 // do nothing
1836 }
1837
1838 private Status(String s) {
1839 status = s;
1840 }
1841
1842 /**
1843 * Returns the string representation of the authentication status.
1844 *
1845 * @return String representation of authentication status.
1846 */
1847 public String toString() {
1848 return (status);
1849 }
1850
1851 /**
1852 * Checks if two authentication status objects are equal.
1853 *
1854 * @param authStatus Reference object with which to compare.
1855 * @return <code>true</code> if the objects are same.
1856 */
1857 public boolean equals(Object authStatus) {
1858 if (authStatus instanceof Status) {
1859 Status s = (Status) authStatus;
1860 return (s.status.equalsIgnoreCase(status));
1861 }
1862 return (false);
1863 }
1864 }
1865
1866 /**
1867 * The class <code>IndexType</code> defines the possible kinds of "objects"
1868 * or "resources" for which an authentication can be performed.
1869 *
1870 * @supported.all.api
1871 */
1872 public static class IndexType extends Object {
1873
1874 private String index;
1875
1876 /**
1877 * The <code>USER</code> index type indicates that the index name given
1878 * corresponds to a user.
1879 */
1880 public static final IndexType USER = new IndexType("user");
1881
1882 /**
1883 * The <code>ROLE</code> index type indicates that the index name given
1884 * corresponds to a role.
1885 */
1886 public static final IndexType ROLE = new IndexType("role");
1887
1888 /**
1889 *
1890 * The <code>SERVICE</code> index type indicates that the index name
1891 * given corresponds to a service (or application).
1892 */
1893 public static final IndexType SERVICE = new IndexType("service");
1894
1895 /**
1896 * The <code>LEVEL</code> index type indicates that the index name
1897 * given corresponds to a given authentication level.
1898 */
1899 public static final IndexType LEVEL = new IndexType("level");
1900
1901 /**
1902 * The <code>MODULE_INSTANCE</code> index type indicates that the index
1903 * name given corresponds to one of the authentication modules.
1904 */
1905 public static final IndexType MODULE_INSTANCE =
1906 new IndexType("module_instance");
1907
1908 /**
1909 * The <code>COMPOSITE_ADVICE</code> index type indicates that the
1910 * index name given corresponds to string in the form of XML
1911 * representing different Policy Authentication conditions, example
1912 * <code>AuthSchemeCondition</code>, <code>AuthLevelCondition</code>,
1913 * etc.
1914 */
1915 public static final IndexType COMPOSITE_ADVICE =
1916 new IndexType("composite_advice");
1917
1918 private IndexType() {
1919 // do nothing
1920 }
1921
1922 private IndexType(String s) {
1923 index = s;
1924 }
1925
1926 /**
1927 * Returns the string representation of the index type.
1928 *
1929 * @return String representation of index type.
1930 */
1931 public String toString() {
1932 return (index);
1933 }
1934
1935 /**
1936 * Checks if two index type objects are equal.
1937 *
1938 * @param indexType Reference object with which to compare.
1939 *
1940 * @return <code>true</code> if the objects are same.
1941 */
1942 public boolean equals(Object indexType) {
1943 if (indexType instanceof IndexType) {
1944 IndexType s = (IndexType) indexType;
1945 return (s.index.equalsIgnoreCase(index));
1946 }
1947 return (false);
1948 }
1949 }
1950
1951 private String getAuthHandle() {
1952 String handle = null;
1953
1954 if (receivedDocument != null) {
1955 try {
1956 handle = getAuthenticationHandle(receivedDocument);
1957 } catch (Exception e) {
1958 // do nothing
1959 }
1960 }
1961 if ( handle == null ) {
1962 handle = "0";
1963 }
1964 return handle;
1965 }
1966
1967 private static URL getAuthServiceURL(
1968 String protocol,
1969 String host,
1970 String port,
1971 String uri
1972 ) {
1973 URL authservice = null;
1974 try {
1975 authservice = WebtopNaming.getServiceURL(AuthXMLTags.AUTH_SERVICE,
1976 protocol, host, port, uri);
1977 } catch (Exception e) {
1978 authDebug.error("Failed to obtain auth service url from server: " +
1979 protocol + "://" + host + ":" + port);
1980 }
1981 return authservice;
1982 }
1983
1984 private void onSuccessLocal() {
1985 if (localSessionChecked) {
1986 return;
1987 }
1988 SSOToken currToken = acLocal.getSSOToken();
1989 com.iplanet.dpro.session.service.InternalSession oldSess
1990 = acLocal.getLoginState().getOldSession();
1991 if (oldSess != null) {
1992 if (forceAuth) {
1993 try {
1994 SSOTokenManager.getInstance().
1995 destroyToken(currToken);
1996 } catch (SSOException ssoExp) {
1997 authDebug.error("AuthContext.onSuccessLocal: ",
1998 ssoExp);
1999
2000 }
2001 acLocal.getLoginState().setSession(oldSess);
2002 acLocal.getLoginState().setSid(oldSess
2003 .getID());
2004 acLocal.getLoginState().setForceAuth(false);
2005 ssoToken = acLocal.getSSOToken();
2006 ssoTokenID = ssoToken.getTokenID().toString();
2007
2008 } else {
2009 com.iplanet.dpro.session.service.SessionService.
2010 getSessionService().destroyInternalSession
2011 (oldSess.getID());
2012 }
2013 }
2014 localSessionChecked = true;
2015 }
2016 }