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/09/20 14:36:28 UTC

[04/12] knox git commit: KNOX-1047 - Add some tests for the Knox Token Service

KNOX-1047 - Add some tests for the Knox Token Service


Project: http://git-wip-us.apache.org/repos/asf/knox/repo
Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/3557612d
Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/3557612d
Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/3557612d

Branch: refs/heads/KNOX-998-Package_Restructuring
Commit: 3557612d5a5d904c3dfa61ba03cccfbbd365b296
Parents: 4978951
Author: Colm O hEigeartaigh <co...@apache.org>
Authored: Tue Sep 19 12:17:59 2017 +0100
Committer: Colm O hEigeartaigh <co...@apache.org>
Committed: Tue Sep 19 12:17:59 2017 +0100

----------------------------------------------------------------------
 .../federation/AbstractJWTFilterTest.java       |  14 +-
 .../federation/JWTFederationFilterTest.java     |   1 -
 .../federation/SSOCookieProviderTest.java       |   1 -
 gateway-service-knoxtoken/pom.xml               |  29 ++-
 .../service/knoxtoken/TokenResource.java        |  31 +--
 .../knoxtoken/TokenServiceResourceTest.java     | 256 ++++++++++++++++++-
 6 files changed, 293 insertions(+), 39 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/knox/blob/3557612d/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/AbstractJWTFilterTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/AbstractJWTFilterTest.java b/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/AbstractJWTFilterTest.java
index 6f221a9..d477f1f 100644
--- a/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/AbstractJWTFilterTest.java
+++ b/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/AbstractJWTFilterTest.java
@@ -60,7 +60,7 @@ import org.apache.hadoop.gateway.services.security.token.impl.JWTToken;
 import org.easymock.EasyMock;
 import org.junit.After;
 import org.junit.Assert;
