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