You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by mo...@apache.org on 2017/10/25 19:20:48 UTC
[12/17] knox git commit: Merge branch 'master' into
KNOX-998-Package_Restructuring
http://git-wip-us.apache.org/repos/asf/knox/blob/58780d37/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/impl/JWTToken.java
----------------------------------------------------------------------
diff --cc gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/impl/JWTToken.java
index 27b1a30,0000000..e765c27
mode 100644,000000..100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/impl/JWTToken.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/impl/JWTToken.java
@@@ -1,273 -1,0 +1,281 @@@
+ /**
+ * 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.knox.gateway.services.security.token.impl;
+
- import java.io.UnsupportedEncodingException;
+import java.text.ParseException;
+import java.util.Date;
+import java.util.ArrayList;
+import java.util.List;
- import java.util.Map;
+
- import org.apache.commons.codec.binary.Base64;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.JWSHeader;
+import com.nimbusds.jose.JWSSigner;
+import com.nimbusds.jose.JWSVerifier;
+import com.nimbusds.jose.Payload;
+import com.nimbusds.jose.util.Base64URL;
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.jwt.SignedJWT;
+
+public class JWTToken implements JWT {
+ private static JWTProviderMessages log = MessagesFactory.get( JWTProviderMessages.class );
+
+ SignedJWT jwt = null;
+
+ private JWTToken(String header, String claims, String signature) throws ParseException {
+ jwt = new SignedJWT(new Base64URL(header), new Base64URL(claims), new Base64URL(signature));
+ }
+
+ public JWTToken(String serializedJWT) throws ParseException {
+ try {
+ jwt = SignedJWT.parse(serializedJWT);
+ } catch (ParseException e) {
+ log.unableToParseToken(e);
+ throw e;
+ }
+ }
+
+ public JWTToken(String alg, String[] claimsArray) {
+ this(alg, claimsArray, null);
+ }
+
+ public JWTToken(String alg, String[] claimsArray, List<String> audiences) {
+ JWSHeader header = new JWSHeader(new JWSAlgorithm(alg));
+
+ if (claimsArray[2] != null) {
+ if (audiences == null) {
+ audiences = new ArrayList<String>();
+ }
+ audiences.add(claimsArray[2]);
+ }
+ JWTClaimsSet claims = null;
+ JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder()
+ .issuer(claimsArray[0])
+ .subject(claimsArray[1])
+ .audience(audiences);
+ if(claimsArray[3] != null) {
+ builder = builder.expirationTime(new Date(Long.parseLong(claimsArray[3])));
+ }
+
+ claims = builder.build();
+
+ jwt = new SignedJWT(header, claims);
+ }
+
+ /* (non-Javadoc)
- * @see JWT#getPayloadToSign()
++ * @see org.apache.knox.gateway.services.security.token.impl.JWT#getPayloadToSign()
+ */
+ @Override
+ public String getHeader() {
+ JWSHeader header = jwt.getHeader();
+ return header.toString();
+ }
+
+ /* (non-Javadoc)
- * @see JWT#getPayloadToSign()
++ * @see org.apache.knox.gateway.services.security.token.impl.JWT#getPayloadToSign()
+ */
+ @Override
+ public String getClaims() {
+ String c = null;
+ JWTClaimsSet claims = null;
+ try {
+ claims = (JWTClaimsSet) jwt.getJWTClaimsSet();
+ c = claims.toJSONObject().toJSONString();
+ } catch (ParseException e) {
+ log.unableToParseToken(e);
+ }
+ return c;
+ }
+
+ /* (non-Javadoc)
- * @see JWT#getPayloadToSign()
++ * @see org.apache.knox.gateway.services.security.token.impl.JWT#getPayloadToSign()
+ */
+ @Override
+ public String getPayload() {
+ Payload payload = jwt.getPayload();
+ return payload.toString();
+ }
+
+ public String toString() {
+ return jwt.serialize();
+ }
+
+ /* (non-Javadoc)
- * @see JWT#setSignaturePayload(byte[])
++ * @see org.apache.knox.gateway.services.security.token.impl.JWT#setSignaturePayload(byte[])
+ */
+ @Override
+ public void setSignaturePayload(byte[] payload) {
+// this.payload = payload;
+ }
+
+ /* (non-Javadoc)
- * @see JWT#getSignaturePayload()
++ * @see org.apache.knox.gateway.services.security.token.impl.JWT#getSignaturePayload()
+ */
+ @Override
+ public byte[] getSignaturePayload() {
+ byte[] b = null;
+ Base64URL b64 = jwt.getSignature();
+ if (b64 != null) {
+ b = b64.decode();
+ }
+ return b;
+ }
+
+ public static JWTToken parseToken(String wireToken) throws ParseException {
+ log.parsingToken(wireToken);
+ String[] parts = wireToken.split("\\.");
+ return new JWTToken(parts[0], parts[1], parts[2]);
+ }
+
+ /* (non-Javadoc)
- * @see JWT#getClaim(java.lang.String)
++ * @see org.apache.knox.gateway.services.security.token.impl.JWT#getClaim(java.lang.String)
+ */
+ @Override
+ public String getClaim(String claimName) {
+ String claim = null;
+
+ try {
+ claim = jwt.getJWTClaimsSet().getStringClaim(claimName);
+ } catch (ParseException e) {
+ log.unableToParseToken(e);
+ }
+
+ return claim;
+ }
+
+ /* (non-Javadoc)
- * @see JWT#getSubject()
++ * @see org.apache.knox.gateway.services.security.token.impl.JWT#getSubject()
+ */
+ @Override
+ public String getSubject() {
+ return getClaim(JWT.SUBJECT);
+ }
+
+ /* (non-Javadoc)
- * @see JWT#getIssuer()
++ * @see org.apache.knox.gateway.services.security.token.impl.JWT#getIssuer()
+ */
+ @Override
+ public String getIssuer() {
+ return getClaim(JWT.ISSUER);
+ }
+
+ /* (non-Javadoc)
- * @see JWT#getAudience()
++ * @see org.apache.knox.gateway.services.security.token.impl.JWT#getAudience()
+ */
+ @Override
+ public String getAudience() {
+ String[] claim = null;
+ String c = null;
+
+ claim = getAudienceClaims();
+ if (claim != null) {
+ c = claim[0];
+ }
+
+ return c;
+ }
+
+ /* (non-Javadoc)
- * @see JWT#getAudienceClaims()
++ * @see org.apache.knox.gateway.services.security.token.impl.JWT#getAudienceClaims()
+ */
+ @Override
+ public String[] getAudienceClaims() {
+ String[] claims = null;
+
+ try {
+ claims = jwt.getJWTClaimsSet().getStringArrayClaim(JWT.AUDIENCE);
+ } catch (ParseException e) {
+ log.unableToParseToken(e);
+ }
+
+ return claims;
+ }
+
+ /* (non-Javadoc)
- * @see JWT#getExpires()
++ * @see org.apache.knox.gateway.services.security.token.impl.JWT#getExpires()
+ */
+ @Override
+ public String getExpires() {
+ Date expires = getExpiresDate();
+ if (expires != null) {
+ return String.valueOf(expires.getTime());
+ }
+ return null;
+ }
+
+ @Override
+ public Date getExpiresDate() {
+ Date date = null;
+ try {
+ date = jwt.getJWTClaimsSet().getExpirationTime();
+ } catch (ParseException e) {
+ log.unableToParseToken(e);
+ }
+ return date;
+ }
+
++ @Override
++ public Date getNotBeforeDate() {
++ Date date = null;
++ try {
++ date = jwt.getJWTClaimsSet().getNotBeforeTime();
++ } catch (ParseException e) {
++ log.unableToParseToken(e);
++ }
++ return date;
++ }
++
+ /* (non-Javadoc)
- * @see JWT#getPrincipal()
++ * @see org.apache.knox.gateway.services.security.token.impl.JWT#getPrincipal()
+ */
+ @Override
+ public String getPrincipal() {
+ return getClaim(JWT.PRINCIPAL);
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.apache.knox.gateway.services.security.token.impl.JWT#sign(JWSSigner)
+ */
+ @Override
+ public void sign(JWSSigner signer) {
+ try {
+ jwt.sign(signer);
+ } catch (JOSEException e) {
+ log.unableToSignToken(e);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.knox.gateway.services.security.token.impl.JWT#verify(JWSVerifier)
+ */
+ public boolean verify(JWSVerifier verifier) {
+ boolean rc = false;
+
+ try {
+ rc = jwt.verify(verifier);
+ } catch (JOSEException e) {
+ // TODO Auto-generated catch block
+ log.unableToVerifyToken(e);
+ }
+
+ return rc;
+ }
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/58780d37/gateway-spi/src/test/java/org/apache/knox/gateway/services/security/token/impl/JWTTokenTest.java
----------------------------------------------------------------------
diff --cc gateway-spi/src/test/java/org/apache/knox/gateway/services/security/token/impl/JWTTokenTest.java
index 1b0df9e,0000000..2c23e92
mode 100644,000000..100644
--- a/gateway-spi/src/test/java/org/apache/knox/gateway/services/security/token/impl/JWTTokenTest.java
+++ b/gateway-spi/src/test/java/org/apache/knox/gateway/services/security/token/impl/JWTTokenTest.java
@@@ -1,223 -1,0 +1,240 @@@
+/**
+ * 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.knox.gateway.services.security.token.impl;
+
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
++import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
++import java.util.List;
+
++import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.JWSSigner;
+import com.nimbusds.jose.JWSVerifier;
+import com.nimbusds.jose.crypto.RSASSASigner;
+import com.nimbusds.jose.crypto.RSASSAVerifier;
+
+public class JWTTokenTest extends org.junit.Assert {
+ private static final String JWT_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MTY5MjkxMDksImp0aSI6ImFhN2Y4ZDBhOTVjIiwic2NvcGVzIjpbInJlcG8iLCJwdWJsaWNfcmVwbyJdfQ.XCEwpBGvOLma4TCoh36FU7XhUbcskygS81HE1uHLf0E";
+ private static final String HEADER = "{\"typ\":\"JWT\",\"alg\":\"HS256\"}";
+
- private RSAPublicKey publicKey;
- private RSAPrivateKey privateKey;
++ private static RSAPublicKey publicKey;
++ private static RSAPrivateKey privateKey;
+
- public JWTTokenTest() throws Exception, NoSuchAlgorithmException {
++ @BeforeClass
++ public static void setup() throws Exception, NoSuchAlgorithmException {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+ kpg.initialize(2048);
+
+ KeyPair kp = kpg.genKeyPair();
+ publicKey = (RSAPublicKey) kp.getPublic();
+ privateKey = (RSAPrivateKey) kp.getPrivate();
+ }
+
+ @Test
+ public void testTokenParsing() throws Exception {
+ JWTToken token = JWTToken.parseToken(JWT_TOKEN);
+ assertEquals(token.getHeader(), HEADER);
+
+ assertEquals(token.getClaim("jti"), "aa7f8d0a95c");
+ }
+
+ @Test
+ public void testTokenCreation() throws Exception {
+ String[] claims = new String[4];
+ claims[0] = "KNOXSSO";
+ claims[1] = "john.doe@example.com";
+ claims[2] = "https://login.example.com";
+ claims[3] = Long.toString( ( System.currentTimeMillis()/1000 ) + 300);
- JWTToken token = new JWTToken("RS256", claims);
++ JWT token = new JWTToken("RS256", claims);
+
+ assertEquals("KNOXSSO", token.getIssuer());
+ assertEquals("john.doe@example.com", token.getSubject());
+ assertEquals("https://login.example.com", token.getAudience());
+ }
+
+ @Test
+ public void testTokenCreationWithAudienceListSingle() throws Exception {
+ String[] claims = new String[4];
+ claims[0] = "KNOXSSO";
+ claims[1] = "john.doe@example.com";
+ claims[2] = null;
+ claims[3] = Long.toString( ( System.currentTimeMillis()/1000 ) + 300);
- ArrayList<String> audiences = new ArrayList<String>();
++ List<String> audiences = new ArrayList<String>();
+ audiences.add("https://login.example.com");
+
- JWTToken token = new JWTToken("RS256", claims, audiences);
++ JWT token = new JWTToken("RS256", claims, audiences);
+
+ assertEquals("KNOXSSO", token.getIssuer());
+ assertEquals("john.doe@example.com", token.getSubject());
+ assertEquals("https://login.example.com", token.getAudience());
+ assertEquals(1, token.getAudienceClaims().length);
+ }
+
+ @Test
+ public void testTokenCreationWithAudienceListMultiple() throws Exception {
+ String[] claims = new String[4];
+ claims[0] = "KNOXSSO";
+ claims[1] = "john.doe@example.com";
+ claims[2] = null;
+ claims[3] = Long.toString( ( System.currentTimeMillis()/1000 ) + 300);
- ArrayList<String> audiences = new ArrayList<String>();
++ List<String> audiences = new ArrayList<String>();
+ audiences.add("https://login.example.com");
+ audiences.add("KNOXSSO");
+
- JWTToken token = new JWTToken("RS256", claims, audiences);
++ JWT token = new JWTToken("RS256", claims, audiences);
+
+ assertEquals("KNOXSSO", token.getIssuer());
+ assertEquals("john.doe@example.com", token.getSubject());
+ assertEquals("https://login.example.com", token.getAudience());
+ assertEquals(2, token.getAudienceClaims().length);
+ }
+
+ @Test
+ public void testTokenCreationWithAudienceListCombined() throws Exception {
+ String[] claims = new String[4];
+ claims[0] = "KNOXSSO";
+ claims[1] = "john.doe@example.com";
+ claims[2] = "LJM";
+ claims[3] = Long.toString( ( System.currentTimeMillis()/1000 ) + 300);
+ ArrayList<String> audiences = new ArrayList<String>();
+ audiences.add("https://login.example.com");
+ audiences.add("KNOXSSO");
+
+ JWTToken token = new JWTToken("RS256", claims, audiences);
+
+ assertEquals("KNOXSSO", token.getIssuer());
+ assertEquals("john.doe@example.com", token.getSubject());
+ assertEquals("https://login.example.com", token.getAudience());
+ assertEquals(3, token.getAudienceClaims().length);
+ }
+
+ @Test
+ public void testTokenCreationWithNullAudienceList() throws Exception {
+ String[] claims = new String[4];
+ claims[0] = "KNOXSSO";
+ claims[1] = "john.doe@example.com";
+ claims[2] = null;
+ claims[3] = Long.toString( ( System.currentTimeMillis()/1000 ) + 300);
- ArrayList<String> audiences = null;
++ List<String> audiences = null;
+
- JWTToken token = new JWTToken("RS256", claims, audiences);
++ JWT token = new JWTToken("RS256", claims, audiences);
+
+ assertEquals("KNOXSSO", token.getIssuer());
+ assertEquals("john.doe@example.com", token.getSubject());
+ assertEquals(null, token.getAudience());
+ assertArrayEquals(null, token.getAudienceClaims());
+ }
+
+ @Test
+ public void testTokenCreationRS512() throws Exception {
+ String[] claims = new String[4];
+ claims[0] = "KNOXSSO";
+ claims[1] = "john.doe@example.com";
+ claims[2] = "https://login.example.com";
+ claims[3] = Long.toString( ( System.currentTimeMillis()/1000 ) + 300);
+ JWTToken token = new JWTToken(JWSAlgorithm.RS512.getName(), claims);
+
+ assertEquals("KNOXSSO", token.getIssuer());
+ assertEquals("john.doe@example.com", token.getSubject());
+ assertEquals("https://login.example.com", token.getAudience());
+ assertTrue(token.getHeader().contains(JWSAlgorithm.RS512.getName()));
+ }
+
+ @Test
+ public void testTokenSignature() throws Exception {
+ String[] claims = new String[4];
+ claims[0] = "KNOXSSO";
+ claims[1] = "john.doe@example.com";
+ claims[2] = "https://login.example.com";
+ claims[3] = Long.toString( ( System.currentTimeMillis()/1000 ) + 300);
- JWTToken token = new JWTToken("RS256", claims);
-
++ JWT token = new JWTToken("RS256", claims);
+
+ assertEquals("KNOXSSO", token.getIssuer());
+ assertEquals("john.doe@example.com", token.getSubject());
+ assertEquals("https://login.example.com", token.getAudience());
+
+ // Sign the token
+ JWSSigner signer = new RSASSASigner(privateKey);
+ token.sign(signer);
+ assertTrue(token.getSignaturePayload().length > 0);
+
+ // Verify the signature
+ JWSVerifier verifier = new RSASSAVerifier((RSAPublicKey) publicKey);
+ assertTrue(token.verify(verifier));
+ }
+
+ @Test
+ public void testTokenSignatureRS512() throws Exception {
+ String[] claims = new String[4];
+ claims[0] = "KNOXSSO";
+ claims[1] = "john.doe@example.com";
+ claims[2] = "https://login.example.com";
+ claims[3] = Long.toString( ( System.currentTimeMillis()/1000 ) + 300);
- JWTToken token = new JWTToken(JWSAlgorithm.RS512.getName(), claims);
++ JWT token = new JWTToken(JWSAlgorithm.RS512.getName(), claims);
+
+ assertEquals("KNOXSSO", token.getIssuer());
+ assertEquals("john.doe@example.com", token.getSubject());
+ assertEquals("https://login.example.com", token.getAudience());
+ assertTrue(token.getHeader().contains(JWSAlgorithm.RS512.getName()));
+
+ // Sign the token
+ JWSSigner signer = new RSASSASigner(privateKey);
+ token.sign(signer);
+ assertTrue(token.getSignaturePayload().length > 0);
+
+ // Verify the signature
+ JWSVerifier verifier = new RSASSAVerifier((RSAPublicKey) publicKey);
+ assertTrue(token.verify(verifier));
+ }
+
+ @Test
+ public void testTokenExpiry() throws Exception {
+ String[] claims = new String[4];
+ claims[0] = "KNOXSSO";
+ claims[1] = "john.doe@example.com";
+ claims[2] = "https://login.example.com";
+ claims[3] = Long.toString( ( System.currentTimeMillis()/1000 ) + 300);
- JWTToken token = new JWTToken("RS256", claims);
++ JWT token = new JWTToken("RS256", claims);
+
+ assertNotNull(token.getExpires());
+ assertNotNull(token.getExpiresDate());
+ assertEquals(token.getExpiresDate(), new Date(Long.valueOf(token.getExpires())));
+ }
++
++ @Test
++ public void testUnsignedToken() throws Exception {
++ String unsignedToken = "eyJhbGciOiJub25lIn0.eyJzdWIiOiJhbGljZSIsImp0aSI6ImY2YmNj"
++ + "MDVjLWI4MTktNGM0Mi1iMGMyLWJlYmY1MDE4YWFiZiJ9.";
++
++ try {
++ new JWTToken(unsignedToken);
++ fail("Failure expected on an unsigned token");
++ } catch (ParseException ex) {
++ // expected
++ }
++ }
++
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/58780d37/pom.xml
----------------------------------------------------------------------