You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by co...@apache.org on 2015/11/09 20:27:56 UTC
[5/5] cxf git commit: Fixing time/expiry stuff for JWT in the STS +
tests
Fixing time/expiry stuff for JWT in the STS + tests
Project: http://git-wip-us.apache.org/repos/asf/cxf/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/8516661b
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/8516661b
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/8516661b
Branch: refs/heads/3.1.x-fixes
Commit: 8516661b64e630e033425b24b7af53680d1229ca
Parents: 0848bdb
Author: Colm O hEigeartaigh <co...@apache.org>
Authored: Mon Nov 9 16:42:31 2015 +0000
Committer: Colm O hEigeartaigh <co...@apache.org>
Committed: Mon Nov 9 19:27:42 2015 +0000
----------------------------------------------------------------------
.../provider/DefaultConditionsProvider.java | 43 +-
.../sts/token/provider/TokenProviderUtils.java | 82 ++++
.../provider/jwt/DefaultJWTClaimsProvider.java | 209 +++++++++-
.../token/provider/JWTProviderLifetimeTest.java | 409 +++++++++++++++++++
4 files changed, 696 insertions(+), 47 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cxf/blob/8516661b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/DefaultConditionsProvider.java
----------------------------------------------------------------------
diff --git a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/DefaultConditionsProvider.java b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/DefaultConditionsProvider.java
index f720ed6..eeb2862 100644
--- a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/DefaultConditionsProvider.java
+++ b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/DefaultConditionsProvider.java
@@ -25,16 +25,9 @@ import java.util.Date;
import java.util.List;
import java.util.logging.Logger;
-import javax.xml.bind.JAXBElement;
-import javax.xml.namespace.QName;
-
-import org.w3c.dom.Element;
import org.apache.cxf.common.logging.LogUtils;
-import org.apache.cxf.helpers.DOMUtils;
-import org.apache.cxf.sts.STSConstants;
import org.apache.cxf.sts.request.Lifetime;
import org.apache.cxf.sts.request.Participants;
-import org.apache.cxf.ws.addressing.EndpointReferenceType;
import org.apache.cxf.ws.security.sts.provider.STSException;
import org.apache.wss4j.common.saml.bean.AudienceRestrictionBean;
import org.apache.wss4j.common.saml.bean.ConditionsBean;
@@ -261,41 +254,7 @@ public class DefaultConditionsProvider implements ConditionsProvider {
* Extract an address from a Participants EPR DOM element
*/
protected String extractAddressFromParticipantsEPR(Object participants) {
- if (participants instanceof Element) {
- String localName = ((Element)participants).getLocalName();
- String namespace = ((Element)participants).getNamespaceURI();
-
- if (STSConstants.WSA_NS_05.equals(namespace) && "EndpointReference".equals(localName)) {
- LOG.fine("Found EndpointReference element");
- Element address =
- DOMUtils.getFirstChildWithName((Element)participants,
- STSConstants.WSA_NS_05, "Address");
- if (address != null) {
- LOG.fine("Found address element");
- return address.getTextContent();
- }
- } else if ((STSConstants.WSP_NS.equals(namespace) || STSConstants.WSP_NS_04.equals(namespace))
- && "URI".equals(localName)) {
- return ((Element)participants).getTextContent();
- }
- LOG.fine("Participants element does not exist or could not be parsed");
- return null;
- } else if (participants instanceof JAXBElement<?>) {
- JAXBElement<?> jaxbElement = (JAXBElement<?>) participants;
- QName participantsName = jaxbElement.getName();
- if (STSConstants.WSA_NS_05.equals(participantsName.getNamespaceURI())
- && "EndpointReference".equals(participantsName.getLocalPart())) {
- LOG.fine("Found EndpointReference element");
- EndpointReferenceType endpointReference = (EndpointReferenceType)jaxbElement.getValue();
- if (endpointReference.getAddress() != null) {
- LOG.fine("Found address element");
- return endpointReference.getAddress().getValue();
- }
- }
- LOG.fine("Participants element does not exist or could not be parsed");
- }
-
- return null;
+ return TokenProviderUtils.extractAddressFromParticipantsEPR(participants);
}
}
http://git-wip-us.apache.org/repos/asf/cxf/blob/8516661b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/TokenProviderUtils.java
----------------------------------------------------------------------
diff --git a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/TokenProviderUtils.java b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/TokenProviderUtils.java
new file mode 100644
index 0000000..406c02e
--- /dev/null
+++ b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/TokenProviderUtils.java
@@ -0,0 +1,82 @@
+/**
+ * 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.sts.token.provider;
+
+import java.util.logging.Logger;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.namespace.QName;
+
+import org.w3c.dom.Element;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.helpers.DOMUtils;
+import org.apache.cxf.sts.STSConstants;
+import org.apache.cxf.ws.addressing.EndpointReferenceType;
+
+public final class TokenProviderUtils {
+
+ private static final Logger LOG = LogUtils.getL7dLogger(TokenProviderUtils.class);
+
+ private TokenProviderUtils() {
+ // complete
+ }
+
+ /**
+ * Extract an address from a Participants EPR DOM element
+ */
+ public static String extractAddressFromParticipantsEPR(Object participants) {
+ if (participants instanceof Element) {
+ String localName = ((Element)participants).getLocalName();
+ String namespace = ((Element)participants).getNamespaceURI();
+
+ if (STSConstants.WSA_NS_05.equals(namespace) && "EndpointReference".equals(localName)) {
+ LOG.fine("Found EndpointReference element");
+ Element address =
+ DOMUtils.getFirstChildWithName((Element)participants,
+ STSConstants.WSA_NS_05, "Address");
+ if (address != null) {
+ LOG.fine("Found address element");
+ return address.getTextContent();
+ }
+ } else if ((STSConstants.WSP_NS.equals(namespace) || STSConstants.WSP_NS_04.equals(namespace))
+ && "URI".equals(localName)) {
+ return ((Element)participants).getTextContent();
+ }
+ LOG.fine("Participants element does not exist or could not be parsed");
+ return null;
+ } else if (participants instanceof JAXBElement<?>) {
+ JAXBElement<?> jaxbElement = (JAXBElement<?>) participants;
+ QName participantsName = jaxbElement.getName();
+ if (STSConstants.WSA_NS_05.equals(participantsName.getNamespaceURI())
+ && "EndpointReference".equals(participantsName.getLocalPart())) {
+ LOG.fine("Found EndpointReference element");
+ EndpointReferenceType endpointReference = (EndpointReferenceType)jaxbElement.getValue();
+ if (endpointReference.getAddress() != null) {
+ LOG.fine("Found address element");
+ return endpointReference.getAddress().getValue();
+ }
+ }
+ LOG.fine("Participants element does not exist or could not be parsed");
+ }
+
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/8516661b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/jwt/DefaultJWTClaimsProvider.java
----------------------------------------------------------------------
diff --git a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/jwt/DefaultJWTClaimsProvider.java b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/jwt/DefaultJWTClaimsProvider.java
index 1e80f96..dcdc7c8 100644
--- a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/jwt/DefaultJWTClaimsProvider.java
+++ b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/jwt/DefaultJWTClaimsProvider.java
@@ -19,8 +19,11 @@
package org.apache.cxf.sts.token.provider.jwt;
import java.security.Principal;
+import java.text.ParseException;
+import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
+import java.util.List;
import java.util.UUID;
import java.util.logging.Logger;
@@ -28,14 +31,19 @@ import javax.security.auth.x500.X500Principal;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.rs.security.jose.jwt.JwtClaims;
+import org.apache.cxf.rs.security.jose.jwt.JwtConstants;
import org.apache.cxf.sts.STSPropertiesMBean;
import org.apache.cxf.sts.claims.ClaimsUtils;
import org.apache.cxf.sts.claims.ProcessedClaim;
import org.apache.cxf.sts.claims.ProcessedClaimCollection;
+import org.apache.cxf.sts.request.Lifetime;
+import org.apache.cxf.sts.request.Participants;
import org.apache.cxf.sts.request.ReceivedToken;
import org.apache.cxf.sts.request.ReceivedToken.STATE;
import org.apache.cxf.sts.token.provider.TokenProviderParameters;
+import org.apache.cxf.sts.token.provider.TokenProviderUtils;
import org.apache.cxf.ws.security.sts.provider.STSException;
+import org.apache.wss4j.dom.util.XmlSchemaDateFormat;
/**
* A default implementation to create a JWTClaims object. The Subject name is the name
@@ -43,8 +51,16 @@ import org.apache.cxf.ws.security.sts.provider.STSException;
*/
public class DefaultJWTClaimsProvider implements JWTClaimsProvider {
+ public static final long DEFAULT_MAX_LIFETIME = 60L * 60L * 12L;
+
private static final Logger LOG = LogUtils.getL7dLogger(DefaultJWTClaimsProvider.class);
private boolean useX500CN;
+
+ private long lifetime = 60L * 30L;
+ private long maxLifetime = DEFAULT_MAX_LIFETIME;
+ private boolean failLifetimeExceedance = true;
+ private boolean acceptClientLifetime;
+ private long futureTimeToLive = 60L;
/**
* Get a JwtClaims object.
@@ -66,11 +82,9 @@ public class DefaultJWTClaimsProvider implements JWTClaimsProvider {
handleWSTrustClaims(jwtClaimsProviderParameters, claims);
- Date currentDate = new Date();
- claims.setIssuedAt(currentDate.getTime() / 1000L);
- long currentTime = currentDate.getTime() + 300L * 1000L;
- currentDate.setTime(currentTime);
- claims.setExpiryTime(currentDate.getTime() / 1000L);
+ handleConditions(jwtClaimsProviderParameters, claims);
+
+ handleAudienceRestriction(jwtClaimsProviderParameters, claims);
return claims;
}
@@ -155,6 +169,109 @@ public class DefaultJWTClaimsProvider implements JWTClaimsProvider {
}
}
+ protected void handleConditions(JWTClaimsProviderParameters jwtClaimsProviderParameters, JwtClaims claims) {
+ TokenProviderParameters providerParameters = jwtClaimsProviderParameters.getProviderParameters();
+
+ Date currentDate = new Date();
+ long currentTimeInSeconds = currentDate.getTime() / 1000L;
+
+ // Set the defaults first
+ claims.setIssuedAt(currentTimeInSeconds);
+ claims.setNotBefore(currentTimeInSeconds);
+ claims.setExpiryTime(currentTimeInSeconds + lifetime);
+
+ Lifetime tokenLifetime = providerParameters.getTokenRequirements().getLifetime();
+ if (lifetime > 0 && acceptClientLifetime && tokenLifetime != null
+ && tokenLifetime.getCreated() != null && tokenLifetime.getExpires() != null) {
+ try {
+ XmlSchemaDateFormat fmt = new XmlSchemaDateFormat();
+ Date creationTime = fmt.parse(tokenLifetime.getCreated());
+ Date expirationTime = fmt.parse(tokenLifetime.getExpires());
+ if (creationTime == null || expirationTime == null) {
+ LOG.fine("Error in parsing Timestamp Created or Expiration Strings");
+ throw new STSException(
+ "Error in parsing Timestamp Created or Expiration Strings",
+ STSException.INVALID_TIME
+ );
+ }
+
+ // Check to see if the created time is in the future
+ Date validCreation = new Date();
+ long currentTime = validCreation.getTime();
+ if (futureTimeToLive > 0) {
+ validCreation.setTime(currentTime + futureTimeToLive * 1000L);
+ }
+ if (creationTime.after(validCreation)) {
+ LOG.fine("The Created Time is too far in the future");
+ throw new STSException("The Created Time is too far in the future", STSException.INVALID_TIME);
+ }
+
+ long requestedLifetime = expirationTime.getTime() - creationTime.getTime();
+ if (requestedLifetime > (getMaxLifetime() * 1000L)) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Requested lifetime [").append(requestedLifetime / 1000L);
+ sb.append(" sec] exceed configured maximum lifetime [").append(getMaxLifetime());
+ sb.append(" sec]");
+ LOG.warning(sb.toString());
+ if (isFailLifetimeExceedance()) {
+ throw new STSException("Requested lifetime exceeds maximum lifetime",
+ STSException.INVALID_TIME);
+ } else {
+ expirationTime.setTime(creationTime.getTime() + (getMaxLifetime() * 1000L));
+ }
+ }
+
+ long creationTimeInSeconds = creationTime.getTime() / 1000L;
+ claims.setIssuedAt(creationTimeInSeconds);
+ claims.setNotBefore(creationTimeInSeconds);
+ claims.setExpiryTime(expirationTime.getTime() / 1000L);
+ } catch (ParseException e) {
+ LOG.warning("Failed to parse life time element: " + e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Set the audience restriction claim. The Audiences are from an AppliesTo address, and the wst:Participants
+ * (if either exist).
+ */
+ protected void handleAudienceRestriction(
+ JWTClaimsProviderParameters jwtClaimsProviderParameters, JwtClaims claims
+ ) {
+ TokenProviderParameters providerParameters = jwtClaimsProviderParameters.getProviderParameters();
+
+ List<String> audiences = new ArrayList<String>();
+ String appliesToAddress = providerParameters.getAppliesToAddress();
+ if (appliesToAddress != null) {
+ audiences.add(appliesToAddress);
+ }
+
+ Participants participants = providerParameters.getTokenRequirements().getParticipants();
+ if (participants != null) {
+ String address = TokenProviderUtils.extractAddressFromParticipantsEPR(participants.getPrimaryParticipant());
+ if (address != null) {
+ audiences.add(address);
+ }
+
+ if (participants.getParticipants() != null) {
+ for (Object participant : participants.getParticipants()) {
+ if (participant != null) {
+ address = TokenProviderUtils.extractAddressFromParticipantsEPR(participant);
+ if (address != null) {
+ audiences.add(address);
+ }
+ }
+ }
+ }
+ }
+
+ if (audiences.size() == 1) {
+ claims.setAudience(audiences.get(0));
+ } else if (!audiences.isEmpty()) {
+ claims.setProperty(JwtConstants.CLAIM_AUDIENCE, audiences);
+ }
+ }
+
public boolean isUseX500CN() {
return useX500CN;
}
@@ -162,4 +279,86 @@ public class DefaultJWTClaimsProvider implements JWTClaimsProvider {
public void setUseX500CN(boolean useX500CN) {
this.useX500CN = useX500CN;
}
+
+ /**
+ * Get how long (in seconds) a client-supplied Created Element is allowed to be in the future.
+ * The default is 60 seconds to avoid common problems relating to clock skew.
+ */
+ public long getFutureTimeToLive() {
+ return futureTimeToLive;
+ }
+
+ /**
+ * Set how long (in seconds) a client-supplied Created Element is allowed to be in the future.
+ * The default is 60 seconds to avoid common problems relating to clock skew.
+ */
+ public void setFutureTimeToLive(long futureTimeToLive) {
+ this.futureTimeToLive = futureTimeToLive;
+ }
+
+ /**
+ * Set the default lifetime in seconds for issued JWT tokens
+ * @param default lifetime in seconds
+ */
+ public void setLifetime(long lifetime) {
+ this.lifetime = lifetime;
+ }
+
+ /**
+ * Get the default lifetime in seconds for issued JWT token where requestor
+ * doesn't specify a lifetime element
+ * @return the lifetime in seconds
+ */
+ public long getLifetime() {
+ return lifetime;
+ }
+
+ /**
+ * Set the maximum lifetime in seconds for issued JWT tokens
+ * @param maximum lifetime in seconds
+ */
+ public void setMaxLifetime(long maxLifetime) {
+ this.maxLifetime = maxLifetime;
+ }
+
+ /**
+ * Get the maximum lifetime in seconds for issued JWT token
+ * if requestor specifies lifetime element
+ * @return the maximum lifetime in seconds
+ */
+ public long getMaxLifetime() {
+ return maxLifetime;
+ }
+
+ /**
+ * Is client lifetime element accepted
+ * Default: false
+ */
+ public boolean isAcceptClientLifetime() {
+ return this.acceptClientLifetime;
+ }
+
+ /**
+ * Set whether client lifetime is accepted
+ */
+ public void setAcceptClientLifetime(boolean acceptClientLifetime) {
+ this.acceptClientLifetime = acceptClientLifetime;
+ }
+
+ /**
+ * If requested lifetime exceeds shall it fail (default)
+ * or overwrite with maximum lifetime
+ */
+ public boolean isFailLifetimeExceedance() {
+ return this.failLifetimeExceedance;
+ }
+
+ /**
+ * If requested lifetime exceeds shall it fail (default)
+ * or overwrite with maximum lifetime
+ */
+ public void setFailLifetimeExceedance(boolean failLifetimeExceedance) {
+ this.failLifetimeExceedance = failLifetimeExceedance;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/cxf/blob/8516661b/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/provider/JWTProviderLifetimeTest.java
----------------------------------------------------------------------
diff --git a/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/provider/JWTProviderLifetimeTest.java b/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/provider/JWTProviderLifetimeTest.java
new file mode 100644
index 0000000..3d16d40
--- /dev/null
+++ b/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/provider/JWTProviderLifetimeTest.java
@@ -0,0 +1,409 @@
+/**
+ * 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.sts.token.provider;
+
+import java.util.Date;
+import java.util.Properties;
+
+import org.apache.cxf.jaxws.context.WebServiceContextImpl;
+import org.apache.cxf.jaxws.context.WrappedMessageContext;
+import org.apache.cxf.message.MessageImpl;
+import org.apache.cxf.rs.security.jose.jws.JwsJwtCompactConsumer;
+import org.apache.cxf.rs.security.jose.jwt.JwtConstants;
+import org.apache.cxf.rs.security.jose.jwt.JwtToken;
+import org.apache.cxf.sts.StaticSTSProperties;
+import org.apache.cxf.sts.common.PasswordCallbackHandler;
+import org.apache.cxf.sts.request.KeyRequirements;
+import org.apache.cxf.sts.request.Lifetime;
+import org.apache.cxf.sts.request.TokenRequirements;
+import org.apache.cxf.sts.service.EncryptionProperties;
+import org.apache.cxf.sts.token.provider.jwt.DefaultJWTClaimsProvider;
+import org.apache.cxf.sts.token.provider.jwt.JWTTokenProvider;
+import org.apache.cxf.ws.security.sts.provider.STSException;
+import org.apache.wss4j.common.crypto.Crypto;
+import org.apache.wss4j.common.crypto.CryptoFactory;
+import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.common.principal.CustomTokenPrincipal;
+import org.apache.wss4j.dom.util.XmlSchemaDateFormat;
+
+
+/**
+ * Some unit tests for creating JWT Tokens with lifetime
+ */
+public class JWTProviderLifetimeTest extends org.junit.Assert {
+
+ /**
+ * Issue JWT token with a valid requested lifetime
+ */
+ @org.junit.Test
+ public void testJWTValidLifetime() throws Exception {
+
+ int requestedLifetime = 60;
+ JWTTokenProvider tokenProvider = new JWTTokenProvider();
+ DefaultJWTClaimsProvider claimsProvider = new DefaultJWTClaimsProvider();
+ claimsProvider.setAcceptClientLifetime(true);
+ tokenProvider.setJwtClaimsProvider(claimsProvider);
+
+ TokenProviderParameters providerParameters =
+ createProviderParameters(JWTTokenProvider.JWT_TOKEN_TYPE);
+
+ // Set expected lifetime to 1 minute
+ Date creationTime = new Date();
+ Date expirationTime = new Date();
+ expirationTime.setTime(creationTime.getTime() + (requestedLifetime * 1000L));
+ Lifetime lifetime = new Lifetime();
+ XmlSchemaDateFormat fmt = new XmlSchemaDateFormat();
+ lifetime.setCreated(fmt.format(creationTime));
+ lifetime.setExpires(fmt.format(expirationTime));
+ providerParameters.getTokenRequirements().setLifetime(lifetime);
+
+ TokenProviderResponse providerResponse = tokenProvider.createToken(providerParameters);
+ assertTrue(providerResponse != null);
+ assertTrue(providerResponse.getToken() != null && providerResponse.getTokenId() != null);
+ assertEquals(requestedLifetime * 1000L, providerResponse.getExpires().getTime()
+ - providerResponse.getCreated().getTime());
+
+ String token = (String)providerResponse.getToken();
+ assertNotNull(token);
+
+ JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer(token);
+ JwtToken jwt = jwtConsumer.getJwtToken();
+ assertEquals(jwt.getClaim(JwtConstants.CLAIM_ISSUED_AT), providerResponse.getCreated().getTime() / 1000L);
+ }
+
+ /**
+ * Issue JWT token with a lifetime configured in JWTTokenProvider
+ * No specific lifetime requested
+ */
+ @org.junit.Test
+ public void testJWTProviderLifetime() throws Exception {
+
+ long providerLifetime = 10 * 600L;
+ JWTTokenProvider tokenProvider = new JWTTokenProvider();
+ DefaultJWTClaimsProvider claimsProvider = new DefaultJWTClaimsProvider();
+ claimsProvider.setLifetime(providerLifetime);
+ tokenProvider.setJwtClaimsProvider(claimsProvider);
+
+ TokenProviderParameters providerParameters = createProviderParameters(JWTTokenProvider.JWT_TOKEN_TYPE);
+
+ TokenProviderResponse providerResponse = tokenProvider.createToken(providerParameters);
+ assertTrue(providerResponse != null);
+ assertTrue(providerResponse.getToken() != null && providerResponse.getTokenId() != null);
+
+ assertEquals(providerLifetime * 1000L, providerResponse.getExpires().getTime()
+ - providerResponse.getCreated().getTime());
+
+ String token = (String)providerResponse.getToken();
+ assertNotNull(token);
+
+ JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer(token);
+ JwtToken jwt = jwtConsumer.getJwtToken();
+ assertEquals(jwt.getClaim(JwtConstants.CLAIM_ISSUED_AT), providerResponse.getCreated().getTime() / 1000L);
+ }
+
+
+ /**
+ * Issue JWT token with a with a lifetime
+ * which exceeds configured maximum lifetime
+ */
+ @org.junit.Test
+ public void testJWTExceededConfiguredMaxLifetime() throws Exception {
+
+ long maxLifetime = 30 * 60L; // 30 minutes
+ JWTTokenProvider tokenProvider = new JWTTokenProvider();
+ DefaultJWTClaimsProvider claimsProvider = new DefaultJWTClaimsProvider();
+ claimsProvider.setMaxLifetime(maxLifetime);
+ claimsProvider.setAcceptClientLifetime(true);
+ tokenProvider.setJwtClaimsProvider(claimsProvider);
+
+ TokenProviderParameters providerParameters = createProviderParameters(JWTTokenProvider.JWT_TOKEN_TYPE);
+
+ // Set expected lifetime to 35 minutes
+ long requestedLifetime = 35 * 60L;
+ Date creationTime = new Date();
+ Date expirationTime = new Date();
+ expirationTime.setTime(creationTime.getTime() + (requestedLifetime * 1000L));
+ Lifetime lifetime = new Lifetime();
+ XmlSchemaDateFormat fmt = new XmlSchemaDateFormat();
+ lifetime.setCreated(fmt.format(creationTime));
+ lifetime.setExpires(fmt.format(expirationTime));
+ providerParameters.getTokenRequirements().setLifetime(lifetime);
+
+ try {
+ tokenProvider.createToken(providerParameters);
+ fail("Failure expected due to exceeded lifetime");
+ } catch (STSException ex) {
+ //expected
+ }
+ }
+
+ /**
+ * Issue JWT token with a with a lifetime
+ * which exceeds default maximum lifetime
+ */
+ @org.junit.Test
+ public void testJWTExceededDefaultMaxLifetime() throws Exception {
+
+ JWTTokenProvider tokenProvider = new JWTTokenProvider();
+ DefaultJWTClaimsProvider claimsProvider = new DefaultJWTClaimsProvider();
+ claimsProvider.setAcceptClientLifetime(true);
+ tokenProvider.setJwtClaimsProvider(claimsProvider);
+
+ TokenProviderParameters providerParameters =
+ createProviderParameters(JWTTokenProvider.JWT_TOKEN_TYPE);
+
+ // Set expected lifetime to Default max lifetime plus 1
+ long requestedLifetime = DefaultConditionsProvider.DEFAULT_MAX_LIFETIME + 1;
+ Date creationTime = new Date();
+ Date expirationTime = new Date();
+ expirationTime.setTime(creationTime.getTime() + (requestedLifetime * 1000L));
+ Lifetime lifetime = new Lifetime();
+ XmlSchemaDateFormat fmt = new XmlSchemaDateFormat();
+ lifetime.setCreated(fmt.format(creationTime));
+ lifetime.setExpires(fmt.format(expirationTime));
+ providerParameters.getTokenRequirements().setLifetime(lifetime);
+
+ try {
+ tokenProvider.createToken(providerParameters);
+ fail("Failure expected due to exceeded lifetime");
+ } catch (STSException ex) {
+ //expected
+ }
+ }
+
+ /**
+ * Issue JWT token with a with a lifetime
+ * which exceeds configured maximum lifetime
+ * Lifetime reduced to maximum lifetime
+ */
+ @org.junit.Test
+ public void testJWTExceededConfiguredMaxLifetimeButUpdated() throws Exception {
+
+ long maxLifetime = 30 * 60L; // 30 minutes
+ JWTTokenProvider tokenProvider = new JWTTokenProvider();
+ DefaultJWTClaimsProvider claimsProvider = new DefaultJWTClaimsProvider();
+ claimsProvider.setMaxLifetime(maxLifetime);
+ claimsProvider.setFailLifetimeExceedance(false);
+ claimsProvider.setAcceptClientLifetime(true);
+ tokenProvider.setJwtClaimsProvider(claimsProvider);
+
+ TokenProviderParameters providerParameters =
+ createProviderParameters(JWTTokenProvider.JWT_TOKEN_TYPE);
+
+ // Set expected lifetime to 35 minutes
+ long requestedLifetime = 35 * 60L;
+ Date creationTime = new Date();
+ Date expirationTime = new Date();
+ expirationTime.setTime(creationTime.getTime() + (requestedLifetime * 1000L));
+ Lifetime lifetime = new Lifetime();
+ XmlSchemaDateFormat fmt = new XmlSchemaDateFormat();
+ lifetime.setCreated(fmt.format(creationTime));
+ lifetime.setExpires(fmt.format(expirationTime));
+ providerParameters.getTokenRequirements().setLifetime(lifetime);
+
+ TokenProviderResponse providerResponse = tokenProvider.createToken(providerParameters);
+ assertTrue(providerResponse != null);
+ assertTrue(providerResponse.getToken() != null && providerResponse.getTokenId() != null);
+ assertEquals(maxLifetime * 1000L, providerResponse.getExpires().getTime()
+ - providerResponse.getCreated().getTime());
+
+ String token = (String)providerResponse.getToken();
+ assertNotNull(token);
+
+ JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer(token);
+ JwtToken jwt = jwtConsumer.getJwtToken();
+ assertEquals(jwt.getClaim(JwtConstants.CLAIM_ISSUED_AT), providerResponse.getCreated().getTime() / 1000L);
+ }
+
+ /**
+ * Issue JWT token with a near future Created Lifetime. This should pass as we allow a future
+ * dated Lifetime up to 60 seconds to avoid clock skew problems.
+ */
+ @org.junit.Test
+ public void testJWTNearFutureCreatedLifetime() throws Exception {
+
+ int requestedLifetime = 60;
+ JWTTokenProvider tokenProvider = new JWTTokenProvider();
+ DefaultJWTClaimsProvider claimsProvider = new DefaultJWTClaimsProvider();
+ claimsProvider.setAcceptClientLifetime(true);
+ tokenProvider.setJwtClaimsProvider(claimsProvider);
+
+ TokenProviderParameters providerParameters =
+ createProviderParameters(JWTTokenProvider.JWT_TOKEN_TYPE);
+
+ // Set expected lifetime to 1 minute
+ Date creationTime = new Date();
+ Date expirationTime = new Date();
+ expirationTime.setTime(creationTime.getTime() + (requestedLifetime * 1000L));
+ creationTime.setTime(creationTime.getTime() + (10 * 1000L));
+ Lifetime lifetime = new Lifetime();
+ XmlSchemaDateFormat fmt = new XmlSchemaDateFormat();
+ lifetime.setCreated(fmt.format(creationTime));
+ lifetime.setExpires(fmt.format(expirationTime));
+ providerParameters.getTokenRequirements().setLifetime(lifetime);
+
+ TokenProviderResponse providerResponse = tokenProvider.createToken(providerParameters);
+ assertTrue(providerResponse != null);
+ assertTrue(providerResponse.getToken() != null && providerResponse.getTokenId() != null);
+ assertEquals(50L * 1000L, providerResponse.getExpires().getTime()
+ - providerResponse.getCreated().getTime());
+
+ String token = (String)providerResponse.getToken();
+ assertNotNull(token);
+
+ JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer(token);
+ JwtToken jwt = jwtConsumer.getJwtToken();
+ assertEquals(jwt.getClaim(JwtConstants.CLAIM_ISSUED_AT), providerResponse.getCreated().getTime() / 1000L);
+ }
+
+ /**
+ * Issue JWT token with a future Created Lifetime. This should fail as we only allow a future
+ * dated Lifetime up to 60 seconds to avoid clock skew problems.
+ */
+ @org.junit.Test
+ public void testJWTFarFutureCreatedLifetime() throws Exception {
+
+ int requestedLifetime = 60;
+ JWTTokenProvider tokenProvider = new JWTTokenProvider();
+ DefaultJWTClaimsProvider claimsProvider = new DefaultJWTClaimsProvider();
+ claimsProvider.setAcceptClientLifetime(true);
+ tokenProvider.setJwtClaimsProvider(claimsProvider);
+
+ TokenProviderParameters providerParameters =
+ createProviderParameters(JWTTokenProvider.JWT_TOKEN_TYPE);
+
+ // Set expected lifetime to 1 minute
+ Date creationTime = new Date();
+ creationTime.setTime(creationTime.getTime() + (60L * 2L * 1000L));
+ Date expirationTime = new Date();
+ expirationTime.setTime(creationTime.getTime() + (requestedLifetime * 1000L));
+ Lifetime lifetime = new Lifetime();
+ XmlSchemaDateFormat fmt = new XmlSchemaDateFormat();
+ lifetime.setCreated(fmt.format(creationTime));
+ lifetime.setExpires(fmt.format(expirationTime));
+ providerParameters.getTokenRequirements().setLifetime(lifetime);
+
+ try {
+ tokenProvider.createToken(providerParameters);
+ fail("Failure expected on a Created Element too far in the future");
+ } catch (STSException ex) {
+ // expected
+ }
+
+ // Now allow this sort of Created Element
+ claimsProvider.setFutureTimeToLive(60L * 60L);
+
+ TokenProviderResponse providerResponse = tokenProvider.createToken(providerParameters);
+ assertTrue(providerResponse != null);
+ assertTrue(providerResponse.getToken() != null && providerResponse.getTokenId() != null);
+
+ String token = (String)providerResponse.getToken();
+ assertNotNull(token);
+
+ JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer(token);
+ JwtToken jwt = jwtConsumer.getJwtToken();
+ assertEquals(jwt.getClaim(JwtConstants.CLAIM_ISSUED_AT), providerResponse.getCreated().getTime() / 1000L);
+ }
+
+ /**
+ * Issue JWT token with no Expires element. This will be rejected, but will default to the
+ * configured TTL and so the request will pass.
+ */
+ @org.junit.Test
+ public void testJWTNoExpires() throws Exception {
+
+ JWTTokenProvider tokenProvider = new JWTTokenProvider();
+ DefaultJWTClaimsProvider claimsProvider = new DefaultJWTClaimsProvider();
+ claimsProvider.setAcceptClientLifetime(true);
+ tokenProvider.setJwtClaimsProvider(claimsProvider);
+
+ TokenProviderParameters providerParameters =
+ createProviderParameters(JWTTokenProvider.JWT_TOKEN_TYPE);
+
+ // Set expected lifetime to 1 minute
+ Date creationTime = new Date();
+ creationTime.setTime(creationTime.getTime() + (60L * 2L * 1000L));
+ Lifetime lifetime = new Lifetime();
+ XmlSchemaDateFormat fmt = new XmlSchemaDateFormat();
+ lifetime.setCreated(fmt.format(creationTime));
+ providerParameters.getTokenRequirements().setLifetime(lifetime);
+
+ TokenProviderResponse providerResponse = tokenProvider.createToken(providerParameters);
+ assertTrue(providerResponse != null);
+ assertTrue(providerResponse.getToken() != null && providerResponse.getTokenId() != null);
+ assertEquals(claimsProvider.getLifetime() * 1000L, providerResponse.getExpires().getTime()
+ - providerResponse.getCreated().getTime());
+
+ String token = (String)providerResponse.getToken();
+ assertNotNull(token);
+
+ JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer(token);
+ JwtToken jwt = jwtConsumer.getJwtToken();
+ assertEquals(jwt.getClaim(JwtConstants.CLAIM_ISSUED_AT), providerResponse.getCreated().getTime() / 1000L);
+ }
+
+ private TokenProviderParameters createProviderParameters(String tokenType) throws WSSecurityException {
+ TokenProviderParameters parameters = new TokenProviderParameters();
+
+ TokenRequirements tokenRequirements = new TokenRequirements();
+ tokenRequirements.setTokenType(tokenType);
+ parameters.setTokenRequirements(tokenRequirements);
+
+ KeyRequirements keyRequirements = new KeyRequirements();
+ parameters.setKeyRequirements(keyRequirements);
+
+ parameters.setPrincipal(new CustomTokenPrincipal("alice"));
+ // Mock up message context
+ MessageImpl msg = new MessageImpl();
+ WrappedMessageContext msgCtx = new WrappedMessageContext(msg);
+ WebServiceContextImpl webServiceContext = new WebServiceContextImpl(msgCtx);
+ parameters.setWebServiceContext(webServiceContext);
+
+ parameters.setAppliesToAddress("http://dummy-service.com/dummy");
+
+ // Add STSProperties object
+ StaticSTSProperties stsProperties = new StaticSTSProperties();
+ Crypto crypto = CryptoFactory.getInstance(getEncryptionProperties());
+ stsProperties.setEncryptionCrypto(crypto);
+ stsProperties.setSignatureCrypto(crypto);
+ stsProperties.setEncryptionUsername("myservicekey");
+ stsProperties.setSignatureUsername("mystskey");
+ stsProperties.setCallbackHandler(new PasswordCallbackHandler());
+ stsProperties.setIssuer("STS");
+ parameters.setStsProperties(stsProperties);
+
+ parameters.setEncryptionProperties(new EncryptionProperties());
+
+ return parameters;
+ }
+
+ private Properties getEncryptionProperties() {
+ Properties properties = new Properties();
+ properties.put(
+ "org.apache.wss4j.crypto.provider", "org.apache.wss4j.common.crypto.Merlin"
+ );
+ properties.put("org.apache.wss4j.crypto.merlin.keystore.password", "stsspass");
+ properties.put("org.apache.wss4j.crypto.merlin.keystore.file", "stsstore.jks");
+
+ return properties;
+ }
+
+
+
+}