001/* 002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 003 * 004 * Copyright (c) 2006 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: SecurityTokenManagerClient.java,v 1.9 2008/08/19 19:11:09 veiming Exp $ 026 * 027 * Portions Copyright 2013-2015 ForgeRock AS. 028 */ 029 030package com.sun.identity.liberty.ws.security; 031 032import com.sun.identity.shared.locale.Locale; 033import com.sun.identity.shared.configuration.SystemPropertiesManager; 034import com.sun.identity.shared.xml.XMLUtils; 035 036import com.sun.identity.common.SystemConfigurationUtil; 037import com.sun.identity.shared.encode.Base64; 038import com.sun.identity.shared.encode.Base64; 039 040import com.sun.identity.liberty.ws.common.wsse.BinarySecurityToken; 041import com.sun.identity.liberty.ws.disco.EncryptedResourceID; 042 043import com.sun.identity.plugin.session.SessionManager; 044import com.sun.identity.saml.assertion.Assertion; 045import com.sun.identity.saml.assertion.AssertionIDReference; 046import com.sun.identity.saml.assertion.Attribute; 047import com.sun.identity.saml.assertion.NameIdentifier; 048import com.sun.identity.saml.common.SAMLConstants; 049import com.sun.identity.saml.common.SAMLException; 050import com.sun.identity.saml.common.SAMLUtils; 051import com.sun.identity.shared.jaxrpc.SOAPClient; 052import com.sun.identity.saml.protocol.AssertionArtifact; 053 054import java.net.InetAddress; 055import java.net.URL; 056 057import java.rmi.RemoteException; 058import java.rmi.ServerException; 059 060import java.security.cert.X509Certificate; 061 062import java.util.Iterator; 063import java.util.ResourceBundle; 064 065import javax.xml.soap.SOAPException; 066 067/** 068 * The class <code>SecurityTokenManagerClient</code> is a <code>final</code> 069 * class that provides interfaces to create, get and destroy 070 * <code>Assertion</code>s. 071 * <p> 072 * The class provides mechanisms to manage the <code>Assertion</code>s either 073 * locally (i.e., within the same JVM process) or remotely on another instance 074 * of OpenAM. The default constructor will manage the <code> 075 * Assertion</code>s locally if it detects SAML web services running locally, 076 * else will use on of the configured OpenAM. The constructor which 077 * accepts an <code>URL</code> will always use the URL to manage the assertions. 078 * <p> 079 * Having obtained an instance of <code>AssertionManagerClient</code>, its 080 * methods can be called to create/get <code>Assertion</code>, and 081 * <code>AssertionArtifact</code>, and to obtain decision from an 082 * <code>Query</code>. 083 * 084 * @supported.api 085 */ 086public final class SecurityTokenManagerClient { 087 088 // Service name in naming 089 private static String SERVICE_NAME = "securitytokenmanager"; 090 091 // Flag to determine if AssertionManager is local or remote 092 private static boolean checkedForLocal; 093 private static boolean isLocal; 094 private boolean useLocal; 095 096 // Remote JAX-RPC server for objects that use default constructor 097 private static SOAPClient remoteStub; 098 099 // If local pointer to SecurityTokenManager instance 100 private SecurityTokenManager securityTokenManager; 101 private String ssoToken = null; 102 103 // JAX-RPC remote stub 104 private SOAPClient stub; 105 106 static ResourceBundle bundle = 107 Locale.getInstallResourceBundle("libLibertySecurity"); 108 /** 109 * Returns an instance of <code>SecurityTokenManagerClient</code> 110 * 111 * @param credential credential of the caller used to see 112 * if access to this security token manager client is allowed. 113 * @throws SecurityTokenException if unable to access the 114 * the security token manager client. 115 */ 116 public SecurityTokenManagerClient(Object credential) 117 throws SecurityTokenException { 118 if (!checkedForLocal) { 119 try { 120 // Construct the URL for local server. 121 remoteStub = getServiceEndPoint( 122 SystemPropertiesManager.get(SAMLConstants.SERVER_PROTOCOL), 123 SystemPropertiesManager.get(SAMLConstants.SERVER_HOST), 124 SystemPropertiesManager.get(SAMLConstants.SERVER_PORT), 125 SystemPropertiesManager.get(SAMLConstants.SERVER_URI)); 126 remoteStub.send("checkForLocal", null, null, null); 127 if (SecurityTokenManagerImpl.isLocal) { 128 isLocal = true; 129 SecurityTokenManager.debug.warning( 130 "STMC(): Using local service"); 131 securityTokenManager = new SecurityTokenManager(credential); 132 } 133 checkedForLocal = true; 134 } catch (Exception e) { 135 checkedForLocal = true; 136 if (SecurityTokenManager.debug.warningEnabled()) { 137 SecurityTokenManager.debug.warning( 138 "SecurityTokenManagerClient()Exception", e); 139 } 140 throw (new SecurityTokenException(e.getMessage())); 141 } 142 } 143 if (isLocal) { 144 useLocal = true; 145 } else { 146 // Use the remoteStub if set 147 stub = remoteStub; 148 try { 149 ssoToken = 150 SessionManager.getProvider().getSessionID(credential); 151 stub.send("initialization", ssoToken, null, ssoToken); 152 } catch (Exception e) { 153 if (SecurityTokenManager.debug.warningEnabled()) { 154 SecurityTokenManager.debug.warning( 155 "SecurityTokenManagerClient()Exception", e); 156 } 157 throw (new SecurityTokenException(e.getMessage())); 158 } 159 } 160 } 161 162 /** 163 * Returns an instance of <code>SecurityTokenManagerClient</code> 164 * that will use the provided <code>URL</code> for the management 165 * of security tokens. 166 * 167 * @param url the <code>SecurityTokenManagerClient</code> service URL that 168 * will be used to get <code>BinarySecurityToken</code> and 169 * <code>SAMLSecurityToken</code>. 170 * @param credential credential of the caller used to see 171 * if access to this security token manager client is allowed. 172 * @throws SecurityTokenException if unable to access the 173 * the security token manager client. 174 */ 175 public SecurityTokenManagerClient(String url, Object credential) 176 throws SecurityTokenException { 177 try { 178 // Construct the JAX-RPC stub and set the URL endpoint 179 ssoToken = SessionManager.getProvider().getSessionID(credential); 180 String[] urls = {url}; 181 stub = new SOAPClient(urls); 182 stub.send("initialization", ssoToken, null, ssoToken); 183 useLocal = false; 184 } catch (Exception e) { 185 if (SecurityTokenManager.debug.warningEnabled()) { 186 SecurityTokenManager.debug.warning("STMC() Exception", e); 187 } 188 throw (new SecurityTokenException(e.getMessage())); 189 } 190 } 191 192 // Private method to get the service endpoint URL 193 private static SOAPClient getServiceEndPoint(String protocol, 194 String hostname, String port, String uri) throws Exception { 195 // Obtain the URL for the service endpoint 196 int intPort = Integer.parseInt(port); 197 URL weburl = SystemConfigurationUtil.getServiceURL(SERVICE_NAME, 198 protocol, hostname, intPort, uri); 199 String iurl = weburl.toString(); 200 if (SecurityTokenManager.debug.messageEnabled()) { 201 SecurityTokenManager.debug.message( 202 "SecurityTokenManagerClient with URL: " + iurl); 203 } 204 String[] urls = {iurl}; 205 return new SOAPClient(urls); 206 } 207 208 private static SOAPClient getRemoteStub() 209 throws SecurityTokenException { 210 boolean foundServer = false; 211 Exception ee = null; 212 SOAPClient remoteStub = null; 213 try { 214 // Get the list of platform servers 215 Iterator serverList = 216 SystemConfigurationUtil.getServerList().iterator(); 217 218 // Get a server that is responding 219 while (serverList.hasNext() && !foundServer) { 220 URL u = new URL((String) serverList.next()); 221 remoteStub = getServiceEndPoint(u.getProtocol(), u.getHost(), 222 Integer.toString(u.getPort()), u.getPath()); 223 // Check if the server is active 224 try { 225 // this call will throw an exception if server is down 226 remoteStub.send("checkForLocal", null, null, null); 227 if (SecurityTokenManager.debug.messageEnabled()) { 228 SecurityTokenManager.debug.message( 229 "STMC(): Using the remote URL: " + u.toString()); 230 } 231 foundServer = true; 232 if (SecurityTokenManager.debug.warningEnabled()) { 233 SecurityTokenManager.debug.warning( 234 "STMC:getRemoteStub: remote server being used: " 235 + u.toString()); 236 } 237 } catch (Exception e) { 238 ee = e; 239 if (SecurityTokenManager.debug.warningEnabled()) { 240 SecurityTokenManager.debug.warning( 241 "STMC:getRemoteStub: server (" + 242 u.toString() + ") error: ", e); 243 } 244 } 245 } 246 } catch (Exception f) { 247 ee = f; 248 if (SecurityTokenManager.debug.warningEnabled()) { 249 SecurityTokenManager.debug.warning( 250 "STMC:getRemoteStub: generic error: ", f); 251 } 252 } 253 254 if (!foundServer) { 255 // No valid server found. Return the last exception 256 if (ee != null) { 257 throw (new SecurityTokenException(ee.getMessage())); 258 } else { 259 throw (new SecurityTokenException( 260 bundle.getString("serverNotFound"))); 261 } 262 } 263 return (remoteStub); 264 } 265 266 /** 267 * Sets the alias of the certificate used for issuing <code>WSS</code> 268 * token, i.e. <code>WSS</code> <code>X509</code> Token, <code>WSS</code> 269 * SAML Token. If the <code>certAlias</code> is never set, a default 270 * certificate will be used for issuing <code>WSS</code> tokens. 271 * 272 * @param certAlias String alias name for the certificate. 273 * @throws SecurityTokenException if certificate for the 274 * <code>certAlias</code> could not be found in key store. 275 * 276 * @supported.api 277 */ 278 public void setCertAlias(java.lang.String certAlias) 279 throws SecurityTokenException { 280 if (useLocal) { 281 securityTokenManager.setCertAlias(certAlias); 282 } else { 283 try { 284 Object[] obj = {certAlias, Boolean.TRUE}; 285 stub.send("setCertificate", obj, null, ssoToken); 286 } catch (Exception e) { 287 if (SecurityTokenManager.debug.warningEnabled()) { 288 SecurityTokenManager.debug.warning( 289 "STMC:setCertAlias()", e); 290 } 291 throw (new SecurityTokenException(e.getMessage())); 292 } 293 } 294 } 295 296 /** 297 * Sets the certificate used for issuing <code>WSS</code> token, i.e. 298 * <code>WSS</code> <code>X509</code> Token, <code>WSS</code> SAML Token. 299 * If the certificate is never set, a default certificate will 300 * be used for issuing <code>WSS</code> tokens 301 * 302 * @param cert <code>X509</code> certificate 303 * @throws SecurityTokenException if could not set Certificate. 304 */ 305 public void setCertificate(X509Certificate cert) 306 throws SecurityTokenException { 307 if (useLocal) { 308 securityTokenManager.setCertificate(cert); 309 } else { 310 try { 311 String certString = Base64.encode(cert.getEncoded()); 312 Object[] obj = {certString, Boolean.FALSE}; 313 stub.send("setCertificate", obj, null, ssoToken); 314 } catch (Exception e) { 315 if (SecurityTokenManager.debug.warningEnabled()) { 316 SecurityTokenManager.debug.warning( 317 "STMC:setCertificate()", e); 318 } 319 throw (new SecurityTokenException(e.getMessage())); 320 } 321 } 322 } 323 324 /** 325 * Gets the <code>X509</code> certificate Token. 326 * 327 * @return <code>X509</code> certificate Token. 328 * @throws SecurityTokenException if the binary security token could 329 * not be obtained. 330 */ 331 public BinarySecurityToken getX509CertificateToken() 332 throws SecurityTokenException { 333 if (useLocal) { 334 return securityTokenManager.getX509CertificateToken(); 335 } 336 337 String bst = null; 338 try { 339 bst = (String) stub.send("getX509CertificateToken", null, null, 340 ssoToken); 341 return (new BinarySecurityToken(XMLUtils.toDOMDocument(bst, 342 SecurityTokenManager.debug).getDocumentElement())); 343 } catch (Exception e) { 344 if (SecurityTokenManager.debug.warningEnabled()) { 345 SecurityTokenManager.debug.warning( 346 "STMC:getX509CertificateToken()", e); 347 } 348 throw (new SecurityTokenException(e.getMessage())); 349 } 350 } 351 352 /** 353 * Creates a SAML Assertion for message authentication. 354 * 355 * @param senderIdentity name identifier of the sender. 356 * @return Assertion which contains an <code>AuthenticationStatement</code>. 357 * @throws SecurityTokenException if the assertion could not be obtained. 358 * @throws SAMLException if unable to generate the SAML Assertion. 359 */ 360 public SecurityAssertion getSAMLAuthenticationToken( 361 NameIdentifier senderIdentity) 362 throws SecurityTokenException, SAMLException { 363 if (useLocal) { 364 return (securityTokenManager.getSAMLAuthenticationToken( 365 senderIdentity)); 366 } 367 368 try { 369 String ni = senderIdentity.toString(true, true); 370 String assertion = (String) stub.send("getSAMLAuthenticationToken", 371 ni, null, ssoToken); 372 return (new SecurityAssertion(XMLUtils.toDOMDocument(assertion, 373 SecurityTokenManager.debug).getDocumentElement())); 374 } catch (Exception re) { 375 if (SecurityTokenManager.debug.warningEnabled()) { 376 SecurityTokenManager.debug.warning( 377 "STMC:getSAMLAuthenticationToken()", re); 378 } 379 throw (new SAMLException(re.getMessage())); 380 } 381 } 382 383 /** 384 * Creates a SAML Assertion for message authorization, the assertion could 385 * optionally contain an <code>AuthenticationStatement</code> which will be 386 * used for message authentication. 387 * 388 * @param senderIdentity name identifier of the sender. 389 * @param invocatorSession <code>SessionContext</code> of the invocation 390 * identity, it is normally obtained by the credential reference in 391 * the SAML <code>AttributeDesignator</code> for discovery resource 392 * offering which is part of the liberty <code>ID-FF</code> 393 * <code>AuthenResponse</code>. 394 * @param resourceID id for the resource to be accessed. 395 * @param includeAuthN if true, include an 396 * <code>AutheticationStatement</code> in the Assertion which will be 397 * used for message authentication. 398 * @param includeResourceAccessStatement if true, a 399 * <code>ResourceAccessStatement</code> 400 * will be included in the Assertion 401 * (for <code>AuthorizeRequester</code> directive). If false, 402 * a <code>SessionContextStatement</code> will be included in the 403 * Assertion (for <code>AuthenticationSessionContext</code> 404 * directive). In the case when both <code>AuthorizeRequester</code> 405 * and <code>AuthenticationSessionContext</code> directive need to be 406 * handled, use "true" as parameter here since the 407 * <code>SessionContext</code> will always be included in the 408 * <code>ResourceAccessStatement</code>. 409 * @param recipientProviderID recipient's provider ID. 410 * @return the <code>SecurityAssertion</code> object. 411 * @throws SecurityTokenException if the assertion could not be obtained. 412 * @throws SAMLException if unable to generate the SAML Assertion. 413 */ 414 public SecurityAssertion getSAMLAuthorizationToken( 415 NameIdentifier senderIdentity, 416 SessionContext invocatorSession, 417 String resourceID, 418 boolean includeAuthN, 419 boolean includeResourceAccessStatement, 420 String recipientProviderID) 421 throws SecurityTokenException, SAMLException { 422 if (useLocal) { 423 return (securityTokenManager.getSAMLAuthorizationToken( 424 senderIdentity, invocatorSession, resourceID, 425 includeAuthN, includeResourceAccessStatement, 426 recipientProviderID)); 427 } 428 429 try { 430 String ni = senderIdentity.toString(true, true); 431 String sc = invocatorSession.toXMLString(true, true); 432 Object[] obj = {ni, sc, resourceID, Boolean.FALSE, 433 Boolean.valueOf(includeAuthN), 434 Boolean.valueOf(includeResourceAccessStatement), 435 recipientProviderID}; 436 String assertion = (String) stub.send("getSAMLAuthorizationToken", 437 obj, null, ssoToken); 438 return (new SecurityAssertion(XMLUtils.toDOMDocument(assertion, 439 SecurityTokenManager.debug).getDocumentElement())); 440 } catch (Exception e) { 441 if (SecurityTokenManager.debug.warningEnabled()) { 442 SecurityTokenManager.debug.warning( 443 "STMC:createAssertionArtifact:", e); 444 } 445 throw (new SecurityTokenException(e.getMessage())); 446 } 447 } 448 449 /** 450 * Creates a SAML Assertion for message authorization, the assertion could 451 * optionally contain an <code>AuthenticationStatement</code> which will be 452 * used for message authentication. 453 * 454 * @param senderIdentity name identifier of the sender. 455 * @param invocatorSession <code>SessionContext</code> of the invocation 456 * identity, it is normally obtained by the credential reference in 457 * the SAML <code>AttributeDesignator</code> for discovery resource 458 * offering which is part of the liberty <code>ID-FF</code> 459 * <code>AuthenResponse</code>. 460 * @param encResourceID Encrypted ID for the resource to be accessed. 461 * @param includeAuthN if true, include an 462 * <code>AutheticationStatement</code> in the 463 * Assertion which will be used for message authentication. 464 * @param includeResourceAccessStatement if true, 465 * a <code>ResourceAccessStatement</code> will be included in the 466 * Assertion (for <code>AuthorizeRequester</code> directive). If 467 * false, a <code>SessionContextStatement</code> will be included in 468 * the Assertion (for <code>AuthenticationSessionContext</code> 469 * directive). In the case when both <code>AuthorizeRequester</code> 470 * and <code>AuthenticationSessionContext</code> directive need to be 471 * handled, use "true" as parameter here since the 472 * <code>SessionContext</code> will always be included in the 473 * <code>ResourceAccessStatement</code>. 474 * @param recipientProviderID recipient's provider ID. 475 * @return the <code>SecurityAssertion</code> object. 476 * @throws SecurityTokenException if the assertion could not be obtained. 477 * @throws SAMLException if unable to generate the SAML Assertion. 478 */ 479 public SecurityAssertion getSAMLAuthorizationToken( 480 NameIdentifier senderIdentity, 481 SessionContext invocatorSession, 482 EncryptedResourceID encResourceID, 483 boolean includeAuthN, 484 boolean includeResourceAccessStatement, 485 String recipientProviderID) 486 throws SecurityTokenException, SAMLException { 487 if (useLocal) { 488 return (securityTokenManager.getSAMLAuthorizationToken( 489 senderIdentity, invocatorSession, encResourceID, 490 includeAuthN, includeResourceAccessStatement, 491 recipientProviderID)); 492 } 493 494 String assertion = null; 495 496 try { 497 String ni = senderIdentity.toString(true, true); 498 String sc = invocatorSession.toXMLString(true, true); 499 String resourceID = encResourceID.toString(); 500 Object[] obj = {ni, sc, resourceID, Boolean.TRUE, 501 Boolean.valueOf(includeAuthN), 502 Boolean.valueOf(includeResourceAccessStatement), 503 recipientProviderID}; 504 assertion = (String) stub.send("getSAMLAuthorizationToken", 505 obj, null, ssoToken); 506 return (new SecurityAssertion(XMLUtils.toDOMDocument(assertion, 507 SecurityTokenManager.debug).getDocumentElement())); 508 } catch (Exception e) { 509 if (SecurityTokenManager.debug.warningEnabled()) { 510 SecurityTokenManager.debug.warning( 511 "STMC:getSAMLAuthorizationToken() ", e); 512 } 513 throw (new SecurityTokenException(e.getMessage())); 514 } 515 } 516}