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: SSOTokenManager.java,v 1.7 2009/02/18 23:59:36 qcheng Exp $ 026 * 027 */ 028 029package com.iplanet.sso; 030 031import com.iplanet.services.util.I18n; 032import com.iplanet.sso.providers.dpro.SSOProviderBundle; 033import com.iplanet.ums.IUMSConstants; 034import com.sun.identity.shared.debug.Debug; 035import java.security.Principal; 036import java.util.Set; 037 038/** 039 * SSOTokenManager is the final class that is the mediator between the SSO APIs 040 * and SSO providers. When an SSO client makes an API invocation, 041 * SSOTokenManager will delegate that call to the SSO provider/plug-in. The SSO 042 * provider will execute the call and return the results to SSOTokenManager, 043 * which in turn returns the results to the SSO client. This decouples the SSO 044 * clients from the actual SSO providers. You should be able to replace the SSO 045 * provider without having to modify the SSO client. However, the clients can 046 * invoke the class methods on the objects returned by the SSOTokenManager. 047 * <p> 048 * SSOTokenManager is a singleton class; there can be, at most, only one 049 * instance of SSOTokenManager in any given JVM. <p> SSOTokenManager currently 050 * supports only two kinds of provider, one for Grappa and another for Sun 051 * OpenSSO. In the future, this will be extended to support 052 * <p> It is assumed that the provider classes or the JAR file is in the 053 * CLASSPATH so that they can be found automatically. Providers can be 054 * configured using <code>providerimplclass</code> property. 055 * This property must be set to the complete (absolute) package name of the 056 * main class of the provider. For example, if the provider class is 057 * com.iplanet.sso.providers.dpro.SSOProviderImpl, that entire class name 058 * including package prefixes MUST be specified. The main class MUST implement 059 * the com.iplanet.sso.SSOProvider interface and MUST have a public no-arg 060 * default constructor. 061 * <p> 062 * The class <code>SSOTokenManager</code> is a <code>final</code> class that 063 * provides interfaces to create and validate <code>SSOToken</code>s. 064 * <p> 065 * It is a singleton class; an instance of this class can be obtained by calling 066 * <code>SSOTokenManager.getInstance()</code>. 067 * <p> 068 * Having obtained an instance of <code>SSOTokenManager</code>, its methods 069 * can be called to create <code>SSOToken</code>, get <code>SSOToken</code> 070 * given the <code>SSOTokenID</code> in string format, and to validate 071 * <code>SSOToken</code>s. 072 * 073 * @supported.api 074 */ 075public class SSOTokenManager { 076 077 /* 078 * SSOTokenManager is not a real provider but implements SSOProvider for 079 * consistency in the methods. 080 */ 081 082 /** 083 * Grappa SSOProvider class that will be used by default if 084 * providerimplclass property is not present. 085 */ 086 static final String GRAPPA_PROVIDER_PACKAGE = 087 "com.sun.identity.authentication.internal"; 088 089 static SSOProvider grappaProvider = null; 090 091 /** 092 * DPRO SSOProvider class 093 */ 094 static SSOProvider dProProvider = null; 095 096 /** Debug class that can be used by SSOProvider implementations */ 097 public static Debug debug = Debug.getInstance(IUMSConstants.UMS_DEBUG); 098 099 // Singleton instance of SSOTokenManager 100 private static SSOTokenManager instance = null; 101 102 /** 103 * Returns the singleton instance of 104 * <code>SSOTokenManager</code>. 105 * 106 * @return The singleton <code>SSOTokenManager</code> instance 107 * @throws SSOException 108 * if unable to get the singleton <code>SSOTokenManager</code> 109 * instance. 110 * @supported.api 111 */ 112 public static SSOTokenManager getInstance() throws SSOException { 113 114 /* 115 * We will use the double-checked locking pattern. Rarely entered block. 116 * Push synchronization inside it. This is the first check. 117 */ 118 119 if (instance == null) { 120 /* 121 * Only 1 thread at a time gets past the next point. Rarely executed 122 * synchronization statement and hence synchronization penalty is 123 * not paid every time this method is called. 124 */ 125 126 synchronized (SSOTokenManager.class) { 127 /* 128 * If a second thread was waiting to get here, it will now find 129 * that the instance has already been initialized, and it will 130 * not re-initialize the instance variable. This is the 131 * double-check. 132 */ 133 134 if (instance == null) { 135 /* 136 * Here is the critical section that lazy initializes the 137 * singleton variable. 138 */ 139 debug.message( 140 "Constructing a new instance of SSOTokenManager"); 141 instance = new SSOTokenManager(); 142 } 143 } 144 } 145 return (instance); 146 } 147 148 /** 149 * Since this class is a singleton, the constructor is suppressed. This 150 * constructor will try to find the provider jar files, load them, then find 151 * the provider mainclass, instantiate it and store it in provider. 152 * Providers can be configured using <code>providerimplclass</code> Java 153 * property. This property must be set to the complete (absolute) package 154 * name of the main class of the provider. The main class MUST implement the 155 * com.iplanet.sso.SSOProvider interface and MUST have a public no-arg 156 * default constructor. 157 */ 158 private SSOTokenManager() throws SSOException { 159 Throwable dProException = null; 160 // Obtain the Grappa provider class 161 try { 162 grappaProvider = new 163 com.sun.identity.authentication.internal.AuthSSOProvider(); 164 if (debug.messageEnabled()) { 165 debug.message("Obtained Grappa SSO Provider"); 166 } 167 } catch (Throwable e) { 168 debug.error("Unable to obtain Grappa SSO provider", e); 169 dProException = e; 170 } 171 172 // Obtain the DPRO provide class 173 try { 174 dProProvider = new com.iplanet.sso.providers.dpro.SSOProviderImpl(); 175 if (debug.messageEnabled()) { 176 debug.message("Obtained DPRO SSO Provider"); 177 } 178 } catch (Throwable e) { 179 debug.error("DPRO SSO Provider Exception", e); 180 dProException = e; 181 } 182 183 if (dProProvider == null && grappaProvider == null) { 184 debug.error("Unable to obtain either GRAPPA or DPRO SSO providers"); 185 I18n i18n = I18n.getInstance(IUMSConstants.UMS_PKG); 186 String rbName = i18n.getResBundleName(); 187 if (dProException instanceof ClassNotFoundException) 188 throw new SSOException(rbName, 189 IUMSConstants.SSO_NOPROVIDERCLASS, null); 190 else if (dProException instanceof InstantiationException) 191 throw new SSOException(rbName, 192 IUMSConstants.SSO_NOPROVIDERINSTANCE, null); 193 else if (dProException instanceof IllegalAccessException) 194 throw new SSOException(rbName, IUMSConstants.SSO_ILLEGALACCESS, 195 null); 196 else 197 throw new SSOException(dProException); 198 } 199 } 200 201 /** 202 * Get provider based on SSOToken provided 203 * @param token Single signon SSOToken 204 * @exception SSOException in case of erros when getting the provider 205 */ 206 protected static SSOProvider getProvider(SSOToken token) 207 throws SSOException { 208 if (token == null) { 209 throw new SSOException(SSOProviderBundle.rbName, "ssotokennull", 210 null); 211 } 212 String packageName = token.getClass().getName(); 213 if (packageName.startsWith(GRAPPA_PROVIDER_PACKAGE)) { 214 if (grappaProvider == null) { 215 I18n i18n = I18n.getInstance(IUMSConstants.UMS_PKG); 216 throw new SSOException(i18n.getResBundleName(), 217 IUMSConstants.SSO_NOPROVIDERCLASS, null); 218 } 219 return (grappaProvider); 220 } 221 return (dProProvider); 222 } 223 224 /** 225 * Creates a single sign on token from <code>HttpServletRequest</code> 226 * 227 * @param request 228 * The <code>HttpServletRequest</code> object which contains 229 * the session string. 230 * @return single sign on <code>SSOToken</code> 231 * @exception SSOException 232 * if the single sign on token cannot be created. 233 * @exception UnsupportedOperationException 234 * if this is an unsupported operation. 235 * @supported.api 236 */ 237 public SSOToken createSSOToken( 238 javax.servlet.http.HttpServletRequest request) 239 throws UnsupportedOperationException, SSOException { 240 if (dProProvider != null) 241 return (dProProvider.createSSOToken(request)); 242 else 243 return (grappaProvider.createSSOToken(request)); 244 } 245 246 /** 247 * Creates a single sign on token after authenticating 248 * the principal with the given password. This method of creating a single 249 * sign on token should only be used for command line applications and it is 250 * forbidden to use this single sign on token in any other context (e.g. 251 * policy, federation, etc.). A token created with this method is only valid 252 * within the context of the calling application. Once the process exits the 253 * token will be destroyed. If token is created using this constructor then 254 * ONLY these methods of single sign on token is supported - 255 * 256 * <pre> 257 * getAuthType(), 258 * getHostName(), 259 * getIPAddress(), 260 * setProperty(String name, String value), 261 * getProperty(String name), 262 * isValid(), 263 * validate(). 264 * </pre> 265 * 266 * @param user 267 * Principal representing a user or service 268 * @param password 269 * The password supplied for the principal 270 * @return single sign on token 271 * @exception SSOException 272 * if the single sign on token cannot be created. 273 * @exception UnsupportedOperationException 274 * if this is an unsupported operation. 275 * @deprecated This method has been deprecated. Please use the regular LDAP 276 * authentication mechanism instead. More information on how to 277 * use the authentication programming interfaces as well as the 278 * code samples can be obtained from the "Authentication 279 * Service" chapter of the OpenSSO Developer's Guide. 280 */ 281 public SSOToken createSSOToken(Principal user, String password) 282 throws UnsupportedOperationException, SSOException { 283 if (dProProvider != null) 284 return (dProProvider.createSSOToken(user, password)); 285 else 286 return (grappaProvider.createSSOToken(user, password)); 287 } 288 289 /** 290 * Creates a single sign on token from the single sign 291 * on token ID. Note:-If you want to do Client's IP address validation for 292 * the single sign on token then use 293 * <code>creatSSOToken(String, String)</code> OR 294 * <code>createSSOToken(HttpServletRequest)</code>. 295 * 296 * @param tokenId 297 * Token ID of the single sign on token 298 * @return single sign on token 299 * @exception SSOException 300 * if the single sign on token cannot be created. 301 * @exception UnsupportedOperationException 302 * @supported.api 303 */ 304 public SSOToken createSSOToken(String tokenId) 305 throws UnsupportedOperationException, SSOException { 306 if (dProProvider != null) 307 return (dProProvider.createSSOToken(tokenId)); 308 else 309 return (grappaProvider.createSSOToken(tokenId)); 310 } 311 312 /** 313 * Creates a single sign on token from the single sign 314 * on token ID. 315 * 316 * @param tokenId 317 * Token ID of the single sign on token 318 * @param clientIP 319 * Client IP address. This must be the IP address of the 320 * client/user who is accessing the application. 321 * @return single sign on token 322 * @exception SSOException 323 * if the single sign on token cannot be created. 324 * @exception UnsupportedOperationException 325 * @supported.api 326 */ 327 public SSOToken createSSOToken(String tokenId, String clientIP) 328 throws UnsupportedOperationException, SSOException { 329 if (dProProvider != null) 330 return (dProProvider.createSSOToken(tokenId, clientIP)); 331 else 332 return (grappaProvider.createSSOToken(tokenId, clientIP)); 333 } 334 335 /** 336 * Returns true if a single sign on token is valid. 337 * 338 * @param token 339 * The single sign on token object to be validated. 340 * @return true if the single sign on token is valid. 341 * @supported.api 342 */ 343 public boolean isValidToken(SSOToken token) { 344 try { 345 return (getProvider(token).isValidToken(token)); 346 } catch (SSOException ssoe) { 347 return (false); 348 } 349 } 350 351 /** 352 * Returns true if the single sign on token is valid. 353 * 354 * @param token 355 * The single sign on token object to be validated. 356 * @exception SSOException 357 * if the single sign on token is not valid. 358 * @supported.api 359 */ 360 public void validateToken(SSOToken token) throws SSOException { 361 getProvider(token).validateToken(token); 362 } 363 364 /** 365 * Destroys a single sign on token. 366 * 367 * @param token 368 * The single sign on token object to be destroyed. 369 * @exception SSOException 370 * if there was an error while destroying the token, or the 371 * corresponding session reached its maximum session/idle 372 * time, or the session was destroyed. 373 * @supported.api 374 */ 375 public void destroyToken(SSOToken token) throws SSOException { 376 getProvider(token).destroyToken(token); 377 } 378 379 /** 380 * Refresh the Session corresponding to the single 381 * sign on token from the Session Server. This method should only be used 382 * when the client cannot wait the "session cache interval" for updates on 383 * any changes made to the session properties in the session server. If the 384 * client is remote, calling this method results in an over the wire request 385 * to the session server. 386 * 387 * @param token 388 * single sign on token 389 * @exception SSOException 390 * if the session reached its maximum session time, or the 391 * session was destroyed, or there was an error while 392 * refreshing the session. 393 * @supported.api 394 */ 395 public void refreshSession(SSOToken token) throws SSOException { 396 try { 397 getProvider(token).refreshSession(token); 398 } catch (Exception e) { 399 debug.error("Error in refreshing the session from session server"); 400 throw new SSOException(e); 401 } 402 } 403 404 /** 405 * Destroys a single sign on token. 406 * 407 * @param destroyer 408 * The single sign on token object used to authorize the 409 * operation 410 * @param destroyed 411 * The single sign on token object to be destroyed. 412 * @throws SSOException 413 * if the there was an error during communication with session 414 * service. 415 * @supported.api 416 */ 417 public void destroyToken(SSOToken destroyer, SSOToken destroyed) 418 throws SSOException { 419 getProvider(destroyer).destroyToken(destroyer, destroyed); 420 } 421 422 /** 423 * Returns a list of single sign on token objects 424 * which correspond to valid Sessions accessible to requester. Single sign 425 * on tokens returned are restricted: they can only be used to retrieve 426 * properties and destroy sessions they represent. 427 * 428 * @param requester 429 * The single sign on token object used to authorize the 430 * operation 431 * @param server 432 * The server for which the valid sessions are to be retrieved 433 * @return Set The set of single sign on tokens representing valid Sessions. 434 * @throws SSOException 435 * if the there was an error during communication with session 436 * service. 437 * @supported.api 438 */ 439 public Set getValidSessions(SSOToken requester, String server) 440 throws SSOException { 441 return getProvider(requester).getValidSessions(requester, server); 442 } 443}