Repository: cxf Updated Branches: refs/heads/master e441a15af -> 6bdc9257b
First part of [CXF-6267]: issuing and renewing SAML token functionality into utility Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/6bdc9257 Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/6bdc9257 Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/6bdc9257 Branch: refs/heads/master Commit: 6bdc9257b691e140f435a567e0b4f566c71be6cf Parents: e441a15 Author: Andrei Shakirin <[email protected]> Authored: Sun Mar 15 20:18:42 2015 +0100 Committer: Andrei Shakirin <[email protected]> Committed: Sun Mar 15 20:18:42 2015 +0100 ---------------------------------------------------------------------- .../IssuedTokenInterceptorProvider.java | 401 +------------- .../policy/interceptors/STSTokenHelper.java | 538 +++++++++++++++++++ 2 files changed, 542 insertions(+), 397 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/6bdc9257/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/IssuedTokenInterceptorProvider.java ---------------------------------------------------------------------- diff --git a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/IssuedTokenInterceptorProvider.java b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/IssuedTokenInterceptorProvider.java index 5e5b0d1..5761f78 100644 --- a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/IssuedTokenInterceptorProvider.java +++ b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/IssuedTokenInterceptorProvider.java @@ -24,40 +24,26 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.xml.namespace.QName; -import org.w3c.dom.Element; -import org.apache.cxf.common.logging.LogUtils; -import org.apache.cxf.endpoint.Endpoint; import org.apache.cxf.helpers.CastUtils; import org.apache.cxf.interceptor.Fault; import org.apache.cxf.message.Message; -import org.apache.cxf.message.MessageUtils; import org.apache.cxf.phase.AbstractPhaseInterceptor; import org.apache.cxf.phase.Phase; -import org.apache.cxf.ws.addressing.AddressingProperties; import org.apache.cxf.ws.policy.AbstractPolicyInterceptorProvider; import org.apache.cxf.ws.policy.AssertionInfo; import org.apache.cxf.ws.policy.AssertionInfoMap; import org.apache.cxf.ws.security.SecurityConstants; import org.apache.cxf.ws.security.policy.PolicyUtils; import org.apache.cxf.ws.security.tokenstore.SecurityToken; -import org.apache.cxf.ws.security.tokenstore.TokenStore; -import org.apache.cxf.ws.security.trust.STSClient; -import org.apache.cxf.ws.security.trust.STSUtils; import org.apache.cxf.ws.security.wss4j.PolicyBasedWSS4JInInterceptor; import org.apache.cxf.ws.security.wss4j.PolicyBasedWSS4JOutInterceptor; import org.apache.cxf.ws.security.wss4j.PolicyBasedWSS4JStaxInInterceptor; import org.apache.cxf.ws.security.wss4j.PolicyBasedWSS4JStaxOutInterceptor; import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor; -import org.apache.cxf.ws.security.wss4j.WSS4JUtils; import org.apache.cxf.ws.security.wss4j.policyvalidators.IssuedTokenPolicyValidator; -import org.apache.wss4j.common.ext.WSSecurityException; import org.apache.wss4j.common.saml.SAMLKeyInfo; import org.apache.wss4j.common.saml.SamlAssertionWrapper; import org.apache.wss4j.dom.WSConstants; @@ -70,19 +56,13 @@ import org.apache.wss4j.policy.SP11Constants; import org.apache.wss4j.policy.SP12Constants; import org.apache.wss4j.policy.SPConstants; import org.apache.wss4j.policy.model.IssuedToken; -import org.apache.wss4j.policy.model.Trust10; -import org.apache.wss4j.policy.model.Trust13; /** * */ public class IssuedTokenInterceptorProvider extends AbstractPolicyInterceptorProvider { - private static final Logger LOG = LogUtils.getL7dLogger(IssuedTokenInterceptorProvider.class); - private static final long serialVersionUID = -6936475570762840527L; - private static final String ASSOCIATED_TOKEN = - IssuedTokenInterceptorProvider.class.getName() + "-" + "Associated_Token"; public IssuedTokenInterceptorProvider() { super(Arrays.asList(SP11Constants.ISSUED_TOKEN, SP12Constants.ISSUED_TOKEN)); @@ -133,17 +113,6 @@ public class IssuedTokenInterceptorProvider extends AbstractPolicyInterceptorPro public IssuedTokenOutInterceptor() { super(Phase.PREPARE_SEND); } - private static void mapSecurityProps(Message message, Map<String, Object> ctx) { - for (String s : SecurityConstants.ALL_PROPERTIES) { - Object v = message.getContextualProperty(s + ".it"); - if (v == null) { - v = message.getContextualProperty(s); - } - if (!ctx.containsKey(s) && v != null) { - ctx.put(s, v); - } - } - } public void handleMessage(Message message) throws Fault { AssertionInfoMap aim = message.get(AssertionInfoMap.class); // extract Assertion information @@ -156,33 +125,14 @@ public class IssuedTokenInterceptorProvider extends AbstractPolicyInterceptorPro } if (isRequestor(message)) { IssuedToken itok = (IssuedToken)ais.iterator().next().getAssertion(); - assertIssuedToken(itok, aim); - SecurityToken tok = retrieveCachedToken(message); - if (tok == null) { - tok = issueToken(message, aim, itok); - } else { - tok = renewToken(message, aim, itok, tok); - } + SecurityToken tok = STSTokenHelper.getTokenByWSPolicy(message, itok, aim); + if (tok != null) { + assertIssuedToken(itok, aim); for (AssertionInfo ai : ais) { ai.setAsserted(true); } - boolean cacheIssuedToken = - MessageUtils.getContextualBoolean( - message, SecurityConstants.CACHE_ISSUED_TOKEN_IN_ENDPOINT, true - ) && !isOneTimeUse(tok); - if (cacheIssuedToken) { - message.getExchange().get(Endpoint.class).put(SecurityConstants.TOKEN, tok); - message.getExchange().put(SecurityConstants.TOKEN, tok); - message.getExchange().put(SecurityConstants.TOKEN_ID, tok.getId()); - message.getExchange().get(Endpoint.class).put(SecurityConstants.TOKEN_ID, - tok.getId()); - } else { - message.put(SecurityConstants.TOKEN, tok); - message.put(SecurityConstants.TOKEN_ID, tok.getId()); - } - WSS4JUtils.getTokenStore(message).add(tok); } } else { //server side should be checked on the way in @@ -193,350 +143,7 @@ public class IssuedTokenInterceptorProvider extends AbstractPolicyInterceptorPro assertIssuedToken(itok, aim); } } - } - - private Trust10 getTrust10(AssertionInfoMap aim) { - Collection<AssertionInfo> ais = - PolicyUtils.getAllAssertionsByLocalname(aim, SPConstants.TRUST_10); - if (ais.isEmpty()) { - return null; - } - return (Trust10)ais.iterator().next().getAssertion(); - } - private Trust13 getTrust13(AssertionInfoMap aim) { - Collection<AssertionInfo> ais = - PolicyUtils.getAllAssertionsByLocalname(aim, SPConstants.TRUST_13); - if (ais.isEmpty()) { - return null; - } - return (Trust13)ais.iterator().next().getAssertion(); - } - - // Check to see if the received token is a SAML2 Token with "OneTimeUse" set. If so, - // it should not be cached on the endpoint, but only on the message. - private boolean isOneTimeUse(SecurityToken issuedToken) { - Element token = issuedToken.getToken(); - if (token != null && "Assertion".equals(token.getLocalName()) - && WSConstants.SAML2_NS.equals(token.getNamespaceURI())) { - try { - SamlAssertionWrapper assertion = new SamlAssertionWrapper(token); - - if (assertion.getSaml2().getConditions() != null - && assertion.getSaml2().getConditions().getOneTimeUse() != null) { - return true; - } - } catch (WSSecurityException ex) { - throw new Fault(ex); - } - } - - return false; - } - - private SecurityToken retrieveCachedToken(Message message) { - boolean cacheIssuedToken = - MessageUtils.getContextualBoolean( - message, SecurityConstants.CACHE_ISSUED_TOKEN_IN_ENDPOINT, true - ); - SecurityToken tok = null; - if (cacheIssuedToken) { - tok = (SecurityToken)message.getContextualProperty(SecurityConstants.TOKEN); - if (tok == null) { - String tokId = (String)message.getContextualProperty(SecurityConstants.TOKEN_ID); - if (tokId != null) { - tok = WSS4JUtils.getTokenStore(message).getToken(tokId); - } - } - } else { - tok = (SecurityToken)message.get(SecurityConstants.TOKEN); - if (tok == null) { - String tokId = (String)message.get(SecurityConstants.TOKEN_ID); - if (tokId != null) { - tok = WSS4JUtils.getTokenStore(message).getToken(tokId); - } - } - } - return tok; - } - - /** - * Parse ActAs/OnBehalfOf appropriately. See if the required token is stored in the cache. - */ - private SecurityToken handleDelegation( - Message message, - Element onBehalfOfToken, - Element actAsToken, - String appliesTo, - boolean enableAppliesTo - ) throws Exception { - TokenStore tokenStore = WSS4JUtils.getTokenStore(message); - String key = appliesTo; - if (!enableAppliesTo || key == null || "".equals(key)) { - key = ASSOCIATED_TOKEN; - } - // See if the token corresponding to the OnBehalfOf Token is stored in the cache - // and if it points to an issued token - if (onBehalfOfToken != null) { - String id = getIdFromToken(onBehalfOfToken); - SecurityToken cachedToken = tokenStore.getToken(id); - if (cachedToken != null) { - Properties properties = cachedToken.getProperties(); - if (properties != null && properties.containsKey(key)) { - String associatedToken = properties.getProperty(key); - SecurityToken issuedToken = tokenStore.getToken(associatedToken); - if (issuedToken != null) { - return issuedToken; - } - } - } - } - - // See if the token corresponding to the ActAs Token is stored in the cache - // and if it points to an issued token - if (actAsToken != null) { - String id = getIdFromToken(actAsToken); - SecurityToken cachedToken = tokenStore.getToken(id); - if (cachedToken != null) { - Properties properties = cachedToken.getProperties(); - if (properties != null && properties.containsKey(key)) { - String associatedToken = properties.getProperty(key); - SecurityToken issuedToken = tokenStore.getToken(associatedToken); - if (issuedToken != null) { - return issuedToken; - } - } - } - } - return null; - } - - private String getIdFromToken(Element token) { - if (token != null) { - // Try to find the "Id" on the token. - if (token.hasAttributeNS(WSConstants.WSU_NS, "Id")) { - return token.getAttributeNS(WSConstants.WSU_NS, "Id"); - } else if (token.hasAttributeNS(null, "ID")) { - return token.getAttributeNS(null, "ID"); - } else if (token.hasAttributeNS(null, "AssertionID")) { - return token.getAttributeNS(null, "AssertionID"); - } - } - return ""; - } - - private void storeDelegationTokens( - Message message, - SecurityToken issuedToken, - Element onBehalfOfToken, - Element actAsToken, - String appliesTo, - boolean enableAppliesTo - ) throws Exception { - if (issuedToken == null) { - return; - } - TokenStore tokenStore = WSS4JUtils.getTokenStore(message); - String key = appliesTo; - if (!enableAppliesTo || key == null || "".equals(key)) { - key = ASSOCIATED_TOKEN; - } - if (onBehalfOfToken != null) { - String id = getIdFromToken(onBehalfOfToken); - SecurityToken cachedToken = tokenStore.getToken(id); - if (cachedToken == null) { - cachedToken = new SecurityToken(id); - cachedToken.setToken(onBehalfOfToken); - } - Properties properties = cachedToken.getProperties(); - if (properties == null) { - properties = new Properties(); - cachedToken.setProperties(properties); - } - properties.put(key, issuedToken.getId()); - tokenStore.add(cachedToken); - } - if (actAsToken != null) { - String id = getIdFromToken(actAsToken); - SecurityToken cachedToken = tokenStore.getToken(id); - if (cachedToken == null) { - cachedToken = new SecurityToken(id); - cachedToken.setToken(actAsToken); - } - Properties properties = cachedToken.getProperties(); - if (properties == null) { - properties = new Properties(); - cachedToken.setProperties(properties); - } - properties.put(key, issuedToken.getId()); - tokenStore.add(cachedToken); - } - } - - private SecurityToken getTokenFromSTS( - Message message, - STSClient client, - AssertionInfoMap aim, - AddressingProperties maps, - IssuedToken itok, - String appliesTo - ) throws Exception { - client.setTrust(getTrust10(aim)); - client.setTrust(getTrust13(aim)); - client.setTemplate(itok.getRequestSecurityTokenTemplate()); - if (itok.getPolicy() != null && itok.getPolicy().getNamespace() != null) { - client.setWspNamespace(itok.getPolicy().getNamespace()); - } - if (maps != null && maps.getNamespaceURI() != null) { - client.setAddressingNamespace(maps.getNamespaceURI()); - } - if (itok.getClaims() != null) { - client.setClaims(itok.getClaims()); - } - return client.requestSecurityToken(appliesTo); - } - - private SecurityToken renewToken( - Message message, - AssertionInfoMap aim, - IssuedToken itok, - SecurityToken tok - ) { - String imminentExpiryValue = - (String)message.getContextualProperty(SecurityConstants.STS_TOKEN_IMMINENT_EXPIRY_VALUE); - long imminentExpiry = 10L; - if (imminentExpiryValue != null) { - imminentExpiry = Long.parseLong(imminentExpiryValue); - } - - // If the token has not expired then we don't need to renew it - if (!(tok.isExpired() || tok.isAboutToExpire(imminentExpiry))) { - return tok; - } - - // Remove token from cache - message.getExchange().get(Endpoint.class).remove(SecurityConstants.TOKEN); - message.getExchange().get(Endpoint.class).remove(SecurityConstants.TOKEN_ID); - message.getExchange().remove(SecurityConstants.TOKEN_ID); - message.getExchange().remove(SecurityConstants.TOKEN); - NegotiationUtils.getTokenStore(message).remove(tok.getId()); - - // If the user has explicitly disabled Renewing then we can't renew a token, - // so just get a new one - STSClient client = STSUtils.getClient(message, "sts", itok); - if (!client.isAllowRenewing()) { - return issueToken(message, aim, itok); - } - - AddressingProperties maps = - (AddressingProperties)message - .get("javax.xml.ws.addressing.context.outbound"); - if (maps == null) { - maps = (AddressingProperties)message - .get("javax.xml.ws.addressing.context"); - } - synchronized (client) { - try { - Map<String, Object> ctx = client.getRequestContext(); - mapSecurityProps(message, ctx); - - client.setMessage(message); - - if (maps != null && maps.getNamespaceURI() != null) { - client.setAddressingNamespace(maps.getNamespaceURI()); - } - - client.setTrust(getTrust10(aim)); - client.setTrust(getTrust13(aim)); - - client.setTemplate(itok.getRequestSecurityTokenTemplate()); - return client.renewSecurityToken(tok); - } catch (RuntimeException ex) { - LOG.log(Level.WARNING, "Error renewing a token", ex); - boolean issueAfterFailedRenew = - MessageUtils.getContextualBoolean( - message, SecurityConstants.STS_ISSUE_AFTER_FAILED_RENEW, true - ); - if (issueAfterFailedRenew) { - // Perhaps the STS does not support renewing, so try to issue a new token - return issueToken(message, aim, itok); - } else { - throw ex; - } - } catch (Exception ex) { - LOG.log(Level.WARNING, "Error renewing a token", ex); - boolean issueAfterFailedRenew = - MessageUtils.getContextualBoolean( - message, SecurityConstants.STS_ISSUE_AFTER_FAILED_RENEW, true - ); - if (issueAfterFailedRenew) { - // Perhaps the STS does not support renewing, so try to issue a new token - return issueToken(message, aim, itok); - } else { - throw new Fault(ex); - } - } - } - } - - private SecurityToken issueToken( - Message message, - AssertionInfoMap aim, - IssuedToken itok - ) { - STSClient client = STSUtils.getClient(message, "sts", itok); - AddressingProperties maps = - (AddressingProperties)message - .get("javax.xml.ws.addressing.context.outbound"); - if (maps == null) { - maps = (AddressingProperties)message - .get("javax.xml.ws.addressing.context"); - } - synchronized (client) { - try { - // Transpose ActAs/OnBehalfOf info from original request to the STS client. - Object token = - message.getContextualProperty(SecurityConstants.STS_TOKEN_ACT_AS); - if (token != null) { - client.setActAs(token); - } - token = - message.getContextualProperty(SecurityConstants.STS_TOKEN_ON_BEHALF_OF); - if (token != null) { - client.setOnBehalfOf(token); - } - Map<String, Object> ctx = client.getRequestContext(); - mapSecurityProps(message, ctx); - - Object o = message.getContextualProperty(SecurityConstants.STS_APPLIES_TO); - String appliesTo = o == null ? null : o.toString(); - appliesTo = appliesTo == null - ? message.getContextualProperty(Message.ENDPOINT_ADDRESS).toString() - : appliesTo; - boolean enableAppliesTo = client.isEnableAppliesTo(); - - client.setMessage(message); - Element onBehalfOfToken = client.getOnBehalfOfToken(); - Element actAsToken = client.getActAsToken(); - - SecurityToken secToken = - handleDelegation( - message, onBehalfOfToken, actAsToken, appliesTo, enableAppliesTo - ); - if (secToken == null) { - secToken = getTokenFromSTS(message, client, aim, maps, itok, appliesTo); - } - storeDelegationTokens( - message, secToken, onBehalfOfToken, actAsToken, appliesTo, enableAppliesTo - ); - return secToken; - } catch (RuntimeException e) { - throw e; - } catch (Exception e) { - throw new Fault(e); - } - } - } - + } } static class IssuedTokenInInterceptor extends AbstractPhaseInterceptor<Message> { http://git-wip-us.apache.org/repos/asf/cxf/blob/6bdc9257/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/STSTokenHelper.java ---------------------------------------------------------------------- diff --git a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/STSTokenHelper.java b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/STSTokenHelper.java new file mode 100644 index 0000000..a4d3f41 --- /dev/null +++ b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/STSTokenHelper.java @@ -0,0 +1,538 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.cxf.ws.security.policy.interceptors; + +import java.util.Collection; +import java.util.Map; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.w3c.dom.Element; + +import org.apache.cxf.common.logging.LogUtils; +import org.apache.cxf.endpoint.Endpoint; +import org.apache.cxf.interceptor.Fault; +import org.apache.cxf.message.Message; +import org.apache.cxf.message.MessageUtils; +import org.apache.cxf.ws.addressing.AddressingProperties; +import org.apache.cxf.ws.policy.AssertionInfo; +import org.apache.cxf.ws.policy.AssertionInfoMap; +import org.apache.cxf.ws.security.SecurityConstants; +import org.apache.cxf.ws.security.policy.PolicyUtils; +import org.apache.cxf.ws.security.tokenstore.SecurityToken; +import org.apache.cxf.ws.security.tokenstore.TokenStore; +import org.apache.cxf.ws.security.trust.STSClient; +import org.apache.cxf.ws.security.trust.STSUtils; +import org.apache.cxf.ws.security.wss4j.WSS4JUtils; +import org.apache.wss4j.common.ext.WSSecurityException; +import org.apache.wss4j.common.saml.SamlAssertionWrapper; +import org.apache.wss4j.dom.WSConstants; +import org.apache.wss4j.policy.SPConstants; +import org.apache.wss4j.policy.model.IssuedToken; +import org.apache.wss4j.policy.model.Trust10; +import org.apache.wss4j.policy.model.Trust13; + +public final class STSTokenHelper { + private static final Logger LOG = LogUtils.getL7dLogger(STSTokenHelper.class); + private static final String ASSOCIATED_TOKEN = + STSTokenHelper.class.getName() + "-" + "Associated_Token"; + + private STSTokenHelper() { + } + + public static SecurityToken getTokenByWSPolicy(Message message, IssuedToken issuedToken, + AssertionInfoMap aim) { + TokenRequestParams params = new TokenRequestParams(); + params.setIssuer(issuedToken.getIssuer()); + params.setClaims(issuedToken.getClaims()); + if (issuedToken.getPolicy() != null) { + params.setWspNamespace(issuedToken.getPolicy().getNamespace()); + } + params.setTrust10(getTrust10(aim)); + params.setTrust13(getTrust13(aim)); + params.setTokenTemplate(issuedToken.getRequestSecurityTokenTemplate()); + + return getToken(message, params); + } + + public static SecurityToken getToken(Message message, TokenRequestParams params) { + SecurityToken tok = retrieveCachedToken(message); + if (tok == null) { + tok = issueToken(message, params); + } else { + tok = renewToken(message, tok, params); + } + + boolean cacheIssuedToken = + MessageUtils.getContextualBoolean( + message, + SecurityConstants.CACHE_ISSUED_TOKEN_IN_ENDPOINT, + true) + && !isOneTimeUse(tok); + if (cacheIssuedToken) { + message.getExchange().get(Endpoint.class).put(SecurityConstants.TOKEN, tok); + message.getExchange().put(SecurityConstants.TOKEN, tok); + message.getExchange().put(SecurityConstants.TOKEN_ID, tok.getId()); + message.getExchange().get(Endpoint.class).put(SecurityConstants.TOKEN_ID, + tok.getId()); + } else { + message.put(SecurityConstants.TOKEN, tok); + message.put(SecurityConstants.TOKEN_ID, tok.getId()); + } + // ? + WSS4JUtils.getTokenStore(message).add(tok); + + return tok; + } + + private static SecurityToken retrieveCachedToken(Message message) { + boolean cacheIssuedToken = + MessageUtils.getContextualBoolean( + message, + SecurityConstants.CACHE_ISSUED_TOKEN_IN_ENDPOINT, + true); + SecurityToken tok = null; + if (cacheIssuedToken) { + tok = (SecurityToken)message.getContextualProperty(SecurityConstants.TOKEN); + if (tok == null) { + String tokId = (String)message.getContextualProperty(SecurityConstants.TOKEN_ID); + if (tokId != null) { + tok = WSS4JUtils.getTokenStore(message).getToken(tokId); + } + } + } else { + tok = (SecurityToken)message.get(SecurityConstants.TOKEN); + if (tok == null) { + String tokId = (String)message.get(SecurityConstants.TOKEN_ID); + if (tokId != null) { + tok = WSS4JUtils.getTokenStore(message).getToken(tokId); + } + } + } + return tok; + } + + private static SecurityToken issueToken(Message message, TokenRequestParams params) { + AddressingProperties maps = + (AddressingProperties)message + .get("javax.xml.ws.addressing.context.outbound"); + if (maps == null) { + maps = (AddressingProperties)message + .get("javax.xml.ws.addressing.context"); + } + STSClient client = STSUtils.getClientWithIssuer(message, "sts", params.getIssuer()); + synchronized (client) { + try { + // Transpose ActAs/OnBehalfOf info from original request to the STS client. + Object token = + message.getContextualProperty(SecurityConstants.STS_TOKEN_ACT_AS); + if (token != null) { + client.setActAs(token); + } + token = + message.getContextualProperty(SecurityConstants.STS_TOKEN_ON_BEHALF_OF); + if (token != null) { + client.setOnBehalfOf(token); + } + Map<String, Object> ctx = client.getRequestContext(); + mapSecurityProps(message, ctx); + + Object o = message.getContextualProperty(SecurityConstants.STS_APPLIES_TO); + String appliesTo = o == null ? null : o.toString(); + appliesTo = appliesTo == null + ? message.getContextualProperty(Message.ENDPOINT_ADDRESS).toString() + : appliesTo; + boolean enableAppliesTo = client.isEnableAppliesTo(); + + client.setMessage(message); + Element onBehalfOfToken = client.getOnBehalfOfToken(); + Element actAsToken = client.getActAsToken(); + + SecurityToken secToken = + handleDelegation( + message, onBehalfOfToken, actAsToken, appliesTo, + enableAppliesTo + ); + if (secToken == null) { + secToken = getTokenFromSTS(message, client, maps, appliesTo, params); + } + storeDelegationTokens( + message, secToken, onBehalfOfToken, actAsToken, appliesTo, + enableAppliesTo); + return secToken; + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new Fault(e); + } finally { + client.setTrust((Trust10)null); + client.setTrust((Trust13)null); + client.setTemplate(null); + client.setAddressingNamespace(null); + } + } + } + + private static SecurityToken renewToken( + Message message, + SecurityToken tok, + TokenRequestParams params) { + String imminentExpiryValue = + (String)message + .getContextualProperty(SecurityConstants.STS_TOKEN_IMMINENT_EXPIRY_VALUE); + long imminentExpiry = 10L; + if (imminentExpiryValue != null) { + imminentExpiry = Long.parseLong(imminentExpiryValue); + } + + // If the token has not expired then we don't need to renew it + if (!(tok.isExpired() || tok.isAboutToExpire(imminentExpiry))) { + return tok; + } + + // Remove token from cache + message.getExchange().get(Endpoint.class).remove(SecurityConstants.TOKEN); + message.getExchange().get(Endpoint.class).remove(SecurityConstants.TOKEN_ID); + message.getExchange().remove(SecurityConstants.TOKEN_ID); + message.getExchange().remove(SecurityConstants.TOKEN); + NegotiationUtils.getTokenStore(message).remove(tok.getId()); + + // If the user has explicitly disabled Renewing then we can't renew a token, + // so just get a new one + STSClient client = STSUtils.getClientWithIssuer(message, "sts", params.getIssuer()); + if (!client.isAllowRenewing()) { + return issueToken(message, params); + } + + AddressingProperties maps = + (AddressingProperties)message + .get("javax.xml.ws.addressing.context.outbound"); + if (maps == null) { + maps = (AddressingProperties)message + .get("javax.xml.ws.addressing.context"); + } + synchronized (client) { + try { + Map<String, Object> ctx = client.getRequestContext(); + mapSecurityProps(message, ctx); + + client.setMessage(message); + + if (maps != null) { + client.setAddressingNamespace(maps.getNamespaceURI()); + } + + client.setTrust(params.getTrust10()); + client.setTrust(params.getTrust13()); + + client.setTemplate(params.getTokenTemplate()); + return client.renewSecurityToken(tok); + } catch (RuntimeException ex) { + LOG.log(Level.WARNING, "Error renewing a token", ex); + boolean issueAfterFailedRenew = + MessageUtils + .getContextualBoolean( + message, + SecurityConstants.STS_ISSUE_AFTER_FAILED_RENEW, true); + if (issueAfterFailedRenew) { + // Perhaps the STS does not support renewing, so try to issue a new token + return issueToken(message, params); + } else { + throw ex; + } + } catch (Exception ex) { + LOG.log(Level.WARNING, "Error renewing a token", ex); + boolean issueAfterFailedRenew = + MessageUtils + .getContextualBoolean( + message, + SecurityConstants.STS_ISSUE_AFTER_FAILED_RENEW, true); + if (issueAfterFailedRenew) { + // Perhaps the STS does not support renewing, so try to issue a new token + return issueToken(message, params); + } else { + throw new Fault(ex); + } + } finally { + client.setTrust((Trust10)null); + client.setTrust((Trust13)null); + client.setTemplate(null); + client.setAddressingNamespace(null); + } + } + } + + // Check to see if the received token is a SAML2 Token with "OneTimeUse" set. If so, + // it should not be cached on the endpoint, but only on the message. + private static boolean isOneTimeUse(SecurityToken issuedToken) { + Element token = issuedToken.getToken(); + if (token != null && "Assertion".equals(token.getLocalName()) + && WSConstants.SAML2_NS.equals(token.getNamespaceURI())) { + try { + SamlAssertionWrapper assertion = new SamlAssertionWrapper(token); + + if (assertion.getSaml2().getConditions() != null + && assertion.getSaml2().getConditions().getOneTimeUse() != null) { + return true; + } + } catch (WSSecurityException ex) { + throw new Fault(ex); + } + } + + return false; + } + + private static void mapSecurityProps(Message message, Map<String, Object> ctx) { + for (String s : SecurityConstants.ALL_PROPERTIES) { + Object v = message.getContextualProperty(s + ".it"); + if (v == null) { + v = message.getContextualProperty(s); + } + if (!ctx.containsKey(s) && v != null) { + ctx.put(s, v); + } + } + } + + /** + * Parse ActAs/OnBehalfOf appropriately. See if the required token is stored in the cache. + */ + private static SecurityToken handleDelegation( + Message message, + Element onBehalfOfToken, + Element actAsToken, + String appliesTo, + boolean enableAppliesTo) throws Exception { + TokenStore tokenStore = WSS4JUtils.getTokenStore(message); + String key = appliesTo; + if (!enableAppliesTo || key == null || "".equals(key)) { + key = ASSOCIATED_TOKEN; + } + // See if the token corresponding to the OnBehalfOf Token is stored in the cache + // and if it points to an issued token + if (onBehalfOfToken != null) { + String id = getIdFromToken(onBehalfOfToken); + SecurityToken cachedToken = tokenStore.getToken(id); + if (cachedToken != null) { + Properties properties = cachedToken.getProperties(); + if (properties != null && properties.containsKey(key)) { + String associatedToken = properties.getProperty(key); + SecurityToken issuedToken = tokenStore.getToken(associatedToken); + if (issuedToken != null) { + return issuedToken; + } + } + } + } + + // See if the token corresponding to the ActAs Token is stored in the cache + // and if it points to an issued token + if (actAsToken != null) { + String id = getIdFromToken(actAsToken); + SecurityToken cachedToken = tokenStore.getToken(id); + if (cachedToken != null) { + Properties properties = cachedToken.getProperties(); + if (properties != null && properties.containsKey(key)) { + String associatedToken = properties.getProperty(key); + SecurityToken issuedToken = tokenStore.getToken(associatedToken); + if (issuedToken != null) { + return issuedToken; + } + } + } + } + return null; + } + + private static String getIdFromToken(Element token) { + if (token != null) { + // Try to find the "Id" on the token. + if (token.hasAttributeNS(WSConstants.WSU_NS, "Id")) { + return token.getAttributeNS(WSConstants.WSU_NS, "Id"); + } else if (token.hasAttributeNS(null, "ID")) { + return token.getAttributeNS(null, "ID"); + } else if (token.hasAttributeNS(null, "AssertionID")) { + return token.getAttributeNS(null, "AssertionID"); + } + } + return ""; + } + + private static void storeDelegationTokens( + Message message, + SecurityToken issuedToken, + Element onBehalfOfToken, + Element actAsToken, + String appliesTo, + boolean enableAppliesTo) throws Exception { + if (issuedToken == null) { + return; + } + TokenStore tokenStore = WSS4JUtils.getTokenStore(message); + String key = appliesTo; + if (!enableAppliesTo || key == null || "".equals(key)) { + key = ASSOCIATED_TOKEN; + } + if (onBehalfOfToken != null) { + String id = getIdFromToken(onBehalfOfToken); + SecurityToken cachedToken = tokenStore.getToken(id); + if (cachedToken == null) { + cachedToken = new SecurityToken(id); + cachedToken.setToken(onBehalfOfToken); + } + Properties properties = cachedToken.getProperties(); + if (properties == null) { + properties = new Properties(); + cachedToken.setProperties(properties); + } + properties.put(key, issuedToken.getId()); + tokenStore.add(cachedToken); + } + if (actAsToken != null) { + String id = getIdFromToken(actAsToken); + SecurityToken cachedToken = tokenStore.getToken(id); + if (cachedToken == null) { + cachedToken = new SecurityToken(id); + cachedToken.setToken(actAsToken); + } + Properties properties = cachedToken.getProperties(); + if (properties == null) { + properties = new Properties(); + cachedToken.setProperties(properties); + } + properties.put(key, issuedToken.getId()); + tokenStore.add(cachedToken); + } + } + + private static SecurityToken getTokenFromSTS(Message message, STSClient client, + AddressingProperties maps, String appliesTo, + TokenRequestParams params) throws Exception { + client.setTrust(params.getTrust10()); + client.setTrust(params.getTrust13()); + client.setTemplate(params.getTokenTemplate()); + if (params.getWspNamespace() != null) { + client.setWspNamespace(params.getWspNamespace()); + } + if (maps != null && maps.getNamespaceURI() != null) { + client.setAddressingNamespace(maps.getNamespaceURI()); + } + if (params.getClaims() != null) { + client.setClaims(params.getClaims()); + } + return client.requestSecurityToken(appliesTo); + } + + private static Trust10 getTrust10(AssertionInfoMap aim) { + Collection<AssertionInfo> ais = + PolicyUtils.getAllAssertionsByLocalname(aim, SPConstants.TRUST_10); + if (ais.isEmpty()) { + return null; + } + return (Trust10)ais.iterator().next().getAssertion(); + } + + private static Trust13 getTrust13(AssertionInfoMap aim) { + Collection<AssertionInfo> ais = + PolicyUtils.getAllAssertionsByLocalname(aim, SPConstants.TRUST_13); + if (ais.isEmpty()) { + return null; + } + return (Trust13)ais.iterator().next().getAssertion(); + } + + public static class TokenRequestParams { + private Element issuer; + private Trust10 trust10; + private Trust13 trust13; + private Element tokenTemplate; + private String wspNamespace; + private Element claims; + + public Element getIssuer() { + return issuer; + } + + public void setIssuer(Element issuer) { + this.issuer = issuer; + } + + public Trust10 getTrust10() { + return trust10; + } + + public void setTrust10(Trust10 trust10) { + this.trust10 = trust10; + } + + public Trust13 getTrust13() { + return trust13; + } + + public void setTrust13(Trust13 trust13) { + this.trust13 = trust13; + } + + public Element getTokenTemplate() { + return tokenTemplate; + } + + public void setTokenTemplate(Element tokenTemplate) { + this.tokenTemplate = tokenTemplate; + } + + public String getWspNamespace() { + return wspNamespace; + } + + public void setWspNamespace(String wspNamespace) { + this.wspNamespace = wspNamespace; + } + + public Element getClaims() { + return claims; + } + + public void setClaims(Element claims) { + this.claims = claims; + } + } +} + +/* + * STSClient stsClient = new STSClient(bus); stsClient.setServiceQName(new QName(stsProps.get(STS_NAMESPACE), + * stsProps.get(STS_SERVICE_NAME))); Map<String, Object> props = new HashMap<String, Object>(); for + * (Map.Entry<String, String> entry : stsProps.entrySet()) { if + * (SecurityConstants.ALL_PROPERTIES.contains(entry.getKey())) { props.put(entry.getKey(), + * processFileURI(entry.getValue())); } } stsClient.setProperties(props); + * stsClient.setWsdlLocation(stsProps.get(STS_WSDL_LOCATION)); stsClient.setEndpointQName(new + * QName(stsProps.get(STS_NAMESPACE), stsProps.get(STS_ENDPOINT_NAME))); + * stsClient.setAllowRenewingAfterExpiry(true); stsClient.setEnableLifetime(true); + * stsClient.setTokenType(SAML2_TOKEN_TYPE); stsClient.setKeyType(BEARER_KEYTYPE); if (token != null) { + * stsClient.setActAs(token); } token = + * message.getContextualProperty(SecurityConstants.STS_TOKEN_ON_BEHALF_OF); if (token != null) { + * stsClient.setOnBehalfOf(token); } Object o = + * message.getContextualProperty(SecurityConstants.STS_APPLIES_TO); String appliesTo = null == o ? null : + * o.toString(); appliesTo = null == appliesTo ? + * message.getContextualProperty(Message.ENDPOINT_ADDRESS).toString() : appliesTo; + * stsClient.setMessage(message); + */
