Added JWK-set web-controller listing kustvakt public keys.

Change-Id: If8244161d7979008c65e3de5b9154cc5dd427a17
diff --git a/full/src/test/java/de/ids_mannheim/korap/config/ConfigTest.java b/full/src/test/java/de/ids_mannheim/korap/config/ConfigTest.java
index ed263c0..380d5fb 100644
--- a/full/src/test/java/de/ids_mannheim/korap/config/ConfigTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/config/ConfigTest.java
@@ -60,7 +60,7 @@
 
     @Test(expected = KustvaktException.class)
     @Ignore
-    public void testBeanOverrideInjection () throws KustvaktException, URISyntaxException {
+    public void testBeanOverrideInjection () throws Exception {
         helper().getContext()
                 .getConfiguration()
                 .setPropertiesAsStream(
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java
index 6bd081a..5459c6d 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java
@@ -4,27 +4,17 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.net.URI;
-import java.security.KeyFactory;
 import java.security.NoSuchAlgorithmException;
-import java.security.interfaces.RSAPublicKey;
 import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-import java.security.spec.X509EncodedKeySpec;
 import java.text.ParseException;
 import java.util.Date;
 
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 
-import org.apache.commons.codec.binary.Base64;
 import org.apache.http.entity.ContentType;
 import org.apache.oltu.oauth2.common.message.types.TokenType;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.util.MultiValueMap;
@@ -35,6 +25,8 @@
 import com.nimbusds.jose.JOSEException;
 import com.nimbusds.jose.JWSVerifier;
 import com.nimbusds.jose.crypto.RSASSAVerifier;
+import com.nimbusds.jose.jwk.JWKSet;
+import com.nimbusds.jose.jwk.RSAKey;
 import com.nimbusds.jwt.SignedJWT;
 import com.sun.jersey.api.client.ClientHandlerException;
 import com.sun.jersey.api.client.ClientResponse;
@@ -60,19 +52,6 @@
             "https://korap.ids-mannheim.de/confidential/redirect";
     private String username = "dory";
 
-    private static String publicKey;
-
-    @BeforeClass
-    public static void init () throws IOException {
-        InputStream is = OAuth2OpenIdControllerTest.class.getClassLoader()
-                .getResourceAsStream("kustvakt-public.key");
-
-        try (BufferedReader reader =
-                new BufferedReader(new InputStreamReader(is));) {
-            publicKey = reader.readLine();
-        }
-    }
-
     private ClientResponse sendAuthorizationRequest (
             MultivaluedMap<String, String> form) throws KustvaktException {
         return resource().path("oauth2").path("openid").path("authorize")
@@ -254,7 +233,8 @@
      * <li>code id_token token</li>
      * </ul>
      * 
-     * @throws KustvaktException
+     * @throws KustvaktExceptiony);
+     *             assertTrue(signedJWT.verify(verifier));
      */
 
     @Test
@@ -317,10 +297,8 @@
     private void verifyingIdToken (String id_token, String username,
             String client_id) throws ParseException, InvalidKeySpecException,
             NoSuchAlgorithmException, JOSEException {
-        byte[] decodedPuk = Base64.decodeBase64(publicKey);
-        KeySpec keySpec = new X509EncodedKeySpec(decodedPuk);
-        RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA")
-                .generatePublic(keySpec);
+        JWKSet keySet = config.getPublicKeySet();
+        RSAKey publicKey = (RSAKey) keySet.getKeyByKeyId(config.getRsaKeyId());
 
         SignedJWT signedJWT = SignedJWT.parse(id_token);
         JWSVerifier verifier = new RSASSAVerifier(publicKey);
@@ -334,4 +312,18 @@
         assertTrue(new Date()
                 .before(signedJWT.getJWTClaimsSet().getExpirationTime()));
     }
+
+    @Test
+    public void testPublicKeyAPI () throws KustvaktException {
+        ClientResponse response = resource().path("oauth2").path("openid")
+                .path("key").path("public").get(ClientResponse.class);
+        String entity = response.getEntity(String.class);
+        JsonNode node = JsonUtils.readTree(entity);
+        assertEquals(1,node.at("/keys").size());
+        node = node.at("/keys/0");
+        assertEquals("RSA", node.at("/kty").asText());
+        assertEquals(config.getRsaKeyId(), node.at("/kid").asText());
+        assertNotNull(node.at("/e").asText());
+        assertNotNull(node.at("/n").asText());
+    }
 }
diff --git a/full/src/test/resources/kustvakt-private.key b/full/src/test/resources/kustvakt-private.key
deleted file mode 100644
index d419b89..0000000
--- a/full/src/test/resources/kustvakt-private.key
+++ /dev/null
@@ -1 +0,0 @@
-MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAIlVfcPe+PXGph6BX1zU9HQ1kSt0lz2LIGAB+krHcj5oaWeS/4xicvmmGRE5MeJQEMIcijl3OXjdZR7lK1dxn1UUHuZa3ijMnMgDcQz9BuGg+49R5KdSkkMwlVW5Bdt08TmU9teFdQpg+7bsVGKpSuW6yE6wkgo+Wwufw23ULNkjAgMBAAECgYBVq8o3zTm7gH+SmhwWOhaBBAWaeTH7x3WbzsAHtCG1gsb2QMJAHg4hZJdQokBXMKEzpkAoFxL4Lgxt2IJQG2ZL778uiQiy+xHI8VTXBNXmdo+F3hlNzEmJySSSCxYefSSv+DN/yBrOx0heGXR3vbefXey4a6q8RhthCuRfpHmqmQJBALyFdf4Oj4rozi/KI8yiD71+NNR7hHMtepn3YyY0zBXxk2YEwpcPkzBhdDiL6fYJjjoGFnqKLNqlgO8gHx+ET70CQQC6faQiLjUp50wbEAZqLY7Q353k2qTdAX8W9L2lF/79GEA+EJumQ2iWOu9qYqQuSMSKwheY6mdOVWj8yOMiu2pfAkEAll0cr3aNpw3o5tUjmKPqSgnPuWqLShKMJyHaQy75WMdF+ajyS+pwS7ZvLGrsQQF+H2mbpEFxZTN8kz3blRfDQQJBAKADPdm2HBegRkTSMy7XeDrwI+JBWEPpDMr9o9sMA9XWAQk/5s15+Tstxk9Z49VyynDkqKqkNY+Y6UQ8eedLN7ECQQCDiAsbwOe79EpsHdQBOZeNvpWu1x1TxieN0nCAa/zQz8qupHkL/u8VI8csz+s3qOcgxpJqsn58G8eb9Jmk9fGY
\ No newline at end of file
diff --git a/full/src/test/resources/kustvakt-public.key b/full/src/test/resources/kustvakt-public.key
deleted file mode 100644
index 087d6f7..0000000
--- a/full/src/test/resources/kustvakt-public.key
+++ /dev/null
@@ -1 +0,0 @@
-MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJVX3D3vj1xqYegV9c1PR0NZErdJc9iyBgAfpKx3I+aGlnkv+MYnL5phkROTHiUBDCHIo5dzl43WUe5StXcZ9VFB7mWt4ozJzIA3EM/QbhoPuPUeSnUpJDMJVVuQXbdPE5lPbXhXUKYPu27FRiqUrlushOsJIKPlsLn8Nt1CzZIwIDAQAB
\ No newline at end of file
diff --git a/full/src/test/resources/kustvakt-test.conf b/full/src/test/resources/kustvakt-test.conf
index ebfb216..48ce51c 100644
--- a/full/src/test/resources/kustvakt-test.conf
+++ b/full/src/test/resources/kustvakt-test.conf
@@ -53,10 +53,15 @@
 oauth2.default.scopes = openid read_username read_email 
 oauth2.client.credentials.scopes = read_client_info
 
-# JWT
+## JWT
 security.jwt.issuer=korap.ids-mannheim.de
 
-## token expiration
+## JWK
+rsa.private = kustvakt_rsa.key
+rsa.public = kustvakt_rsa_public.key
+rsa.key.id = 74caa3a9-217c-49e6-94e9-2368fdd02c35
+
+## token expiration time
 security.longTokenTTL = 1D
 security.tokenTTL = 9S
 security.shortTokenTTL = 5S
@@ -73,7 +78,7 @@
 security.validation.stringLength = 150
 security.validation.emailLength = 50
 security.encryption.algo=BCRYPT
-security.sharedSecret=testSecret
+security.sharedSecret=testSecretCodeMustContainsMinimum256Bits$87aL2t0sklnf66roGDerNsw2s9
 
 ## applicable: rewrite, foundry, filter, deny
 security.rewrite.strategies=filter, foundry, rewrite
\ No newline at end of file
diff --git a/full/src/test/resources/kustvakt_rsa.key b/full/src/test/resources/kustvakt_rsa.key
new file mode 100644
index 0000000..1db25e9
--- /dev/null
+++ b/full/src/test/resources/kustvakt_rsa.key
@@ -0,0 +1,12 @@
+{
+  "p": "y7t3f2VRo5TN3IsCjshSWWwe4H1-Xd7iBbtPS_fmBeaVDbLr-05LsGRJxXzKheMJ5DwBzhvWAlCig5uSJG3Gk4i0LgLY5YO33shb9qqqEnF54ZkJbiqxSs5l_dggzZgYB5z0riVl2VA3yfNm1qJIE2eipBouUjBEXMOEtJlOrFc",
+  "kty": "RSA",
+  "q": "v4HHIpOddl_78fVQgvZCsINygpLuniJ3sVShLhX7LnCU0Eb4TMK_Fyz9_JPb3YFvEoPpQw3kfnAhkOBTATTpXzg_dNtR6eQfvDJfHl9R6FuSoVTJoNAO_rqEpKzQOGXl4ohBxVjhXcbEo6GEVp4pZAeXMM8D02IWfvGbJd0Yw0k",
+  "d": "OJFnms4n3ajWKvK26aOh_r8JGgQwbQNIXpx8UqFnc_EB4nzxcLns8-FGKa9Vg3VMAs8cFC4iM9evx1084yqsCeSKgwiV5ZVQkwnp35Gd5BslZxuH8kCdR1mL5y0V0RMwgW-W1ry_YtdhBSIze8XCJXB7udNk7bviiJylEm8OouyxAq-5uUy_qMWYk-mtDSpmPW9SfFf91c6P7-ataDFcd_zxFotd1UwXDVDaPfUnxpOA6Jh1WsvIFhX4IzETuUG8n5C-j6FrK_YlU7U-zFzzF8qWTthQVj5l7A0zOGmq6OC9mv_xtnSc6z9I-HklWFXa8eDsc2JasYqJY8CmTDSy8Q",
+  "e": "AQAB",
+  "kid": "74caa3a9-217c-49e6-94e9-2368fdd02c35",
+  "qi": "Iv8_jAuCTdU7xZ1GXK0Zaql3Azu1-qXiZseod9urLFFZK6OvxrhH0BexG_P1tRikUfEUQiyqNVCU544Z0Y0AdDbgb5aEYNa3Bkb5WAHHXsLDtzXSsxgvR4Pzg3PhT3HTrLkgTlWy9g0u7bwfhb-KTRszcw4SyFXz9o62xJLPJZo",
+  "dp": "pA8_qHhHqMoAiNPsaFyKa_Y0WyTTqPX93w26SnvDYQcRCqoFfCbNrqrj-UOHtw9gfMmRzo795HlYlVCm--zmlxHjvpWOYiyS2bVQ0S8Xq6hztKbPQEbi5FGXMjZkHAuZdi__nWkCPmBpvJfkPX0LO40eHLX0jTzPIEBWUjSOdRs",
+  "dq": "GtnydumlqWRZ6hoQWNx4i1FS6_X4GRoSGD4af2C7oE5Ov0lEJVck_fXkAtcke9FbJohyW2GGSSglvK-HU-L8WcqEMzlRKe8_d97EMXkB_gdg7tf5kV-6yoKSeJh2dYHsErAyMJ5-suxcw-iwqohwm0LpMwHDso7NQq1TqKJwh2k",
+  "n": "mGgmGYIN06ibCh98nsXp0a77xRQNnB9rKpRGKm41tVi0zLQWqmEdDh2CmrMiOOxTJFSlAuAVkwK-KVQZ5Men5dJvRyTwZPtBWSJZk32Znj3VshFloSQlQU-g3oh3c2htP03EDtBLmecZMI-OUV1hRCvrRUrS-qF24CJ-rheFsCmpSievEJDQqTTfXcbAG2DdRQJHWb3y1iyNojB_mV1H2Gztg9DGEZarloqXoTFeDcxs7SpZJqAWCWTJQk8n6Ye79SfGMNrzaaqN9aHx__6FU-GFdZexlWE0CemQcfx_hTEkCTa2EsGgI_GETQIjeCZRB29x91E3AlWVvEgA591pzw"
+}
\ No newline at end of file
diff --git a/full/src/test/resources/kustvakt_rsa_public.key b/full/src/test/resources/kustvakt_rsa_public.key
new file mode 100644
index 0000000..28c2fad
--- /dev/null
+++ b/full/src/test/resources/kustvakt_rsa_public.key
@@ -0,0 +1,6 @@
+{"keys": [{
+  "kty": "RSA",
+  "e": "AQAB",
+  "kid": "74caa3a9-217c-49e6-94e9-2368fdd02c35",
+  "n": "mGgmGYIN06ibCh98nsXp0a77xRQNnB9rKpRGKm41tVi0zLQWqmEdDh2CmrMiOOxTJFSlAuAVkwK-KVQZ5Men5dJvRyTwZPtBWSJZk32Znj3VshFloSQlQU-g3oh3c2htP03EDtBLmecZMI-OUV1hRCvrRUrS-qF24CJ-rheFsCmpSievEJDQqTTfXcbAG2DdRQJHWb3y1iyNojB_mV1H2Gztg9DGEZarloqXoTFeDcxs7SpZJqAWCWTJQk8n6Ye79SfGMNrzaaqN9aHx__6FU-GFdZexlWE0CemQcfx_hTEkCTa2EsGgI_GETQIjeCZRB29x91E3AlWVvEgA591pzw"
+}]}
\ No newline at end of file