[CXF-5975] - Add support for renewing tokens "about to expire"
Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/5127aef7 Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/5127aef7 Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/5127aef7 Branch: refs/heads/2.7.x-fixes Commit: 5127aef729a085332c140efade15500751cbd678 Parents: 9d28233 Author: Colm O hEigeartaigh <[email protected]> Authored: Wed Sep 24 15:36:16 2014 +0100 Committer: Colm O hEigeartaigh <[email protected]> Committed: Wed Sep 24 15:43:20 2014 +0100 ---------------------------------------------------------------------- .../cxf/ws/security/SecurityConstants.java | 14 ++++++- .../IssuedTokenInterceptorProvider.java | 9 +++- .../ws/security/tokenstore/SecurityToken.java | 14 +++++++ .../tokenstore/MemoryTokenStoreTest.java | 13 ++++++ .../cxf/systest/sts/caching/CachingTest.java | 43 ++++++++++++++++++++ 5 files changed, 91 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/5127aef7/rt/ws/security/src/main/java/org/apache/cxf/ws/security/SecurityConstants.java ---------------------------------------------------------------------- diff --git a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/SecurityConstants.java b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/SecurityConstants.java index b195a71..ee4df9f 100644 --- a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/SecurityConstants.java +++ b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/SecurityConstants.java @@ -550,6 +550,18 @@ public final class SecurityConstants { * client credentials. */ public static final String DELEGATED_CREDENTIAL = "ws-security.delegated.credential"; + + /** + * This is the value in seconds within which a token is considered to be expired by the + * client. When a cached token (from a STS) is retrieved by the client, it is considered + * to be expired if it will expire in a time less than the value specified by this tag. + * This prevents token expiry when the message is en route / being processed by the + * service. When the token is found to be expired then it will be renewed via the STS. + * + * The default value is 10 (seconds). Specify 0 to avoid this check. + */ + public static final String STS_TOKEN_IMMINENT_EXPIRY_VALUE = + "ws-security.sts.token.imminent-expiry-value"; // // Internal tags @@ -581,7 +593,7 @@ public final class SecurityConstants { ASYMMETRIC_SIGNATURE_ALGORITHM, ENABLE_SAML_ONE_TIME_USE_CACHE, SAML_ONE_TIME_USE_CACHE_INSTANCE, CACHE_IDENTIFIER, CACHE_ISSUED_TOKEN_IN_ENDPOINT, PREFER_WSMEX_OVER_STS_CLIENT_CONFIG, DELEGATED_CREDENTIAL, KERBEROS_USE_CREDENTIAL_DELEGATION, - KERBEROS_IS_USERNAME_IN_SERVICENAME_FORM + KERBEROS_IS_USERNAME_IN_SERVICENAME_FORM, STS_TOKEN_IMMINENT_EXPIRY_VALUE })); ALL_PROPERTIES = Collections.unmodifiableSet(s); } http://git-wip-us.apache.org/repos/asf/cxf/blob/5127aef7/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 9130a2d..4e34915 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 @@ -388,8 +388,15 @@ public class IssuedTokenInterceptorProvider extends AbstractPolicyInterceptorPro 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()) { + if (!(tok.isExpired() || tok.isAboutToExpire(imminentExpiry))) { return tok; } http://git-wip-us.apache.org/repos/asf/cxf/blob/5127aef7/rt/ws/security/src/main/java/org/apache/cxf/ws/security/tokenstore/SecurityToken.java ---------------------------------------------------------------------- diff --git a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/tokenstore/SecurityToken.java b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/tokenstore/SecurityToken.java index 58ed569..6ebbc20 100644 --- a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/tokenstore/SecurityToken.java +++ b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/tokenstore/SecurityToken.java @@ -373,6 +373,20 @@ public class SecurityToken implements Serializable { } return false; } + + /** + * Return whether this SecurityToken is about to expire or not + */ + public boolean isAboutToExpire(long secondsToExpiry) { + if (expires != null && secondsToExpiry > 0) { + Date rightNow = new Date(); + rightNow.setTime(rightNow.getTime() + (secondsToExpiry * 1000L)); + if (expires.before(rightNow)) { + return true; + } + } + return false; + } /** * @param expires The expires to set. http://git-wip-us.apache.org/repos/asf/cxf/blob/5127aef7/rt/ws/security/src/test/java/org/apache/cxf/ws/security/tokenstore/MemoryTokenStoreTest.java ---------------------------------------------------------------------- diff --git a/rt/ws/security/src/test/java/org/apache/cxf/ws/security/tokenstore/MemoryTokenStoreTest.java b/rt/ws/security/src/test/java/org/apache/cxf/ws/security/tokenstore/MemoryTokenStoreTest.java index a124c02..3f855a8 100644 --- a/rt/ws/security/src/test/java/org/apache/cxf/ws/security/tokenstore/MemoryTokenStoreTest.java +++ b/rt/ws/security/src/test/java/org/apache/cxf/ws/security/tokenstore/MemoryTokenStoreTest.java @@ -93,4 +93,17 @@ public class MemoryTokenStoreTest extends org.junit.Assert { store.remove(token2.getId()); assertTrue(store.getTokenIdentifiers().size() == 0); } + + @org.junit.Test + public void testTokenExpiry() { + SecurityToken token = new SecurityToken(); + + Date expires = new Date(); + expires.setTime(expires.getTime() + (5L * 60L * 1000L)); + token.setExpires(expires); + + assertFalse(token.isExpired()); + assertFalse(token.isAboutToExpire(100L)); + assertTrue(token.isAboutToExpire((5L * 60L * 1000L) + 1L)); + } } http://git-wip-us.apache.org/repos/asf/cxf/blob/5127aef7/services/sts/systests/advanced/src/test/java/org/apache/cxf/systest/sts/caching/CachingTest.java ---------------------------------------------------------------------- diff --git a/services/sts/systests/advanced/src/test/java/org/apache/cxf/systest/sts/caching/CachingTest.java b/services/sts/systests/advanced/src/test/java/org/apache/cxf/systest/sts/caching/CachingTest.java index 151fae5..93e77ee 100644 --- a/services/sts/systests/advanced/src/test/java/org/apache/cxf/systest/sts/caching/CachingTest.java +++ b/services/sts/systests/advanced/src/test/java/org/apache/cxf/systest/sts/caching/CachingTest.java @@ -19,6 +19,7 @@ package org.apache.cxf.systest.sts.caching; import java.net.URL; +import java.util.Date; import javax.xml.namespace.QName; import javax.xml.ws.BindingProvider; @@ -36,6 +37,8 @@ import org.apache.cxf.systest.sts.common.SecurityTestUtil; import org.apache.cxf.systest.sts.deployment.STSServer; import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase; 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.trust.STSClient; import org.example.contract.doubleit.DoubleItPortType; import org.junit.BeforeClass; @@ -163,6 +166,46 @@ public class CachingTest extends AbstractBusClientServerTestBase { bus.shutdown(true); } + @org.junit.Test + public void testImminentExpiry() throws Exception { + + SpringBusFactory bf = new SpringBusFactory(); + URL busFile = CachingTest.class.getResource("cxf-client.xml"); + + Bus bus = bf.createBus(busFile.toString()); + SpringBusFactory.setDefaultBus(bus); + SpringBusFactory.setThreadDefaultBus(bus); + + URL wsdl = CachingTest.class.getResource("DoubleIt.wsdl"); + Service service = Service.create(wsdl, SERVICE_QNAME); + QName portQName = new QName(NAMESPACE, "DoubleItTransportSAML1Port"); + DoubleItPortType port = + service.getPort(portQName, DoubleItPortType.class); + ((BindingProvider)port).getRequestContext().put("thread.local.request.context", "true"); + updateAddressPort(port, PORT); + + // Make a successful invocation + doubleIt(port, 25); + + Client client = ClientProxy.getClient(port); + Endpoint ep = client.getEndpoint(); + String id = (String)ep.get(SecurityConstants.TOKEN_ID); + TokenStore store = (TokenStore)ep.getEndpointInfo().getProperty(TokenStore.class.getName()); + SecurityToken tok = store.getToken(id); + assertNotNull(tok); + + // Make the token "about to expire" + Date expiredDate = new Date(); + expiredDate.setTime(expiredDate.getTime() + 5000L); + tok.setExpires(expiredDate); + assertTrue(tok.isAboutToExpire(10L)); + + doubleIt(port, 25); + + ((java.io.Closeable)port).close(); + bus.shutdown(true); + } + private void clearSTSClient(BindingProvider p, Bus bus) throws BusException, EndpointException { p.getRequestContext().put(SecurityConstants.STS_CLIENT, new STSClient(bus)); }
