You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by sm...@apache.org on 2021/06/10 11:27:31 UTC

[knox] branch master updated: KNOX-2620 - Using the proper signature algorithm name in JWKS endpoint (#457)

This is an automated email from the ASF dual-hosted git repository.

smolnar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git


The following commit(s) were added to refs/heads/master by this push:
     new ec66f35  KNOX-2620 - Using the proper signature algorithm name in JWKS endpoint (#457)
ec66f35 is described below

commit ec66f35ae3619afee6b86b4c254e163a8d5328bc
Author: Sandor Molnar <sm...@apache.org>
AuthorDate: Thu Jun 10 13:27:21 2021 +0200

    KNOX-2620 - Using the proper signature algorithm name in JWKS endpoint (#457)
---
 .../gateway/service/knoxtoken/JWKSResource.java    |  21 ++--
 .../service/knoxtoken/JWKSResourceTest.java        | 109 ++++++++++++---------
 2 files changed, 74 insertions(+), 56 deletions(-)

diff --git a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/JWKSResource.java b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/JWKSResource.java
index 0477dd4..0fba2c2 100644
--- a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/JWKSResource.java
+++ b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/JWKSResource.java
@@ -25,6 +25,8 @@ import com.nimbusds.jose.jwk.RSAKey;
 import org.apache.knox.gateway.config.GatewayConfig;
 import org.apache.knox.gateway.services.GatewayServices;
 import org.apache.knox.gateway.services.ServiceType;
+import org.apache.knox.gateway.services.security.AliasService;
+import org.apache.knox.gateway.services.security.AliasServiceException;
 import org.apache.knox.gateway.services.security.KeystoreService;
 import org.apache.knox.gateway.services.security.KeystoreServiceException;
 import org.apache.knox.gateway.services.security.token.TokenUtils;
@@ -50,18 +52,23 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 public class JWKSResource {
   public static final String JWKS_PATH = "/jwks.json";
   static final String RESOURCE_PATH = "knoxtoken/api/v1";
+  private static final String TOKEN_SIG_ALG = "knox.token.sigalg";
 
   @Context
   HttpServletRequest request;
   @Context
   ServletContext context;
   private KeystoreService keystoreService;
+  private String signatureAlgorithm;
 
   @PostConstruct
-  public void init() {
-    final GatewayServices services = (GatewayServices) context
-        .getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
+  public void init() throws AliasServiceException {
+    final GatewayServices services = (GatewayServices) context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
     keystoreService = services.getService(ServiceType.KEYSTORE_SERVICE);
+
+    final String configuredSigAlg = context.getInitParameter(TOKEN_SIG_ALG);
+    final GatewayConfig config = (GatewayConfig) context.getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE);
+    this.signatureAlgorithm = TokenUtils.getSignatureAlgorithm(configuredSigAlg, (AliasService) services.getService(ServiceType.ALIAS_SERVICE), config.getSigningKeystoreName());
   }
 
   @GET
@@ -84,7 +91,7 @@ public class JWKSResource {
       final String kid = TokenUtils.getThumbprint(rsa, "SHA-256");
       final RSAKey.Builder builder = new RSAKey.Builder(rsa)
           .keyUse(KeyUse.SIGNATURE)
-          .algorithm(new JWSAlgorithm(rsa.getAlgorithm()))
+          .algorithm(new JWSAlgorithm(this.signatureAlgorithm))
           .keyID(kid);
 
       jwks = new JWKSet(builder.build());
@@ -101,16 +108,14 @@ public class JWKSResource {
         .entity(jwks.toJSONObject().toString()).build();
   }
 
-  protected RSAPublicKey getPublicKey(final String keystore)
-      throws KeystoreServiceException, KeyStoreException {
+  protected RSAPublicKey getPublicKey(final String keystore) throws KeystoreServiceException, KeyStoreException {
     final KeyStore ks = keystoreService.getSigningKeystore(keystore);
     final Certificate cert = ks.getCertificate(getSigningKeyAlias());
     return (cert != null) ? (RSAPublicKey) cert.getPublicKey() : null;
   }
 
   private String getSigningKeyAlias() {
-    final GatewayConfig config = (GatewayConfig) request.getServletContext()
-        .getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE);
+    final GatewayConfig config = (GatewayConfig) context.getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE);
     final String alias = config.getSigningKeyAlias();
     return (alias == null) ? GatewayConfig.DEFAULT_SIGNING_KEY_ALIAS : alias;
   }
diff --git a/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/JWKSResourceTest.java b/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/JWKSResourceTest.java
index 09100e2..27963ab 100644
--- a/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/JWKSResourceTest.java
+++ b/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/JWKSResourceTest.java
@@ -17,35 +17,40 @@
  */
 package org.apache.knox.gateway.service.knoxtoken;
 
-import com.nimbusds.jose.JOSEException;
-import com.nimbusds.jose.JWSSigner;
-import com.nimbusds.jose.JWSVerifier;
-import com.nimbusds.jose.crypto.RSASSASigner;
-import com.nimbusds.jose.crypto.RSASSAVerifier;
-import com.nimbusds.jose.jwk.JWK;
-import com.nimbusds.jose.jwk.JWKSet;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStoreSpi;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.cert.Certificate;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Collections;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.Response;
+
+import org.apache.knox.gateway.config.GatewayConfig;
 import org.apache.knox.gateway.services.GatewayServices;
 import org.apache.knox.gateway.services.ServiceType;
+import org.apache.knox.gateway.services.security.AliasService;
 import org.apache.knox.gateway.services.security.KeystoreService;
-import org.apache.knox.gateway.services.security.KeystoreServiceException;
 import org.apache.knox.gateway.services.security.token.impl.JWT;
 import org.apache.knox.gateway.services.security.token.impl.JWTToken;
 import org.easymock.EasyMock;
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-import javax.servlet.ServletContext;
-import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.core.Response;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.KeyStoreException;
-import java.security.PublicKey;
-import java.security.interfaces.RSAPrivateKey;
-import java.security.interfaces.RSAPublicKey;
-import java.text.ParseException;
-import java.util.Collections;
+import com.nimbusds.jose.JWSSigner;
+import com.nimbusds.jose.JWSVerifier;
+import com.nimbusds.jose.crypto.RSASSASigner;
+import com.nimbusds.jose.crypto.RSASSAVerifier;
+import com.nimbusds.jose.jwk.JWK;
+import com.nimbusds.jose.jwk.JWKSet;
 
 /**
  * Unit tests for JWKS Resource
@@ -57,7 +62,6 @@ public class JWKSResourceTest {
   private ServletContext context;
   private HttpServletRequest request;
   private GatewayServices services;
-  private JWKSResource jwksResource;
 
   @BeforeClass
   public static void setUpBeforeClass() throws Exception {
@@ -69,49 +73,51 @@ public class JWKSResourceTest {
     privateKey = (RSAPrivateKey) KPair.getPrivate();
   }
 
-  private void init() throws KeystoreServiceException, KeyStoreException {
-    final KeystoreService ks = EasyMock.createNiceMock(KeystoreService.class);
+  @Before
+  public void init() throws Exception {
     services = EasyMock.createNiceMock(GatewayServices.class);
     context = EasyMock.createNiceMock(ServletContext.class);
     request = EasyMock.createNiceMock(HttpServletRequest.class);
 
-    jwksResource = EasyMock.partialMockBuilder(JWKSResource.class)
-        .addMockedMethod("getPublicKey", String.class).createMock();
-
-    EasyMock.expect(services.getService(ServiceType.KEYSTORE_SERVICE))
-        .andReturn(ks).anyTimes();
-    EasyMock.expect(
-        context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE))
-        .andReturn(services).anyTimes();
-    EasyMock.expect(jwksResource.getPublicKey(null)).andReturn(publicKey)
-        .anyTimes();
-    EasyMock.replay(jwksResource, context, request, services, ks);
+    final KeystoreService ks = EasyMock.createNiceMock(KeystoreService.class);
+    final KeyStoreSpi keyStoreSpi = EasyMock.createNiceMock(KeyStoreSpi.class);
+    final KeyStore keystore = new KeyStoreMock(keyStoreSpi, null, "test");
+    keystore.load(null);
+    EasyMock.expect(ks.getSigningKeystore(null)).andReturn(keystore).anyTimes();
+    final Certificate cert = EasyMock.createNiceMock(Certificate.class);
+    EasyMock.expect(keyStoreSpi.engineGetCertificate(EasyMock.anyString())).andReturn(cert).anyTimes();
+    EasyMock.expect(cert.getPublicKey()).andReturn(publicKey).anyTimes();
+    EasyMock.expect(services.getService(ServiceType.KEYSTORE_SERVICE)).andReturn(ks).anyTimes();
+    EasyMock.expect(services.getService(ServiceType.ALIAS_SERVICE)).andReturn(EasyMock.createNiceMock(AliasService.class)).anyTimes();
+    EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services).anyTimes();
+    final GatewayConfig config = EasyMock.createNiceMock(GatewayConfig.class);
+    EasyMock.expect(config.getSigningKeyAlias()).andReturn(null).anyTimes();
+    EasyMock.expect(context.getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE)).andReturn(config).anyTimes();
+    EasyMock.replay(context, request, services, ks, keyStoreSpi, cert, config);
   }
 
   @Test
-  public void testJWKSrequest()
-      throws KeystoreServiceException, KeyStoreException {
-    init();
-    Response retResponse = jwksResource.getJwksResponse();
-    Assert.assertEquals(Response.Status.OK.getStatusCode(),
-        retResponse.getStatus());
+  public void testJWKSrequest() throws Exception {
+    final JWKSResource jwksResource = new JWKSResource();
+    jwksResource.context = context;
+    jwksResource.request = request;
+    jwksResource.init();
+    final Response retResponse = jwksResource.getJwksResponse();
+    Assert.assertEquals(Response.Status.OK.getStatusCode(), retResponse.getStatus());
   }
 
   /**
    * End to End test that verifies the token acquired from JWKS endpoint.
-   *
-   * @throws KeystoreServiceException
-   * @throws KeyStoreException
-   * @throws ParseException
-   * @throws JOSEException
    */
   @Test
-  public void testE2E()
-      throws KeystoreServiceException, KeyStoreException, ParseException,
-      JOSEException {
-    init();
+  public void testE2E() throws Exception {
     /* get a signed JWT token */
     final JWT testToken = getTestToken("RS256");
+
+    final JWKSResource jwksResource = new JWKSResource();
+    jwksResource.context = context;
+    jwksResource.request = request;
+    jwksResource.init();
     /* get JWKS keyset */
     final Response retResponse = jwksResource.getJwksResponse();
 
@@ -142,4 +148,11 @@ public class JWKSResourceTest {
     return token;
   }
 
+  private static final class KeyStoreMock extends KeyStore {
+
+    protected KeyStoreMock(KeyStoreSpi keyStoreSpi, Provider provider, String type) {
+      super(keyStoreSpi, provider, type);
+    }
+  }
+
 }
\ No newline at end of file