-import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 import com.nimbusds.jose.*;
@@ -74,16 +74,16 @@ public abstract class AbstractJWTFilterTest  {
   private static final String dnTemplate = "CN={0},OU=Test,O=Hadoop,L=Test,ST=Test,C=US";
 
   protected AbstractJWTFilter handler = null;
-  protected RSAPublicKey publicKey = null;
-  protected RSAPrivateKey privateKey = null;
-  protected String pem = null;
+  protected static RSAPublicKey publicKey = null;
+  protected static RSAPrivateKey privateKey = null;
+  protected static String pem = null;
 
   protected abstract void setTokenOnRequest(HttpServletRequest request, SignedJWT jwt);
   protected abstract void setGarbledTokenOnRequest(HttpServletRequest request, SignedJWT jwt);
   protected abstract String getAudienceProperty();
   protected abstract String getVerificationPemProperty();
 
-  private String buildDistinguishedName(String hostname) {
+  private static String buildDistinguishedName(String hostname) {
     MessageFormat headerFormatter = new MessageFormat(dnTemplate);
     String[] paramArray = new String[1];
     paramArray[0] = hostname;
@@ -91,8 +91,8 @@ public abstract class AbstractJWTFilterTest  {
     return dn;
   }
 
-  @Before
-  public void setup() throws Exception, NoSuchAlgorithmException {
+  @BeforeClass
+  public static void generateKeys() throws Exception, NoSuchAlgorithmException {
     KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
     kpg.initialize(2048);
     KeyPair KPair = kpg.generateKeyPair();

http://git-wip-us.apache.org/repos/asf/knox/blob/3557612d/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/JWTFederationFilterTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/JWTFederationFilterTest.java b/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/JWTFederationFilterTest.java
index d19d999..99a3780 100644
--- a/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/JWTFederationFilterTest.java
+++ b/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/JWTFederationFilterTest.java
@@ -32,7 +32,6 @@ public class JWTFederationFilterTest extends AbstractJWTFilterTest {
 
     @Before
     public void setup() throws Exception, NoSuchAlgorithmException {
-      super.setup();
       handler = new TestJWTFederationFilter();
       ((TestJWTFederationFilter) handler).setTokenService(new TestJWTokenAuthority(publicKey));
     }

http://git-wip-us.apache.org/repos/asf/knox/blob/3557612d/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/SSOCookieProviderTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/SSOCookieProviderTest.java b/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/SSOCookieProviderTest.java
index 85f7d59..768755b 100644
--- a/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/SSOCookieProviderTest.java
+++ b/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/SSOCookieProviderTest.java
@@ -45,7 +45,6 @@ public class SSOCookieProviderTest extends AbstractJWTFilterTest {
 
   @Before
   public void setup() throws Exception, NoSuchAlgorithmException {
-    super.setup();
     handler = new TestSSOCookieFederationProvider();
     ((TestSSOCookieFederationProvider) handler).setTokenService(new TestJWTokenAuthority(publicKey));
   }

http://git-wip-us.apache.org/repos/asf/knox/blob/3557612d/gateway-service-knoxtoken/pom.xml
----------------------------------------------------------------------
diff --git a/gateway-service-knoxtoken/pom.xml b/gateway-service-knoxtoken/pom.xml
index 1dafa20..e27b7b0 100644
--- a/gateway-service-knoxtoken/pom.xml
+++ b/gateway-service-knoxtoken/pom.xml
@@ -56,19 +56,20 @@
 	    <groupId>${gateway-group}</groupId>
 	    <artifactId>gateway-provider-jersey</artifactId>
 	  </dependency>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.knox</groupId>
-      <artifactId>gateway-test-utils</artifactId>
-      <scope>test</scope>
-    </dependency>
       <dependency>
-          <groupId>org.easymock</groupId>
-          <artifactId>easymock</artifactId>
-          <scope>test</scope>
-      </dependency>  </dependencies>
+        <groupId>junit</groupId>
+        <artifactId>junit</artifactId>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.knox</groupId>
+        <artifactId>gateway-test-utils</artifactId>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.easymock</groupId>
+        <artifactId>easymock</artifactId>
+        <scope>test</scope>
+      </dependency>
+  </dependencies>
 </project>

http://git-wip-us.apache.org/repos/asf/knox/blob/3557612d/gateway-service-knoxtoken/src/main/java/org/apache/hadoop/gateway/service/knoxtoken/TokenResource.java
----------------------------------------------------------------------
diff --git a/gateway-service-knoxtoken/src/main/java/org/apache/hadoop/gateway/service/knoxtoken/TokenResource.java b/gateway-service-knoxtoken/src/main/java/org/apache/hadoop/gateway/service/knoxtoken/TokenResource.java
index 4fda69f..43dd526 100644
--- a/gateway-service-knoxtoken/src/main/java/org/apache/hadoop/gateway/service/knoxtoken/TokenResource.java
+++ b/gateway-service-knoxtoken/src/main/java/org/apache/hadoop/gateway/service/knoxtoken/TokenResource.java
@@ -22,6 +22,8 @@ import java.security.Principal;
 import java.util.ArrayList;
 import java.util.Map;
 import java.util.HashMap;
+import java.util.List;
+
 import javax.annotation.PostConstruct;
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
@@ -55,15 +57,15 @@ public class TokenResource {
   static final String RESOURCE_PATH = "knoxtoken/api/v1/token";
   private static TokenServiceMessages log = MessagesFactory.get( TokenServiceMessages.class );
   private long tokenTTL = 30000l;
-  private String[] targetAudiences = null;
+  private List<String> targetAudiences = new ArrayList<>();
   private String tokenTargetUrl = null;
   private Map<String,Object> tokenClientDataMap = null;
 
   @Context
-  private HttpServletRequest request;
+  HttpServletRequest request;
 
   @Context
-  private HttpServletResponse response;
+  HttpServletResponse response;
 
   @Context
   ServletContext context;
@@ -73,7 +75,10 @@ public class TokenResource {
 
     String audiences = context.getInitParameter(TOKEN_AUDIENCES_PARAM);
     if (audiences != null) {
-      targetAudiences = audiences.split(",");
+      String[] auds = audiences.split(",");
+      for (int i = 0; i < auds.length; i++) {
+        targetAudiences.add(auds[i]);
+      }
     }
 
     String ttl = context.getInitParameter(TOKEN_TTL_PARAM);
@@ -85,7 +90,7 @@ public class TokenResource {
         log.invalidTokenTTLEncountered(ttl);
       }
     }
-    
+
     tokenTargetUrl = context.getInitParameter(TOKEN_TARGET_URL);
 
     String clientData = context.getInitParameter(TOKEN_CLIENT_DATA);
@@ -115,22 +120,18 @@ public class TokenResource {
     JWTokenAuthority ts = services.getService(GatewayServices.TOKEN_SERVICE);
     Principal p = ((HttpServletRequest)request).getUserPrincipal();
     long expires = getExpiry();
-    
+
     try {
       JWT token = null;
-      if (targetAudiences == null || targetAudiences.length == 0) {
-        token = ts.issueToken(p, "RS256", getExpiry());
+      if (targetAudiences.isEmpty()) {
+        token = ts.issueToken(p, "RS256", expires);
       } else {
-        ArrayList<String> aud = new ArrayList<String>();
-        for (int i = 0; i < targetAudiences.length; i++) {
-          aud.add(targetAudiences[i]);
-        }
-        token = ts.issueToken(p, aud, "RS256", expires);
+        token = ts.issueToken(p, targetAudiences, "RS256", expires);
       }
 
       if (token != null) {
         String accessToken = token.toString();
-  
+
         HashMap<String, Object> map = new HashMap<>();
         map.put(ACCESS_TOKEN, accessToken);
         map.put(TOKEN_TYPE, BEARER);
@@ -141,7 +142,7 @@ public class TokenResource {
         if (tokenClientDataMap != null) {
           map.putAll(tokenClientDataMap);
         }
-  
+
         String jsonResponse = JsonUtils.renderAsJsonString(map);
 
         response.getWriter().write(jsonResponse);

http://git-wip-us.apache.org/repos/asf/knox/blob/3557612d/gateway-service-knoxtoken/src/test/java/org/apache/hadoop/gateway/service/knoxtoken/TokenServiceResourceTest.java
----------------------------------------------------------------------
diff --git a/gateway-service-knoxtoken/src/test/java/org/apache/hadoop/gateway/service/knoxtoken/TokenServiceResourceTest.java b/gateway-service-knoxtoken/src/test/java/org/apache/hadoop/gateway/service/knoxtoken/TokenServiceResourceTest.java
index 2b4fea1..9faa073 100644
--- a/gateway-service-knoxtoken/src/test/java/org/apache/hadoop/gateway/service/knoxtoken/TokenServiceResourceTest.java
+++ b/gateway-service-knoxtoken/src/test/java/org/apache/hadoop/gateway/service/knoxtoken/TokenServiceResourceTest.java
@@ -18,17 +18,63 @@
 package org.apache.hadoop.gateway.service.knoxtoken;
 
 import org.apache.hadoop.gateway.service.knoxtoken.TokenResource;
+import org.apache.hadoop.gateway.services.GatewayServices;
+import org.apache.hadoop.gateway.services.security.token.JWTokenAuthority;
+import org.apache.hadoop.gateway.services.security.token.TokenServiceException;
+import org.apache.hadoop.gateway.services.security.token.impl.JWT;
+import org.apache.hadoop.gateway.services.security.token.impl.JWTToken;
+import org.easymock.EasyMock;
 import org.junit.Assert;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
+import com.nimbusds.jose.JWSSigner;
+import com.nimbusds.jose.JWSVerifier;
+import com.nimbusds.jose.crypto.RSASSASigner;
+import com.nimbusds.jose.crypto.RSASSAVerifier;
+
 import java.util.Map;
+
+import javax.security.auth.Subject;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.Response;
+
+import static org.junit.Assert.*;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 
 /**
- *
+ * Some tests for the token service
  */
 public class TokenServiceResourceTest {
 
+  protected static RSAPublicKey publicKey;
+  protected static RSAPrivateKey privateKey;
+
+  @BeforeClass
+  public static void setup() throws Exception, NoSuchAlgorithmException {
+    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+    kpg.initialize(1024);
+    KeyPair KPair = kpg.generateKeyPair();
+
+    publicKey = (RSAPublicKey) KPair.getPublic();
+    privateKey = (RSAPrivateKey) KPair.getPrivate();
+  }
+
   @Test
   public void testTokenService() throws Exception {
     Assert.assertTrue(true);
@@ -50,4 +96,212 @@ public class TokenServiceResourceTest {
     tr.addClientDataToMap("".split(","), clientDataMap);
     Assert.assertTrue(clientDataMap.size() == 0);
   }
+
+  @Test
+  public void testGetToken() throws Exception {
+    TokenResource tr = new TokenResource();
+
+    ServletContext context = EasyMock.createNiceMock(ServletContext.class);
+    //tr.context = context;
+    // tr.init();
+
+    HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
+    EasyMock.expect(request.getServletContext()).andReturn(context).anyTimes();
+    Principal principal = EasyMock.createNiceMock(Principal.class);
+    EasyMock.expect(principal.getName()).andReturn("alice").anyTimes();
+    EasyMock.expect(request.getUserPrincipal()).andReturn(principal).anyTimes();
+
+    GatewayServices services = EasyMock.createNiceMock(GatewayServices.class);
+    EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services);
+
+    JWTokenAuthority authority = new TestJWTokenAuthority(publicKey, privateKey);
+    EasyMock.expect(services.getService(GatewayServices.TOKEN_SERVICE)).andReturn(authority);
+
+    StringWriter writer = new StringWriter();
+    PrintWriter printWriter = new PrintWriter(writer);
+    HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
+    EasyMock.expect(response.getWriter()).andReturn(printWriter);
+
+    EasyMock.replay(principal, services, context, request, response);
+
+    tr.request = request;
+    tr.response = response;
+
+    // Issue a token
+    Response retResponse = tr.doGet();
+
+    assertEquals(200, retResponse.getStatus());
+
+    // Parse the response
+    String retString = writer.toString();
+    String accessToken = getTagValue(retString, "access_token");
+    assertNotNull(accessToken);
+    String expiry = getTagValue(retString, "expires_in");
+    assertNotNull(expiry);
+
+    // Verify the token
+    JWTToken parsedToken = new JWTToken(accessToken);
+    assertEquals("alice", parsedToken.getSubject());
+    assertTrue(authority.verifyToken(parsedToken));
+  }
+
+  @Test
+  public void testAudiences() throws Exception {
+
+    ServletContext context = EasyMock.createNiceMock(ServletContext.class);
+    EasyMock.expect(context.getInitParameter("knox.token.audiences")).andReturn("recipient1,recipient2");
+    EasyMock.expect(context.getInitParameter("knox.token.ttl")).andReturn(null);
+    EasyMock.expect(context.getInitParameter("knox.token.target.url")).andReturn(null);
+    EasyMock.expect(context.getInitParameter("knox.token.client.data")).andReturn(null);
+
+    HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
+    EasyMock.expect(request.getServletContext()).andReturn(context).anyTimes();
+    Principal principal = EasyMock.createNiceMock(Principal.class);
+    EasyMock.expect(principal.getName()).andReturn("alice").anyTimes();
+    EasyMock.expect(request.getUserPrincipal()).andReturn(principal).anyTimes();
+
+    GatewayServices services = EasyMock.createNiceMock(GatewayServices.class);
+    EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services);
+
+    JWTokenAuthority authority = new TestJWTokenAuthority(publicKey, privateKey);
+    EasyMock.expect(services.getService(GatewayServices.TOKEN_SERVICE)).andReturn(authority);
+
+    StringWriter writer = new StringWriter();
+    PrintWriter printWriter = new PrintWriter(writer);
+    HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
+    EasyMock.expect(response.getWriter()).andReturn(printWriter);
+
+    EasyMock.replay(principal, services, context, request, response);
+
+    TokenResource tr = new TokenResource();
+    tr.request = request;
+    tr.response = response;
+    tr.context = context;
+    tr.init();
+
+    // Issue a token
+    Response retResponse = tr.doGet();
+
+    assertEquals(200, retResponse.getStatus());
+
+    // Parse the response
+    String retString = writer.toString();
+    String accessToken = getTagValue(retString, "access_token");
+    assertNotNull(accessToken);
+    String expiry = getTagValue(retString, "expires_in");
+    assertNotNull(expiry);
+
+    // Verify the token
+    JWTToken parsedToken = new JWTToken(accessToken);
+    assertEquals("alice", parsedToken.getSubject());
+    assertTrue(authority.verifyToken(parsedToken));
+
+    // Verify the audiences
+    List<String> audiences = Arrays.asList(parsedToken.getAudienceClaims());
+    assertEquals(2, audiences.size());
+    assertTrue(audiences.contains("recipient1"));
+    assertTrue(audiences.contains("recipient2"));
+  }
+
+  private String getTagValue(String token, String tagName) {
+    String searchString = tagName + "\":";
+    String value = token.substring(token.indexOf(searchString) + searchString.length());
+    if (value.startsWith("\"")) {
+      value = value.substring(1);
+    }
+    if (value.contains("\"")) {
+      return value.substring(0, value.indexOf("\""));
+    } else if (value.contains(",")) {
+      return value.substring(0, value.indexOf(","));
+    } else {
+      return value.substring(0, value.length() - 1);
+    }
+  }
+
+  private static class TestJWTokenAuthority implements JWTokenAuthority {
+
+    private RSAPublicKey publicKey;
+    private RSAPrivateKey privateKey;
+
+    public TestJWTokenAuthority(RSAPublicKey publicKey, RSAPrivateKey privateKey) {
+      this.publicKey = publicKey;
+      this.privateKey = privateKey;
+    }
+
+    @Override
+    public JWTToken issueToken(Subject subject, String algorithm)
+      throws TokenServiceException {
+      Principal p = (Principal) subject.getPrincipals().toArray()[0];
+      return issueToken(p, algorithm);
+    }
+
+    @Override
+    public JWTToken issueToken(Principal p, String algorithm)
+      throws TokenServiceException {
+      return issueToken(p, null, algorithm);
+    }
+
+    @Override
+    public JWTToken issueToken(Principal p, String audience, String algorithm)
+      throws TokenServiceException {
+      return issueToken(p, audience, algorithm, -1);
+    }
+
+    @Override
+    public boolean verifyToken(JWTToken token) throws TokenServiceException {
+      JWSVerifier verifier = new RSASSAVerifier(publicKey);
+      return token.verify(verifier);
+    }
+
+    @Override
+    public JWTToken issueToken(Principal p, String audience, String algorithm,
+                               long expires) throws TokenServiceException {
+      ArrayList<String> audiences = null;
+      if (audience != null) {
+        audiences = new ArrayList<String>();
+        audiences.add(audience);
+      }
+      return issueToken(p, audiences, algorithm, expires);
+    }
+
+    @Override
+    public JWTToken issueToken(Principal p, List<String> audiences, String algorithm,
+                               long expires) throws TokenServiceException {
+      String[] claimArray = new String[4];
+      claimArray[0] = "KNOXSSO";
+      claimArray[1] = p.getName();
+      claimArray[2] = null;
+      if (expires == -1) {
+        claimArray[3] = null;
+      } else {
+        claimArray[3] = String.valueOf(expires);
+      }
+
+      JWTToken token = null;
+      if ("RS256".equals(algorithm)) {
+        token = new JWTToken("RS256", claimArray, audiences);
+        JWSSigner signer = new RSASSASigner(privateKey);
+        token.sign(signer);
+      } else {
+        throw new TokenServiceException("Cannot issue token - Unsupported algorithm");
+      }
+
+      return token;
+    }
+
+    @Override
+    public JWT issueToken(Principal p, String algorithm, long expiry)
+        throws TokenServiceException {
+      return issueToken(p, Collections.<String>emptyList(), algorithm, expiry);
+    }
+
+    @Override
+    public boolean verifyToken(JWTToken token, RSAPublicKey publicKey) throws TokenServiceException {
+      JWSVerifier verifier = new RSASSAVerifier(publicKey);
+      return token.verify(verifier);
+    }
+
+  }
+
+
 }