Repository: cxf
Updated Branches:
refs/heads/3.0.x-fixes 4406f0ee5 -> 6ecda5285
[CXF-6607] - Cached STS-issued tokens are not renewed on expiry in delegation
scenario
Conflicts:
rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/STSTokenRetriever.java
Project: http://git-wip-us.apache.org/repos/asf/cxf/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/949883ba
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/949883ba
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/949883ba
Branch: refs/heads/3.0.x-fixes
Commit: 949883baef755e5e25339069621166a420af98de
Parents: 4406f0e
Author: Colm O hEigeartaigh <[email protected]>
Authored: Thu Sep 24 14:39:23 2015 +0100
Committer: Colm O hEigeartaigh <[email protected]>
Committed: Thu Sep 24 14:40:25 2015 +0100
----------------------------------------------------------------------
.../ws/security/trust/STSTokenRetriever.java | 479 +++++++++++++++++++
.../cxf/systest/sts/renew/SAMLRenewTest.java | 13 +
.../sts/renew/UsernameTokenValidator.java | 67 +++
.../apache/cxf/systest/sts/renew/DoubleIt.wsdl | 3 +
.../apache/cxf/systest/sts/renew/cxf-client.xml | 34 +-
.../cxf/systest/sts/renew/cxf-service.xml | 6 +
.../cxf/systest/sts/renew/cxf-sts-pop.xml | 9 +
7 files changed, 610 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cxf/blob/949883ba/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/STSTokenRetriever.java
----------------------------------------------------------------------
diff --git
a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/STSTokenRetriever.java
b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/STSTokenRetriever.java
new file mode 100644
index 0000000..3b57bda
--- /dev/null
+++
b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/STSTokenRetriever.java
@@ -0,0 +1,479 @@
+/**
+ * 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.trust;
+
+import java.util.HashMap;
+import java.util.Map;
+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.interceptor.Fault;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.rt.security.utils.SecurityUtils;
+import org.apache.cxf.ws.addressing.AddressingProperties;
+import org.apache.cxf.ws.security.SecurityConstants;
+import org.apache.cxf.ws.security.tokenstore.SecurityToken;
+import org.apache.cxf.ws.security.tokenstore.TokenStore;
+import org.apache.cxf.ws.security.tokenstore.TokenStoreUtils;
+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.model.Trust10;
+import org.apache.wss4j.policy.model.Trust13;
+
+/**
+ * A Helper utility class to cache STS token and issue or renew the token from
STS.
+ */
+public final class STSTokenRetriever {
+ private static final Logger LOG =
LogUtils.getL7dLogger(STSTokenRetriever.class);
+ private static final String ASSOCIATED_TOKEN =
+ STSTokenRetriever.class.getName() + "-" + "Associated_Token";
+
+ private STSTokenRetriever() {
+ }
+
+ 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 =
+
SecurityUtils.getSecurityPropertyBoolean(SecurityConstants.CACHE_ISSUED_TOKEN_IN_ENDPOINT,
+ message,
+ true)
+ && !isOneTimeUse(tok);
+ if (cacheIssuedToken) {
+ message.getExchange().getEndpoint().put(SecurityConstants.TOKEN,
tok);
+ message.getExchange().put(SecurityConstants.TOKEN, tok);
+ message.put(SecurityConstants.TOKEN_ELEMENT, tok.getToken());
+ message.getExchange().put(SecurityConstants.TOKEN_ID, tok.getId());
+ message.getExchange().getEndpoint().put(SecurityConstants.TOKEN_ID,
+ tok.getId());
+ } else {
+ message.put(SecurityConstants.TOKEN, tok);
+ message.put(SecurityConstants.TOKEN_ID, tok.getId());
+ message.put(SecurityConstants.TOKEN_ELEMENT, tok.getToken());
+ }
+ // ?
+ TokenStoreUtils.getTokenStore(message).add(tok);
+
+ return tok;
+ }
+
+ private static SecurityToken retrieveCachedToken(Message message) {
+ boolean cacheIssuedToken =
+
SecurityUtils.getSecurityPropertyBoolean(SecurityConstants.CACHE_ISSUED_TOKEN_IN_ENDPOINT,
+ message,
+ 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 =
TokenStoreUtils.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 =
TokenStoreUtils.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 =
+
SecurityUtils.getSecurityPropertyValue(SecurityConstants.STS_TOKEN_ACT_AS,
message);
+ if (token != null) {
+ client.setActAs(token);
+ }
+ token =
+
SecurityUtils.getSecurityPropertyValue(SecurityConstants.STS_TOKEN_ON_BEHALF_OF,
message);
+ if (token != null) {
+ client.setOnBehalfOf(token);
+ }
+ Map<String, Object> ctx = client.getRequestContext();
+ mapSecurityProps(message, ctx);
+
+ Object o =
SecurityUtils.getSecurityPropertyValue(SecurityConstants.STS_APPLIES_TO,
message);
+ 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) {
+ // Check to see whether the delegated token needs to be
renewed
+ secToken = renewToken(message, secToken, params);
+ } else {
+ 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)SecurityUtils.getSecurityPropertyValue(SecurityConstants.STS_TOKEN_IMMINENT_EXPIRY_VALUE,
+ message);
+ 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().getEndpoint().remove(SecurityConstants.TOKEN);
+ message.getExchange().getEndpoint().remove(SecurityConstants.TOKEN_ID);
+ message.getExchange().remove(SecurityConstants.TOKEN_ID);
+ message.getExchange().remove(SecurityConstants.TOKEN);
+ TokenStoreUtils.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 =
+ SecurityUtils.getSecurityPropertyBoolean(
+
SecurityConstants.STS_ISSUE_AFTER_FAILED_RENEW, message, 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 =
+ SecurityUtils.getSecurityPropertyBoolean(
+
SecurityConstants.STS_ISSUE_AFTER_FAILED_RENEW, message, 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 = TokenStoreUtils.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) {
+ Map<String, Object> properties = cachedToken.getProperties();
+ if (properties != null && properties.containsKey(key)) {
+ String associatedToken = (String)properties.get(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) {
+ Map<String, Object> properties = cachedToken.getProperties();
+ if (properties != null && properties.containsKey(key)) {
+ String associatedToken = (String)properties.get(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 = TokenStoreUtils.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);
+ }
+ Map<String, Object> properties = cachedToken.getProperties();
+ if (properties == null) {
+ properties = new HashMap<>();
+ 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);
+ }
+ Map<String, Object> properties = cachedToken.getProperties();
+ if (properties == null) {
+ properties = new HashMap<>();
+ 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);
+ }
+
+ 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;
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cxf/blob/949883ba/services/sts/systests/advanced/src/test/java/org/apache/cxf/systest/sts/renew/SAMLRenewTest.java
----------------------------------------------------------------------
diff --git
a/services/sts/systests/advanced/src/test/java/org/apache/cxf/systest/sts/renew/SAMLRenewTest.java
b/services/sts/systests/advanced/src/test/java/org/apache/cxf/systest/sts/renew/SAMLRenewTest.java
index a2fd15d..9a2c957 100644
---
a/services/sts/systests/advanced/src/test/java/org/apache/cxf/systest/sts/renew/SAMLRenewTest.java
+++
b/services/sts/systests/advanced/src/test/java/org/apache/cxf/systest/sts/renew/SAMLRenewTest.java
@@ -105,11 +105,21 @@ public class SAMLRenewTest extends
AbstractBusClientServerTestBase {
service.getPort(saml2NoRenewPortQName, DoubleItPortType.class);
updateAddressPort(saml2NoRenewPort, PORT);
+ QName saml2IntermediaryPortQName = new QName(NAMESPACE,
"DoubleItTransportSaml2IntermediaryPort");
+ DoubleItPortType saml2IntermediaryPort =
+ service.getPort(saml2IntermediaryPortQName,
DoubleItPortType.class);
+ updateAddressPort(saml2IntermediaryPort, PORT);
+
+ ((BindingProvider)saml2IntermediaryPort).getRequestContext().put(
+ "security.username", "alice"
+ );
+
// Make initial successful invocation(s)
doubleIt(saml1Port, 25);
doubleIt(saml1BearerPort, 30);
doubleIt(saml2Port, 35);
doubleIt(saml2NoRenewPort, 35);
+ doubleIt(saml2IntermediaryPort, 40);
// Now sleep to expire the token(s)
Thread.sleep(8 * 1000);
@@ -138,9 +148,12 @@ public class SAMLRenewTest extends
AbstractBusClientServerTestBase {
// Renew should fail here, but it should fall back to issue
doubleIt(saml2NoRenewPort, 35);
+ doubleIt(saml2IntermediaryPort, 40);
+
((java.io.Closeable)saml1Port).close();
((java.io.Closeable)saml1BearerPort).close();
((java.io.Closeable)saml2Port).close();
+ ((java.io.Closeable)saml2IntermediaryPort).close();
bus.shutdown(true);
}
http://git-wip-us.apache.org/repos/asf/cxf/blob/949883ba/services/sts/systests/advanced/src/test/java/org/apache/cxf/systest/sts/renew/UsernameTokenValidator.java
----------------------------------------------------------------------
diff --git
a/services/sts/systests/advanced/src/test/java/org/apache/cxf/systest/sts/renew/UsernameTokenValidator.java
b/services/sts/systests/advanced/src/test/java/org/apache/cxf/systest/sts/renew/UsernameTokenValidator.java
new file mode 100644
index 0000000..7f0ec75
--- /dev/null
+++
b/services/sts/systests/advanced/src/test/java/org/apache/cxf/systest/sts/renew/UsernameTokenValidator.java
@@ -0,0 +1,67 @@
+/**
+ * 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.systest.sts.renew;
+
+import org.apache.cxf.sts.request.ReceivedToken;
+import org.apache.cxf.sts.request.ReceivedToken.STATE;
+import org.apache.cxf.sts.token.validator.TokenValidator;
+import org.apache.cxf.sts.token.validator.TokenValidatorParameters;
+import org.apache.cxf.sts.token.validator.TokenValidatorResponse;
+import org.apache.cxf.ws.security.sts.provider.model.secext.UsernameTokenType;
+import org.apache.wss4j.common.principal.CustomTokenPrincipal;
+
+public class UsernameTokenValidator implements TokenValidator {
+
+ /**
+ * Return true if this TokenValidator implementation is capable of
validating the
+ * ReceivedToken argument.
+ */
+ public boolean canHandleToken(ReceivedToken validateTarget) {
+ return canHandleToken(validateTarget, null);
+ }
+
+ /**
+ * Return true if this TokenValidator implementation is capable of
validating the
+ * ReceivedToken argument. The realm is ignored in this token Validator.
+ */
+ public boolean canHandleToken(ReceivedToken validateTarget, String realm) {
+ return validateTarget.getToken() instanceof UsernameTokenType;
+ }
+
+ /**
+ * Validate a Token using the given TokenValidatorParameters.
+ */
+ public TokenValidatorResponse validateToken(TokenValidatorParameters
tokenParameters) {
+ TokenValidatorResponse response = new TokenValidatorResponse();
+ ReceivedToken validateTarget = tokenParameters.getToken();
+ validateTarget.setState(STATE.INVALID);
+ response.setToken(validateTarget);
+
+ UsernameTokenType usernameTokenType =
(UsernameTokenType)validateTarget.getToken();
+ // Ignore the fact that no password is provided
+ // Some other requirements must be met to issue a token onbehalfof a
subject
+ // whose authentication is not proved
+ validateTarget.setState(STATE.VALID);
+ response.setPrincipal(new
CustomTokenPrincipal(usernameTokenType.getUsername().getValue()));
+
+ return response;
+ }
+
+}
+
http://git-wip-us.apache.org/repos/asf/cxf/blob/949883ba/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/renew/DoubleIt.wsdl
----------------------------------------------------------------------
diff --git
a/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/renew/DoubleIt.wsdl
b/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/renew/DoubleIt.wsdl
index b586a48..ff4eb32 100644
---
a/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/renew/DoubleIt.wsdl
+++
b/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/renew/DoubleIt.wsdl
@@ -77,6 +77,9 @@
<wsdl:port name="DoubleItTransportSaml2NoRenewPort"
binding="tns:DoubleItTransportSaml2Binding">
<soap:address
location="https://localhost:8081/doubleit/services/doubleittransportsaml2norenew"/>
</wsdl:port>
+ <wsdl:port name="DoubleItTransportSaml2IntermediaryPort"
binding="tns:DoubleItTransportSaml2Binding">
+ <soap:address
location="https://localhost:8081/doubleit/services/doubleittransportsaml2intermediary"/>
+ </wsdl:port>
</wsdl:service>
<wsp:Policy wsu:Id="DoubleItBindingTransportSaml1Policy">
<wsp:ExactlyOne>
http://git-wip-us.apache.org/repos/asf/cxf/blob/949883ba/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/renew/cxf-client.xml
----------------------------------------------------------------------
diff --git
a/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/renew/cxf-client.xml
b/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/renew/cxf-client.xml
index 487f44f..9e36aa3 100644
---
a/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/renew/cxf-client.xml
+++
b/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/renew/cxf-client.xml
@@ -96,7 +96,7 @@
</jaxws:properties>
</jaxws:client>
- <bean id="saml2STSNoRenewClient"
class="org.apache.cxf.ws.security.trust.STSClient">
+ <bean id="saml2STSNoRenewClient"
class="org.apache.cxf.ws.security.trust.STSClient">
<constructor-arg ref="cxf"/>
<property name="wsdlLocation"
value="https://localhost:${testutil.ports.renew.STSServerPOP}/SecurityTokenService/TransportSoap12?wsdl"/>
<property name="serviceName"
value="{http://docs.oasis-open.org/ws-sx/ws-trust/200512/}SecurityTokenService"/>
@@ -122,6 +122,38 @@
<entry key="ws-security.sts.client"
value-ref="saml2STSNoRenewClient" />
</jaxws:properties>
</jaxws:client>
+
+ <bean id="delegationCallbackHandler"
class="org.apache.cxf.ws.security.trust.delegation.WSSUsernameCallbackHandler"/>
+
+ <bean id="saml2STSIntermediaryClient"
class="org.apache.cxf.ws.security.trust.STSClient">
+ <constructor-arg ref="cxf"/>
+ <property name="wsdlLocation"
value="https://localhost:${testutil.ports.renew.STSServerPOP}/SecurityTokenService/Transport?wsdl"/>
+ <property name="serviceName"
value="{http://docs.oasis-open.org/ws-sx/ws-trust/200512/}SecurityTokenService"/>
+ <property name="endpointName"
value="{http://docs.oasis-open.org/ws-sx/ws-trust/200512/}Transport_Port"/>
+ <property name="ttl" value="8"/>
+ <property name="enableLifetime" value="true"/>
+ <property name="allowRenewingAfterExpiry" value="true"/>
+ <property name="onBehalfOf" ref="delegationCallbackHandler"/>
+ <property name="properties">
+ <map>
+ <entry key="security.sts.token.username" value="myclientkey"/>
+ <entry key="security.sts.token.properties"
value="clientKeystore.properties"/>
+ <entry key="security.sts.token.usecert" value="true"/>
+ </map>
+ </property>
+ </bean>
+
+ <jaxws:client
name="{http://www.example.org/contract/DoubleIt}DoubleItTransportSaml2IntermediaryPort"
createdFromAPI="true">
+ <jaxws:properties>
+ <entry key="security.username" value="alice"/>
+ <entry key="security.callback-handler"
value="org.apache.cxf.systest.sts.common.CommonCallbackHandler"/>
+ <entry key="security.signature.properties"
value="clientKeystore.properties"/>
+ <entry key="security.signature.username" value="myclientkey"/>
+ <entry key="security.sts.client"
value-ref="saml2STSIntermediaryClient" />
+ <entry key="ws-security.cache.issued.token.in.endpoint"
value="false"/>
+ </jaxws:properties>
+ </jaxws:client>
+
<http:conduit name="https://localhost:.*">
<http:tlsClientParameters disableCNCheck="true">
<sec:trustManagers>
http://git-wip-us.apache.org/repos/asf/cxf/blob/949883ba/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/renew/cxf-service.xml
----------------------------------------------------------------------
diff --git
a/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/renew/cxf-service.xml
b/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/renew/cxf-service.xml
index 53572b0..bfc7b09 100644
---
a/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/renew/cxf-service.xml
+++
b/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/renew/cxf-service.xml
@@ -48,6 +48,12 @@
<entry key="ws-security.signature.properties"
value="serviceKeystore.properties"/>
</jaxws:properties>
</jaxws:endpoint>
+ <jaxws:endpoint xmlns:s="http://www.example.org/contract/DoubleIt"
id="doubleittransportsaml2intermediary"
implementor="org.apache.cxf.systest.sts.common.DoubleItPortTypeImpl"
endpointName="s:DoubleItTransportSaml2IntermediaryPort"
serviceName="s:DoubleItService" depends-on="ClientAuthHttpsSettings"
address="https://localhost:${testutil.ports.renew.Server}/doubleit/services/doubleittransportsaml2intermediary"
wsdlLocation="org/apache/cxf/systest/sts/renew/DoubleIt.wsdl">
+ <jaxws:properties>
+ <entry key="security.callback-handler"
value="org.apache.cxf.systest.sts.common.CommonCallbackHandler"/>
+ <entry key="security.signature.properties"
value="serviceKeystore.properties"/>
+ </jaxws:properties>
+ </jaxws:endpoint>
<httpj:engine-factory id="ClientAuthHttpsSettings" bus="cxf">
<httpj:engine port="${testutil.ports.renew.Server}">
<httpj:tlsServerParameters>
http://git-wip-us.apache.org/repos/asf/cxf/blob/949883ba/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/renew/cxf-sts-pop.xml
----------------------------------------------------------------------
diff --git
a/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/renew/cxf-sts-pop.xml
b/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/renew/cxf-sts-pop.xml
index ed4c5e3..21600a6 100644
---
a/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/renew/cxf-sts-pop.xml
+++
b/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/renew/cxf-sts-pop.xml
@@ -24,6 +24,12 @@
<cxf:logging/>
</cxf:features>
</cxf:bus>
+
+ <bean id="utDelegationHandler"
class="org.apache.cxf.sts.token.delegation.UsernameTokenDelegationHandler"/>
+ <util:list id="delegationHandlers">
+ <ref bean="utDelegationHandler"/>
+ </util:list>
+
<bean id="transportSTSProviderBean"
class="org.apache.cxf.ws.security.sts.provider.SecurityTokenServiceProvider">
<property name="issueOperation" ref="transportIssueDelegate"/>
<property name="validateOperation" ref="transportValidateDelegate"/>
@@ -35,6 +41,8 @@
<property name="stsProperties" ref="transportSTSProperties"/>
<property name="claimsManager" ref="claimsManager"/>
<property name="tokenStore" ref="defaultTokenStore"/>
+ <property name="delegationHandlers" ref="delegationHandlers"/>
+ <property name="tokenValidators" ref="transportTokenValidators"/>
</bean>
<bean id="transportValidateDelegate"
class="org.apache.cxf.sts.operation.TokenValidateOperation">
<property name="tokenProviders" ref="transportTokenProviders"/>
@@ -55,6 +63,7 @@
</util:list>
<util:list id="transportTokenValidators">
<ref bean="transportSamlTokenValidator"/>
+ <bean class="org.apache.cxf.systest.sts.renew.UsernameTokenValidator"/>
</util:list>
<util:list id="transportTokenRenewers">
<ref bean="transportSamlTokenRenewer"/>