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.