You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by co...@apache.org on 2017/06/15 11:06:25 UTC
syncope git commit: Fixing issue with getting bytes for jwtKey +
adding JWT tests
Repository: syncope
Updated Branches:
refs/heads/master 03d5364b1 -> e0798eaa1
Fixing issue with getting bytes for jwtKey + adding JWT tests
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/e0798eaa
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/e0798eaa
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/e0798eaa
Branch: refs/heads/master
Commit: e0798eaa1c39a02db05bb517b5ceb37ac6e93bdb
Parents: 03d5364
Author: Colm O hEigeartaigh <co...@apache.org>
Authored: Thu Jun 15 12:05:54 2017 +0100
Committer: Colm O hEigeartaigh <co...@apache.org>
Committed: Thu Jun 15 12:06:22 2017 +0100
----------------------------------------------------------------------
.../src/main/resources/securityContext.xml | 4 +-
.../org/apache/syncope/fit/AbstractITCase.java | 9 +
.../org/apache/syncope/fit/core/JWTITCase.java | 303 +++++++++++++++++++
3 files changed, 314 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/syncope/blob/e0798eaa/core/spring/src/main/resources/securityContext.xml
----------------------------------------------------------------------
diff --git a/core/spring/src/main/resources/securityContext.xml b/core/spring/src/main/resources/securityContext.xml
index 809b78d..2705b42 100644
--- a/core/spring/src/main/resources/securityContext.xml
+++ b/core/spring/src/main/resources/securityContext.xml
@@ -49,13 +49,13 @@ under the License.
<constructor-arg value="${jwsKey}"/>
</bean>
<bean id="jwsSignatureVerifier" class="org.apache.cxf.rs.security.jose.jws.HmacJwsSignatureVerifier">
- <constructor-arg value="${jwsKey}.bytes" index="0"/>
+ <constructor-arg value="#{jwsKey.getBytes()}" index="0"/>
<constructor-arg index="1">
<value type="org.apache.cxf.rs.security.jose.jwa.SignatureAlgorithm">HS512</value>
</constructor-arg>
</bean>
<bean id="jwsSignatureProvider" class="org.apache.cxf.rs.security.jose.jws.HmacJwsSignatureProvider">
- <constructor-arg value="${jwsKey}.bytes" index="0"/>
+ <constructor-arg value="#{jwsKey.getBytes()}" index="0"/>
<constructor-arg index="1">
<value type="org.apache.cxf.rs.security.jose.jwa.SignatureAlgorithm">HS512</value>
</constructor-arg>
http://git-wip-us.apache.org/repos/asf/syncope/blob/e0798eaa/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
index f22a045..d39ca3c 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
@@ -59,6 +59,7 @@ import org.apache.syncope.common.lib.types.ConnConfProperty;
import org.apache.syncope.common.lib.types.PatchOperation;
import org.apache.syncope.common.lib.types.SchemaType;
import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.common.rest.api.service.AccessTokenService;
import org.apache.syncope.common.rest.api.service.AnyObjectService;
import org.apache.syncope.common.rest.api.service.AnyTypeClassService;
import org.apache.syncope.common.rest.api.service.AnyTypeService;
@@ -163,6 +164,10 @@ public abstract class AbstractITCase {
protected static String ANONYMOUS_KEY;
+ protected static String JWS_KEY;
+
+ protected static String JWT_ISSUER;
+
protected static SyncopeClientFactoryBean clientFactory;
protected static SyncopeClient adminClient;
@@ -235,6 +240,8 @@ public abstract class AbstractITCase {
ANONYMOUS_UNAME = props.getProperty("anonymousUser");
ANONYMOUS_KEY = props.getProperty("anonymousKey");
+ JWS_KEY = props.getProperty("jwsKey");
+ JWT_ISSUER = props.getProperty("jwtIssuer");
} catch (Exception e) {
LOG.error("Could not read secretKey", e);
} finally {
@@ -243,6 +250,8 @@ public abstract class AbstractITCase {
assertNotNull(ANONYMOUS_UNAME);
assertNotNull(ANONYMOUS_KEY);
+ assertNotNull(JWS_KEY);
+ assertNotNull(JWT_ISSUER);
}
@BeforeClass
http://git-wip-us.apache.org/repos/asf/syncope/blob/e0798eaa/fit/core-reference/src/test/java/org/apache/syncope/fit/core/JWTITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/JWTITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/JWTITCase.java
new file mode 100644
index 0000000..722b8b7
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/JWTITCase.java
@@ -0,0 +1,303 @@
+/*
+ * 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.syncope.fit.core;
+
+import static org.junit.Assert.*;
+
+import java.security.AccessControlException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.ws.rs.core.Response;
+import javax.xml.ws.WebServiceException;
+
+import org.apache.cxf.rs.security.jose.common.JoseType;
+import org.apache.cxf.rs.security.jose.jwa.SignatureAlgorithm;
+import org.apache.cxf.rs.security.jose.jws.HmacJwsSignatureProvider;
+import org.apache.cxf.rs.security.jose.jws.HmacJwsSignatureVerifier;
+import org.apache.cxf.rs.security.jose.jws.JwsHeaders;
+import org.apache.cxf.rs.security.jose.jws.JwsJwtCompactConsumer;
+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.JwsSignatureVerifier;
+import org.apache.cxf.rs.security.jose.jwt.JwtClaims;
+import org.apache.cxf.rs.security.jose.jwt.JwtToken;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.common.rest.api.service.AccessTokenService;
+import org.apache.syncope.common.rest.api.service.UserSelfService;
+import org.apache.syncope.fit.AbstractITCase;
+import org.junit.Test;
+
+/**
+ * Some tests for JWT Tokens
+ */
+public class JWTITCase extends AbstractITCase {
+
+ @Test
+ public void testGetJWTToken() throws ParseException {
+ // Get the token
+ SyncopeClient adminClient = clientFactory.create(ADMIN_UNAME, ADMIN_PWD);
+ AccessTokenService accessTokenService = adminClient.getService(AccessTokenService.class);
+
+ Response response = accessTokenService.login();
+ String token = response.getHeaderString(RESTHeaders.TOKEN);
+ assertNotNull(token);
+ String expiry = response.getHeaderString(RESTHeaders.TOKEN_EXPIRE);
+ assertNotNull(expiry);
+
+ // Validate the signature
+ JwsJwtCompactConsumer consumer = new JwsJwtCompactConsumer(token);
+ JwsSignatureVerifier jwsSignatureVerifier =
+ new HmacJwsSignatureVerifier(JWS_KEY.getBytes(), SignatureAlgorithm.HS512);
+ assertTrue(consumer.verifySignatureWith(jwsSignatureVerifier));
+
+ Date now = new Date();
+
+ // Verify the expiry header matches that of the token
+ Long expiryTime = consumer.getJwtClaims().getExpiryTime();
+ assertNotNull(expiryTime);
+
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
+ Date tokenDate = dateFormat.parse(dateFormat.format(new Date(expiryTime.longValue())));
+ Date parsedDate = dateFormat.parse(expiry);
+
+ assertEquals(tokenDate, parsedDate);
+ assertTrue(parsedDate.after(now));
+
+ // Verify issuedAt
+ Long issuedAt = consumer.getJwtClaims().getIssuedAt();
+ assertNotNull(issuedAt);
+ assertTrue(new Date(issuedAt.longValue()).before(now));
+
+ // Validate subject + issuer
+ assertEquals("admin", consumer.getJwtClaims().getSubject());
+ assertEquals(JWT_ISSUER, consumer.getJwtClaims().getIssuer());
+
+ // Verify NotBefore
+ Long notBefore = consumer.getJwtClaims().getNotBefore();
+ assertNotNull(notBefore);
+ assertTrue(new Date(notBefore.longValue()).before(now));
+ }
+
+ @Test
+ public void testQueryUsingToken() throws ParseException {
+ // Get the token
+ SyncopeClient adminClient = clientFactory.create(ADMIN_UNAME, ADMIN_PWD);
+ AccessTokenService accessTokenService = adminClient.getService(AccessTokenService.class);
+
+ Response response = accessTokenService.login();
+ String token = response.getHeaderString(RESTHeaders.TOKEN);
+ assertNotNull(token);
+
+ // Query the UserSelfService using the token
+ SyncopeClient jwtClient = clientFactory.create(token);
+ UserSelfService jwtUserSelfService = jwtClient.getService(UserSelfService.class);
+ jwtUserSelfService.read();
+
+ // Test a "bad" token
+ jwtClient = clientFactory.create(token + "xyz");
+ jwtUserSelfService = jwtClient.getService(UserSelfService.class);
+ try {
+ jwtUserSelfService.read();
+ fail("Failure expected on a modified token");
+ } catch (WebServiceException ex) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testTokenValidation() throws ParseException {
+ // Get an initial token
+ SyncopeClient adminClient = clientFactory.create(ADMIN_UNAME, ADMIN_PWD);
+ AccessTokenService accessTokenService = adminClient.getService(AccessTokenService.class);
+
+ Response response = accessTokenService.login();
+ String token = response.getHeaderString(RESTHeaders.TOKEN);
+ assertNotNull(token);
+ JwsJwtCompactConsumer consumer = new JwsJwtCompactConsumer(token);
+ String tokenId = consumer.getJwtClaims().getTokenId();
+
+ // Create a new token using the Id of the first token
+ Date now = new Date();
+
+ Calendar expiry = Calendar.getInstance();
+ expiry.setTime(now);
+ expiry.add(Calendar.MINUTE, 5);
+
+ JwtClaims jwtClaims = new JwtClaims();
+ jwtClaims.setTokenId(tokenId);
+ jwtClaims.setSubject("admin");
+ jwtClaims.setIssuedAt(now.getTime());
+ jwtClaims.setIssuer(JWT_ISSUER);
+ jwtClaims.setExpiryTime(expiry.getTime().getTime());
+ jwtClaims.setNotBefore(now.getTime());
+
+ JwsHeaders jwsHeaders = new JwsHeaders(JoseType.JWT, SignatureAlgorithm.HS512);
+ JwtToken jwtToken = new JwtToken(jwsHeaders, jwtClaims);
+ JwsJwtCompactProducer producer = new JwsJwtCompactProducer(jwtToken);
+
+ JwsSignatureProvider jwsSignatureProvider =
+ new HmacJwsSignatureProvider(JWS_KEY.getBytes(), SignatureAlgorithm.HS512);
+ String signed = producer.signWith(jwsSignatureProvider);
+
+ SyncopeClient jwtClient = clientFactory.create(signed);
+ UserSelfService jwtUserSelfService = jwtClient.getService(UserSelfService.class);
+ jwtUserSelfService.read();
+ }
+
+ @Test
+ public void testInvalidIssuer() throws ParseException {
+ // Get an initial token
+ SyncopeClient adminClient = clientFactory.create(ADMIN_UNAME, ADMIN_PWD);
+ AccessTokenService accessTokenService = adminClient.getService(AccessTokenService.class);
+
+ Response response = accessTokenService.login();
+ String token = response.getHeaderString(RESTHeaders.TOKEN);
+ assertNotNull(token);
+ JwsJwtCompactConsumer consumer = new JwsJwtCompactConsumer(token);
+ String tokenId = consumer.getJwtClaims().getTokenId();
+
+ // Create a new token using the Id of the first token
+ Date now = new Date();
+
+ Calendar expiry = Calendar.getInstance();
+ expiry.setTime(now);
+ expiry.add(Calendar.MINUTE, 5);
+
+ JwtClaims jwtClaims = new JwtClaims();
+ jwtClaims.setTokenId(tokenId);
+ jwtClaims.setSubject("admin");
+ jwtClaims.setIssuedAt(now.getTime());
+ jwtClaims.setIssuer("UnknownIssuer");
+ jwtClaims.setExpiryTime(expiry.getTime().getTime());
+ jwtClaims.setNotBefore(now.getTime());
+
+ JwsHeaders jwsHeaders = new JwsHeaders(JoseType.JWT, SignatureAlgorithm.HS512);
+ JwtToken jwtToken = new JwtToken(jwsHeaders, jwtClaims);
+ JwsJwtCompactProducer producer = new JwsJwtCompactProducer(jwtToken);
+
+ JwsSignatureProvider jwsSignatureProvider =
+ new HmacJwsSignatureProvider(JWS_KEY.getBytes(), SignatureAlgorithm.HS512);
+ String signed = producer.signWith(jwsSignatureProvider);
+
+ SyncopeClient jwtClient = clientFactory.create(signed);
+ UserSelfService jwtUserSelfService = jwtClient.getService(UserSelfService.class);
+ try {
+ jwtUserSelfService.read();
+ fail("Failure expected on an invalid issuer");
+ } catch (AccessControlException ex) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testExpiredToken() throws ParseException {
+ // Get an initial token
+ SyncopeClient adminClient = clientFactory.create(ADMIN_UNAME, ADMIN_PWD);
+ AccessTokenService accessTokenService = adminClient.getService(AccessTokenService.class);
+
+ Response response = accessTokenService.login();
+ String token = response.getHeaderString(RESTHeaders.TOKEN);
+ assertNotNull(token);
+ JwsJwtCompactConsumer consumer = new JwsJwtCompactConsumer(token);
+ String tokenId = consumer.getJwtClaims().getTokenId();
+
+ // Create a new token using the Id of the first token
+ Date now = new Date();
+
+ Calendar expiry = Calendar.getInstance();
+ expiry.setTime(now);
+ expiry.add(Calendar.MINUTE, 5);
+
+ JwtClaims jwtClaims = new JwtClaims();
+ jwtClaims.setTokenId(tokenId);
+ jwtClaims.setSubject("admin");
+ jwtClaims.setIssuedAt(now.getTime());
+ jwtClaims.setIssuer(JWT_ISSUER);
+ jwtClaims.setExpiryTime(now.getTime() - 5000L);
+ jwtClaims.setNotBefore(now.getTime());
+
+ JwsHeaders jwsHeaders = new JwsHeaders(JoseType.JWT, SignatureAlgorithm.HS512);
+ JwtToken jwtToken = new JwtToken(jwsHeaders, jwtClaims);
+ JwsJwtCompactProducer producer = new JwsJwtCompactProducer(jwtToken);
+
+ JwsSignatureProvider jwsSignatureProvider =
+ new HmacJwsSignatureProvider(JWS_KEY.getBytes(), SignatureAlgorithm.HS512);
+ String signed = producer.signWith(jwsSignatureProvider);
+
+ SyncopeClient jwtClient = clientFactory.create(signed);
+ UserSelfService jwtUserSelfService = jwtClient.getService(UserSelfService.class);
+ try {
+ jwtUserSelfService.read();
+ fail("Failure expected on an expired token");
+ } catch (AccessControlException ex) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testNotBefore() throws ParseException {
+ // Get an initial token
+ SyncopeClient adminClient = clientFactory.create(ADMIN_UNAME, ADMIN_PWD);
+ AccessTokenService accessTokenService = adminClient.getService(AccessTokenService.class);
+
+ Response response = accessTokenService.login();
+ String token = response.getHeaderString(RESTHeaders.TOKEN);
+ assertNotNull(token);
+ JwsJwtCompactConsumer consumer = new JwsJwtCompactConsumer(token);
+ String tokenId = consumer.getJwtClaims().getTokenId();
+
+ // Create a new token using the Id of the first token
+ Date now = new Date();
+
+ Calendar expiry = Calendar.getInstance();
+ expiry.setTime(now);
+ expiry.add(Calendar.MINUTE, 5);
+
+ JwtClaims jwtClaims = new JwtClaims();
+ jwtClaims.setTokenId(tokenId);
+ jwtClaims.setSubject("admin");
+ jwtClaims.setIssuedAt(now.getTime());
+ jwtClaims.setIssuer(JWT_ISSUER);
+ jwtClaims.setExpiryTime(expiry.getTime().getTime());
+ jwtClaims.setNotBefore(now.getTime() + 60000L);
+
+ JwsHeaders jwsHeaders = new JwsHeaders(JoseType.JWT, SignatureAlgorithm.HS512);
+ JwtToken jwtToken = new JwtToken(jwsHeaders, jwtClaims);
+ JwsJwtCompactProducer producer = new JwsJwtCompactProducer(jwtToken);
+
+ JwsSignatureProvider jwsSignatureProvider =
+ new HmacJwsSignatureProvider(JWS_KEY.getBytes(), SignatureAlgorithm.HS512);
+ String signed = producer.signWith(jwsSignatureProvider);
+
+ SyncopeClient jwtClient = clientFactory.create(signed);
+ UserSelfService jwtUserSelfService = jwtClient.getService(UserSelfService.class);
+ try {
+ jwtUserSelfService.read();
+ fail("Failure expected on a token that is not valid yet");
+ } catch (AccessControlException ex) {
+ // expected
+ }
+ }
+}