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 17:48:05 UTC

[1/2] cxf git commit: Adding support for claims in JWT Tokens in the STS

Repository: cxf
Updated Branches:
  refs/heads/master b71f22c12 -> ae74e760b


Adding support for claims in JWT Tokens in the STS


Project: http://git-wip-us.apache.org/repos/asf/cxf/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/48f8f31d
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/48f8f31d
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/48f8f31d

Branch: refs/heads/master
Commit: 48f8f31d337b63b79c6d5afb970748dc6b296d77
Parents: b71f22c
Author: Colm O hEigeartaigh <co...@apache.org>
Authored: Mon Nov 9 14:49:09 2015 +0000
Committer: Colm O hEigeartaigh <co...@apache.org>
Committed: Mon Nov 9 16:47:18 2015 +0000

----------------------------------------------------------------------
 .../ClaimsAttributeStatementProvider.java       |  30 +-
 .../org/apache/cxf/sts/claims/ClaimsUtils.java  |  67 ++
 .../provider/jwt/DefaultJWTClaimsProvider.java  |  26 +
 .../sts/operation/IssueJWTClaimsUnitTest.java   | 775 +++++++++++++++++++
 .../cxf/sts/token/provider/JWTClaimsTest.java   | 288 +++++++
 5 files changed, 1157 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf/blob/48f8f31d/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ClaimsAttributeStatementProvider.java
