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: AdminTokenAction.java,v 1.14 2009/06/19 02:35:11 bigfatrat Exp $
026 *
027 */
028
029/*
030 * Portions Copyrighted 2010-2011 ForgeRock AS
031 */
032package com.sun.identity.security;
033
034import java.security.PrivilegedAction;
035
036import com.iplanet.am.util.AdminUtils;
037import com.iplanet.am.util.SystemProperties;
038import com.iplanet.services.util.Crypt;
039import com.iplanet.sso.SSOException;
040import com.iplanet.sso.SSOToken;
041import com.iplanet.sso.SSOTokenManager;
042import com.sun.identity.authentication.internal.AuthContext;
043import com.sun.identity.authentication.internal.AuthPrincipal;
044import com.sun.identity.common.ShutdownListener;
045import com.sun.identity.common.ShutdownManager;
046import com.sun.identity.shared.debug.Debug;
047
048/**
049 * The class is used to perform privileged operations using
050 * <code>java.security.AccessController.doPrivileged()
051 * </code> when trying to
052 * get Application single sign on token. There are four approaches to get single
053 * sign on token. 1. Return the single sign on token of the administrator
054 * configured in <code>serverconfig.xml</code> if the code runs on server
055 * site. 2. If #1 fails, it implies the client is using remote SDK. If
056 * <code>com.sun.identity.security.AdminToken</code> is specified in
057 * <code>AMConfig.properties</code>, we will call this application token
058 * provider plug-in to retrieve the single sign on token. 3. If #2 fails, we
059 * look for <code>com.sun.identity.agents.app.username</code> and
060 * <code>com.iplanet.am.service.password</code> in
061 * <code>AMConfig.properties</code>, if so, we will generate single sign
062 * token of administrator based on the user name and password. 4. If #3 fails,
063 * we look for <code>com.sun.identity.agents.app.username</code> and
064 * <code>com.iplanet.am.service.secret</code> in
065 * <code>AMConfig.properties</code>. If so, we will generate single sign on
066 * token based on the user name and secret.
067 * 
068 * Note: Java security permissions check for OpenSSO can be enabled
069 * by setting the property <code>com.sun.identity.security.checkcaller</code> to
070 * true in <code>AMConfig.properties</code> file.
071 * 
072 * </PRE>
073 * 
074 * @supported.all.api
075 */
076public class AdminTokenAction implements PrivilegedAction<SSOToken> {
077    
078    private static SSOTokenManager tokenManager;
079    
080    private static SSOToken appSSOToken;
081    
082    private static SSOToken internalAppSSOToken;
083    
084    private static AdminTokenAction instance;
085
086    private static boolean authInitialized;
087
088    static Debug debug = Debug.getInstance("amSecurity");
089    
090    static final String ADMIN_TOKEN_PROVIDER =
091        "com.sun.identity.security.AdminToken";
092    
093    static final String APP_USERNAME =
094        "com.sun.identity.agents.app.username";
095    
096    static final String APP_SECRET =
097        "com.iplanet.am.service.secret";
098    
099    static final String APP_PASSWORD =
100        "com.iplanet.am.service.password";
101    
102    public static final String AMADMIN_MODE =
103        "com.sun.identity.security.amadmin";
104
105    /**
106     * Returns a cached instance <code>AdminTokenAction</code>.
107     *
108     * @return instance of <code>AdminTokenAction</code>.
109     */
110    public static AdminTokenAction getInstance() {
111        if (instance == null) {
112            instance = new AdminTokenAction();
113        }
114        return instance;
115    }
116
117    /**
118     * Default constructor
119     */
120    public AdminTokenAction() {
121        if (tokenManager == null) {
122            try {
123                tokenManager = SSOTokenManager.getInstance();
124                ShutdownManager.getInstance().addApplicationSSOTokenDestoryer(
125                    new ShutdownListener() {
126                        public void shutdown() {
127                            AdminTokenAction.reset();
128                        }
129                    }); 
130            } catch (SSOException ssoe) {
131                debug.error("AdminTokenAction::init Unable to get " +
132                    "SSOTokenManager", ssoe);
133            }
134        }
135    }
136
137    /**
138     * Informs AdminTokenAction that Authentication has been initialized
139     * This class will start using Authentication service to obtain
140     * SSOToken for admin users
141     */
142    public void authenticationInitialized() {
143        authInitialized = true;
144        // Generate the DPro's SSOToken
145        appSSOToken = getSSOToken();
146        if (debug.messageEnabled()) {
147            debug.message("AdminTokenAction:authenticationInit " +
148                "called. AppSSOToken className=" + (String)
149                ((appSSOToken == null) ? "null" :
150                appSSOToken.getClass().getName()));
151        }
152        // Clear internalAppSSOToken
153        internalAppSSOToken = null;
154    }
155
156    /**
157     * Resets cached SSOToken. WITHOUT destroying.  Called when we know the 
158     * token is invalid
159     */
160    public static void invalid() {
161        appSSOToken = null;
162
163        if (debug.messageEnabled()) {
164            debug.message("AdminTokenAction:invalid called");
165        }
166   }
167
168    /**
169     * Resets cached SSOToken.
170     */
171    public static void reset() {
172        if (appSSOToken != null) {
173            if (tokenManager != null) {
174                try {
175                    tokenManager.destroyToken(appSSOToken);
176                } catch (SSOException ssoe) {
177                    debug.error(
178                        "AdminTokenAction.reset: cannot destroy appSSOToken.",
179                        ssoe);
180                }
181            }
182            
183            appSSOToken = null;
184        }
185        internalAppSSOToken = null;
186    }
187
188    /* (non-Javadoc)
189     * @see java.security.PrivilegedAction#run()
190     */
191    public SSOToken run() {
192        // Check if we have a valid cached SSOToken
193        if ((appSSOToken != null) && tokenManager.isValidToken(appSSOToken)) {
194            return (appSSOToken);
195        }
196
197        // Check if internalAppSSOToken is present
198        if ((internalAppSSOToken != null) &&
199            tokenManager.isValidToken(internalAppSSOToken)) {
200            return (internalAppSSOToken);
201        }
202
203        // Try getting the token from serverconfig.xml
204        SSOToken answer = getSSOToken();
205        if (answer != null) {
206            if (!SystemProperties.isServerMode() || authInitialized) {
207                appSSOToken = answer;
208            }
209            return answer;
210        } else if (debug.messageEnabled()) {
211            debug.message("AdminTokenAction::run Unable to get SSOToken " +
212                " from serverconfig.xml");
213        }
214
215        // Check for configured Application Token Provider
216        // in AMConfig.properties
217        String appTokenProviderName = SystemProperties.get(
218             ADMIN_TOKEN_PROVIDER);
219        if (appTokenProviderName != null) {
220            try {
221                AppSSOTokenProvider appSSOTokenProvider = 
222                    (AppSSOTokenProvider) Class.
223                    forName(appTokenProviderName).newInstance(); 
224                
225                answer = appSSOTokenProvider.getAppSSOToken();
226            } catch (Throwable ce) {
227                if (debug.warningEnabled()) {
228                    debug.warning("AdminTokenAction: Exception " +
229                        "while calling appSSOToken provider plugin.", ce);
230                }
231            } 
232        } else {
233            String appUserName = SystemProperties.get(APP_USERNAME);
234            String tmp = SystemProperties.get(APP_SECRET);
235            String passwd = SystemProperties.get(APP_PASSWORD);
236            String appPassword = null; 
237
238            if (passwd != null && passwd.length() != 0) {
239                appPassword = passwd; 
240            } else if (tmp != null && tmp.length() != 0) {
241                try {
242                    appPassword = Crypt.decode(tmp);
243                } catch (Throwable t) {
244                    if (debug.messageEnabled()) {
245                        debug.message("AdminTokenAction::run Unable to " +
246                            " decrypt secret password", t);
247                    }
248                }
249            }
250
251            if ((appUserName == null) || (appUserName.length() == 0) || 
252               (appPassword == null) || (appPassword.length() == 0)) {
253                debug.message(
254                    "AdminTokenAction: App user name or password is empty");
255            } else {
256                if (AdminTokenAction.debug.messageEnabled()) {
257                    debug.message("App user name: " + appUserName);
258                }
259                SystemAppTokenProvider tokenProd =
260                    new SystemAppTokenProvider(appUserName, appPassword);
261                answer = tokenProd.getAppSSOToken();  
262            }
263        }    
264
265        // If SSOToken is NULL, AM would not bootstrap: fatal error
266        if (answer == null) {
267            debug.error("AdminTokenAction: FATAL ERROR: " +
268                "Cannot obtain Application SSO token." +
269                "\nCheck AMConfig.properties for the following properties" +
270                "\n\tcom.sun.identity.agents.app.username" +
271                "\n\tcom.iplanet.am.service.password");
272            throw new AMSecurityPropertiesException("AdminTokenAction: " + 
273                " FATAL ERROR: Cannot obtain Application SSO token." +
274                "\nCheck AMConfig.properties for the following properties" +
275                "\n\tcom.sun.identity.agents.app.username" +
276                "\n\tcom.iplanet.am.service.password");
277        } else if (!SystemProperties.isServerMode() || authInitialized) {
278            // Cache the SSOToken if not in server mode (i.e., in the
279            // case of client sdk) or if the authN has been initialized
280            appSSOToken = answer;
281        }
282        return answer;
283    }
284    
285    private static SSOToken getSSOToken() {
286        // Please NEVER make this method public!!!!!!!!!!
287        // This can only be used in server site. 
288        SSOToken ssoAuthToken = null;
289
290        try {
291            //call method directly 
292            if (AdminUtils.getAdminPassword() != null) {
293                String adminDN = AdminUtils.getAdminDN();
294                String adminPassword = new String(AdminUtils.getAdminPassword());
295                if (!authInitialized && (SystemProperties.isServerMode() ||
296                    SystemProperties.get(AMADMIN_MODE) != null)) {
297                    // Use internal auth context to get the SSOToken
298                    AuthContext ac = new AuthContext(new AuthPrincipal(adminDN),
299                        adminPassword.toCharArray());
300                    internalAppSSOToken = ssoAuthToken = ac.getSSOToken();
301                } else {
302                    // Copy the authentication state
303                    boolean authInit = authInitialized;
304                    if (authInit) {
305                        authInitialized = false;
306                    }
307
308                    // Obtain SSOToken using AuthN service
309                    ssoAuthToken = (new SystemAppTokenProvider(adminDN,
310                        adminPassword)).getAppSSOToken();
311
312                    // Restore the authentication state
313                    if (authInit && ssoAuthToken != null) {
314                        authInitialized = true;
315                    }
316                }
317            }
318        } catch (NoClassDefFoundError ne) {
319            if (debug.messageEnabled()) {
320                debug.message("AdminTokenAction::getSSOToken " +
321                    "Not found AdminDN and AdminPassword.", ne);
322            }
323        } catch (Throwable t) {
324            if (debug.messageEnabled()) {
325                debug.message("AdminTokenAction::getSSOToken " +
326                    "Exception reading from serverconfig.xml", t);
327            }
328        }
329        return ssoAuthToken;
330    }
331}