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.10 2009/01/28 05:34:52 ww203982 Exp $
026 *
027 * Portions Copyrighted 2011-2015 ForgeRock AS.
028 */
029
030package com.sun.identity.authentication.internal;
031
032
033import static org.forgerock.openam.ldap.LDAPUtils.isDN;
034import static org.forgerock.openam.ldap.LDAPUtils.rdnValueFromDn;
035
036import javax.security.auth.callback.Callback;
037import javax.security.auth.callback.ChoiceCallback;
038import javax.security.auth.callback.NameCallback;
039import javax.security.auth.callback.PasswordCallback;
040import javax.security.auth.callback.TextInputCallback;
041import javax.security.auth.callback.TextOutputCallback;
042import javax.security.auth.login.LoginException;
043import java.net.InetAddress;
044import java.security.Principal;
045import java.security.SecureRandom;
046import java.util.Iterator;
047import java.util.Set;
048
049import com.iplanet.am.util.SecureRandomManager;
050import com.iplanet.am.util.SystemProperties;
051import com.iplanet.services.util.I18n;
052import com.iplanet.sso.SSOToken;
053import com.sun.identity.authentication.internal.server.AuthSPrincipal;
054import com.sun.identity.authentication.internal.util.AuthI18n;
055import com.sun.identity.shared.Constants;
056import com.sun.identity.shared.debug.Debug;
057import com.sun.identity.sm.ServiceManager;
058import org.forgerock.i18n.LocalizedIllegalArgumentException;
059import org.forgerock.opendj.ldap.DN;
060
061
062/**
063 * The AuthContext provides the implementation for authenticating users using
064 * the JAAS technology. It complements <code>LoginContext
065 * </code> provided by
066 * JAAS by supporting organization environments that cannot handle sessions, for
067 * example, HTTP/HTML.
068 * <p>
069 * A typical caller instantiates this class and starts the login process. The
070 * caller then obtains an array of <code>Callback</code> objects, which
071 * contains the information required by the authentication plug-in module. The
072 * caller requests information from the user. On receiving the information from
073 * the user, the caller submits the same to this class. If more information is
074 * required, the above process continues until all the information required by
075 * the plug-ins has been supplied. The caller then checks if the user has
076 * successfully been authenticated. If successfully authenticated, the caller
077 * can then get the <code>
078 * Subject</code> for the user; if not successfully
079 * authenticated, the caller obtains the LoginException.
080 *
081 * @supported.api
082 */
083public final class AuthContext extends Object {
084
085    /**
086     * This login status indicates that the login process
087     * has not started yet. Basically, it means that the method
088     * <code>startLogin</code> has not been called.
089     *
090     * @supported.api
091     */
092    public static final int AUTH_NOT_STARTED = 1;
093
094    /**
095     * This login status indicates that the login process
096     * is in progress. Basically, it means that the <code>startLogin</code>
097     * method has been called and that this object is waiting for the user to
098     * send authentication information.
099     *
100     * @supported.api
101     */
102    public static final int AUTH_IN_PROGRESS = 2;
103
104    /**
105     * This login status indicates that the login process
106     * has succeeded.
107     *
108     * @supported.api
109     */
110    public static final int AUTH_SUCCESS = 3;
111
112    /**
113     * This login status indicates that the login process
114     * has failed.
115     *
116     * @supported.api
117     */
118    public static final int AUTH_FAILED = 4;
119
120    /**
121     * This login status indicates that the user has been
122     * successfully logged out.
123     *
124     * @supported.api
125     */
126    public static final int AUTH_COMPLETED = 5;
127
128    /*
129     * Protected variables used locally
130     */
131    protected final String authComponentName = "Authentication";
132
133    protected final static String authKeyName = "authContext";
134
135    // Debug class
136    protected final static String authDebugName = "amAuthInternal";
137
138    protected static Debug authDebug = Debug.getInstance(authDebugName);
139
140    protected String organizationName = null;
141
142    protected String applicationName = null;
143
144    protected int loginStatus;
145
146    protected LoginException loginException;
147
148    protected Callback[] informationRequired;
149
150    protected Callback[] submittedInformation;
151
152    protected AuthLoginThread loginThread;
153
154    protected LoginContext loginContext;
155
156    protected SSOToken token;
157
158    protected static I18n myAuthI18n = AuthI18n.authI18n;
159
160    private static boolean isEnableHostLookUp = Boolean.valueOf(
161            SystemProperties.get(Constants.ENABLE_HOST_LOOKUP)).booleanValue();
162
163    //
164    // overall, AuthContext is a "conduit" between the application and the
165    // login module. the Principal implementation must be agreed upon at
166    // those two endpoints; AuthContext just passes the Subject that contains
167    // the Principal(s).
168    //
169
170    /**
171     * Constructor to get an instance of
172     * <code>AuthContext</code>. Caller would then use
173     * <code>getRequirements()</code> and <code>submitRequirements()</code>
174     * to pass the credentials needed for authentication by the plugin modules.
175     *
176     * @throws LoginException
177     *
178     * @supported.api
179     */
180    public AuthContext() throws LoginException {
181        // initialize
182        this("");
183    }
184
185    /**
186     * Constructor to get an authenticated instance
187     * of this class given the <code>java.security.Principal</code> the user
188     * would like to be authenticated as, and the <code>password</code> for
189     * the user.
190     *
191     * @param principal
192     *            name of the user to be authenticated
193     * @param password
194     *            password for the user
195     * @throws LoginException
196     *
197     * @supported.api
198     */
199    public AuthContext(Principal principal, char[] password)
200            throws LoginException {
201        this(null, principal, password);
202    }
203
204    /*
205     * Constructor for DPro to provide hostname and port for LDAP
206     * authentication.
207     */
208    public AuthContext(Principal principal, char[] password, String hostname,
209            int port) throws LoginException {
210        this(LoginContext.LDAP_AUTH_URL + hostname + ":" + port, principal,
211                password);
212    }
213
214    /**
215     * Constructor to get an instance of this class
216     * given the organization name <code>orgName</code> the user would like to
217     * access, the <code>java.security.Principal
218     * </code>the user would like to
219     * be authenticated as, and the <code>password</code> for the user.
220     *
221     * @param orgName
222     *            name of the user's organization
223     * @param principal
224     *            name of the user to be authenticated
225     * @param password
226     *            password for the user
227     * @throws LoginException
228     *
229     * @supported.api
230     */
231    public AuthContext(String orgName, Principal principal, char[] password)
232            throws LoginException {
233        // Make sure principal and password are not null
234        if (principal == null)
235            throw (new LoginException(myAuthI18n
236                    .getString("com.iplanet.auth.invalid-username")));
237        if (password == null)
238            throw (new LoginException(myAuthI18n
239                    .getString("com.iplanet.auth.invalid-password")));
240
241        AuthSubject subject = new AuthSubject();
242
243        if (orgName != null)
244            organizationName = orgName;
245        reset(subject);
246
247        // Set the username and password in LoginContext's sharedState
248        loginContext.updateSharedState(principal.getName(), password);
249
250        boolean gotName = false;
251        boolean gotPassword = false;
252        Callback[] callbacks;
253
254        if (authDebug.messageEnabled()) {
255            authDebug.message("Instantiated AuthContext with parameters "
256                    + "organization name: "
257                    + organizationName
258                    + "; "
259                    + ((principal == null) ? "principal is null"
260                            : "principal: ")
261                    + principal
262                    + "; "
263                    + ((password.length == 0) ? "password is empty\n"
264                            : "password present\n"));
265        }
266        this.startLogin();
267
268        //
269        // assume that there are requirements, and they are NameCallback and
270        // PasswordCallback. then submit those.
271        //
272        while (this.hasMoreRequirements()) {
273            authDebug.message("AuthContext::init() Has requirements");
274            callbacks = this.getRequirements();
275            for (int i = 0; i < callbacks.length; i++) {
276                if (callbacks[i] instanceof NameCallback) {
277                    authDebug.message("Got NameCallback");
278                    NameCallback nc = (NameCallback) callbacks[i];
279                    Set sops = subject.getPrincipals();
280                    AuthSPrincipal[] aps = (AuthSPrincipal[]) sops
281                            .toArray(new AuthSPrincipal[0]);
282                    if (aps.length == 1) {
283                        nc.setName(aps[0].getName());
284                        authDebug.message("Set namecallback name = "
285                                + aps[0].getName());
286                        gotName = true;
287                    }
288                } else if (callbacks[i] instanceof PasswordCallback) {
289                    authDebug.message("Got PasswordCallback");
290                    PasswordCallback pc = (PasswordCallback) callbacks[i];
291                    pc.setPassword(password);
292                    gotPassword = true;
293                } else if (callbacks[i] instanceof TextOutputCallback) {
294                    authDebug.message(
295                            "AuthContext::init() Got TextOutputCallback");
296                } else if (callbacks[i] instanceof TextInputCallback) {
297                    authDebug.message(
298                            "AuthContext::init() Got TextInputCallback");
299                } else if (callbacks[i] instanceof ChoiceCallback) {
300                    authDebug.message("AuthContext::init() Got ChoiceCallback");
301                    ChoiceCallback cc = (ChoiceCallback) callbacks[i];
302                    cc.setSelectedIndex(0);
303                } else {
304                    authDebug.message(
305                            "AuthContext::init() Got Unknown Callback");
306                }
307
308            }
309            this.submitRequiredInformation(callbacks);
310        }
311
312        // Debug messages
313        if (authDebug.messageEnabled() && gotName && gotPassword) {
314            authDebug.message(
315                    "AuthContext::init() Got name and password callbacks");
316        }
317        if (authDebug.messageEnabled()) {
318            authDebug.message("AuthContext::init() Login status: "
319                    + this.getLoginStatus());
320        }
321
322        // Check login status
323        if (getLoginStatus() == AUTH_FAILED) {
324            throw (getLoginException());
325        }
326    }
327
328    /**
329     * Constructor to get an instance of this class given the organization name
330     * <code>orgName</code> the user would like to access, and the principal's
331     * <code>subject</code> the user would like to be authenticated as.
332     */
333    protected AuthContext(String orgName, AuthSubject subject)
334            throws LoginException {
335        String orgname = orgName;
336
337        if (authDebug.messageEnabled()) {
338            authDebug.message("Instantiating AuthContext with parameters "
339                    + "organization name: "
340                    + orgName
341                    + "; "
342                    + ((subject == null) ? "subject is null" : "subject: "
343                            + subject));
344        }
345
346        if (orgName != null) {
347            if (orgName.startsWith("auth://")) {
348                int i2, offset;
349                String subsample;
350                String appName = null;
351
352                offset = 7; // char count of "auth://"
353                subsample = orgName.substring(offset);
354                // the org + appname, supposedly
355                i2 = subsample.indexOf("/");
356                if (i2 != -1) {
357                    //
358                    // from offset to i2 should be the orgName
359                    //
360                    orgname = subsample.substring(0, i2);
361                    authDebug.message("AuthContext::init() auth:// "
362                            + "form, orgname = " + orgname);
363
364                    //
365                    // get past the "/" after the orgName; look for appName
366                    //
367                    subsample = subsample.substring(i2 + 1);
368                    if (subsample.length() > 0) {
369                        //
370                        // the next check could be for a "?", this is for
371                        // possible
372                        // future use where parameters such as
373                        // "?userid=<userid>&password=<pswd>" could be passed
374                        //
375                        i2 = subsample.indexOf("?");
376                        if (i2 != -1) {
377                            //
378                            // parameters specified; pick off appName first
379                            //
380                            appName = subsample.substring(0, i2);
381
382                            //
383                            // the rest assumes the userid and password
384                            // parameters as
385                            // described above. To be implmented
386                            //
387                            // subsample = subsample.substring(i2+1);
388                        } else {
389                            //
390                            // Only appName was provided, no user name and
391                            // password
392                            //
393                            appName = subsample;
394                        }
395                    } else {
396                        //
397                        // no appName, just OrgName and "/" at the end
398                        //
399                        appName = null;
400                    }
401                } else {
402                    //
403                    // means just the orgName was specified
404                    //
405                    orgname = subsample;
406                }
407                if (appName != null) {
408                    applicationName = appName;
409                }
410            } else if (orgName.startsWith("local://")) {
411                authDebug.message("local form AuthContext specified; "
412                        + orgName);
413                int offset = 8; // char count of "local://"
414                orgname = orgName.substring(offset); // just the org,
415                                                        // hopefully
416            }
417        }
418
419        this.organizationName = orgname;
420        reset(subject);
421    }
422
423    // An alternate form of the <code>orgName</code> is
424    // "auth://<orgName>/<appName>"
425    //
426    // note that a private form of orgName is
427    // "local://...". this is for administrative-type
428    // configuration information for install commands,
429    // for example.
430    //
431    /**
432     * Constructor to get an instance of this class
433     * given the organization name <code>orgName</code>. The plug-in modules
434     * would then query for the user name and related information.
435     *
436     * @param orgName organization name.
437     * @throws LoginException
438     *
439     * @supported.api
440     */
441    public AuthContext(String orgName) throws LoginException {
442        this(orgName, null);
443        authDebug.message("Instantiated AuthContext with organization name: "
444                + orgName);
445    }
446
447    /**
448     * Method to reset this instance of <code>AuthContext</code> object, so
449     * that a new login process can be initiated. Authenticates the user to the
450     * same organization or resource this object was instantiated with. If this
451     * object was instantiated with a <code>
452     * Subject</code>, it will be
453     * ignored.
454     */
455    protected void reset() throws LoginException {
456        authDebug.message("AuthContext::reset()");
457        reset(null);
458        authDebug.message("AuthContext::reset() exiting");
459    }
460
461    /**
462     * Method to reset this instance of <code>AuthContext</code> object, so
463     * that a new login process can be initiated for the given
464     * <code>Subject</code>. Authenticates the user to the same organization
465     * or resource this object was instantiated with.
466     */
467    protected void reset(AuthSubject subject) throws LoginException {
468
469        if (authDebug.messageEnabled()) {
470            authDebug.message("AuthContext::reset(" + organizationName + ", "
471                    + ((subject == null) ? "null" : subject.toString()) + ")");
472        }
473
474        loginStatus = AUTH_NOT_STARTED;
475        informationRequired = null;
476        submittedInformation = null;
477        loginException = null;
478        loginThread = new AuthLoginThread(this);
479        authDebug.message("AuthLoginThread isAlive = " + loginThread.isAlive());
480
481        String contextName = null;
482
483        if (applicationName == null) {
484            contextName = organizationName;
485        } else {
486            contextName = organizationName + "%" + applicationName;
487        }
488
489        authDebug
490                .message("AuthContext::reset:using contextName=" + contextName);
491        if (subject == null) {
492            loginContext = new LoginContext(contextName, loginThread);
493        } else {
494            loginContext = new LoginContext(contextName, subject, loginThread);
495        }
496
497        if (authDebug.messageEnabled()) {
498            authDebug
499                    .message("Successfully reset AuthContext for organization: "
500                            + organizationName
501                            + ((subject == null) ? " with no subject name "
502                                    : " with subjects: " + subject));
503        }
504    }
505
506    /**
507     * Returns the set of Principals the user has been authenticated as. This
508     * can be invoked only after successful authentication. If the
509     * authentication fails, this will return <code>null</code>.
510     */
511    protected AuthSubject getSubject() {
512        authDebug.message("AuthContext::getSubject()");
513        return (loginContext.getSubject());
514    }
515
516    /**
517     * Method to start the login process. This method will
518     * read the plug-ins configured for the application and initialize them.
519     *
520     * @throws LoginException
521     *
522     * @supported.api
523     */
524    public void startLogin() throws LoginException {
525
526        authDebug.message("AuthContext::startLogin() called");
527
528        // Make sure we are the current state
529        if (getLoginStatus() != AUTH_NOT_STARTED) {
530
531            authDebug.message("AuthContext::startLogin called "
532                    + "when the current login state is" + getLoginStatus());
533
534            throw (new LoginException(myAuthI18n
535                    .getString("authError-invalidMethod" + getLoginStatus())));
536        }
537
538        // Change the login status
539        loginStatus = AUTH_IN_PROGRESS;
540
541        // Initiate the login
542        authDebug.message("AuthContext::startLogin() "
543                + "starting a new thread to run the login process");
544
545        try {
546            loginThread.start();
547        } catch (Exception ex) {
548            authDebug.message("exception starting thread: " + ex);
549            throw (new LoginException(ex.getMessage()));
550        }
551    }
552
553    /**
554     * Returns true if the login process requires more
555     * information from the user to complete the authentication.
556     *
557     * @return true if the login process requires more information from the user
558     *         to complete the authentication.
559     *
560     * @supported.api
561     */
562    public boolean hasMoreRequirements() {
563        authDebug.message("AuthContext::requiresMoreInformation()");
564
565        if (getRequirements() == null)
566            return (false);
567        else
568            return (true);
569    }
570
571    /**
572     * Returns an array of <code>Callback</code> objects
573     * that must be populated by the user and returned back. These objects are
574     * requested by the authentication plug-ins, and these are usually displayed
575     * to the user. The user then provides the requested information for it to
576     * be authenticated.
577     *
578     * @return an array of <code>Callback</code> objects that must be
579     *         populated by the user and returned back.
580     *
581     * @supported.api
582     */
583    public Callback[] getRequirements() {
584        authDebug.message("AuthContext::getInformationRequired()");
585
586        // Check the status of LOGIN
587        if (getLoginStatus() != AUTH_IN_PROGRESS) {
588
589            authDebug.message("AuthContext:getInformationRequired() "
590                    + "called when the current login state is: "
591                    + getLoginStatus());
592
593            // Login has completed, could be either success or failure
594            return (null);
595        }
596
597        // Check if information required is present
598        while ((informationRequired == null)
599                && (getLoginStatus() == AUTH_IN_PROGRESS)) {
600            // wait for required information to be available
601            try {
602                authDebug.message("AuthContext::getInformationRequired"
603                        + "() waiting for Callback array");
604
605                synchronized (loginThread) {
606                    if ((informationRequired == null)
607                            && (getLoginStatus() == AUTH_IN_PROGRESS)) {
608                        loginThread.wait();
609                    }
610                }
611
612                authDebug.message("AuthContext::getInformationRequired"
613                        + "() returned from waiting for Callback array");
614
615            } catch (InterruptedException ie) {
616                // do nothing
617            }
618        }
619        return (informationRequired);
620    }
621
622    /**
623     * Submits the populated <code>Callback</code>
624     * objects to the authentication plug-in modules. Called after
625     * <code>getInformationRequired</code> method and obtaining user's
626     * response to these requests.
627     *
628     * @param info
629     *            array of <code>Callback</code> objects.
630     *
631     * @supported.api
632     */
633    public void submitRequiredInformation(Callback[] info) {
634        authDebug.message("AuthContext::submitRequestedInformation()");
635
636        informationRequired = null;
637
638        // Set the submitted info & wake up the callback hander thread
639        synchronized (loginThread) {
640            submittedInformation = info;
641            loginThread.notify();
642        }
643        authDebug.message("AuthContext::submitRequestedInformation"
644                + "() sending notify to sleeping threads");
645    }
646
647    /**
648     * Logs the user out.
649     *
650     * @throws LoginException
651     *
652     * @supported.api
653     */
654    public void logout() throws LoginException {
655        authDebug.message("AuthContext::logout()");
656        loginContext.logout();
657
658        authDebug.message("Called LoginContext::logout()");
659        loginStatus = AUTH_COMPLETED;
660    }
661
662    /**
663     * Returns login exception, if any, during the
664     * authentication process. Typically set when the login fails.
665     *
666     * @return login exception.
667     *
668     * @supported.api
669     */
670    public LoginException getLoginException() {
671        authDebug.message("AuthContext::getLoginException()");
672        return (loginException);
673    }
674
675    /**
676     * Returns the current state of the login process.
677     * Possible states are listed above.
678     *
679     * @return the current state of the login process.
680     *
681     * @supported.api
682     */
683    public int getLoginStatus() {
684        authDebug.message("AuthContext::getLoginStatus()");
685        return (loginStatus);
686    }
687
688    /**
689     * Method to set the login status. Used internally and not visible outside
690     * this package.
691     */
692    protected void setLoginStatus(int status) {
693        authDebug.message("AuthContext::setLoginStatus()");
694        loginStatus = status;
695    }
696
697    /**
698     * Returns the (first) <code>AuthPrincipal</code> in
699     * the <code>Subject</code>. Returns the first <code>Principal</code>,
700     * if more than one exists.
701     *
702     * @return the (first) <code>AuthPrincipal</code> in the
703     *         <code>Subject</code>.
704     *
705     * @supported.api
706     */
707    public Principal getPrincipal() {
708        Set sop = getSubject().getPrincipals();
709        if (authDebug.messageEnabled()) {
710            authDebug.message("AuthContext::getAuthPrincipal(): " + sop);
711        }
712        Iterator items = sop.iterator();
713        if (items.hasNext()) {
714            return ((Principal) items.next());
715        } else {
716            return null;
717        }
718    }
719
720    /**
721     * Method to get the (first) <code>AuthPrincipal</code> in the
722     * <code>Subject</code>. Returns the first <code>Principal</code>, if
723     * more than one exists.
724     *
725     * @deprecated Use getPrincipal() instead
726     */
727    public AuthPrincipal getAuthPrincipal() {
728        authDebug.message("AuthContext::getAuthPrincipal()");
729
730        Set sop = getSubject().getPrincipals();
731        Iterator items = sop.iterator();
732        if (items.hasNext())
733            return ((AuthPrincipal) items.next());
734        else
735            return null;
736    }
737
738    /**
739     * Method to get the set of <code>AuthPrincipal</code>s in the
740     * <code>Subject</code>.
741     */
742    protected Set getPrincipals() {
743        authDebug.message("AuthContext::getAuthPrincipals()");
744        return (getSubject().getPrincipals());
745    }
746
747    /**
748     * Method to get organization name that was set during
749     * construction of this instance.
750     *
751     * @return organization name; <code>null</code> if it was not initialized
752     *         during construction of this instance
753     *
754     * @supported.api
755     */
756    public String getOrganizationName() {
757        if (organizationName == null) {
758            try {
759                organizationName = DN.valueOf(ServiceManager.getBaseDN()).toString().toLowerCase();
760            } catch (LocalizedIllegalArgumentException e) {
761                throw new IllegalStateException("AuthContext.getOrganizationName: Base DN cannot be parsed", e);
762            }
763        }
764        return organizationName;
765    }
766
767    protected String getApplicationName() {
768        return applicationName;
769    }
770
771    /**
772     * Method to get the Single-Sign-On (SSO) Token. This
773     * token can be used as the authenticated token.
774     *
775     * @return single-sign-on token.
776     * @throws InvalidAuthContextException
777     *
778     * @supported.api
779     */
780    public SSOToken getSSOToken() throws InvalidAuthContextException {
781        if (token != null) {
782            return (token);
783        }
784
785        token = new AuthSSOToken(this);
786        try {
787            // Set Organization
788            if (getOrganizationName() != null) {
789                token.setProperty(Constants.ORGANIZATION,
790                    getOrganizationName());
791            }
792
793            // Set Host name
794            InetAddress address = InetAddress.getLocalHost();
795            String ipAddress = address.getHostAddress();
796
797
798            if (authDebug.messageEnabled()) {
799                authDebug.message("Complete Host : " + address.toString());
800                authDebug.message("getSSOToken : IP : " + ipAddress);
801            }
802
803            if (ipAddress != null) {
804                if (isEnableHostLookUp) {
805                    final String strHostName = address.getHostName();
806                    if (authDebug.messageEnabled()) {
807                        authDebug.message("getSSOToken : HOST Name : " + strHostName);
808                    }
809                    if (strHostName != null) {
810                        token.setProperty("HostName", strHostName);
811                    }
812                } else {
813                    token.setProperty("HostName", ipAddress);
814                }
815                token.setProperty("Host", ipAddress);
816            }
817
818            // Set AuthType
819            token.setProperty("AuthType", "ldap");
820
821            // Set Principal
822             String principal = getPrincipal().getName();
823             if (principal != null) {
824                 token.setProperty("Principal", principal);
825                 // Set Universal Identifier
826                 String username = principal;
827                 if (isDN(principal)) {
828                     // Get the username
829                     username = rdnValueFromDn(principal);
830                 }
831                 // Since internal auth will be used during install time
832                 // and during boot strap for users "dsame" and "amadmin"
833                 // the IdType will be hardcoded to User
834                 StringBuilder uuid = new StringBuilder(100);
835                 uuid.append("id=").append(username)
836                 .append(",ou=user,").append(getOrganizationName());
837                 token.setProperty(Constants.UNIVERSAL_IDENTIFIER,
838                     uuid.toString());
839             }
840
841            // Set AuthLevel
842            token.setProperty("AuthLevel", Integer.toString(0));
843
844            //Set ContextId
845            SecureRandom secureRandom =
846                SecureRandomManager.getSecureRandom();
847            String amCtxId =
848                Long.toHexString(secureRandom.nextLong());
849            token.setProperty(Constants.AM_CTX_ID, amCtxId);
850
851            if (authDebug.messageEnabled()) {
852                authDebug.message("SSOToken : Organization : "
853                        + token.getProperty("Organization"));
854                authDebug.message("SSOToken : Principal : "
855                        + token.getProperty("Principal"));
856                authDebug.message("SSOToken : HostName : "
857                        + token.getProperty("HostName"));
858                authDebug.message("SSOToken : Host : "
859                        + token.getProperty("Host"));
860                authDebug.message("SSOToken : getIPAddress : "
861                        + token.getIPAddress());
862                authDebug.message("SSOToken : getHostName : "
863                        + token.getHostName());
864                authDebug.message("SSOToken : ContextId : "
865                        + token.getProperty(Constants.AM_CTX_ID));
866            }
867
868        } catch (Exception e) {
869            if (authDebug.warningEnabled()) {
870                authDebug.warning("getSSOToken: setProperty exception : ", e);
871            }
872        }
873
874        return (token);
875    }
876}