----------------------------------------------------------------------
diff --git a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ClaimsAttributeStatementProvider.java b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ClaimsAttributeStatementProvider.java
index 39469d3..0f1882f 100644
--- a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ClaimsAttributeStatementProvider.java
+++ b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ClaimsAttributeStatementProvider.java
@@ -36,35 +36,7 @@ public class ClaimsAttributeStatementProvider implements AttributeStatementProvi
 
     public AttributeStatementBean getStatement(TokenProviderParameters providerParameters) {
         // Handle Claims
-        ClaimsManager claimsManager = providerParameters.getClaimsManager();
-        ProcessedClaimCollection retrievedClaims = new ProcessedClaimCollection();
-        if (claimsManager != null) {
-            ClaimsParameters params = new ClaimsParameters();
-            params.setAdditionalProperties(providerParameters.getAdditionalProperties());
-            params.setAppliesToAddress(providerParameters.getAppliesToAddress());
-            params.setEncryptionProperties(providerParameters.getEncryptionProperties());
-            params.setKeyRequirements(providerParameters.getKeyRequirements());
-            if (providerParameters.getTokenRequirements().getOnBehalfOf() != null) {
-                params.setPrincipal(providerParameters.getTokenRequirements().getOnBehalfOf().getPrincipal());
-                params.setRoles(providerParameters.getTokenRequirements().getOnBehalfOf().getRoles());
-            } else if (providerParameters.getTokenRequirements().getActAs() != null) {
-                params.setPrincipal(providerParameters.getTokenRequirements().getActAs().getPrincipal());    
-                params.setRoles(providerParameters.getTokenRequirements().getActAs().getRoles());
-            } else {
-                params.setPrincipal(providerParameters.getPrincipal());
-            }
-            params.setRealm(providerParameters.getRealm());
-            params.setStsProperties(providerParameters.getStsProperties());
-            params.setTokenRequirements(providerParameters.getTokenRequirements());
-            params.setTokenStore(providerParameters.getTokenStore());
-            params.setWebServiceContext(providerParameters.getWebServiceContext());
-            retrievedClaims = 
-                claimsManager.retrieveClaimValues(
-                    providerParameters.getRequestedPrimaryClaims(),
-                    providerParameters.getRequestedSecondaryClaims(),
-                    params
-                );
-        }
+        ProcessedClaimCollection retrievedClaims = ClaimsUtils.processClaims(providerParameters);
         if (retrievedClaims == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/cxf/blob/48f8f31d/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ClaimsUtils.java
----------------------------------------------------------------------
diff --git a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ClaimsUtils.java b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ClaimsUtils.java
new file mode 100644
index 0000000..fbd7e1c
--- /dev/null
+++ b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ClaimsUtils.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.sts.claims;
+
+import org.apache.cxf.sts.token.provider.TokenProviderParameters;
+
+/**
+ * Some common utility methods for claims
+ */
+public final class ClaimsUtils {
+    
+    private ClaimsUtils() {
+        // complete
+    }
+    
+    public static ProcessedClaimCollection processClaims(TokenProviderParameters providerParameters) {
+        // Handle Claims
+        ClaimsManager claimsManager = providerParameters.getClaimsManager();
+        ProcessedClaimCollection retrievedClaims = new ProcessedClaimCollection();
+        if (claimsManager != null) {
+            ClaimsParameters params = new ClaimsParameters();
+            params.setAdditionalProperties(providerParameters.getAdditionalProperties());
+            params.setAppliesToAddress(providerParameters.getAppliesToAddress());
+            params.setEncryptionProperties(providerParameters.getEncryptionProperties());
+            params.setKeyRequirements(providerParameters.getKeyRequirements());
+            if (providerParameters.getTokenRequirements().getOnBehalfOf() != null) {
+                params.setPrincipal(providerParameters.getTokenRequirements().getOnBehalfOf().getPrincipal());
+                params.setRoles(providerParameters.getTokenRequirements().getOnBehalfOf().getRoles());
+            } else if (providerParameters.getTokenRequirements().getActAs() != null) {
+                params.setPrincipal(providerParameters.getTokenRequirements().getActAs().getPrincipal());    
+                params.setRoles(providerParameters.getTokenRequirements().getActAs().getRoles());
+            } else {
+                params.setPrincipal(providerParameters.getPrincipal());
+            }
+            params.setRealm(providerParameters.getRealm());
+            params.setStsProperties(providerParameters.getStsProperties());
+            params.setTokenRequirements(providerParameters.getTokenRequirements());
+            params.setTokenStore(providerParameters.getTokenStore());
+            params.setWebServiceContext(providerParameters.getWebServiceContext());
+            retrievedClaims = 
+                claimsManager.retrieveClaimValues(
+                    providerParameters.getRequestedPrimaryClaims(),
+                    providerParameters.getRequestedSecondaryClaims(),
+                    params
+                );
+        }
+        return retrievedClaims;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/cxf/blob/48f8f31d/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 9f29e62..1e80f96 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
@@ -20,6 +20,7 @@ package org.apache.cxf.sts.token.provider.jwt;
 
 import java.security.Principal;
 import java.util.Date;
+import java.util.Iterator;
 import java.util.UUID;
 import java.util.logging.Logger;
 
@@ -28,6 +29,9 @@ 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.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.ReceivedToken;
 import org.apache.cxf.sts.request.ReceivedToken.STATE;
 import org.apache.cxf.sts.token.provider.TokenProviderParameters;
@@ -60,6 +64,8 @@ public class DefaultJWTClaimsProvider implements JWTClaimsProvider {
             claims.setIssuer(issuer);
         }
         
+        handleWSTrustClaims(jwtClaimsProviderParameters, claims);
+        
         Date currentDate = new Date();
         claims.setIssuedAt(currentDate.getTime() / 1000L);
         long currentTime = currentDate.getTime() + 300L * 1000L;
@@ -129,6 +135,26 @@ public class DefaultJWTClaimsProvider implements JWTClaimsProvider {
         return principal;
     }
     
+    protected void handleWSTrustClaims(JWTClaimsProviderParameters jwtClaimsProviderParameters, JwtClaims claims) {
+        TokenProviderParameters providerParameters = jwtClaimsProviderParameters.getProviderParameters();
+        
+        // Handle Claims
+        ProcessedClaimCollection retrievedClaims = ClaimsUtils.processClaims(providerParameters);
+        if (retrievedClaims != null) {
+            Iterator<ProcessedClaim> claimIterator = retrievedClaims.iterator();
+            while (claimIterator.hasNext()) {
+                ProcessedClaim claim = claimIterator.next();
+                if (claim.getClaimType() != null && claim.getValues() != null && !claim.getValues().isEmpty()) {
+                    Object claimValues = claim.getValues();
+                    if (claim.getValues().size() == 1) {
+                        claimValues = claim.getValues().get(0);
+                    }
+                    claims.setProperty(claim.getClaimType().toString(), claimValues);
+                }
+            }
+        }
+    }
+    
     public boolean isUseX500CN() {
         return useX500CN;
     }

http://git-wip-us.apache.org/repos/asf/cxf/blob/48f8f31d/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueJWTClaimsUnitTest.java
----------------------------------------------------------------------
diff --git a/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueJWTClaimsUnitTest.java b/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueJWTClaimsUnitTest.java
new file mode 100644
index 0000000..5e92191
--- /dev/null
+++ b/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueJWTClaimsUnitTest.java
@@ -0,0 +1,775 @@
+/**
+ * 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.operation;
+
+import java.net.URI;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.security.auth.callback.CallbackHandler;
+import javax.xml.bind.JAXBElement;
+import javax.xml.namespace.QName;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.apache.cxf.helpers.DOMUtils;
+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.rt.security.claims.Claim;
+import org.apache.cxf.rt.security.claims.ClaimCollection;
+import org.apache.cxf.security.SecurityContext;
+import org.apache.cxf.sts.QNameConstants;
+import org.apache.cxf.sts.STSConstants;
+import org.apache.cxf.sts.STSPropertiesMBean;
+import org.apache.cxf.sts.StaticSTSProperties;
+import org.apache.cxf.sts.claims.ClaimTypes;
+import org.apache.cxf.sts.claims.ClaimsAttributeStatementProvider;
+import org.apache.cxf.sts.claims.ClaimsHandler;
+import org.apache.cxf.sts.claims.ClaimsManager;
+import org.apache.cxf.sts.claims.ClaimsMapper;
+import org.apache.cxf.sts.common.CustomClaimsHandler;
+import org.apache.cxf.sts.common.PasswordCallbackHandler;
+import org.apache.cxf.sts.request.KeyRequirements;
+import org.apache.cxf.sts.request.TokenRequirements;
+import org.apache.cxf.sts.service.EncryptionProperties;
+import org.apache.cxf.sts.service.ServiceMBean;
+import org.apache.cxf.sts.service.StaticService;
+import org.apache.cxf.sts.token.delegation.SAMLDelegationHandler;
+import org.apache.cxf.sts.token.delegation.TokenDelegationHandler;
+import org.apache.cxf.sts.token.provider.AttributeStatementProvider;
+import org.apache.cxf.sts.token.provider.SAMLTokenProvider;
+import org.apache.cxf.sts.token.provider.TokenProvider;
+import org.apache.cxf.sts.token.provider.TokenProviderParameters;
+import org.apache.cxf.sts.token.provider.TokenProviderResponse;
+import org.apache.cxf.sts.token.provider.jwt.JWTTokenProvider;
+import org.apache.cxf.sts.token.realm.RealmProperties;
+import org.apache.cxf.sts.token.realm.Relationship;
+import org.apache.cxf.sts.token.validator.IssuerSAMLRealmCodec;
+import org.apache.cxf.sts.token.validator.SAMLTokenValidator;
+import org.apache.cxf.sts.token.validator.TokenValidator;
+import org.apache.cxf.ws.security.sts.provider.model.ClaimsType;
+import org.apache.cxf.ws.security.sts.provider.model.OnBehalfOfType;
+import org.apache.cxf.ws.security.sts.provider.model.RequestSecurityTokenResponseCollectionType;
+import org.apache.cxf.ws.security.sts.provider.model.RequestSecurityTokenResponseType;
+import org.apache.cxf.ws.security.sts.provider.model.RequestSecurityTokenType;
+import org.apache.cxf.ws.security.sts.provider.model.RequestedSecurityTokenType;
+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.common.saml.builder.SAML2Constants;
+import org.apache.wss4j.common.util.DOM2Writer;
+import org.apache.wss4j.dom.WSConstants;
+import org.junit.Assert;
+
+/**
+ * Some unit tests for the issue operation to issue JWT tokens with Claims information.
+ */
+public class IssueJWTClaimsUnitTest extends org.junit.Assert {
+    
+    public static final QName REQUESTED_SECURITY_TOKEN = 
+        QNameConstants.WS_TRUST_FACTORY.createRequestedSecurityToken(null).getName();
+    
+    private static final URI ROLE_CLAIM = 
+            URI.create("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role");
+    
+    /**
+     * Test to successfully issue a JWT token.
+     */
+    @org.junit.Test
+    public void testIssueJWTToken() throws Exception {
+        TokenIssueOperation issueOperation = new TokenIssueOperation();
+
+        // Add Token Provider
+        List<TokenProvider> providerList = new ArrayList<TokenProvider>();
+        providerList.add(new JWTTokenProvider());
+        issueOperation.setTokenProviders(providerList);
+        
+        addService(issueOperation);
+        
+        addSTSProperties(issueOperation);
+        
+        // Set the ClaimsManager
+        ClaimsManager claimsManager = new ClaimsManager();
+        ClaimsHandler claimsHandler = new CustomClaimsHandler();
+        claimsManager.setClaimHandlers(Collections.singletonList(claimsHandler));
+        issueOperation.setClaimsManager(claimsManager);
+        
+        // Mock up a request
+        RequestSecurityTokenType request = new RequestSecurityTokenType();
+        JAXBElement<String> tokenType = 
+            new JAXBElement<String>(
+                QNameConstants.TOKEN_TYPE, String.class, JWTTokenProvider.JWT_TOKEN_TYPE
+            );
+        request.getAny().add(tokenType);
+        Element secondaryParameters = createSecondaryParameters();
+        request.getAny().add(secondaryParameters);
+        request.getAny().add(createAppliesToElement("http://dummy-service.com/dummy"));
+        
+        WebServiceContextImpl webServiceContext = setupMessageContext();
+        
+        List<RequestSecurityTokenResponseType> securityTokenResponse = issueToken(issueOperation, request,
+                webServiceContext);
+        
+        // Test the generated token.
+        String jwtToken = null;
+        for (Object tokenObject : securityTokenResponse.get(0).getAny()) {
+            if (tokenObject instanceof Element
+                && REQUESTED_SECURITY_TOKEN.getLocalPart().equals(((Element)tokenObject).getLocalName())
+                && REQUESTED_SECURITY_TOKEN.getNamespaceURI().equals(((Element)tokenObject).getNamespaceURI())) {
+                jwtToken = ((Element)tokenObject).getTextContent();
+                break;
+            }
+        }
+        
+        assertNotNull(jwtToken);
+        
+        // Validate the token
+        JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer(jwtToken);
+        JwtToken jwt = jwtConsumer.getJwtToken();
+        Assert.assertEquals("alice", jwt.getClaim(JwtConstants.CLAIM_SUBJECT));
+        assertEquals(jwt.getClaim(ClaimTypes.LASTNAME.toString()), "doe");
+        assertEquals(jwt.getClaim(ROLE_CLAIM.toString()), "administrator");
+    }
+    
+    /**
+     * @param issueOperation
+     * @param request
+     * @param webServiceContext
+     * @return
+     */
+    private List<RequestSecurityTokenResponseType> issueToken(TokenIssueOperation issueOperation,
+            RequestSecurityTokenType request, WebServiceContextImpl webServiceContext) {
+        RequestSecurityTokenResponseCollectionType response = 
+            issueOperation.issue(request, webServiceContext);
+        List<RequestSecurityTokenResponseType> securityTokenResponse = 
+            response.getRequestSecurityTokenResponse();
+        assertTrue(!securityTokenResponse.isEmpty());
+        return securityTokenResponse;
+    }
+
+    /**
+     * @return
+     */
+    private WebServiceContextImpl setupMessageContext() {
+        MessageImpl msg = new MessageImpl();
+        WrappedMessageContext msgCtx = new WrappedMessageContext(msg);
+        msgCtx.put(
+            SecurityContext.class.getName(), 
+            createSecurityContext(new CustomTokenPrincipal("alice"))
+        );
+        return new WebServiceContextImpl(msgCtx);
+    }
+
+    /**
+     * @param issueOperation
+     * @throws WSSecurityException
+     */
+    private void addSTSProperties(TokenIssueOperation issueOperation) throws WSSecurityException {
+        STSPropertiesMBean 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");
+        issueOperation.setStsProperties(stsProperties);
+    }
+
+    /**
+     * @param issueOperation
+     */
+    private void addService(TokenIssueOperation issueOperation) {
+        ServiceMBean service = new StaticService();
+        service.setEndpoints(Collections.singletonList("http://dummy-service.com/dummy"));
+        issueOperation.setServices(Collections.singletonList(service));
+    }
+    
+    /**
+     * Test to successfully issue a JWT token. The claims information is included as a 
+     * JAXB Element under RequestSecurityToken, rather than as a child of SecondaryParameters.
+     */
+    @org.junit.Test
+    public void testIssueJaxbJWTToken() throws Exception {
+        TokenIssueOperation issueOperation = new TokenIssueOperation();
+        
+        // Add Token Provider
+        List<TokenProvider> providerList = new ArrayList<TokenProvider>();
+        providerList.add(new JWTTokenProvider());
+        issueOperation.setTokenProviders(providerList);
+        
+        addService(issueOperation);
+        
+        addSTSProperties(issueOperation);
+        
+        // Set the ClaimsManager
+        ClaimsManager claimsManager = new ClaimsManager();
+        ClaimsHandler claimsHandler = new CustomClaimsHandler();
+        claimsManager.setClaimHandlers(Collections.singletonList(claimsHandler));
+        issueOperation.setClaimsManager(claimsManager);
+        
+        // Mock up a request
+        RequestSecurityTokenType request = new RequestSecurityTokenType();
+        JAXBElement<String> tokenType = 
+            new JAXBElement<String>(
+                QNameConstants.TOKEN_TYPE, String.class, JWTTokenProvider.JWT_TOKEN_TYPE
+            );
+        request.getAny().add(tokenType);
+        
+        // Add a ClaimsType
+        ClaimsType claimsType = new ClaimsType();
+        claimsType.setDialect(STSConstants.IDT_NS_05_05);
+        Document doc = DOMUtils.createDocument();
+        Element claimType = createClaimsType(doc);
+        claimsType.getAny().add(claimType);
+        
+        JAXBElement<ClaimsType> claimsTypeJaxb = 
+            new JAXBElement<ClaimsType>(
+                QNameConstants.CLAIMS, ClaimsType.class, claimsType
+            );
+        request.getAny().add(claimsTypeJaxb);
+        
+        request.getAny().add(createAppliesToElement("http://dummy-service.com/dummy"));
+        
+        WebServiceContextImpl webServiceContext = setupMessageContext();
+        
+        List<RequestSecurityTokenResponseType> securityTokenResponse = issueToken(issueOperation, request,
+                webServiceContext);
+        
+        // Test the generated token.
+        String jwtToken = null;
+        for (Object tokenObject : securityTokenResponse.get(0).getAny()) {
+            if (tokenObject instanceof Element
+                && REQUESTED_SECURITY_TOKEN.getLocalPart().equals(((Element)tokenObject).getLocalName())
+                && REQUESTED_SECURITY_TOKEN.getNamespaceURI().equals(((Element)tokenObject).getNamespaceURI())) {
+                jwtToken = ((Element)tokenObject).getTextContent();
+                break;
+            }
+        }
+        
+        assertNotNull(jwtToken);
+        
+        // Validate the token
+        JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer(jwtToken);
+        JwtToken jwt = jwtConsumer.getJwtToken();
+        Assert.assertEquals("alice", jwt.getClaim(JwtConstants.CLAIM_SUBJECT));
+        assertEquals(jwt.getClaim(ClaimTypes.LASTNAME.toString()), "doe");
+    }
+    
+    /**
+     * Test to successfully issue a SAML 2 token (realm "B") on-behalf-of a SAML 2 token
+     * which was issued by realm "A".
+     * The relationship type between realm A and B is: FederateClaims
+     * TODO
+     */
+    @org.junit.Test
+    @org.junit.Ignore
+    public void testIssueSaml2TokenOnBehalfOfSaml2DifferentRealmFederateClaims() 
+        throws Exception {
+        TokenIssueOperation issueOperation = new TokenIssueOperation();
+        
+        Map<String, RealmProperties> realms = createSamlRealms();
+        
+        // Add Token Provider
+        List<TokenProvider> providerList = new ArrayList<TokenProvider>();
+        SAMLTokenProvider samlTokenProvider = new SAMLTokenProvider();
+        samlTokenProvider.setRealmMap(realms);
+        List<AttributeStatementProvider> customProviderList = 
+            new ArrayList<AttributeStatementProvider>();
+        customProviderList.add(new ClaimsAttributeStatementProvider());
+        samlTokenProvider.setAttributeStatementProviders(customProviderList);
+        providerList.add(samlTokenProvider);
+        issueOperation.setTokenProviders(providerList);
+        
+        TokenDelegationHandler delegationHandler = new SAMLDelegationHandler();
+        issueOperation.setDelegationHandlers(Collections.singletonList(delegationHandler));
+        
+        // Add Token Validator
+        List<TokenValidator> validatorList = new ArrayList<TokenValidator>();
+        SAMLTokenValidator samlTokenValidator = new SAMLTokenValidator();
+        samlTokenValidator.setSamlRealmCodec(new IssuerSAMLRealmCodec());
+        validatorList.add(samlTokenValidator);
+        issueOperation.setTokenValidators(validatorList);
+
+        addService(issueOperation);
+        
+        // Add Relationship list
+        List<Relationship> relationshipList = new ArrayList<Relationship>();
+        Relationship rs = createRelationship();
+        relationshipList.add(rs);
+        
+        // Add STSProperties object
+        Crypto crypto = CryptoFactory.getInstance(getEncryptionProperties());
+        STSPropertiesMBean stsProperties = createSTSPropertiesMBean(crypto);
+        stsProperties.setRealmParser(new CustomRealmParser());
+        stsProperties.setIdentityMapper(new CustomIdentityMapper());
+        stsProperties.setRelationships(relationshipList);
+        issueOperation.setStsProperties(stsProperties);
+        
+        // Set the ClaimsManager
+        ClaimsManager claimsManager = new ClaimsManager();
+        ClaimsHandler claimsHandler = new CustomClaimsHandler();
+        claimsManager.setClaimHandlers(Collections.singletonList(claimsHandler));
+        issueOperation.setClaimsManager(claimsManager);
+        
+        // Mock up a request
+        RequestSecurityTokenType request = new RequestSecurityTokenType();
+        JAXBElement<String> tokenType = 
+            new JAXBElement<String>(
+                QNameConstants.TOKEN_TYPE, String.class, WSConstants.WSS_SAML2_TOKEN_TYPE
+            );
+        request.getAny().add(tokenType);
+        
+        // Add a ClaimsType
+        ClaimsType claimsType = new ClaimsType();
+        claimsType.setDialect(STSConstants.IDT_NS_05_05);
+        
+        Document doc = DOMUtils.createDocument();
+        Element claimType = createClaimsType(doc);
+        claimsType.getAny().add(claimType);
+        
+        JAXBElement<ClaimsType> claimsTypeJaxb = 
+            new JAXBElement<ClaimsType>(
+                QNameConstants.CLAIMS, ClaimsType.class, claimsType
+            );
+        request.getAny().add(claimsTypeJaxb);
+        
+        //request.getAny().add(createAppliesToElement("http://dummy-service.com/dummy"));
+        
+        // create a SAML Token via the SAMLTokenProvider which contains claims
+        CallbackHandler callbackHandler = new PasswordCallbackHandler();
+        Element samlToken = 
+            createSAMLAssertion(WSConstants.WSS_SAML2_TOKEN_TYPE, crypto, "mystskey",
+                    callbackHandler, realms);
+        Document docToken = samlToken.getOwnerDocument();
+        samlToken = (Element)docToken.appendChild(samlToken);
+        String samlString = DOM2Writer.nodeToString(samlToken);
+        assertTrue(samlString.contains("AttributeStatement"));
+        assertTrue(samlString.contains("alice"));
+        assertTrue(samlString.contains("doe"));
+        assertTrue(samlString.contains(SAML2Constants.CONF_BEARER));
+        
+        // add SAML token as On-Behalf-Of element
+        OnBehalfOfType onbehalfof = new OnBehalfOfType();
+        onbehalfof.setAny(samlToken);
+        JAXBElement<OnBehalfOfType> onbehalfofType = 
+            new JAXBElement<OnBehalfOfType>(
+                    QNameConstants.ON_BEHALF_OF, OnBehalfOfType.class, onbehalfof
+            );
+        request.getAny().add(onbehalfofType);
+        
+        // Mock up message context
+        MessageImpl msg = new MessageImpl();
+        WrappedMessageContext msgCtx = new WrappedMessageContext(msg);
+        msgCtx.put("url", "https");
+        WebServiceContextImpl webServiceContext = new WebServiceContextImpl(msgCtx);
+        
+        List<RequestSecurityTokenResponseType> securityTokenResponseList = issueToken(issueOperation,
+                request, webServiceContext);       
+        RequestSecurityTokenResponseType securityTokenResponse = securityTokenResponseList.get(0);
+        
+        // Test the generated token.
+        Element assertion = null;
+        for (Object tokenObject : securityTokenResponse.getAny()) {
+            if (tokenObject instanceof JAXBElement<?>
+                && REQUESTED_SECURITY_TOKEN.equals(((JAXBElement<?>)tokenObject).getName())) {
+                RequestedSecurityTokenType rstType = 
+                    (RequestedSecurityTokenType)((JAXBElement<?>)tokenObject).getValue();
+                assertion = (Element)rstType.getAny();
+                break;
+            }
+        }
+        assertNotNull(assertion);
+        String tokenString = DOM2Writer.nodeToString(assertion);
+        assertTrue(tokenString.contains("AttributeStatement"));
+        assertTrue(tokenString.contains("alice"));  //subject unchanged
+        assertTrue(tokenString.contains("DOE")); //transformed claim (to uppercase)
+        assertTrue(tokenString.contains(SAML2Constants.CONF_BEARER));
+    }
+    
+    /**
+     * Test to successfully issue a SAML 2 token (realm "B") on-behalf-of a SAML 2 token
+     * which was issued by realm "A".
+     * The relationship type between realm A and B is: FederateIdentity
+     * IdentityMapper is configured globally in STSPropertiesMBean
+     * TODO
+     */
+    @org.junit.Test
+    @org.junit.Ignore
+    public void testIssueSaml2TokenOnBehalfOfSaml2DifferentRealmFederateIdentityGlobalConfig()
+        throws Exception {
+        runIssueSaml2TokenOnBehalfOfSaml2DifferentRealmFederateIdentity(true);
+    }
+    
+    
+    /**
+     * Test to successfully issue a SAML 2 token (realm "B") on-behalf-of a SAML 2 token
+     * which was issued by realm "A".
+     * The relationship type between realm A and B is: FederateIdentity
+     * IdentityMapper is configured in the Relationship
+     * TODO
+     */
+    @org.junit.Test
+    @org.junit.Ignore
+    public void testIssueSaml2TokenOnBehalfOfSaml2DifferentRealmFederateIdentityRelationshipConfig()
+        throws Exception {
+        runIssueSaml2TokenOnBehalfOfSaml2DifferentRealmFederateIdentity(false);
+    }
+
+    private void runIssueSaml2TokenOnBehalfOfSaml2DifferentRealmFederateIdentity(
+            boolean useGlobalIdentityMapper) throws WSSecurityException {
+        TokenIssueOperation issueOperation = new TokenIssueOperation();
+        
+        Map<String, RealmProperties> realms = createSamlRealms();
+        
+        // Add Token Provider
+        List<TokenProvider> providerList = new ArrayList<TokenProvider>();
+        SAMLTokenProvider samlTokenProvider = new SAMLTokenProvider();
+        samlTokenProvider.setRealmMap(realms);
+        List<AttributeStatementProvider> customProviderList = 
+            new ArrayList<AttributeStatementProvider>();
+        customProviderList.add(new ClaimsAttributeStatementProvider());
+        samlTokenProvider.setAttributeStatementProviders(customProviderList);
+        providerList.add(samlTokenProvider);
+        issueOperation.setTokenProviders(providerList);
+        
+        TokenDelegationHandler delegationHandler = new SAMLDelegationHandler();
+        issueOperation.setDelegationHandlers(Collections.singletonList(delegationHandler));
+        
+        // Add Token Validator
+        List<TokenValidator> validatorList = new ArrayList<TokenValidator>();
+        SAMLTokenValidator samlTokenValidator = new SAMLTokenValidator();
+        samlTokenValidator.setSamlRealmCodec(new IssuerSAMLRealmCodec());
+        validatorList.add(samlTokenValidator);
+        issueOperation.setTokenValidators(validatorList);
+
+        addService(issueOperation);
+        
+        // Add Relationship list
+        List<Relationship> relationshipList = new ArrayList<Relationship>();
+        Relationship rs = createRelationship();
+        rs.setType(Relationship.FED_TYPE_IDENTITY);
+        rs.setIdentityMapper(new CustomIdentityMapper());
+        relationshipList.add(rs);
+        
+        // Add STSProperties object
+        Crypto crypto = CryptoFactory.getInstance(getEncryptionProperties());
+        STSPropertiesMBean stsProperties = createSTSPropertiesMBean(crypto);
+        stsProperties.setRealmParser(new CustomRealmParser());
+        
+        if (useGlobalIdentityMapper) {
+            stsProperties.setIdentityMapper(new CustomIdentityMapper());
+        } else { 
+            stsProperties.setRelationships(relationshipList);
+        }  
+
+        issueOperation.setStsProperties(stsProperties);
+        
+        // Set the ClaimsManager
+        ClaimsManager claimsManager = new ClaimsManager();
+        claimsManager.setClaimHandlers(Collections.singletonList((ClaimsHandler)new CustomClaimsHandler()));
+        issueOperation.setClaimsManager(claimsManager);
+        
+        // Mock up a request
+        RequestSecurityTokenType request = new RequestSecurityTokenType();
+        JAXBElement<String> tokenType = 
+            new JAXBElement<String>(
+                QNameConstants.TOKEN_TYPE, String.class, WSConstants.WSS_SAML2_TOKEN_TYPE
+            );
+        request.getAny().add(tokenType);
+        
+        // Add a ClaimsType
+        ClaimsType claimsType = new ClaimsType();
+        claimsType.setDialect(STSConstants.IDT_NS_05_05);
+        
+        Document doc = DOMUtils.createDocument();
+        Element claimType = createClaimsType(doc);
+        claimsType.getAny().add(claimType);
+        
+        JAXBElement<ClaimsType> claimsTypeJaxb = 
+            new JAXBElement<ClaimsType>(
+                QNameConstants.CLAIMS, ClaimsType.class, claimsType
+            );
+        request.getAny().add(claimsTypeJaxb);
+        
+        //request.getAny().add(createAppliesToElement("http://dummy-service.com/dummy"));
+        
+        // create a SAML Token via the SAMLTokenProvider which contains claims
+        CallbackHandler callbackHandler = new PasswordCallbackHandler();
+        Element samlToken = 
+            createSAMLAssertion(WSConstants.WSS_SAML2_TOKEN_TYPE, crypto, "mystskey",
+                    callbackHandler, realms);
+        Document docToken = samlToken.getOwnerDocument();
+        samlToken = (Element)docToken.appendChild(samlToken);
+        String samlString = DOM2Writer.nodeToString(samlToken);
+        assertTrue(samlString.contains("AttributeStatement"));
+        assertTrue(samlString.contains("alice"));
+        assertTrue(samlString.contains("doe"));
+        assertTrue(samlString.contains(SAML2Constants.CONF_BEARER));
+        
+        // add SAML token as On-Behalf-Of element
+        OnBehalfOfType onbehalfof = new OnBehalfOfType();
+        onbehalfof.setAny(samlToken);
+        JAXBElement<OnBehalfOfType> onbehalfofType = 
+            new JAXBElement<OnBehalfOfType>(
+                    QNameConstants.ON_BEHALF_OF, OnBehalfOfType.class, onbehalfof
+            );
+        request.getAny().add(onbehalfofType);
+        
+        // Mock up message context
+        MessageImpl msg = new MessageImpl();
+        WrappedMessageContext msgCtx = new WrappedMessageContext(msg);
+        msgCtx.put("url", "https");
+        WebServiceContextImpl webServiceContext = new WebServiceContextImpl(msgCtx);
+        
+        List<RequestSecurityTokenResponseType> securityTokenResponseList = issueToken(issueOperation,
+                request, webServiceContext);       
+        RequestSecurityTokenResponseType securityTokenResponse = securityTokenResponseList.get(0);
+        
+        // Test the generated token.
+        Element assertion = null;
+        for (Object tokenObject : securityTokenResponse.getAny()) {
+            if (tokenObject instanceof JAXBElement<?>
+                && REQUESTED_SECURITY_TOKEN.equals(((JAXBElement<?>)tokenObject).getName())) {
+                RequestedSecurityTokenType rstType = 
+                    (RequestedSecurityTokenType)((JAXBElement<?>)tokenObject).getValue();
+                assertion = (Element)rstType.getAny();
+                break;
+            }
+        }
+        
+        assertNotNull(assertion);
+        String tokenString = DOM2Writer.nodeToString(assertion);
+        assertTrue(tokenString.contains("AttributeStatement"));
+        assertTrue(tokenString.contains("ALICE"));  //subject changed (to uppercase)
+        assertTrue(tokenString.contains("doe"));  //claim unchanged but requested
+        assertTrue(tokenString.contains(SAML2Constants.CONF_BEARER));
+    }
+    
+
+    private Relationship createRelationship() {
+        Relationship rs = new Relationship();
+        ClaimsMapper claimsMapper = new CustomClaimsMapper();
+        rs.setClaimsMapper(claimsMapper);
+        rs.setSourceRealm("A");
+        rs.setTargetRealm("B");
+        rs.setType(Relationship.FED_TYPE_CLAIMS);
+        return rs;
+    }
+    
+    
+    /*
+     * Create STSPropertiesMBean object
+     */
+    private STSPropertiesMBean createSTSPropertiesMBean(Crypto crypto) throws WSSecurityException {
+        STSPropertiesMBean stsProperties = new StaticSTSProperties();
+        stsProperties.setEncryptionCrypto(crypto);
+        stsProperties.setSignatureCrypto(crypto);
+        stsProperties.setEncryptionUsername("myservicekey");
+        stsProperties.setSignatureUsername("mystskey");
+        stsProperties.setCallbackHandler(new PasswordCallbackHandler());
+        stsProperties.setIssuer("STS");
+        return stsProperties;
+    }
+    
+    
+    /*
+     * Create a security context object
+     */
+    private SecurityContext createSecurityContext(final Principal p) {
+        return new SecurityContext() {
+            public Principal getUserPrincipal() {
+                return p;
+            }
+            public boolean isUserInRole(String role) {
+                return false;
+            }
+        };
+    }
+    
+    /*
+     * Mock up an AppliesTo element using the supplied address
+     */
+    private Element createAppliesToElement(String addressUrl) {
+        Document doc = DOMUtils.createDocument();
+        Element appliesTo = doc.createElementNS(STSConstants.WSP_NS, "wsp:AppliesTo");
+        appliesTo.setAttributeNS(WSConstants.XMLNS_NS, "xmlns:wsp", STSConstants.WSP_NS);
+        Element endpointRef = doc.createElementNS(STSConstants.WSA_NS_05, "wsa:EndpointReference");
+        endpointRef.setAttributeNS(WSConstants.XMLNS_NS, "xmlns:wsa", STSConstants.WSA_NS_05);
+        Element address = doc.createElementNS(STSConstants.WSA_NS_05, "wsa:Address");
+        address.setAttributeNS(WSConstants.XMLNS_NS, "xmlns:wsa", STSConstants.WSA_NS_05);
+        address.setTextContent(addressUrl);
+        endpointRef.appendChild(address);
+        appliesTo.appendChild(endpointRef);
+        return appliesTo;
+    }
+    
+    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;
+    }
+    
+    /*
+     * Mock up a SecondaryParameters DOM Element containing some claims
+     */
+    private Element createSecondaryParameters() {
+        Document doc = DOMUtils.createDocument();
+        Element secondary = doc.createElementNS(STSConstants.WST_NS_05_12, "SecondaryParameters");
+        secondary.setAttributeNS(WSConstants.XMLNS_NS, "xmlns", STSConstants.WST_NS_05_12);
+        
+        Element claims = doc.createElementNS(STSConstants.WST_NS_05_12, "Claims");
+        claims.setAttributeNS(null, "Dialect", STSConstants.IDT_NS_05_05);
+        
+        Element claimType = createClaimsType(doc);
+        claims.appendChild(claimType);
+        Element claimValue = createClaimValue(doc);
+        claims.appendChild(claimValue);
+        secondary.appendChild(claims);
+
+        return secondary;
+    }
+    
+    private Element createClaimsType(Document doc) {
+        Element claimType = doc.createElementNS(STSConstants.IDT_NS_05_05, "ClaimType");
+        claimType.setAttributeNS(
+            null, "Uri", ClaimTypes.LASTNAME.toString()
+        );
+        claimType.setAttributeNS(WSConstants.XMLNS_NS, "xmlns", STSConstants.IDT_NS_05_05);
+        
+        return claimType;
+    }
+    
+    private Element createClaimValue(Document doc) {
+        Element claimValue = doc.createElementNS(STSConstants.IDT_NS_05_05, "ClaimValue");
+        claimValue.setAttributeNS(null, "Uri", ROLE_CLAIM.toString());
+        claimValue.setAttributeNS(WSConstants.XMLNS_NS, "xmlns", STSConstants.IDT_NS_05_05);
+        Element value = doc.createElementNS(STSConstants.IDT_NS_05_05, "Value");
+        value.setTextContent("administrator");
+        claimValue.appendChild(value);
+        return claimValue;
+    }
+    
+    private Map<String, RealmProperties> createSamlRealms() {
+        // Create Realms
+        Map<String, RealmProperties> samlRealms = new HashMap<String, RealmProperties>();
+        RealmProperties samlRealm = new RealmProperties();
+        samlRealm.setIssuer("A-Issuer");
+        samlRealms.put("A", samlRealm);
+        samlRealm = new RealmProperties();
+        samlRealm.setIssuer("B-Issuer");
+        samlRealms.put("B", samlRealm);
+        return samlRealms;
+    }
+    
+    /*
+     * Mock up an SAML assertion element
+     */
+    private Element createSAMLAssertion(
+            String tokenType, Crypto crypto, String signatureUsername, CallbackHandler callbackHandler,
+            Map<String, RealmProperties> realms
+    ) throws WSSecurityException {
+        
+        SAMLTokenProvider samlTokenProvider = new SAMLTokenProvider();
+        samlTokenProvider.setRealmMap(realms);
+        List<AttributeStatementProvider> customProviderList = 
+            new ArrayList<AttributeStatementProvider>();
+        customProviderList.add(new ClaimsAttributeStatementProvider());
+        samlTokenProvider.setAttributeStatementProviders(customProviderList);
+        
+        TokenProviderParameters providerParameters = 
+            createProviderParameters(
+                    tokenType, STSConstants.BEARER_KEY_KEYTYPE, crypto, signatureUsername, callbackHandler
+            );
+        if (realms != null) {
+            providerParameters.setRealm("A");
+        }
+        
+        // Set the ClaimsManager
+        ClaimsManager claimsManager = new ClaimsManager();
+        ClaimsHandler claimsHandler = new CustomClaimsHandler();
+        claimsManager.setClaimHandlers(Collections.singletonList(claimsHandler));
+        providerParameters.setClaimsManager(claimsManager);
+        
+        ClaimCollection requestedClaims = new ClaimCollection();
+        Claim requestClaim = new Claim();
+        requestClaim.setClaimType(ClaimTypes.LASTNAME);
+        requestClaim.setOptional(false);
+        requestedClaims.add(requestClaim);
+        providerParameters.setRequestedSecondaryClaims(requestedClaims);
+        
+        TokenProviderResponse providerResponse = samlTokenProvider.createToken(providerParameters);
+        assertTrue(providerResponse != null);
+        assertTrue(providerResponse.getToken() != null && providerResponse.getTokenId() != null);
+
+        return (Element)providerResponse.getToken();
+    }
+    
+    private TokenProviderParameters createProviderParameters(
+            String tokenType, String keyType, Crypto crypto, 
+            String signatureUsername, CallbackHandler callbackHandler
+    ) throws WSSecurityException {
+        TokenProviderParameters parameters = new TokenProviderParameters();
+
+        TokenRequirements tokenRequirements = new TokenRequirements();
+        tokenRequirements.setTokenType(tokenType);
+        parameters.setTokenRequirements(tokenRequirements);
+
+        KeyRequirements keyRequirements = new KeyRequirements();
+        keyRequirements.setKeyType(keyType);
+        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();
+        stsProperties.setSignatureCrypto(crypto);
+        stsProperties.setSignatureUsername(signatureUsername);
+        stsProperties.setCallbackHandler(callbackHandler);
+        stsProperties.setIssuer("STS");
+        parameters.setStsProperties(stsProperties);
+
+        parameters.setEncryptionProperties(new EncryptionProperties());
+
+        return parameters;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/48f8f31d/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/provider/JWTClaimsTest.java
----------------------------------------------------------------------
diff --git a/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/provider/JWTClaimsTest.java b/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/provider/JWTClaimsTest.java
new file mode 100644
index 0000000..b735f3a
--- /dev/null
+++ b/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/provider/JWTClaimsTest.java
@@ -0,0 +1,288 @@
+/**
+ * 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.net.URI;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+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.JwtToken;
+import org.apache.cxf.rt.security.claims.Claim;
+import org.apache.cxf.rt.security.claims.ClaimCollection;
+import org.apache.cxf.sts.StaticSTSProperties;
+import org.apache.cxf.sts.claims.ClaimTypes;
+import org.apache.cxf.sts.claims.ClaimsHandler;
+import org.apache.cxf.sts.claims.ClaimsManager;
+import org.apache.cxf.sts.claims.StaticClaimsHandler;
+import org.apache.cxf.sts.common.CustomClaimsHandler;
+import org.apache.cxf.sts.common.PasswordCallbackHandler;
+import org.apache.cxf.sts.request.KeyRequirements;
+import org.apache.cxf.sts.request.TokenRequirements;
+import org.apache.cxf.sts.service.EncryptionProperties;
+import org.apache.cxf.sts.token.provider.jwt.JWTTokenProvider;
+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;
+
+/**
+ * A unit test for creating JWT Tokens with various claims populated by a ClaimsHandler.
+ */
+public class JWTClaimsTest extends org.junit.Assert {
+    
+    public static final URI CLAIM_STATIC_COMPANY = 
+        URI.create("http://apache.org/claims/test/company");
+    
+    public static final URI CLAIM_APPLICATION = 
+        URI.create("http://apache.org/claims/test/applicationId");
+    
+    private static final String CLAIM_STATIC_COMPANY_VALUE = "myc@mpany";
+    
+    private static final String APPLICATION_APPLIES_TO = "http://dummy-service.com/dummy";
+    
+    /**
+     * Test the creation of a JWTToken with various claims set by a ClaimsHandler.
+     */
+    @org.junit.Test
+    public void testJWTClaims() throws Exception {
+        TokenProvider tokenProvider = new JWTTokenProvider();
+        TokenProviderParameters providerParameters = 
+            createProviderParameters(JWTTokenProvider.JWT_TOKEN_TYPE, null);
+        
+        ClaimsManager claimsManager = new ClaimsManager();
+        ClaimsHandler claimsHandler = new CustomClaimsHandler();
+        claimsManager.setClaimHandlers(Collections.singletonList(claimsHandler));
+        providerParameters.setClaimsManager(claimsManager);
+        
+        ClaimCollection claims = createClaims();
+        providerParameters.setRequestedPrimaryClaims(claims);
+        
+        assertTrue(tokenProvider.canHandleToken(JWTTokenProvider.JWT_TOKEN_TYPE));
+        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(ClaimTypes.EMAILADDRESS.toString()), "alice@cxf.apache.org");
+        assertEquals(jwt.getClaim(ClaimTypes.FIRSTNAME.toString()), "alice");
+        assertEquals(jwt.getClaim(ClaimTypes.LASTNAME.toString()), "doe");
+    }
+    
+    /**
+     * Test the creation of a JWTToken with various claims set by a ClaimsHandler.
+     * We have both a primary claim (sent in wst:RequestSecurityToken) and a secondary claim
+     * (send in wst:RequestSecurityToken/wst:SecondaryParameters).
+     */
+    @org.junit.Test
+    public void testJWTMultipleClaims() throws Exception {
+        TokenProvider tokenProvider = new JWTTokenProvider();
+        TokenProviderParameters providerParameters = 
+            createProviderParameters(JWTTokenProvider.JWT_TOKEN_TYPE, null);
+        
+        ClaimsManager claimsManager = new ClaimsManager();
+        ClaimsHandler claimsHandler = new CustomClaimsHandler();
+        claimsManager.setClaimHandlers(Collections.singletonList(claimsHandler));
+        providerParameters.setClaimsManager(claimsManager);
+        
+        ClaimCollection primaryClaims = createClaims();
+        providerParameters.setRequestedPrimaryClaims(primaryClaims);
+        
+        ClaimCollection secondaryClaims = new ClaimCollection();
+        Claim claim = new Claim();
+        claim.setClaimType(ClaimTypes.STREETADDRESS);
+        secondaryClaims.add(claim);
+        providerParameters.setRequestedSecondaryClaims(secondaryClaims);
+        
+        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(ClaimTypes.EMAILADDRESS.toString()), "alice@cxf.apache.org");
+        assertEquals(jwt.getClaim(ClaimTypes.FIRSTNAME.toString()), "alice");
+        assertEquals(jwt.getClaim(ClaimTypes.LASTNAME.toString()), "doe");
+        assertEquals(jwt.getClaim(ClaimTypes.STREETADDRESS.toString()), "1234 1st Street");
+    }
+    
+    /**
+     * Test the creation of a JWTToken with various claims set by a ClaimsHandler.
+     * We have both a primary claim (sent in wst:RequestSecurityToken) and a secondary claim
+     * (send in wst:RequestSecurityToken/wst:SecondaryParameters), and both have the 
+     * same dialect in this test.
+     */
+    @org.junit.Test
+    public void testJWTMultipleClaimsSameDialect() throws Exception {
+        TokenProvider tokenProvider = new JWTTokenProvider();
+        TokenProviderParameters providerParameters = 
+            createProviderParameters(JWTTokenProvider.JWT_TOKEN_TYPE, null);
+        
+        ClaimsManager claimsManager = new ClaimsManager();
+        ClaimsHandler claimsHandler = new CustomClaimsHandler();
+        claimsManager.setClaimHandlers(Collections.singletonList(claimsHandler));
+        providerParameters.setClaimsManager(claimsManager);
+        
+        ClaimCollection primaryClaims = createClaims();
+        primaryClaims.setDialect(ClaimTypes.URI_BASE);
+        providerParameters.setRequestedPrimaryClaims(primaryClaims);
+        
+        ClaimCollection secondaryClaims = new ClaimCollection();
+        Claim claim = new Claim();
+        claim.setClaimType(ClaimTypes.STREETADDRESS);
+        secondaryClaims.add(claim);
+        secondaryClaims.setDialect(ClaimTypes.URI_BASE);
+        providerParameters.setRequestedSecondaryClaims(secondaryClaims);
+        
+        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(ClaimTypes.EMAILADDRESS.toString()), "alice@cxf.apache.org");
+        assertEquals(jwt.getClaim(ClaimTypes.FIRSTNAME.toString()), "alice");
+        assertEquals(jwt.getClaim(ClaimTypes.LASTNAME.toString()), "doe");
+        assertEquals(jwt.getClaim(ClaimTypes.STREETADDRESS.toString()), "1234 1st Street");
+    }
+    
+    /**
+     * Test the creation of a JWTToken with StaticClaimsHandler
+     */
+    @org.junit.Test
+    public void testJWTStaticClaims() throws Exception {
+        TokenProvider tokenProvider = new JWTTokenProvider();
+        TokenProviderParameters providerParameters = 
+            createProviderParameters(JWTTokenProvider.JWT_TOKEN_TYPE, null);
+        
+        ClaimsManager claimsManager = new ClaimsManager();
+        StaticClaimsHandler claimsHandler = new StaticClaimsHandler();
+        Map<String, String> staticClaimsMap = new HashMap<String, String>();
+        staticClaimsMap.put(CLAIM_STATIC_COMPANY.toString(), CLAIM_STATIC_COMPANY_VALUE);
+        claimsHandler.setGlobalClaims(staticClaimsMap);
+        claimsManager.setClaimHandlers(Collections.singletonList((ClaimsHandler)claimsHandler));
+        providerParameters.setClaimsManager(claimsManager);
+        
+        ClaimCollection claims = new ClaimCollection();
+        Claim claim = new Claim();
+        claim.setClaimType(CLAIM_STATIC_COMPANY);
+        claims.add(claim);
+        providerParameters.setRequestedPrimaryClaims(claims);
+        
+        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(CLAIM_STATIC_COMPANY.toString()), CLAIM_STATIC_COMPANY_VALUE);
+    }
+    
+    private TokenProviderParameters createProviderParameters(
+        String tokenType, String appliesTo
+    ) 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);
+        
+        if (appliesTo != null) {
+            parameters.setAppliesToAddress(appliesTo);
+        } else {
+            parameters.setAppliesToAddress(APPLICATION_APPLIES_TO);
+        }
+        
+        // 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;
+    }
+    
+    /**
+     * Create a set of parsed Claims
+     */
+    private ClaimCollection createClaims() {
+        ClaimCollection claims = new ClaimCollection();
+        
+        Claim claim = new Claim();
+        claim.setClaimType(ClaimTypes.FIRSTNAME);
+        claims.add(claim);
+        
+        claim = new Claim();
+        claim.setClaimType(ClaimTypes.LASTNAME);
+        claims.add(claim);
+        
+        claim = new Claim();
+        claim.setClaimType(ClaimTypes.EMAILADDRESS);
+        claims.add(claim);
+        
+        return claims;
+    }
+    
+}


[2/2] cxf git commit: Fixing time/expiry stuff for JWT in the STS + tests

Posted by co...@apache.org.
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/ae74e760
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/ae74e760
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/ae74e760

Branch: refs/heads/master
Commit: ae74e760b6abb0f1705449edf34920809f2b4187
Parents: 48f8f31
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 16:47:19 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/ae74e760/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/ae74e760/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/ae74e760/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/ae74e760/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;
+    }
+    
+  
+    
+}