You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by co...@apache.org on 2015/11/09 20:27:55 UTC
[4/5] cxf git commit: Adding support for claims in JWT Tokens in the
STS
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/0848bdb3
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/0848bdb3
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/0848bdb3
Branch: refs/heads/3.1.x-fixes
Commit: 0848bdb305b5d6e542da417ff5fd9e7c9ace5381
Parents: b4a17ce
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 19:27:41 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/0848bdb3/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/0848bdb3/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/0848bdb3/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/0848bdb3/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/0848bdb3/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;
+ }
+
+}