Implemented signed OpenID token with default algorithm RSA256.
Change-Id: I5bd5bed5c556e550244e06299bc7e54f53226401
diff --git a/full/src/test/java/de/ids_mannheim/korap/authentication/APIAuthenticationTest.java b/full/src/test/java/de/ids_mannheim/korap/authentication/APIAuthenticationTest.java
index 82bab07..962a14f 100644
--- a/full/src/test/java/de/ids_mannheim/korap/authentication/APIAuthenticationTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/authentication/APIAuthenticationTest.java
@@ -12,7 +12,7 @@
import com.nimbusds.jose.JOSEException;
import de.ids_mannheim.korap.config.Attributes;
-import de.ids_mannheim.korap.config.KustvaktConfiguration;
+import de.ids_mannheim.korap.config.FullConfiguration;
import de.ids_mannheim.korap.config.SpringJerseyTest;
import de.ids_mannheim.korap.constant.TokenType;
import de.ids_mannheim.korap.exceptions.KustvaktException;
@@ -23,7 +23,7 @@
public class APIAuthenticationTest extends SpringJerseyTest {
@Autowired
- private KustvaktConfiguration config;
+ private FullConfiguration config;
@Test
public void testCreateGetTokenContext () throws KustvaktException,
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 ac3a131..ed263c0 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
@@ -6,6 +6,7 @@
import java.io.IOException;
import java.io.InputStream;
+import java.net.URISyntaxException;
import java.util.Map;
import java.util.Properties;
@@ -59,7 +60,7 @@
@Test(expected = KustvaktException.class)
@Ignore
- public void testBeanOverrideInjection () throws KustvaktException {
+ public void testBeanOverrideInjection () throws KustvaktException, URISyntaxException {
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 c4156d6..6bd081a 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
@@ -2,14 +2,29 @@
import static org.junit.Assert.assertEquals;
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;
@@ -17,6 +32,10 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.net.HttpHeaders;
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JWSVerifier;
+import com.nimbusds.jose.crypto.RSASSAVerifier;
+import com.nimbusds.jwt.SignedJWT;
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.UniformInterfaceException;
@@ -24,6 +43,7 @@
import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
import de.ids_mannheim.korap.config.Attributes;
+import de.ids_mannheim.korap.config.FullConfiguration;
import de.ids_mannheim.korap.config.SpringJerseyTest;
import de.ids_mannheim.korap.exceptions.KustvaktException;
import de.ids_mannheim.korap.oauth2.constant.OAuth2Error;
@@ -33,24 +53,40 @@
@Autowired
private HttpAuthorizationHandler handler;
+ @Autowired
+ private FullConfiguration config;
private String redirectUri =
"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")
.header(Attributes.AUTHORIZATION,
- handler.createBasicAuthorizationHeaderValue("dory",
+ handler.createBasicAuthorizationHeaderValue(username,
"password"))
.header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
.header(HttpHeaders.CONTENT_TYPE,
ContentType.APPLICATION_FORM_URLENCODED)
.entity(form).post(ClientResponse.class);
}
-
- private ClientResponse sendTokenRequest (MultivaluedMap<String, String> form)
- throws KustvaktException {
+
+ private ClientResponse sendTokenRequest (
+ MultivaluedMap<String, String> form) throws KustvaktException {
return resource().path("oauth2").path("openid").path("token")
.header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
.header(HttpHeaders.CONTENT_TYPE,
@@ -165,33 +201,86 @@
node.at("/error_description").asText());
}
- @Test
- public void testRequestAuthorizationCodeUnsupportedResponseType ()
+ private void testRequestAuthorizationCodeUnsupportedResponseType (
+ MultivaluedMap<String, String> form, String type)
throws KustvaktException {
- MultivaluedMap<String, String> form = new MultivaluedMapImpl();
- form.add("scope", "openid");
- form.add("redirect_uri", redirectUri);
- // we don't support implicit grant
- form.add("response_type", "id_token token");
- form.add("client_id", "fCBbQkAyYzI4NzUxMg");
- form.add("nonce", "nonce");
ClientResponse response = sendAuthorizationRequest(form);
+ System.out.println(response.getEntity(String.class));
URI location = response.getLocation();
- assertEquals(MediaType.APPLICATION_FORM_URLENCODED, response.getType().toString());
+ assertEquals(MediaType.APPLICATION_FORM_URLENCODED,
+ response.getType().toString());
MultiValueMap<String, String> params =
UriComponentsBuilder.fromUri(location).build().getQueryParams();
assertEquals("invalid_request", params.getFirst("error"));
- assertEquals("unsupported+response_type%3A+id_token",
+ assertEquals("unsupported+response_type%3A+" + type,
params.getFirst("error_description"));
}
-
+
+ /**
+ * We don't support implicit grant. Implicit grant allows
+ * response_type:
+ * <ul>
+ * <li>id_token</li>
+ * <li>id_token token</li>
+ * </ul>
+ *
+ * @throws KustvaktException
+ */
@Test
- public void testRequestAccessToken () throws KustvaktException {
+ public void testRequestAuthorizationCodeUnsupportedImplicitFlow ()
+ throws KustvaktException {
+ MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+ form.add("scope", "openid");
+ form.add("redirect_uri", redirectUri);
+ form.add("response_type", "id_token");
+ form.add("client_id", "fCBbQkAyYzI4NzUxMg");
+ form.add("nonce", "nonce");
+
+ testRequestAuthorizationCodeUnsupportedResponseType(form, "id_token");
+
+ form.remove("response_type");
+ form.add("response_type", "id_token token");
+ testRequestAuthorizationCodeUnsupportedResponseType(form, "id_token");
+ }
+
+ /**
+ * Hybrid flow is not supported. Hybrid flow allows
+ * response_type:
+ * <ul>
+ * <li>code id_token</li>
+ * <li>code token</li>
+ * <li>code id_token token</li>
+ * </ul>
+ *
+ * @throws KustvaktException
+ */
+
+ @Test
+ public void testRequestAuthorizationCodeUnsupportedHybridFlow ()
+ throws KustvaktException {
+ MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+ form.add("scope", "openid");
+ form.add("redirect_uri", redirectUri);
+ form.add("response_type", "code id_token");
+ form.add("client_id", "fCBbQkAyYzI4NzUxMg");
+ form.add("nonce", "nonce");
+ testRequestAuthorizationCodeUnsupportedResponseType(form, "id_token");
+
+ form.remove("response_type");
+ form.add("response_type", "code token");
+ testRequestAuthorizationCodeUnsupportedResponseType(form, "token");
+ }
+
+ @Test
+ public void testRequestAccessToken ()
+ throws KustvaktException, ParseException, InvalidKeySpecException,
+ NoSuchAlgorithmException, JOSEException {
+ String client_id = "fCBbQkAyYzI4NzUxMg";
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("response_type", "code");
- form.add("client_id", "fCBbQkAyYzI4NzUxMg");
+ form.add("client_id", client_id);
form.add("redirect_uri", redirectUri);
form.add("scope", "openid");
form.add("state", "thisIsMyState");
@@ -201,17 +290,17 @@
MultiValueMap<String, String> params =
UriComponentsBuilder.fromUri(location).build().getQueryParams();
String code = params.getFirst("code");
-
+
MultivaluedMap<String, String> tokenForm = new MultivaluedMapImpl();
tokenForm.add("grant_type", "authorization_code");
tokenForm.add("redirect_uri", redirectUri);
- tokenForm.add("client_id", "fCBbQkAyYzI4NzUxMg");
+ tokenForm.add("client_id", client_id);
tokenForm.add("client_secret", "secret");
tokenForm.add("code", code);
-
+
ClientResponse tokenResponse = sendTokenRequest(tokenForm);
String entity = tokenResponse.getEntity(String.class);
-// System.out.println(entity);
+ // System.out.println(entity);
JsonNode node = JsonUtils.readTree(entity);
assertNotNull(node.at("/access_token").asText());
@@ -219,7 +308,30 @@
assertEquals(TokenType.BEARER.toString(),
node.at("/token_type").asText());
assertNotNull(node.at("/expires_in").asText());
- assertNotNull(node.at("/id_token").asText());
+ String id_token = node.at("/id_token").asText();
+ assertNotNull(id_token);
+ verifyingIdToken(id_token, username, client_id);
+ }
+
+ 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);
+
+ SignedJWT signedJWT = SignedJWT.parse(id_token);
+ JWSVerifier verifier = new RSASSAVerifier(publicKey);
+ assertTrue(signedJWT.verify(verifier));
+
+ assertEquals(client_id,
+ signedJWT.getJWTClaimsSet().getAudience().get(0));
+ assertEquals(username, signedJWT.getJWTClaimsSet().getSubject());
+ assertEquals(config.getIssuerURI().toString(),
+ signedJWT.getJWTClaimsSet().getIssuer());
+ assertTrue(new Date()
+ .before(signedJWT.getJWTClaimsSet().getExpirationTime()));
}
}
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserControllerTest.java
index 68f1b55..f791244 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserControllerTest.java
@@ -29,6 +29,7 @@
import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
import de.ids_mannheim.korap.config.Attributes;
import de.ids_mannheim.korap.config.BeansFactory;
+import de.ids_mannheim.korap.config.FullConfiguration;
import de.ids_mannheim.korap.config.JWTSigner;
import de.ids_mannheim.korap.config.TestHelper;
import de.ids_mannheim.korap.exceptions.KustvaktException;
@@ -49,7 +50,8 @@
@Autowired
HttpAuthorizationHandler handler;
-
+ @Autowired
+ FullConfiguration config;
private static String[] credentials;
@Override
@@ -201,8 +203,8 @@
String token = node.path("token").asText();
JWTSigner sign = new JWTSigner(BeansFactory.getKustvaktContext().getConfiguration().getSharedSecret(),
- BeansFactory.getKustvaktContext().getConfiguration().getIssuer(), -1);
-
+ config.getIssuer(), -1);
+ //BeansFactory.getKustvaktContext().getConfiguration().getIssuer(), -1);
SignedJWT jwt = sign.verifyToken(token);
while (true) {
diff --git a/full/src/test/resources/kustvakt-private.key b/full/src/test/resources/kustvakt-private.key
new file mode 100644
index 0000000..d419b89
--- /dev/null
+++ b/full/src/test/resources/kustvakt-private.key
@@ -0,0 +1 @@
+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
new file mode 100644
index 0000000..087d6f7
--- /dev/null
+++ b/full/src/test/resources/kustvakt-public.key
@@ -0,0 +1 @@
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJVX3D3vj1xqYegV9c1PR0NZErdJc9iyBgAfpKx3I+aGlnkv+MYnL5phkROTHiUBDCHIo5dzl43WUe5StXcZ9VFB7mWt4ozJzIA3EM/QbhoPuPUeSnUpJDMJVVuQXbdPE5lPbXhXUKYPu27FRiqUrlushOsJIKPlsLn8Nt1CzZIwIDAQAB
\ No newline at end of file