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: SSOProviderImpl.java,v 1.9 2009/02/19 05:04:01 bhavnab Exp $ 026 * 027 */ 028 029/** 030 * Portions copyright 2013-2015 ForgeRock AS. 031 */ 032package com.iplanet.sso.providers.dpro; 033 034import com.iplanet.am.util.SystemProperties; 035import com.iplanet.dpro.session.Session; 036import com.iplanet.dpro.session.SessionException; 037import com.iplanet.dpro.session.SessionID; 038import com.iplanet.sso.SSOException; 039import com.iplanet.sso.SSOProvider; 040import com.iplanet.sso.SSOToken; 041import com.iplanet.sso.SSOTokenID; 042import com.sun.identity.common.SearchResults; 043import com.sun.identity.shared.debug.Debug; 044import org.forgerock.openam.session.SessionCache; 045import org.forgerock.openam.utils.ClientUtils; 046import org.forgerock.util.annotations.VisibleForTesting; 047 048import javax.servlet.http.HttpServletRequest; 049import java.net.InetAddress; 050import java.util.HashSet; 051import java.util.Iterator; 052import java.util.Set; 053 054/** 055 * This <code>final</code> class <code>SSOProviderImpl</code> implements 056 * <code>SSOProvider</code> interface and provides implementation of the methods 057 * to create , destroy , check the validity of a single sign on token. 058 * 059 * @supported.api 060 * 061 * Note: Used by ClientSDK, therefore must not use Guice for initialisation. 062 */ 063public final class SSOProviderImpl implements SSOProvider { 064 065 /** 066 * Debug SSOProvider 067 */ 068 public static Debug debug = null; 069 070 /** 071 * Check to see if the clientIPCheck is enabled 072 */ 073 private static boolean checkIP = Boolean.valueOf( 074 SystemProperties.get("com.iplanet.am.clientIPCheckEnabled")) 075 .booleanValue(); 076 077 private final SessionCache sessionCache; 078 079 // Initialize debug instance; 080 static { 081 debug = Debug.getInstance("amSSOProvider"); 082 } 083 084 /** 085 * Constructs a instance of <code>SSOProviderImpl</code> 086 * 087 * @throws SSOException 088 * @supported.api 089 */ 090 public SSOProviderImpl() throws SSOException { 091 this(SessionCache.getInstance()); 092 } 093 094 @VisibleForTesting 095 SSOProviderImpl(SessionCache sessionCache) { 096 this.sessionCache = sessionCache; 097 } 098 099 /** 100 * Creates a single sign on token for the <code>HttpRequest</code> 101 * 102 * @param request <code>HttpServletRequest</code> 103 * @return single sign on token for the request 104 * @throws SSOException if the single sign on token cannot be created. 105 */ 106 public SSOToken createSSOToken(HttpServletRequest request) 107 throws SSOException { 108 try { 109 SessionID sid = new SessionID(request); 110 Session session = sessionCache.getSession(sid); 111 if (sid != null) { 112 Boolean cookieMode = sid.getCookieMode(); 113 if (debug.messageEnabled()) { 114 debug.message("cookieMode is :" + cookieMode); 115 } 116 if (cookieMode != null) { 117 session.setCookieMode(cookieMode); 118 } 119 } 120 if (checkIP && !isIPValid(session, ClientUtils.getClientIPAddress(request))) { 121 throw new Exception(SSOProviderBundle.getString("invalidIP")); 122 } 123 SSOToken ssoToken = new SSOTokenImpl(session); 124 return ssoToken; 125 } catch (Exception e) { 126 if (debug.messageEnabled()) { 127 debug.message("could not create SSOToken from HttpRequest (" 128 + e.getMessage() 129 + ")"); 130 } 131 throw new SSOException(e); 132 } 133 } 134 135 /** 136 * Creates a single sign on token with user or service as the entity 137 * 138 * @param user Principal representing a user or service 139 * @param password password string. 140 * @return single sign on token 141 * @throws SSOException if the single sign on token cannot be created. 142 * @throws UnsupportedOperationException Thrown to indicate that the 143 * requested operation is not supported. 144 * @deprecated This method has been deprecated. Please use the 145 * regular LDAP authentication mechanism instead. More information 146 * on how to use the authentication programming interfaces as well as the 147 * code samples can be obtained from the "Authenticating Using 148 * OpenAM Java SDK" chapter of the OpenAM Developer's Guide. 149 */ 150 public SSOToken createSSOToken(java.security.Principal user, String password) 151 throws SSOException, UnsupportedOperationException { 152 try { 153 SSOTokenImpl ssoToken = new SSOTokenImpl(user, password); 154 if (debug.messageEnabled()) { 155 debug.message("SSO token ldap auth successful for " 156 + user.toString()); 157 } 158 return ssoToken; 159 } catch (Exception e) { 160 if (debug.messageEnabled()) { 161 debug.message("could not create SSOToken for user \"" 162 + user.getName() 163 + "\"", e); 164 } 165 throw new SSOException(e); 166 } 167 } 168 169 /** 170 * Creates a single sign on token. Note: this method should remain private 171 * and get called only by the AuthContext API. Note also: this method may reset 172 * the idle time of the session. 173 * 174 * @param tokenId single sign on token ID. 175 * @param invokedByAuth boolean flag indicating that this method has 176 * been invoked by the AuthContext.getSSOToken() API. 177 * @return single sign on token. 178 * @throws SSOException if the single sign on token cannot be created. 179 * @throws UnsupportedOperationException Thrown to indicate that the 180 * requested operation is not supported. 181 */ 182 public SSOToken createSSOToken(String tokenId, boolean invokedByAuth) 183 throws SSOException, UnsupportedOperationException { 184 return createSSOToken(tokenId, invokedByAuth, true); 185 } 186 187 /** 188 * Creates a single sign on token. 189 * 190 * @param tokenId single sign on token ID. 191 * @param invokedByAuth boolean flag indicating that this method has been invoked by the AuthContext.getSSOToken() 192 * API. 193 * @param possiblyResetIdleTime If true, the idle time of the token/session may be reset to zero. If false, the 194 * idle time will never be reset. 195 * @return single sign on token. 196 * @throws SSOException if the single sign on token cannot be created for any reason. 197 * @throws java.lang.UnsupportedOperationException only here to satisfy the interface, this is never thrown. 198 */ 199 public SSOToken createSSOToken(String tokenId, boolean invokedByAuth, boolean possiblyResetIdleTime) 200 throws SSOException, UnsupportedOperationException { 201 202 try { 203 SessionID sessionId = new SessionID(tokenId); 204 sessionId.setComingFromAuth(invokedByAuth); 205 Session session = sessionCache.getSession(sessionId, false, possiblyResetIdleTime); 206 SSOToken ssoToken = new SSOTokenImpl(session); 207 return ssoToken; 208 } catch (Exception e) { 209 if (debug.messageEnabled()) { 210 debug.message("SSOProviderImpl.createSSOToken(tokenId, " 211 + invokedByAuth 212 + ", " 213 + possiblyResetIdleTime 214 + ") could not create SSOToken for token ID \"" 215 + tokenId 216 + "\" (" 217 + e.getMessage() 218 + ")"); 219 } 220 throw new SSOException(e); 221 } 222 } 223 224 /** 225 * Creates a single sign on token. 226 * 227 * @param tokenId single sign on token ID. 228 * @return single sign on token. 229 * @throws SSOException if the single sign on token cannot be created. 230 * @throws UnsupportedOperationException 231 * @deprecated Use #createSSOToken(String, String) 232 */ 233 public SSOToken createSSOToken(String tokenId) 234 throws SSOException, 235 UnsupportedOperationException { 236 return createSSOToken(tokenId, false); 237 } 238 239 /** 240 * Creates a single sign on token. 241 * 242 * @param tokenId single sign on token ID. 243 * @param clientIP client IP address 244 * @return single sign on token. 245 * @throws SSOException if the single sign on token cannot be created. 246 * @throws UnsupportedOperationException Thrown to indicate that the 247 * requested operation is not supported. 248 * @deprecated Use #createSSOToken(String, String) 249 */ 250 public SSOToken createSSOToken(String tokenId, String clientIP) 251 throws SSOException, UnsupportedOperationException { 252 try { 253 SessionID sessionId = new SessionID(tokenId); 254 Session session = sessionCache.getSession(sessionId); 255 if (checkIP && !isIPValid(session, clientIP)) { 256 throw new Exception(SSOProviderBundle.getString("invalidIP")); 257 } 258 SSOToken ssoToken = new SSOTokenImpl(session); 259 return ssoToken; 260 } catch (Exception e) { 261 if (debug.messageEnabled()) { 262 debug.message("could not create SSOToken for token ID \"" 263 + tokenId 264 + "\" (" 265 + e.getMessage() 266 + ")"); 267 } 268 throw new SSOException(e); 269 } 270 } 271 272 /** 273 * Checks the validity of the single sign on token 274 * 275 * @param token The single sign on token object to be validated 276 * @return Returns true if the <code>SSOToken</code> is valid 277 */ 278 @Override 279 public boolean isValidToken(SSOToken token) { 280 return isValidToken(token, true); 281 } 282 283 /** 284 * Checks the validity of the single sign on token 285 * 286 * @param token The single sign on token object to be validated 287 * @param refresh Flag indicating whether refreshing the token is allowed 288 * @return Returns true if the <code>SSOToken</code> is valid, false otherwise 289 */ 290 @Override 291 public boolean isValidToken(SSOToken token, boolean refresh) { 292 /* 293 * If the token was created from createSSOToken(Principal, password) 294 * there is no association with session. Use this temp solution for now. 295 * If this method is going to go away, we can remove that method, otherwise 296 * a better mechanism has to be implemented. 297 */ 298 SSOTokenImpl tokenImpl = (SSOTokenImpl) token; 299 return (tokenImpl.isValid(refresh)); 300 } 301 302 /** 303 * Checks if the single sign on token is valid. 304 * 305 * @param token single sign on token. 306 * @throws SSOException if the single sign on token is not valid. 307 */ 308 public void validateToken(SSOToken token) throws SSOException { 309 try { 310 /* 311 * if the token was created from createSSOToken(Principal, password) 312 * there is no association with session. Use this temp solution now. 313 * if this method is going to go away, we can remove that method. 314 * otherwise a better mechanism has to be implemented. 315 */ 316 SSOTokenImpl tokenImpl = (SSOTokenImpl) token; 317 tokenImpl.validate(); 318 } catch (Exception e) { 319 if (debug.messageEnabled()) { 320 debug.message("validateToken: ", e); 321 } 322 throw new SSOException(SSOProviderBundle.rbName, "invalidtoken", null); 323 } 324 } 325 326 /** 327 * Destroys a single sign on token 328 * 329 * @param token The single sign on token object to be destroyed 330 * @throws SSOException if the given token cannot be destroyed 331 */ 332 public void destroyToken(SSOToken token) throws SSOException { 333 try { 334 SSOTokenImpl tokenImpl = (SSOTokenImpl) token; 335 if (tokenImpl.isLdapConnection() == true) { 336 tokenImpl.setStatus(false); 337 return; 338 } 339 SSOTokenID tokenid = token.getTokenID(); 340 String id = tokenid.toString(); 341 SessionID sessid = new SessionID(id); 342 Session session = sessionCache.getSession(sessid); 343 session.destroySession(session); 344 } catch (Exception e) { 345 if (debug.messageEnabled()) { 346 debug.message("DestroyToken: ", e); 347 } 348 throw new SSOException(e); 349 } 350 } 351 352 @Override 353 public void logout(final SSOToken token) throws SSOException { 354 try { 355 Session session = sessionCache.getSession(new SessionID(token.getTokenID().toString())); 356 session.logout(); 357 } catch (SessionException e) { 358 if (debug.messageEnabled()) { 359 debug.message("Logout: ", e); 360 } 361 throw new SSOException(e); 362 } 363 } 364 365 /** 366 * Validate the IP address of the client with the IP stored in Session. 367 * 368 * @param sess Session object associated with the token 369 * @param clientIP IP address of the current client who made 370 * <code>HttpRequest</code>. 371 * @return Returns true if the IP is valid else false. 372 * @throws SSOException if IP cannot be validated for the given session 373 */ 374 public boolean isIPValid(Session sess, String clientIP) throws SSOException { 375 boolean check = false; 376 try { 377 InetAddress sessIPAddress = InetAddress.getByName(sess 378 .getProperty("Host")); 379 InetAddress clientIPAddress = InetAddress.getByName(clientIP); 380 if (sessIPAddress.equals(clientIPAddress)) { 381 check = true; 382 } 383 } catch (Exception e) { 384 if (debug.messageEnabled()) { 385 debug.message("IP address check of Token Failed", e); 386 } 387 } 388 return check; 389 } 390 391 /** 392 * Refresh the Session corresponding to the single sign on token from the 393 * Session Server. 394 * 395 * @param token single sign on token for which session need to be refreshed 396 * @throws SSOException if the session cannot be refreshed 397 */ 398 @Override 399 public void refreshSession(SSOToken token) throws SSOException { 400 refreshSession(token, true); 401 } 402 403 /** 404 * Refresh the Session corresponding to the single sign on token from the 405 * Session Server. 406 * 407 * @param token single sign on token for which session need to be refreshed. 408 * @param possiblyResetIdleTime if true, the idle time may be reset, if false it will never be. 409 * @throws SSOException if the session cannot be refreshed. 410 */ 411 @Override 412 public void refreshSession(SSOToken token, boolean possiblyResetIdleTime) throws SSOException { 413 try { 414 SSOTokenID tokenId = token.getTokenID(); 415 SessionID sid = new SessionID(tokenId.toString()); 416 Session session = sessionCache.getSession(sid); 417 session.refresh(possiblyResetIdleTime); 418 } catch (Exception e) { 419 debug.error("Error in refreshing the session from sessions server"); 420 throw new SSOException(e); 421 } 422 } 423 424 /** 425 * Destroys a single sign on token. 426 * 427 * @param destroyer 428 * The single sign on token object used to authorize the 429 * operation 430 * @param destroyed 431 * The single sign on token object to be destroyed. 432 * @throws SSOException 433 * if the there was an error during communication with session 434 * service. 435 * 436 * @supported.api 437 */ 438 public void destroyToken(SSOToken destroyer, SSOToken destroyed) 439 throws SSOException { 440 try { 441 Session requester = ((SSOTokenImpl) destroyer).getSession(); 442 Session target = ((SSOTokenImpl) destroyed).getSession(); 443 requester.destroySession(target); 444 } catch (SessionException e) { 445 throw new SSOException(e); 446 } 447 } 448 449 /** 450 * Returns a list of single sign on token objects 451 * which correspond to valid Sessions accessible to requester. single sign 452 * on token objects returned are restricted: they can only be used to 453 * retrieve properties and destroy sessions they represent. 454 * 455 * @param requester 456 * The single sign on token object used to authorize the 457 * operation 458 * @param server 459 * The server for which the valid sessions are to be retrieved 460 * @return Set of Valid Sessions 461 * @throws SSOException 462 * if the there was an error during communication with session 463 * service. 464 * 465 * @supported.api 466 */ 467 public Set getValidSessions(SSOToken requester, String server) 468 throws SSOException { 469 Set results = new HashSet(); 470 try { 471 SearchResults result = ((SSOTokenImpl) requester).getSession().getValidSessions(server, null); 472 473 for (Iterator iter = result.getResultAttributes().values().iterator(); iter.hasNext();) { 474 Session s = (Session) iter.next(); 475 if (s != null) { 476 results.add(new SSOTokenImpl(s)); 477 } 478 } 479 } catch (SessionException e) { 480 throw new SSOException(e); 481 } 482 return results; 483 } 484}