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: AuthContextLocal.java,v 1.12 2009/05/21 21:57:34 qcheng Exp $
026 *
027 * Portions Copyright 2013-2017 ForgeRock AS.
028 */
029
030package com.sun.identity.authentication.server;
031
032import static org.forgerock.http.util.Uris.urlEncodeQueryParameterNameOrValue;
033
034import java.security.Principal;
035import java.util.ArrayList;
036import java.util.Collections;
037import java.util.HashMap;
038import java.util.List;
039import java.util.Map;
040import java.util.ResourceBundle;
041import java.util.Set;
042
043import javax.security.auth.Subject;
044import javax.security.auth.callback.Callback;
045import javax.servlet.http.HttpSession;
046
047import com.iplanet.sso.SSOToken;
048import com.sun.identity.authentication.AuthContext;
049import com.sun.identity.authentication.service.AMLoginContext;
050import com.sun.identity.authentication.service.LoginState;
051import com.sun.identity.authentication.service.LoginStatus;
052import com.sun.identity.authentication.spi.AuthLoginException;
053import com.sun.identity.authentication.spi.PagePropertiesCallback;
054import com.sun.identity.authentication.util.ISAuthConstants;
055import com.sun.identity.policy.PolicyException;
056import com.sun.identity.policy.util.PolicyDecisionUtils;
057import com.sun.identity.shared.debug.Debug;
058import com.sun.identity.shared.locale.Locale;
059
060/**
061 * The <code>AuthContextLocal</code> provides the implementation for
062 * authenticating users.
063 * <p>
064 * A typical caller instantiates this class and starts the login process.
065 * The caller then obtains an array of <code>Callback</code> objects,
066 * which contains the information required by the authentication plug-in
067 * module. The caller requests information from the user. On receiving
068 * the information from the user, the caller submits the same to this class.
069 * If more information is required, the above process continues until all
070 * the information required by the plug-ins/authentication modules, has
071 * been supplied. The caller then checks if the user has successfully
072 * been authenticated. If successfully authenticated, the caller can
073 * then get the <code>Subject</code> and <code>SSOToken</code> for the user;
074 * if not successfully authenticated, the caller obtains the AuthLoginException.
075 * <p>
076 * The implementation supports authenticating users either locally
077 * i.e., in process with all authentication modules configured or remotely
078 * to an authentication service/framework. (See documentation to configure
079 * in either of the modes).
080 * <p>
081 * The <code>getRequirements()</code> and <code>submitRequirements()</code> 
082 * are used to pass the user credentials for authentication by the plugin 
083 * modules,<code>getStatus()</code> returns the authentication status.
084 * <p>
085 * It should be serializable as a requirement to be stored in HttpSession.
086 *
087 * @supported.api
088 */
089public final class AuthContextLocal extends Object
090    implements java.io.Serializable {
091
092    /*
093     * Protected variables used locally
094     */
095
096    // Debug & I18N class
097    private static final String amAuthContextLocal = "amAuthContextLocal";
098    /**
099     * Hold the debug instance
100     */
101    protected static Debug authDebug = Debug.getInstance(amAuthContextLocal);
102    
103    /**
104     * Holds the locale-specific information 
105     */
106    protected static ResourceBundle bundle =
107        Locale.getInstallResourceBundle(amAuthContextLocal);
108
109    /**
110     * Holds organizationName
111     */
112    protected String organizationName;
113    /**
114     * Holds the set of module instance names
115     */
116    protected Set moduleInstanceNames;
117    /**
118     * Holds the index type
119     */
120    protected AuthContext.IndexType indexType;
121    /**
122     * Holds the index name
123     */
124    protected String indexName;
125    /**
126     * Holds the login status
127     */
128    protected AuthContext.Status loginStatus;
129    /**
130     * Holds the host name
131     */
132    protected String hostName;
133    /**
134     * Holds the http session
135     */
136    protected HttpSession httpSession;
137    /**
138     * Holds Single Sign on Token
139     */
140    protected SSOToken ssoToken;
141    /**
142     * AuthLoginException
143     */
144    protected volatile AuthLoginException loginException = null;
145    /**
146     * Holds call back information
147     */
148    protected Callback[] informationRequired = null;
149    /**
150     * AuthLoginContext
151     */
152    public AMLoginContext amlc = null;
153    /**
154     * Holds LoginStatus
155     */
156    public LoginStatus ls;
157    /**
158     * Holds subject
159     */
160    protected Subject subject;
161    /**
162     * character array for password
163     */
164    protected char[] password;
165    
166    private LoginState loginState = null;
167
168    private String orgDN = null;
169    
170    /**
171     * Holds information about submittion of requirements
172     */
173    private boolean inSubmitRequirements = false;
174
175    /**
176     * Creates <code>AuthContextLocal</code> instance is obtained for a given
177     * organization name, or sub organization name. <code>login</code> method is
178     * then used to start the authentication process.
179     *
180     * @param orgName name of the user's organization.
181     *
182     * @supported.api
183     */
184    public AuthContextLocal(String orgName) {
185        authDebug.message("AuthContextLocal() constructor called");
186        organizationName = orgName;
187
188        amlc = new AMLoginContext(this);
189        if (authDebug.messageEnabled()) {
190            authDebug.message("AMLoginContext object is... " + amlc);
191        }
192        reset();
193    }
194
195    /**
196     * Returns authentication module/s instances(or) plugin(s) configured
197     * for an organization, or sub-organization that was set during the
198     * <code>AuthContext</code> constructor.
199     *
200     * @return authentication module/s instances (or plugins).
201     * @throws UnsupportedOperationException if an error occurred.
202     *
203     * @supported.api
204     */
205    public Set getModuleInstanceNames() {
206        moduleInstanceNames = amlc.getModuleInstanceNames();
207
208        return (moduleInstanceNames);
209    }
210
211    /**
212     * Starts the login process for the given <code>AuthContextLocal</code>
213     * object.
214     *
215     * @exception AuthLoginException if an error occurred during login.
216     * @supported.api
217     */
218    public void login() throws AuthLoginException {
219        login(null);
220    }
221    
222    /**
223     * Starts the login process for the given <code>AuthContextLocal</code>s
224     * object for the given <code>Principal</code> and the user's password.
225     * This method should be called primarily
226     * when the authenticator knows there would no other
227     * credentials needed to complete the authentication process.
228     *
229     * @param principal <code>Principal</code> of the user to be authenticated.
230     * @param password password for the user.
231     * @throws AuthLoginException if an error occurred 
232     *            during login.
233     * @supported.api
234     */
235    public void login(Principal principal, char[] password) 
236        throws AuthLoginException {
237
238        // Make sure principal and password are not null
239        if (principal == null)
240            throw new AuthLoginException(amAuthContextLocal, 
241                "invalid-username", null);
242        if (password == null)
243            throw new AuthLoginException(amAuthContextLocal, 
244                "invalid-password", null);
245
246        // Copy the password
247        this.password = password;
248
249        login(null, null, principal, password, null);
250    }
251
252    /**
253     * Start the login process for the <code>AuthContextLocal</code> object
254     * identified by the index type and index name.
255     * The <code>IndexType</code> defines the possible kinds
256     * of "objects" or "resources" for which an authentication can
257     * be performed.  Currently supported index types are
258     * users, roles, services (or application), levels and mechanism.
259     *
260     * @param type authentication index type.
261     * @param indexName authentication index name.
262     * @throws AuthLoginException if an error occurred
263     *            during login.
264     * @supported.api
265     */
266    public void login(AuthContext.IndexType type, String indexName)
267        throws AuthLoginException {
268        if (authDebug.messageEnabled()) {
269            authDebug.message("AuthContextLocal::login() called " +
270            "with IndexType : " + type + " & Indexname : " + indexName);
271        }
272
273        login(type, indexName, null, null, null);
274    }
275
276    /**
277     * Starts the login process for the given <code>AuthContextLocal</code>
278     * object for the given <code>Subject</code>.
279     * Refer to JAAS for description on <code>Subject</code>.
280     *
281     * @param subject <code>Subject</code> of the user to be authenticated.
282     * @throws AuthLoginException if an error occurred
283     *            during login.
284     * @supported.api
285     */
286    public void login(Subject subject) throws AuthLoginException {
287        login(null, null, null, null, subject);
288    }
289
290    /**
291     * Starts the login process for the given <code>AuthContextLocal</code>
292     * object identified by the index type and index name.
293     * The <code>IndexType</code> defines the possible kinds
294     * of "objects" or "resources" for which an authentication can
295     * be performed.Currently supported index types are
296     * users, roles, services (or application), levels and mechanism.
297     * The locale specifies the user preferred locale setting.
298     *
299     * @param type authentication index type.
300     * @param indexName authentication index name.
301     * @param locale locale setting.
302     * @throws AuthLoginException if an error occurred during 
303     *            login process.
304     */
305    public void login(
306        AuthContext.IndexType type,
307        String indexName,
308        String locale
309    ) throws AuthLoginException {
310        if (authDebug.messageEnabled()) {
311            authDebug.message("AuthContextLocal::login() called " +
312            "with IndexType : " + type + " & Indexname : " + indexName +
313            " & locale : " + locale);
314        }
315        login(type, indexName, null, null, null, null, locale);
316    }
317    
318    /**
319     * Starts the login process for the given <code>AuthContextLocal</code>
320     * object identified by the index type and index name.
321     * The <code>IndexType</code> defines the possible kinds
322     * of "objects" or "resources" for which an authentication can
323     * be performed.Currently supported index types are
324     * users, roles, services (or application), levels and mechanism.
325     * The locale specifies the user preferred locale setting.
326     *
327     * @param type authentication index type.
328     * @param indexName authentication index name.
329     * @param envMap Environment Map, key is String, value is set of string.
330     *        this is applicable only when the type is 
331     *        <code>AuthContext.IndexType.RESOURCE</code>
332     * @param locale locale setting.
333     * @throws AuthLoginException if an error occurred during 
334     *            login process.
335     */
336    public void login(
337        AuthContext.IndexType type,
338        String indexName,
339        Map envMap,
340        String locale
341    ) throws AuthLoginException {
342        if (authDebug.messageEnabled()) {
343            authDebug.message("AuthContextLocal::login() called " +
344            "with IndexType : " + type + " & Indexname : " + indexName +
345            " & locale : " + locale +
346            " & envMap : " + envMap);
347        }
348        login(type, indexName, null, null, null, envMap, locale);
349    }
350
351    /**
352     * Performs the Login for the given AuthContext
353     * @param type authentication index type
354     * @param indexName authentication index name
355     * @param principal principal name of the user to be authenticated
356     * @param password password for the user
357     * @param subject authentication subject
358     * @throws AuthLoginException if error occurs during login
359     */
360    protected void login(AuthContext.IndexType type, String indexName, 
361        Principal principal, char[] password, Subject subject) throws AuthLoginException {
362        login(type, indexName, principal, password, subject, null, null);
363    }
364
365    /**
366     * Performs the Login for the given AuthContext
367     * @param type authentication index type
368     * @param indexName authentication index name
369     * @param principal principal name of the user to be authenticated
370     * @param password password for the user
371     * @param subject authentication subject
372     * @param envMap Environment map, this is applicable only when the type
373     *        is <code>AuthContext.IndexType.RESOURCE</code>
374     * @param locale locale setting
375     * @throws AuthLoginException if error occurs during login
376     */
377    protected void login(AuthContext.IndexType type, String indexName, 
378        Principal principal, char[] password, Subject subject, Map envMap, String locale)
379        throws AuthLoginException {
380        try {
381            /*if (!getStatus().equals(AuthContext.Status.NOT_STARTED)) {
382                if (authDebug.messageEnabled()) {
383                    authDebug.message("AuthContextLocal::login called " +
384                    "when the current login status is : " + getStatus());
385                }
386                throw new AuthLoginException(amAuthContextLocal, 
387                    "invalidMethod", new Object[]{getStatus()});
388            }*/
389
390            // switch the login status
391            loginStatus = AuthContext.Status.IN_PROGRESS;
392
393            String redirectUrl = null;
394            // specially processing for resouce/IP/Environement based auth
395            if ((type != null) && type.equals(AuthContext.IndexType.RESOURCE)) { 
396                // this is resouce/IP/Env based authentication
397                // call Policy Decision Util to find out the actual auth type 
398                // required by policy
399                List result = Collections.EMPTY_LIST;
400                try {
401                    result = PolicyDecisionUtils.doResourceIPEnvAuth(
402                            indexName, organizationName, envMap);
403                } catch (PolicyException pe) {
404                    // ignore, continue to default realm based authentication
405                    // may need to revisit this in the future
406                    authDebug.warning("AuthContextLocal.login() policy error " +
407                        "indexName=" + indexName, pe);
408                    type = null;
409                    indexName = null;
410                }
411                if (authDebug.messageEnabled()) {
412                    authDebug.message("AuthContextLocal.login: policy decision="
413                        + result);
414                }
415                if (result.size() == 2) {
416                    type = (AuthContext.IndexType) result.get(0);
417                    indexName = (String) result.get(1);
418                } else if (result.size() == 1) {
419                    // this is the redirection case (Policy Redirection Advice)
420                    redirectUrl = (String) result.get(0);
421                    // append goto parameter for federation case
422                    Set tmp = (Set) envMap.get(ISAuthConstants.GOTO_PARAM);
423                    if ((tmp != null) && !tmp.isEmpty()) {
424                        String gotoParam = (String) tmp.iterator().next();
425                        if ((gotoParam != null) && (gotoParam.length() != 0)) {
426                            if ((redirectUrl != null) && 
427                                (redirectUrl.indexOf("?") != -1)) {
428                                redirectUrl = redirectUrl + "&" + 
429                                    ISAuthConstants.GOTO_PARAM + "=" +
430                                    urlEncodeQueryParameterNameOrValue(gotoParam);
431                            } else {
432                                redirectUrl = redirectUrl + "?" + 
433                                    ISAuthConstants.GOTO_PARAM + "=" +
434                                    urlEncodeQueryParameterNameOrValue(gotoParam);
435                            }
436                        }
437                    }
438                    type = null;
439                    indexName = null;
440                } else {
441                    // no policy decision, use default realm login
442                    type = null;
443                    indexName = null;
444                }
445
446            }
447            HashMap loginParamsMap = new HashMap();
448
449            loginParamsMap.put(INDEX_TYPE, type);
450            loginParamsMap.put(INDEX_NAME, indexName);
451            loginParamsMap.put(PRINCIPAL, principal);
452            loginParamsMap.put(PASSWORD, password);
453            loginParamsMap.put(SUBJECT, subject);
454            loginParamsMap.put(LOCALE, locale);
455            if (redirectUrl != null) {
456                loginParamsMap.put(REDIRECT_URL, redirectUrl);
457            }
458
459            if (authDebug.messageEnabled()) {
460                authDebug.message(
461                    "loginParamsMap : " + loginParamsMap.toString());
462            }
463
464            authDebug.message("calling AMLoginContext::exceuteLogin : ");
465            amlc.executeLogin(loginParamsMap);
466            authDebug.message("after AMLoginContext::exceuteLogin : ");
467            if (amlc.getStatus() == LoginStatus.AUTH_SUCCESS) {
468                loginStatus = AuthContext.Status.SUCCESS;
469            } else if (amlc.getStatus() == LoginStatus.AUTH_FAILED) {
470                loginStatus = AuthContext.Status.FAILED;
471            }
472            if (authDebug.messageEnabled()) {
473                authDebug.message(
474                    "Status at the end of login() : " + loginStatus);
475            }
476        } catch (AuthLoginException e) {
477            if (authDebug.messageEnabled()) {
478                authDebug.message("Exception in ac.login : " + e.toString());
479            }
480            throw e;
481        }
482    }
483
484    /**
485     * Resets this instance of <code>AuthContextLocal</code>
486     * object, so that a new login process can be initiated.
487     * A new authentication process can started using any
488     * one of the <code>login</code> methods.
489     */
490    public void reset() {
491        authDebug.message("AuthContextLocal::reset() called");
492        loginStatus = AuthContext.Status.NOT_STARTED;
493        informationRequired = null;
494        loginException = null;
495    }
496
497    /**
498     * Returns the set of Principals the user has been authenticated as.
499     * This should be invoked only after successful authentication.
500     * If the authentication fails or the authentication is in process,
501     * this will return <code>null</code>.
502     *
503     * @return The set of Principals the user has been authenticated as.
504     * @supported.api
505     */
506    public Subject getSubject() {
507        if (!loginStatus.equals(AuthContext.Status.SUCCESS)) {
508            return (null);
509        }
510        if (subject == null) {
511            subject = amlc.getSubject();
512        }
513        return (subject);
514    }
515
516    /**
517     * Checks if the login process requires more information from the user to
518     * complete the authentication.
519     *
520     * @return <code>true</code> if more credentials are required
521     *         from the user.
522     * @supported.api
523     */
524    public boolean hasMoreRequirements() {
525        authDebug.message("AuthContextLocal::hasMoreRequirements()");
526
527        if ((amlc.getStatus() == LoginStatus.AUTH_SUCCESS) ||
528            (amlc.getStatus() == LoginStatus.AUTH_FAILED)
529        ) {
530            return false;
531        } else {
532            informationRequired = amlc.getRequiredInfo();
533            return (informationRequired != null);
534        }
535    }
536
537    /**
538     * Checks if the login process requires more information from the user to
539     * complete the authentication
540     * @param noFilter falg to indicate if there is a Filter
541     * @return <code>true</code> if more credentials are required
542     *         from the user.
543     */
544    public boolean hasMoreRequirements(boolean noFilter) {
545        authDebug.message("AuthContextLocal::hasMoreRequirements()");
546
547        if ((amlc.getStatus() == LoginStatus.AUTH_SUCCESS) ||
548            (amlc.getStatus() == LoginStatus.AUTH_FAILED)
549        ) {
550            return false;
551        } else {
552            informationRequired = amlc.getRequiredInfo();
553            return (getCallbacks(informationRequired, noFilter) != null);
554        }
555    }
556
557    /**
558     * Returns an array of <code>Callback</code> objects that
559     * must be populated by the user and returned back.
560     * These objects are requested by the authentication plug-ins,
561     * and these are usually displayed to the user. The user then provides
562     * the requested information for it to be authenticated.
563     *
564     * @return an array of <code>Callback</code> objects requesting credentials
565     *         from user.
566     * @supported.api
567     */
568    public Callback[] getRequirements() {
569        authDebug.message("AuthContextLocal::getRequirements()");
570
571        if ((amlc.getStatus() == LoginStatus.AUTH_SUCCESS) ||
572            (amlc.getStatus() == LoginStatus.AUTH_FAILED)
573        ) {
574            return null;
575        } else {
576            return (informationRequired);
577        }
578    }
579
580    /**
581     * Returns an array of <code>Callback</code> objects that
582     * must be populated by the user and returned back.
583     * These objects are requested by the authentication plug-ins,
584     * and these are usually displayed to the user. The user then provides
585     * the requested information for it to be authenticated.
586     *
587     * @param noFilter flag to indicate if there is a Filter
588     * @return an array of <code>Callback</code> objects requesting credentials
589     *         from user.
590     * @supported.api
591     */
592    public Callback[] getRequirements(boolean noFilter) {
593        authDebug.message("AuthContextLocal::getRequirements()");
594
595        if ((amlc.getStatus() == LoginStatus.AUTH_SUCCESS) ||
596            (amlc.getStatus() == LoginStatus.AUTH_FAILED)
597        ) {
598            return null;
599        } else {
600            return (getCallbacks(informationRequired, noFilter));
601        }
602    }
603
604    /**
605     * Submit the populated <code>Callback</code> objects
606     * to the authentication plug-in modules. Called after
607     * <code>getRequirements</code> method and obtaining
608     * user's response to these requests.
609     *
610     * @param info array of <code>Callback</code> objects
611     * @supported.api
612     */
613    public void submitRequirements(Callback[] info) {
614        authDebug.message("AuthContextLocal::submitRequirements()");
615        inSubmitRequirements = true;
616        try{
617           informationRequired = null;
618           amlc.submitRequiredInfo(info) ;
619           if (!amlc.isPureJAAS()) {
620                amlc.runLogin();
621           }
622           if (amlc.getStatus() == LoginStatus.AUTH_SUCCESS) {
623                loginStatus = AuthContext.Status.SUCCESS;
624           } else if (amlc.getStatus() == LoginStatus.AUTH_FAILED) {
625                loginStatus = AuthContext.Status.FAILED;
626           }
627           authDebug.message("AuthContextLocal::submitRequirements end");
628           if (authDebug.messageEnabled()) {
629                authDebug.message("Status at the end of submitRequirements() : "
630                                + loginStatus);
631           }
632         } finally {
633           inSubmitRequirements = false;
634         }
635    }
636
637    /**
638     * Logs out the user and also invalidates the <code>SSOToken</code>
639     * associated with this <code>AuthContextLocal</code>.
640     *
641     * @throws AuthLoginException if an error occurred during logout
642     * @supported.api
643     */
644    public void logout() throws AuthLoginException {
645        authDebug.message("AuthContextLocal::logout()");
646
647        try {
648            amlc.logout();
649        } catch (Exception e) {
650            if (authDebug.messageEnabled()) {
651                authDebug.message("Exception in AMLoginContext::logout() "
652                    + e.getMessage());
653            }
654            throw new AuthLoginException(amAuthContextLocal, "logoutError",
655                null, e);
656        }
657
658        authDebug.message("Called AMLoginContext::logout()");
659        loginStatus = AuthContext.Status.COMPLETED;
660    }
661
662    /**
663     * Returns login exception, if any, during
664     * the authentication process. Typically set when the login
665     * fails.
666     *
667     * @return login exception.
668     * @supported.api
669     */
670    public AuthLoginException getLoginException() {
671        authDebug.message("AuthContextLocal::getLoginException()");
672        return (loginException);
673    }
674
675    /**
676     * Sets the login exception that represents errors during the 
677     * authentication process.
678     *
679     * @param exception AuthLoginException to be set.
680     */
681    public void setLoginException(AuthLoginException exception) {
682        loginException = exception;
683    }
684
685    /**
686     * Returns the current status of the authentication process.
687     *
688     * @return the current status of the authentication process.
689     * @supported.api
690     */
691    public AuthContext.Status getStatus() {
692        authDebug.message("AuthContextLocal::getStatus()");
693        if (amlc.getStatus() == LoginStatus.AUTH_SUCCESS) {
694            loginStatus = AuthContext.Status.SUCCESS;
695        }
696        else if (amlc.getStatus() == LoginStatus.AUTH_FAILED) {
697            loginStatus = AuthContext.Status.FAILED;
698        }
699        else if (amlc.getStatus() == LoginStatus.AUTH_RESET) {
700            loginStatus =  AuthContext.Status.RESET;
701        }
702        else if (amlc.getStatus() == LoginStatus.AUTH_ORG_MISMATCH) {
703            loginStatus =  AuthContext.Status.ORG_MISMATCH;
704        }
705        else if (amlc.getStatus() == LoginStatus.AUTH_IN_PROGRESS) {
706            loginStatus =  AuthContext.Status.IN_PROGRESS;
707        }
708        else if (amlc.getStatus() == LoginStatus.AUTH_COMPLETED) {
709            loginStatus =  AuthContext.Status.COMPLETED;
710        }
711
712
713        if (authDebug.messageEnabled()) {
714            authDebug.message("AuthContextLocal:: Status : " + loginStatus);
715        }
716
717        return (loginStatus);
718    }
719
720    /**
721     * Sets the login status. Used internally and
722     * not visible outside this package.
723     * @param status login status
724     */
725    protected void setLoginStatus(AuthContext.Status status) {
726        authDebug.message("AuthContextLocal::setLoginStatus()");
727        loginStatus = status;
728    }
729
730    /**
731     * Returns the Single-Sign-On (SSO) Token for the authenticated
732     * user.Single-Sign-On token can be used as the authenticated token.
733     *
734     * @return single-sign-on token
735     * @supported.api
736     */
737    public SSOToken getSSOToken() {
738        ssoToken = amlc.getSSOToken();
739        return (ssoToken);
740    }
741
742    /**
743     * Returns the Successful Login URL for the authenticated user.
744     * 
745     * @return the Successful Login URL for the authenticated user.
746     */
747    public String getSuccessURL() {        
748        return amlc.getSuccessURL();        
749    }
750    
751    /**
752     * Returns the Failure Login URL for the authenticating user.
753     * 
754     * @return the Failure Login URL for the authenticating user.
755     */
756    public String getFailureURL() {        
757        return amlc.getFailureURL();        
758    }
759    
760    /**
761     * Returns the the organization name that was set during the
762     * <code>AuthContextLocal</code> constructor.
763     *
764     * @return Organization name.
765     *
766     * @supported.api
767     */
768    public String getOrganizationName() {
769        return (amlc.getOrganizationName());
770    }
771
772    /**
773     * Terminates an ongoing <code>login</code> call that has not yet completed.
774     *
775     * @throws AuthLoginException if an error occurred during abort.
776     *
777     * @supported.api
778     */
779    public void abort() throws AuthLoginException {
780        authDebug.message("AuthContextLocal::abort()");
781
782        try {
783            amlc.abort();
784        } catch (Exception e) {
785            if (authDebug.messageEnabled()) {
786                authDebug.message("Exception in AMLoginContext::abort() "
787                + e.getMessage());
788            }
789            throw new AuthLoginException(amAuthContextLocal, "abortError", 
790                null, e);
791        }
792
793        loginStatus = AuthContext.Status.COMPLETED;
794    }
795
796    /**
797     * Returns the error template.
798     *
799     * @return the error template.
800     */
801    public String getErrorTemplate() {
802        return amlc.getErrorTemplate();
803    }
804
805    /**
806     * Returns the error message.
807     *
808     * @return the error message.
809     */
810    public String getErrorMessage() {
811        return amlc.getErrorMessage();
812    }
813
814    /**
815     * Returns the error code.
816     *
817     * @return error code.
818     */
819    public String getErrorCode() {
820        return amlc.getErrorCode();
821    }
822
823    /**
824     * Returns the current 'authIdentifier' of the authentication process as
825     * String Session ID.
826     *
827     * @return <code>authIdentifier</code> of the authentication process
828     */
829    public String getAuthIdentifier() {        
830        return amlc.getAuthIdentifier();
831    }
832    
833    /**
834     * Returns the account lockout message. This can be either a dynamic
835     * message indicating the number of tries left or the the account
836     * deactivated message.
837     *
838     * @return account lockout message.
839     */
840    public String getLockoutMsg() {
841
842        String lockoutMsg = amlc.getLockoutMsg();
843
844        if (authDebug.messageEnabled()) {
845            authDebug.message("getLockoutMsg: lockoutMsg: " + lockoutMsg);
846        }
847
848        return lockoutMsg;
849    }
850
851    /**
852     * Checks the account is locked out
853     * @return <code>true</code> if the account is locked,
854     *         <code>false</code> otherwise
855     */
856    public boolean isLockedOut() {
857        boolean isLockedOut = amlc.isLockedOut();
858        if (authDebug.messageEnabled()) {
859            authDebug.message("isLockedOut : " + isLockedOut);
860        }
861
862        return isLockedOut;
863    }
864
865    /**
866     * Sets the client's host name , this method is used in case of remote 
867     * authentication,to set the client's hostname or IP address. 
868     * This could be used by the policy component to restrict access 
869     * to resources.
870     *
871     * @param hostname Host name.
872     */
873    public void setClientHostName(String hostname) {
874        hostName = hostname;
875    }
876
877    /**
878     * Returns the clients host name
879     * @return hostname
880     */
881    protected String getClientHostName() {
882        return (hostName);
883    }
884
885    public boolean submittedRequirements() {
886        return inSubmitRequirements;
887    }
888
889    /**
890     * Sets the <code>HttpSession</code> that will be used by
891     * the SSO component to store the session information. In the
892     * absence of <code>HttpSession</code> the information is stored
893     * in <code>HashMap</code> and will have issues with fail-over.
894     * With session fail-over turned on <code>HttpSession</code>
895     * would be provide persistance storage mechanism for SSO.
896     *
897     * @param session HttpSession
898     */
899    public void setHttpSession(HttpSession session) {
900        httpSession = session;
901    }
902
903    /**
904     * Returns the <code>HTTPSession</code> associated with the current
905     * authentication context
906     * @return httpSession
907     */
908    protected HttpSession getHttpSession() {
909        return (httpSession);
910    }
911
912    /**
913     * Returns the array of <code>Callback</code> requirements objects
914     * @param recdCallbacks callbacks requirements
915     * @param noFilter boolean to indicate if filter exists
916     * @return an array of <code>Callback</code> objects
917     */
918    protected static Callback[] getCallbacks(
919        Callback[] recdCallbacks,
920        boolean noFilter) {
921        if (recdCallbacks == null) {
922            return (null);
923        } else if (noFilter) {
924            return recdCallbacks;
925        } else {
926            Callback[] answer = new Callback[0];
927            ArrayList callbackList= new ArrayList(); 
928
929            for (int i = 0; i < recdCallbacks.length; i++) {
930                if (authDebug.messageEnabled()) {
931                    authDebug.message("In getCallbacks() callback : "
932                      + recdCallbacks[i]);
933                }
934                if (!(recdCallbacks[i] instanceof PagePropertiesCallback)) {
935                     callbackList.add(recdCallbacks[i]);
936                } 
937            }
938            return (Callback[]) callbackList.toArray(answer);
939        }
940    }
941
942    /**
943     * Sets the Login State
944     * @param state login state
945     */
946    public void setLoginState(LoginState state) {
947        loginState = state;
948    } 
949
950    /**
951     * Returns the login state
952     * @return loginState
953     */
954    public LoginState getLoginState() {
955        return loginState;
956    }
957
958    /**
959     * Sets the Organization DN
960     * @param orgDN Organization DN
961     */
962    public void setOrgDN(String orgDN) {
963        this.orgDN = orgDN;
964    }
965
966    /**
967     * Returns the Organization DN
968     * @return the Organization DN 
969     */
970    public String getOrgDN() {
971        return orgDN;
972    }
973
974    /**
975     * Holds LDAP URL
976     */
977    public final static String LDAP_AUTH_URL = "ldap://";
978
979    /**
980     * Holds principal name to be authenticated
981     */
982    public final static String PRINCIPAL = "principal";
983    /**
984     * Holds Password for the user
985     */
986    public final static String PASSWORD = "password";
987    /**
988     * authentication subject
989     */
990    public final static String SUBJECT = "subject";
991    /**
992     * authentication index type
993     */
994    public final static String INDEX_TYPE = "indexType";
995    
996    /**
997     * authentication index name
998     */
999    public final static String INDEX_NAME = "indexName";
1000
1001    /**
1002     * locale setting
1003     */
1004    public final static String LOCALE = "locale";
1005    
1006    /**
1007     * Redirection URL
1008     */
1009    public static final String REDIRECT_URL = "redirectionURL";
1010}