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/11 18:18:11 UTC
[3/3] cxf git commit: Add the ability to encrypt JWT tokens from the
STS
Add the ability to encrypt JWT tokens from the STS
Project: http://git-wip-us.apache.org/repos/asf/cxf/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/4f92f75a
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/4f92f75a
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/4f92f75a
Branch: refs/heads/master
Commit: 4f92f75aa505a6223932f82812ae582296446ec9
Parents: fd34eab
Author: Colm O hEigeartaigh <co...@apache.org>
Authored: Wed Nov 11 17:17:46 2015 +0000
Committer: Colm O hEigeartaigh <co...@apache.org>
Committed: Wed Nov 11 17:17:46 2015 +0000
----------------------------------------------------------------------
.../token/provider/jwt/JWTTokenProvider.java | 77 +++++++++++-
.../token/provider/JWTTokenProviderTest.java | 125 ++++++++++++++++++-
2 files changed, 195 insertions(+), 7 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cxf/blob/4f92f75a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/jwt/JWTTokenProvider.java
----------------------------------------------------------------------
diff --git a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/jwt/JWTTokenProvider.java b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/jwt/JWTTokenProvider.java
index 5afffda..54a4c4e 100644
--- a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/jwt/JWTTokenProvider.java
+++ b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/jwt/JWTTokenProvider.java
@@ -31,10 +31,16 @@ import java.util.logging.Logger;
import javax.security.auth.callback.CallbackHandler;
import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.StringUtils;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.PhaseInterceptorChain;
import org.apache.cxf.rs.security.jose.common.JoseConstants;
+import org.apache.cxf.rs.security.jose.jwa.ContentAlgorithm;
+import org.apache.cxf.rs.security.jose.jwa.KeyAlgorithm;
import org.apache.cxf.rs.security.jose.jwa.SignatureAlgorithm;
+import org.apache.cxf.rs.security.jose.jwe.JweEncryptionProvider;
+import org.apache.cxf.rs.security.jose.jwe.JweHeaders;
+import org.apache.cxf.rs.security.jose.jwe.JweUtils;
import org.apache.cxf.rs.security.jose.jws.JwsJwtCompactProducer;
import org.apache.cxf.rs.security.jose.jws.JwsSignatureProvider;
import org.apache.cxf.rs.security.jose.jws.JwsUtils;
@@ -43,7 +49,9 @@ import org.apache.cxf.rs.security.jose.jwt.JwtToken;
import org.apache.cxf.sts.STSPropertiesMBean;
import org.apache.cxf.sts.SignatureProperties;
import org.apache.cxf.sts.cache.CacheUtils;
+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.TokenProvider;
import org.apache.cxf.sts.token.provider.TokenProviderParameters;
import org.apache.cxf.sts.token.provider.TokenProviderResponse;
@@ -113,8 +121,13 @@ public class JWTTokenProvider implements TokenProvider {
try {
JwtToken token = new JwtToken(claims);
- String tokenData = signToken(token, jwtRealm, tokenParameters.getStsProperties(),
- tokenParameters.getTokenRequirements());
+ String tokenData = signToken(token, jwtRealm, tokenParameters.getStsProperties());
+ if (tokenParameters.isEncryptToken()) {
+ tokenData = encryptToken(tokenData, token.getJweHeaders(),
+ tokenParameters.getStsProperties(),
+ tokenParameters.getEncryptionProperties(),
+ tokenParameters.getKeyRequirements());
+ }
TokenProviderResponse response = new TokenProviderResponse();
response.setToken(tokenData);
@@ -194,8 +207,7 @@ public class JWTTokenProvider implements TokenProvider {
private String signToken(
JwtToken token,
RealmProperties jwtRealm,
- STSPropertiesMBean stsProperties,
- TokenRequirements tokenRequirements
+ STSPropertiesMBean stsProperties
) throws Exception {
Properties signingProperties = new Properties();
@@ -277,5 +289,62 @@ public class JWTTokenProvider implements TokenProvider {
}
}
+
+ private String encryptToken(
+ String token,
+ JweHeaders jweHeaders,
+ STSPropertiesMBean stsProperties,
+ EncryptionProperties encryptionProperties,
+ KeyRequirements keyRequirements
+ ) throws Exception {
+
+ Properties encProperties = new Properties();
+
+ String name = encryptionProperties.getEncryptionName();
+ if (name == null) {
+ name = stsProperties.getEncryptionUsername();
+ }
+ if (name == null) {
+ LOG.fine("No encryption alias is configured");
+ return token;
+ }
+ encProperties.put(JoseConstants.RSSEC_KEY_STORE_ALIAS, name);
+
+ // Get the encryption algorithm to use - for now we don't allow the client to ask
+ // for a particular encryption algorithm, as with SAML
+ String encryptionAlgorithm = encryptionProperties.getEncryptionAlgorithm();
+ try {
+ ContentAlgorithm.getAlgorithm(encryptionAlgorithm);
+ } catch (IllegalArgumentException ex) {
+ encryptionAlgorithm = ContentAlgorithm.A128GCM.name();
+ }
+ encProperties.put(JoseConstants.RSSEC_ENCRYPTION_CONTENT_ALGORITHM, encryptionAlgorithm);
+
+ // Get the key-wrap algorithm to use - for now we don't allow the client to ask
+ // for a particular encryption algorithm, as with SAML
+ String keyWrapAlgorithm = encryptionProperties.getKeyWrapAlgorithm();
+ try {
+ KeyAlgorithm.getAlgorithm(keyWrapAlgorithm);
+ } catch (IllegalArgumentException ex) {
+ keyWrapAlgorithm = KeyAlgorithm.RSA_OAEP.name();
+ }
+ encProperties.put(JoseConstants.RSSEC_ENCRYPTION_KEY_ALGORITHM, keyWrapAlgorithm);
+
+ // Initialise encryption objects with defaults of STSPropertiesMBean
+ Crypto encryptionCrypto = stsProperties.getEncryptionCrypto();
+
+ if (!(encryptionCrypto instanceof Merlin)) {
+ throw new STSException("Can't get the keystore", STSException.REQUEST_FAILED);
+ }
+ KeyStore keystore = ((Merlin)encryptionCrypto).getKeyStore();
+ encProperties.put(JoseConstants.RSSEC_KEY_STORE, keystore);
+
+ JweEncryptionProvider encProvider =
+ JweUtils.loadEncryptionProvider(encProperties, jweHeaders, false);
+ // token.getJwsHeaders().setSignatureAlgorithm(sigProvider.getAlgorithm());
+
+ return encProvider.encrypt(StringUtils.toBytesUTF8(token), null);
+
+ }
}
http://git-wip-us.apache.org/repos/asf/cxf/blob/4f92f75a/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/provider/JWTTokenProviderTest.java
----------------------------------------------------------------------
diff --git a/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/provider/JWTTokenProviderTest.java b/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/provider/JWTTokenProviderTest.java
index 6273e0e..2af75c2 100644
--- a/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/provider/JWTTokenProviderTest.java
+++ b/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/provider/JWTTokenProviderTest.java
@@ -18,6 +18,7 @@
*/
package org.apache.cxf.sts.token.provider;
+import java.security.KeyStore;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Properties;
@@ -25,13 +26,19 @@ 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.common.JoseConstants;
import org.apache.cxf.rs.security.jose.jwa.SignatureAlgorithm;
+import org.apache.cxf.rs.security.jose.jwe.JweDecryptionOutput;
+import org.apache.cxf.rs.security.jose.jwe.JweDecryptionProvider;
+import org.apache.cxf.rs.security.jose.jwe.JweJwtCompactConsumer;
+import org.apache.cxf.rs.security.jose.jwe.JweUtils;
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.cache.DefaultInMemoryTokenStore;
import org.apache.cxf.sts.common.PasswordCallbackHandler;
+import org.apache.cxf.sts.common.TestUtils;
import org.apache.cxf.sts.request.KeyRequirements;
import org.apache.cxf.sts.request.TokenRequirements;
import org.apache.cxf.sts.service.EncryptionProperties;
@@ -41,6 +48,7 @@ import org.apache.cxf.ws.security.tokenstore.TokenStore;
import org.apache.wss4j.common.crypto.Crypto;
import org.apache.wss4j.common.crypto.CryptoFactory;
import org.apache.wss4j.common.crypto.CryptoType;
+import org.apache.wss4j.common.crypto.Merlin;
import org.apache.wss4j.common.ext.WSSecurityException;
import org.apache.wss4j.common.principal.CustomTokenPrincipal;
import org.junit.Assert;
@@ -49,9 +57,13 @@ import org.junit.Assert;
* Some unit tests for creating JWTTokens.
*/
public class JWTTokenProviderTest extends org.junit.Assert {
-
+ private static boolean unrestrictedPoliciesInstalled;
private static TokenStore tokenStore = new DefaultInMemoryTokenStore();
+ static {
+ unrestrictedPoliciesInstalled = TestUtils.checkUnrestrictedPoliciesInstalled();
+ };
+
@org.junit.Test
public void testCreateUnsignedJWT() throws Exception {
TokenProvider jwtTokenProvider = new JWTTokenProvider();
@@ -147,6 +159,97 @@ public class JWTTokenProviderTest extends org.junit.Assert {
Assert.assertNotNull(secToken);
}
+ @org.junit.Test
+ public void testCreateUnsignedEncryptedJWT() throws Exception {
+ TokenProvider jwtTokenProvider = new JWTTokenProvider();
+ ((JWTTokenProvider)jwtTokenProvider).setSignToken(false);
+
+ TokenProviderParameters providerParameters = createProviderParameters();
+ providerParameters.setEncryptToken(true);
+
+ assertTrue(jwtTokenProvider.canHandleToken(JWTTokenProvider.JWT_TOKEN_TYPE));
+ TokenProviderResponse providerResponse = jwtTokenProvider.createToken(providerParameters);
+ assertTrue(providerResponse != null);
+ assertTrue(providerResponse.getToken() != null && providerResponse.getTokenId() != null);
+
+ String token = (String)providerResponse.getToken();
+ assertNotNull(token);
+ assertTrue(token.split("\\.").length == 5);
+
+ if (unrestrictedPoliciesInstalled) {
+ // Validate the token
+ JweJwtCompactConsumer jwtConsumer = new JweJwtCompactConsumer(token);
+ Properties decProperties = new Properties();
+ Crypto decryptionCrypto = CryptoFactory.getInstance(getDecryptionProperties());
+ KeyStore keystore = ((Merlin)decryptionCrypto).getKeyStore();
+ decProperties.put(JoseConstants.RSSEC_KEY_STORE, keystore);
+ decProperties.put(JoseConstants.RSSEC_KEY_STORE_ALIAS, "myservicekey");
+ decProperties.put(JoseConstants.RSSEC_KEY_PSWD, "skpass");
+
+ JweDecryptionProvider decProvider =
+ JweUtils.loadDecryptionProvider(decProperties, jwtConsumer.getHeaders(), false);
+
+ JweDecryptionOutput decOutput = decProvider.decrypt(token);
+ String decToken = decOutput.getContentText();
+
+ JwsJwtCompactConsumer jwtJwsConsumer = new JwsJwtCompactConsumer(decToken);
+ JwtToken jwt = jwtJwsConsumer.getJwtToken();
+
+ Assert.assertEquals("alice", jwt.getClaim(JwtConstants.CLAIM_SUBJECT));
+ Assert.assertEquals(providerResponse.getTokenId(), jwt.getClaim(JwtConstants.CLAIM_JWT_ID));
+ Assert.assertEquals(providerResponse.getCreated().getTime() / 1000L,
+ jwt.getClaim(JwtConstants.CLAIM_ISSUED_AT));
+ Assert.assertEquals(providerResponse.getExpires().getTime() / 1000L,
+ jwt.getClaim(JwtConstants.CLAIM_EXPIRY));
+ }
+
+ }
+
+ @org.junit.Test
+ public void testCreateSignedEncryptedJWT() throws Exception {
+ TokenProvider jwtTokenProvider = new JWTTokenProvider();
+
+ TokenProviderParameters providerParameters = createProviderParameters();
+ providerParameters.setEncryptToken(true);
+
+ assertTrue(jwtTokenProvider.canHandleToken(JWTTokenProvider.JWT_TOKEN_TYPE));
+ TokenProviderResponse providerResponse = jwtTokenProvider.createToken(providerParameters);
+ assertTrue(providerResponse != null);
+ assertTrue(providerResponse.getToken() != null && providerResponse.getTokenId() != null);
+
+ String token = (String)providerResponse.getToken();
+ assertNotNull(token);
+ assertTrue(token.split("\\.").length == 5);
+
+ if (unrestrictedPoliciesInstalled) {
+ // Validate the token
+ JweJwtCompactConsumer jwtConsumer = new JweJwtCompactConsumer(token);
+ Properties decProperties = new Properties();
+ Crypto decryptionCrypto = CryptoFactory.getInstance(getDecryptionProperties());
+ KeyStore keystore = ((Merlin)decryptionCrypto).getKeyStore();
+ decProperties.put(JoseConstants.RSSEC_KEY_STORE, keystore);
+ decProperties.put(JoseConstants.RSSEC_KEY_STORE_ALIAS, "myservicekey");
+ decProperties.put(JoseConstants.RSSEC_KEY_PSWD, "skpass");
+
+ JweDecryptionProvider decProvider =
+ JweUtils.loadDecryptionProvider(decProperties, jwtConsumer.getHeaders(), false);
+
+ JweDecryptionOutput decOutput = decProvider.decrypt(token);
+ String decToken = decOutput.getContentText();
+
+ JwsJwtCompactConsumer jwtJwsConsumer = new JwsJwtCompactConsumer(decToken);
+ JwtToken jwt = jwtJwsConsumer.getJwtToken();
+
+ Assert.assertEquals("alice", jwt.getClaim(JwtConstants.CLAIM_SUBJECT));
+ Assert.assertEquals(providerResponse.getTokenId(), jwt.getClaim(JwtConstants.CLAIM_JWT_ID));
+ Assert.assertEquals(providerResponse.getCreated().getTime() / 1000L,
+ jwt.getClaim(JwtConstants.CLAIM_ISSUED_AT));
+ Assert.assertEquals(providerResponse.getExpires().getTime() / 1000L,
+ jwt.getClaim(JwtConstants.CLAIM_EXPIRY));
+ }
+
+ }
+
private TokenProviderParameters createProviderParameters() throws WSSecurityException {
TokenProviderParameters parameters = new TokenProviderParameters();
@@ -178,6 +281,9 @@ public class JWTTokenProviderTest extends org.junit.Assert {
parameters.setStsProperties(stsProperties);
parameters.setEncryptionProperties(new EncryptionProperties());
+ stsProperties.setEncryptionCrypto(crypto);
+ stsProperties.setEncryptionUsername("myservicekey");
+ stsProperties.setCallbackHandler(new PasswordCallbackHandler());
return parameters;
}
@@ -188,11 +294,24 @@ public class JWTTokenProviderTest extends org.junit.Assert {
"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");
+ if (unrestrictedPoliciesInstalled) {
+ properties.put("org.apache.wss4j.crypto.merlin.keystore.file", "stsstore.jks");
+ } else {
+ properties.put("org.apache.wss4j.crypto.merlin.keystore.file", "restricted/stsstore.jks");
+ }
return properties;
}
-
+ private Properties getDecryptionProperties() {
+ 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", "sspass");
+ properties.put("org.apache.wss4j.crypto.merlin.keystore.file", "servicestore.jks");
+
+ return properties;
+ }
}