diff --git a/.gitignore b/.gitignore
index 5e6e75d..99f8bb0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,3 +40,6 @@ Thumbs.db
.idea
*.iml
+/bin-test/
+/target-test/
+/test-classes/
diff --git a/AllOauthClientTests.launch b/AllOauthClientTests.launch
new file mode 100644
index 0000000..cd07cbe
--- /dev/null
+++ b/AllOauthClientTests.launch
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build.properties b/build.properties
new file mode 100644
index 0000000..f1e110b
--- /dev/null
+++ b/build.properties
@@ -0,0 +1,4 @@
+source.. = src/main/java/
+bin.includes = META-INF/,\
+ .
+additional.bundles = org.junit
diff --git a/pom.xml b/pom.xml
index 8eedd38..3b2cfab 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,296 +14,386 @@
~ limitations under the License.
-->
- 4.0.0
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+ xmlns="http://maven.apache.org/POM/4.0.0">
+ 4.0.0
- io.curity
- oauth-filter
- 4.0.0
- OAuth API Filter
- A Servlet Filter that authenticates and authorizes requests using OAuth access tokens of various kinds.
- https://github.com/curityio/oauth-filter-for-java
+ io.curity
+ oauth-filter
+ 5.0.0
+ OAuth API Filter
+ A Servlet Filter that authenticates and authorizes requests
+ using OAuth access tokens of various kinds.
+ https://github.com/curityio/oauth-filter-for-java
-
- Curity AB
- https://curity.io
-
+
+ Curity AB
+ https://curity.io
+
-
-
- The Apache License, Version 2.0
- https://www.apache.org/licenses/LICENSE-2.0.txt
-
-
+
+
+ The Apache License, Version 2.0
+ https://www.apache.org/licenses/LICENSE-2.0.txt
+
+
-
-
- Travis Spencer
- travis.spencer@curity.io
- Curity AB
- https://curity.io
-
-
- Michal Trojanowski
- michal.trojanowski@curity.io
- Curity AB
- https://curity.io
-
-
- Judith Kahrer
- judith.kahrer@curity.io
- Curity AB
- https://curity.io
-
-
+
+
+ Travis Spencer
+ travis.spencer@curity.io
+ Curity AB
+ https://curity.io
+
+
+ Michal Trojanowski
+ michal.trojanowski@curity.io
+ Curity AB
+ https://curity.io
+
+
+ Judith Kahrer
+ judith.kahrer@curity.io
+ Curity AB
+ https://curity.io
+
+
+ Marco Descher
+ descher@medevit.at
+ MEDEVIT OG
+ http://medevit.at
+
+
-
- scm:git:git://github.com:curityio/oauth-filter-for-java.git
- scm:git:ssh://github.com:curityio/oauth-filter-for-java.git
- https://github.com/curityio/oauth-filter-for-java
-
+
+ scm:git:git://github.com:curityio/oauth-filter-for-java.git
+
+ scm:git:ssh://github.com:curityio/oauth-filter-for-java.git
+ https://github.com/curityio/oauth-filter-for-java
+
-
- UTF-8
-
+
+ UTF-8
+
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- 3.1
-
- 17
- 17
- true
- false
-
-
+
+
+
+
+ org.apache.felix
+ maven-bundle-plugin
+ 6.0.0
+ true
+
+
+ <_failok>true
+ ${buildNumber}
+ A Servlet Filter that
+ authenticates and authorizes requests using
+ OAuth access tokens of various kinds.
+ ${project.version}
+ io.curity.oauth-filter
+ *
+ ${api.package}
+ ${project.version}
+ ${spec.version}
+ <_versionpolicy>
+ [$(version;==;$(@)),$(version;+;$(@)))
+ <_nodefaultversion>false
+ =1.0.0)(!(version>=2.0.0)))";resolution:=optional,
+ osgi.serviceloader;filter:="(osgi.serviceloader=io.curity.oauth.HttpClientProvider)";osgi.serviceloader="io.curity.oauth.HttpClientProvider";cardinality:=multiple;resolution:=optional,
+ osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=17))"
+ ]]>
+
+
+
+
+ osgi-bundle
+ package
+
+ bundle
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.1
+
+ 17
+ 17
+ true
+ false
+
+
-
-
- maven-failsafe-plugin
- 2.22.2
-
-
- org.apache.logging.log4j.jul.LogManager
-
-
-
- **/integration/**/IntegrationTest*.java
- **/integration/**/*IntegrationTest.java
-
- UTF-8
-
-
-
-
- integration-test
- verify
-
-
-
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
- 2.16
-
-
- org.apache.logging.log4j.jul.LogManager
-
-
-
- **/integration/**/*.java
-
-
-
+
+
+ maven-failsafe-plugin
+ 2.22.2
+
+
+
+ org.apache.logging.log4j.jul.LogManager
+
+
+
+ **/integration/**/IntegrationTest*.java
+ **/integration/**/*IntegrationTest.java
+
+ UTF-8
+
+
+
+
+ integration-test
+ verify
+
+
+
+
-
-
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.16
+
+
+
+ org.apache.logging.log4j.jul.LogManager
+
+
+
+ **/integration/**/*.java
+
+
+
+
+ org.cyclonedx
+ cyclonedx-maven-plugin
+ 2.9.1
+
+
+ package
+
+ makeAggregateBom
+
+
+
+
+ library
+ 1.4
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ true
+ all
+ CycloneDX-Sbom
+
+
-
-
- jakarta.servlet
- jakarta.servlet-api
- 6.0.0
-
-
- javax.json
- javax.json-api
-
-
- org.apache.httpcomponents
- httpclient
- true
-
+
+ org.apache.felix
+ maven-bundle-plugin
+
+
-
+
-
- com.owlike
- genson
- test
-
-
- junit
- junit
- test
-
-
- org.mockito
- mockito-core
- test
-
-
- org.apache.logging.log4j
- log4j-core
- test
-
-
- org.apache.logging.log4j
- log4j-jul
- test
-
-
- org.apache.logging.log4j
- log4j-jcl
- test
-
-
- org.bitbucket.b_c
- jose4j
- test
-
-
+
+
+ jakarta.servlet
+ jakarta.servlet-api
+
+
+ org.apache.httpcomponents
+ httpclient
+ true
+
-
-
-
- org.apache.httpcomponents
- httpclient
- 4.5.13
-
-
- javax.servlet
- javax.servlet-api
- 4.0.1
-
-
- com.google.guava
- guava
- 32.0.0-jre
-
-
- javax.json
- javax.json-api
- 1.1.4
-
-
- com.owlike
- genson
- 1.6
-
-
- org.bitbucket.b_c
- jose4j
- 0.9.4
-
-
- junit
- junit
- 4.13.2
-
-
- org.mockito
- mockito-core
- 3.10.0
- test
-
-
- org.apache.logging.log4j
- log4j-bom
- 2.14.1
- import
- pom
-
-
-
+
-
-
- release
-
-
- ossrh
- https://oss.sonatype.org/content/repositories/snapshots
-
-
- ossrh
- https://oss.sonatype.org/service/local/staging/deploy/maven2/
-
-
-
-
-
- org.apache.maven.plugins
- maven-source-plugin
- 3.2.1
-
-
- attach-sources
-
- jar-no-fork
-
-
-
-
-
- org.apache.maven.plugins
- maven-javadoc-plugin
- 3.3.0
-
-
- attach-javadocs
-
- jar
-
-
-
-
- 8
-
-
-
- org.apache.maven.plugins
- maven-gpg-plugin
- 3.0.1
-
-
- sign-artifacts
- verify
-
- sign
-
-
-
-
-
- org.sonatype.plugins
- nexus-staging-maven-plugin
- 1.6.8
- true
-
- ossrh
- https://oss.sonatype.org/
- true
-
-
-
-
-
-
+
+ com.owlike
+ genson
+ test
+
+
+ junit
+ junit
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+ org.apache.logging.log4j
+ log4j-core
+ test
+
+
+ org.apache.logging.log4j
+ log4j-jul
+ test
+
+
+ org.apache.logging.log4j
+ log4j-jcl
+ test
+
+
+ com.google.code.gson
+ gson
+
+
+ org.bitbucket.b_c
+ jose4j
+
+
+
+
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.13
+
+
+ jakarta.servlet
+ jakarta.servlet-api
+ 6.0.0
+
+
+ com.owlike
+ genson
+ 1.6
+
+
+ org.bitbucket.b_c
+ jose4j
+ 0.9.6
+
+
+ junit
+ junit
+ 4.13.2
+
+
+ org.mockito
+ mockito-core
+ 3.10.0
+ test
+
+
+ org.apache.logging.log4j
+ log4j-bom
+ 2.14.1
+ import
+ pom
+
+
+ com.google.code.gson
+ gson
+ 2.10
+
+
+
+
+
+
+ release
+
+
+ ossrh
+ https://oss.sonatype.org/content/repositories/snapshots
+
+
+ ossrh
+
+ https://oss.sonatype.org/service/local/staging/deploy/maven2/
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 3.3.1
+
+
+ attach-sources
+
+ jar-no-fork
+
+
+
+
+
+ ${project.groupId}.${project.artifactId}.source
+ ${project.version}
+ ${project.groupId}.${project.artifactId};version="${project.version}";roots:="."
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 3.3.0
+
+
+ attach-javadocs
+
+ jar
+
+
+
+
+ 17
+
+
+
+ org.apache.maven.plugins
+ maven-gpg-plugin
+ 3.0.1
+
+
+ sign-artifacts
+ verify
+
+ sign
+
+
+
+
+
+ org.sonatype.plugins
+ nexus-staging-maven-plugin
+ 1.6.8
+ true
+
+ ossrh
+ https://oss.sonatype.org/
+ true
+
+
+
+
+
+
diff --git a/readme.md b/readme.md
index 058d418..ac01cc3 100644
--- a/readme.md
+++ b/readme.md
@@ -3,6 +3,7 @@
[](https://curity.io/resources/code-examples/status/)
[](https://curity.io/resources/code-examples/status/)
+
This project contains a Servlet Filter that authenticates and authorizes requests using OAuth access tokens of various kinds. There are two `OAuthFilter` implementations. `OAuthJwtFilter` and `OAuthOpaqueFilter`. Both implement `jakarta.servlet.Filter`, and can be used to protect APIs built using Java. Depending on the format of the access token, these two concrete implementations can be used in the following manner:
1. If the token is a Json Web Token (JWT) then validate the token using a public key
@@ -11,6 +12,19 @@ This project contains a Servlet Filter that authenticates and authorizes request
An example of how to use this filter can be found in a [separate repository](https://github.com/curityio/example-java-oauth-protected-api).
+# FORK INFO
+
+This is a fork of the original repo https://github.com/curityio/oauth-filter-for-java
+
+It upgrades to version 5 with the following - breaking - changes
+
+* Fully move to `jakarta.servlet` namespace
+* Change JSON parser to `com.google.gson`
+* Update some dependent libraries
+* Generate OSGi capable `META-INF/MANIFEST.MF`
+* Fix some build warnings
+* The value in JWT `aud` now accepts arrays, as the configured `audience` can be one of multiple allowed
+
## Filter Overview
The filter is build to perform two tasks.
diff --git a/src/main/java/io/curity/oauth/AbstractJwtValidator.java b/src/main/java/io/curity/oauth/AbstractJwtValidator.java
index da2a4f1..0c4de6d 100644
--- a/src/main/java/io/curity/oauth/AbstractJwtValidator.java
+++ b/src/main/java/io/curity/oauth/AbstractJwtValidator.java
@@ -16,10 +16,6 @@
package io.curity.oauth;
-import javax.json.JsonObject;
-import javax.json.JsonReader;
-import javax.json.JsonReaderFactory;
-import java.io.StringReader;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.PublicKey;
@@ -28,226 +24,198 @@
import java.time.Instant;
import java.util.Base64;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
+import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
-abstract class AbstractJwtValidator implements JwtValidator
-{
- private static final Logger _logger = Logger.getLogger(AbstractJwtValidator.class.getName());
-
- // Caches with object scope that will ensure that we only decode the same JWT parts once per the lifetime of this
- // object
- private final Map _decodedJwtBodyByEncodedBody = new HashMap<>(1);
- private final Map _decodedJwtHeaderByEncodedHeader = new HashMap<>(1);
- private final JsonReaderFactory _jsonReaderFactory;
- private final String _audience;
- private final String _issuer;
-
- AbstractJwtValidator(String issuer, String audience, JsonReaderFactory jsonReaderFactory)
- {
- _issuer = issuer;
- _audience = audience;
- _jsonReaderFactory = jsonReaderFactory;
- }
-
- public final JsonData validate(String jwt) throws TokenValidationException
- {
- String[] jwtParts = jwt.split("\\.");
-
- if (jwtParts.length != 3)
- {
- throw new InvalidTokenFormatException();
- }
-
- JsonObject jwtBody = decodeJwtBody(jwtParts[1]);
- JwtHeader jwtHeader = decodeJwtHeader(jwtParts[0]);
- byte[] jwtSignature = Base64.getUrlDecoder().decode(jwtParts[2]);
- byte[] headerAndPayload = convertToBytes(jwtParts[0] + "." + jwtParts[1]);
-
- validateSignature(jwtHeader, jwtSignature, headerAndPayload);
-
- try
- {
- long exp = JsonUtils.getLong(jwtBody, "exp");
- long iat = JsonUtils.getLong(jwtBody, "iat");
-
- String aud = JsonUtils.getString(jwtBody, "aud");
- String iss = JsonUtils.getString(jwtBody, "iss");
-
- assert aud != null && aud.length() > 0 : "aud claim is not present in JWT";
- assert iss != null && iss.length() > 0 : "iss claim is not present in JWT";
-
- if (!aud.equals(_audience))
- {
- throw new InvalidAudienceException(_audience, aud);
- }
-
- if (!iss.equals(_issuer))
- {
- throw new InvalidIssuerException(_issuer, iss);
- }
-
- Instant now = Instant.now();
-
- if (now.getEpochSecond() > exp)
- {
- throw new ExpiredTokenException();
- }
-
- if (now.getEpochSecond() < iat)
- {
- throw new InvalidIssuanceInstantException();
- }
- }
- catch (Exception e)
- {
- _logger.log(Level.INFO, "Could not extract token data", e);
-
- throw new InvalidTokenFormatException("Failed to extract data from Token");
- }
-
- return new JsonData(jwtBody);
- }
-
- private void validateSignature(JwtHeader jwtHeader, byte[] jwtSignatureData,
- byte[] headerAndPayload)
- throws TokenValidationException
- {
- String algorithm = jwtHeader.getAlgorithm();
-
- if (algorithm == null || algorithm.length() <= 0)
- {
- throw new MissingAlgorithmException();
- }
-
- if (canRecognizeAlg(algorithm))
- {
- Optional signatureVerificationKey = getPublicKey(jwtHeader);
-
- if (signatureVerificationKey.isEmpty())
- {
- _logger.warning("Received token but could not find matching key");
-
- throw new UnknownSignatureVerificationKey();
- }
-
- if (!verifySignature(algorithm, headerAndPayload, jwtSignatureData, signatureVerificationKey.get()))
- {
- throw new InvalidSignatureException();
- }
- }
- else
- {
- _logger.warning(() -> String.format("Requested JsonWebKey using unrecognizable alg: %s", algorithm));
-
- throw new UnknownAlgorithmException(algorithm);
- }
- }
-
- protected abstract Optional getPublicKey(JwtHeader jwtHeader);
-
- /**
- * Convert base64 to bytes (ASCII)
- *
- * @param input input
- * @return The array of bytes
- */
- private byte[] convertToBytes(String input)
- {
- byte[] bytes = new byte[input.length()];
-
- for (int i = 0; i < input.length(); i++)
- {
- //Convert and treat as ascii.
- int integer = input.charAt(i);
-
- //Since byte is signed in Java we cannot use normal conversion
- //but must drop it into a byte array and truncate.
- byte[] rawBytes = ByteBuffer.allocate(4).putInt(integer).array();
- //Only store the least significant byte (the others should be 0 TODO check)
- bytes[i] = rawBytes[3];
- }
-
- return bytes;
- }
-
- private boolean verifySignature(String algorithm, byte[] signingInput, byte[] signature, PublicKey publicKey)
- {
- try
- {
- Signature verifier = switch (algorithm) {
- case "RS256" -> Signature.getInstance("SHA256withRSA");
- case "EdDSA" -> Signature.getInstance(((EdECPublicKey) publicKey).getParams().getName());
- default -> throw new UnknownAlgorithmException(String.format("Unsupported signature algorithm '%s'", algorithm));
- };
-
- verifier.initVerify(publicKey);
- verifier.update(signingInput);
-
- return verifier.verify(signature);
- }
- catch (Exception e)
- {
- throw new RuntimeException("Unable to validate JWT signature", e);
- }
- }
-
- private boolean canRecognizeAlg(String alg)
- {
- return switch (alg) {
- case "RS256", "EdDSA" -> true;
- default -> false;
- };
- }
-
- private JsonObject decodeJwtBody(String body)
- {
- return _decodedJwtBodyByEncodedBody.computeIfAbsent(body, key ->
- {
- // TODO: Switch to stream
- String decodedBody = new String(Base64.getUrlDecoder().decode(body), StandardCharsets.UTF_8);
- JsonReader jsonBodyReader = _jsonReaderFactory.createReader(new StringReader(decodedBody));
-
- return jsonBodyReader.readObject();
- });
- }
-
- private JwtHeader decodeJwtHeader(String header)
- {
- return _decodedJwtHeaderByEncodedHeader.computeIfAbsent(header, key ->
- {
- Base64.Decoder base64 = Base64.getDecoder();
- String decodedHeader = new String(base64.decode(header), StandardCharsets.UTF_8);
- JsonReader jsonHeaderReader = _jsonReaderFactory.createReader(new StringReader(decodedHeader));
-
- return new JwtHeader(jsonHeaderReader.readObject());
- });
- }
-
- class JwtHeader
- {
- private final JsonObject _jsonObject;
-
- JwtHeader(JsonObject jsonObject)
- {
- _jsonObject = jsonObject;
- }
-
- String getAlgorithm()
- {
- return getString("alg");
- }
-
- String getKeyId()
- {
- return getString("kid");
- }
-
- String getString(String name)
- {
- return JsonUtils.getString(_jsonObject, name);
- }
- }
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonObject;
+
+abstract class AbstractJwtValidator implements JwtValidator {
+ private static final Logger _logger = Logger.getLogger(AbstractJwtValidator.class.getName());
+
+ // Caches with object scope that will ensure that we only decode the same JWT
+ // parts once per the lifetime of this
+ // object
+ private final Map _decodedJwtBodyByEncodedBody = new HashMap<>(1);
+ private final Map _decodedJwtHeaderByEncodedHeader = new HashMap<>(1);
+ private final Gson gson = new GsonBuilder().create();
+ private final String _audience;
+ private final String _issuer;
+
+ AbstractJwtValidator(String issuer, String audience) {
+ _issuer = issuer;
+ _audience = audience;
+ }
+
+ public final JsonData validate(String jwt) throws TokenValidationException {
+ String[] jwtParts = jwt.split("\\.");
+
+ if (jwtParts.length != 3) {
+ throw new InvalidTokenFormatException();
+ }
+
+ JsonObject jwtBody = decodeJwtBody(jwtParts[1]);
+ JwtHeader jwtHeader = decodeJwtHeader(jwtParts[0]);
+ byte[] jwtSignature = Base64.getUrlDecoder().decode(jwtParts[2]);
+ byte[] headerAndPayload = convertToBytes(jwtParts[0] + "." + jwtParts[1]);
+
+ validateSignature(jwtHeader, jwtSignature, headerAndPayload);
+
+ try {
+ long exp = JsonUtils.getLong(jwtBody, "exp");
+ long iat = JsonUtils.getLong(jwtBody, "iat");
+
+ Set aud = new HashSet();
+ String _aud = JsonUtils.getString(jwtBody, "aud");
+ Optional.ofNullable(_aud).ifPresent(aud::add);
+ aud.addAll(JsonUtils.getStringSet(jwtBody, "aud"));
+
+ String iss = JsonUtils.getString(jwtBody, "iss");
+
+ assert !aud.isEmpty() : "aud claim is not present in JWT";
+ assert iss != null && iss.length() > 0 : "iss claim is not present in JWT";
+
+ if (!aud.contains(_audience)) {
+ throw new InvalidAudienceException(_audience, aud.toString());
+ }
+
+ if (!iss.equals(_issuer)) {
+ throw new InvalidIssuerException(_issuer, iss);
+ }
+
+ Instant now = Instant.now();
+
+ if (now.getEpochSecond() > exp) {
+ throw new ExpiredTokenException();
+ }
+
+ if (now.getEpochSecond() < iat) {
+ throw new InvalidIssuanceInstantException();
+ }
+ } catch (Exception e) {
+ _logger.log(Level.INFO, "Could not extract token data", e);
+
+ throw new InvalidTokenFormatException("Failed to extract data from Token");
+ }
+
+ return new JsonData(jwtBody);
+ }
+
+ private void validateSignature(JwtHeader jwtHeader, byte[] jwtSignatureData, byte[] headerAndPayload)
+ throws TokenValidationException {
+ String algorithm = jwtHeader.getAlgorithm();
+
+ if (algorithm == null || algorithm.length() <= 0) {
+ throw new MissingAlgorithmException();
+ }
+
+ if (canRecognizeAlg(algorithm)) {
+ Optional signatureVerificationKey = getPublicKey(jwtHeader);
+
+ if (signatureVerificationKey.isEmpty()) {
+ _logger.warning("Received token but could not find matching key");
+
+ throw new UnknownSignatureVerificationKey();
+ }
+
+ if (!verifySignature(algorithm, headerAndPayload, jwtSignatureData, signatureVerificationKey.get())) {
+ throw new InvalidSignatureException();
+ }
+ } else {
+ _logger.warning(() -> String.format("Requested JsonWebKey using unrecognizable alg: %s", algorithm));
+
+ throw new UnknownAlgorithmException(algorithm);
+ }
+ }
+
+ protected abstract Optional getPublicKey(JwtHeader jwtHeader);
+
+ /**
+ * Convert base64 to bytes (ASCII)
+ *
+ * @param input input
+ * @return The array of bytes
+ */
+ private byte[] convertToBytes(String input) {
+ byte[] bytes = new byte[input.length()];
+
+ for (int i = 0; i < input.length(); i++) {
+ // Convert and treat as ascii.
+ int integer = input.charAt(i);
+
+ // Since byte is signed in Java we cannot use normal conversion
+ // but must drop it into a byte array and truncate.
+ byte[] rawBytes = ByteBuffer.allocate(4).putInt(integer).array();
+ // Only store the least significant byte (the others should be 0 TODO check)
+ bytes[i] = rawBytes[3];
+ }
+
+ return bytes;
+ }
+
+ private boolean verifySignature(String algorithm, byte[] signingInput, byte[] signature, PublicKey publicKey) {
+ try {
+ Signature verifier = switch (algorithm) {
+ case "RS256" -> Signature.getInstance("SHA256withRSA");
+ case "EdDSA" -> Signature.getInstance(((EdECPublicKey) publicKey).getParams().getName());
+ default ->
+ throw new UnknownAlgorithmException(String.format("Unsupported signature algorithm '%s'", algorithm));
+ };
+
+ verifier.initVerify(publicKey);
+ verifier.update(signingInput);
+
+ return verifier.verify(signature);
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to validate JWT signature", e);
+ }
+ }
+
+ private boolean canRecognizeAlg(String alg) {
+ return switch (alg) {
+ case "RS256", "EdDSA" -> true;
+ default -> false;
+ };
+ }
+
+ private JsonObject decodeJwtBody(String body) {
+ return _decodedJwtBodyByEncodedBody.computeIfAbsent(body, key -> {
+ // TODO: Switch to stream
+ String decodedBody = new String(Base64.getUrlDecoder().decode(body), StandardCharsets.UTF_8);
+ return gson.fromJson(decodedBody, JsonObject.class);
+ });
+ }
+
+ private JwtHeader decodeJwtHeader(String header) {
+ return _decodedJwtHeaderByEncodedHeader.computeIfAbsent(header, key -> {
+ Base64.Decoder base64 = Base64.getDecoder();
+ String decodedHeader = new String(base64.decode(header), StandardCharsets.UTF_8);
+ return new JwtHeader(gson.fromJson(decodedHeader, JsonObject.class));
+ });
+ }
+
+ class JwtHeader {
+ private final JsonObject _jsonObject;
+
+ JwtHeader(JsonObject jsonObject) {
+ _jsonObject = jsonObject;
+ }
+
+ String getAlgorithm() {
+ return getString("alg");
+ }
+
+ String getKeyId() {
+ return getString("kid");
+ }
+
+ String getString(String name) {
+ return JsonUtils.getString(_jsonObject, name);
+ }
+ }
}
diff --git a/src/main/java/io/curity/oauth/AuthenticatedUser.java b/src/main/java/io/curity/oauth/AuthenticatedUser.java
index e37d9cb..0cd4632 100644
--- a/src/main/java/io/curity/oauth/AuthenticatedUser.java
+++ b/src/main/java/io/curity/oauth/AuthenticatedUser.java
@@ -16,52 +16,46 @@
package io.curity.oauth;
-import javax.json.JsonObject;
-import javax.json.JsonValue;
import java.util.Objects;
import java.util.Set;
-public class AuthenticatedUser
-{
- private final String _sub;
- private final Set _scopes;
- private final JsonData _jsonData;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
- private AuthenticatedUser(String subject, Set scopes, JsonData jsonData)
- {
- _sub = subject;
- _scopes = scopes;
- _jsonData = jsonData;
- }
+public class AuthenticatedUser {
+ private final String _sub;
+ private final Set _scopes;
+ private final JsonData _jsonData;
- public String getSubject()
- {
- return _sub;
- }
+ private AuthenticatedUser(String subject, Set scopes, JsonData jsonData) {
+ _sub = subject;
+ _scopes = scopes;
+ _jsonData = jsonData;
+ }
- public Set getScopes()
- {
- return _scopes;
- }
+ public String getSubject() {
+ return _sub;
+ }
- public JsonValue getClaim(String name)
- {
- return _jsonData.getClaim(name);
- }
+ public Set getScopes() {
+ return _scopes;
+ }
- public JsonObject getClaims()
- {
- return _jsonData.getClaims();
- }
+ public JsonElement getClaim(String name) {
+ return _jsonData.getClaim(name);
+ }
- static AuthenticatedUser from(JsonData tokenData)
- {
- Objects.requireNonNull(tokenData);
+ public JsonObject getClaims() {
+ return _jsonData.getClaims();
+ }
- String subject = tokenData.getSubject();
+ static AuthenticatedUser from(JsonData tokenData) {
+ Objects.requireNonNull(tokenData);
- Objects.requireNonNull(subject);
+ String subject = tokenData.getSubject();
- return new AuthenticatedUser(subject, tokenData.getScopes(), tokenData);
- }
+ Objects.requireNonNull(subject);
+
+ return new AuthenticatedUser(subject, tokenData.getScopes(), tokenData);
+ }
}
diff --git a/src/main/java/io/curity/oauth/AuthenticatedUserRequestWrapper.java b/src/main/java/io/curity/oauth/AuthenticatedUserRequestWrapper.java
index 0174b28..5349557 100644
--- a/src/main/java/io/curity/oauth/AuthenticatedUserRequestWrapper.java
+++ b/src/main/java/io/curity/oauth/AuthenticatedUserRequestWrapper.java
@@ -16,12 +16,13 @@
package io.curity.oauth;
+import java.io.IOException;
+import java.security.Principal;
+
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import jakarta.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.security.Principal;
class AuthenticatedUserRequestWrapper extends HttpServletRequestWrapper
{
@@ -31,7 +32,6 @@ class AuthenticatedUserRequestWrapper extends HttpServletRequestWrapper
* @see RFC 6750 - The OAuth 2.0 Authorization Framework: Bearer
* Token Usage
*/
- @SuppressWarnings("WeakerAccess")
public static final String OAUTH_AUTH = "OAUTH";
private final HttpServletRequest _request;
diff --git a/src/main/java/io/curity/oauth/JsonData.java b/src/main/java/io/curity/oauth/JsonData.java
index 86ae62a..5f35527 100644
--- a/src/main/java/io/curity/oauth/JsonData.java
+++ b/src/main/java/io/curity/oauth/JsonData.java
@@ -1,70 +1,46 @@
-/*
- * Copyright (C) 2017 Curity AB.
- *
- * Licensed 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 io.curity.oauth;
-import javax.json.JsonObject;
-import javax.json.JsonValue;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
import java.time.Instant;
import java.util.Set;
-public class JsonData implements Expirable
-{
+public class JsonData implements Expirable {
private final JsonObject _jsonObject;
private final Set _scopes;
- JsonData(JsonObject jsonObject)
- {
+ JsonData(JsonObject jsonObject) {
_jsonObject = jsonObject;
_scopes = JsonUtils.getScopes(jsonObject);
}
- JsonObject getJsonObject()
- {
+ JsonObject getJsonObject() {
return _jsonObject;
}
- public String getSubject()
- {
+ public String getSubject() {
return JsonUtils.getString(_jsonObject, "sub");
}
- public Set getScopes()
- {
+ public Set getScopes() {
return _scopes;
}
- public Set getClaimNames()
- {
+ public Set getClaimNames() {
return _jsonObject.keySet();
}
- public JsonObject getClaims()
- {
+ public JsonObject getClaims() {
return _jsonObject;
}
- public JsonValue getClaim(String claimName)
- {
+ public JsonElement getClaim(String claimName) {
return _jsonObject.get(claimName);
}
@Override
- public Instant getExpiresAt()
- {
+ public Instant getExpiresAt() {
return Instant.ofEpochSecond(JsonUtils.getLong(_jsonObject, "exp"));
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/io/curity/oauth/JsonUtils.java b/src/main/java/io/curity/oauth/JsonUtils.java
index 800bce3..69f5c7b 100644
--- a/src/main/java/io/curity/oauth/JsonUtils.java
+++ b/src/main/java/io/curity/oauth/JsonUtils.java
@@ -1,67 +1,45 @@
-/*
- * Copyright (C) 2017 Curity AB.
- *
- * Licensed 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 io.curity.oauth;
-import javax.json.JsonNumber;
-import javax.json.JsonObject;
-import javax.json.JsonReaderFactory;
-import javax.json.JsonString;
-import javax.json.JsonValue;
-import javax.json.spi.JsonProvider;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
-
-final class JsonUtils
-{
- private static final String[] NO_SCOPES = {};
-
- private JsonUtils()
- {
- }
-
- static JsonReaderFactory createDefaultReaderFactory()
- {
- return JsonProvider.provider().createReaderFactory(Collections.emptyMap());
- }
-
- static Set getScopes(JsonObject jsonObject)
- {
- String scopesInToken = getString(jsonObject, "scope");
- String[] presentedScopes = scopesInToken == null ? NO_SCOPES : scopesInToken.split("\\s+");
-
- return Collections.unmodifiableSet(new HashSet<>(Arrays.asList(presentedScopes)));
- }
-
- static String getString(JsonObject jsonObject, String name)
- {
- return Optional.ofNullable(jsonObject.get(name))
- .filter(it -> it.getValueType() == JsonValue.ValueType.STRING)
- .map(it -> ((JsonString) it).getString())
- .orElse(null);
- }
-
- static long getLong(JsonObject jsonObject, String name)
- {
- return Optional.ofNullable(jsonObject.get(name))
- .filter(it -> it.getValueType() == JsonValue.ValueType.NUMBER)
- .map(it -> ((JsonNumber) it).longValue())
- .orElse(Long.MIN_VALUE);
- }
-}
+import java.util.stream.Collectors;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+final class JsonUtils {
+ private static final String[] NO_SCOPES = {};
+
+ private JsonUtils() {
+ }
+
+ static Set getScopes(JsonObject jsonObject) {
+ String scopesInToken = getString(jsonObject, "scope");
+ String[] presentedScopes = scopesInToken == null ? NO_SCOPES : scopesInToken.split("\\s+");
+
+ return Collections.unmodifiableSet(new HashSet<>(Arrays.asList(presentedScopes)));
+ }
+
+ static String getString(JsonObject jsonObject, String name) {
+ return Optional.ofNullable(jsonObject.get(name)).filter(JsonElement::isJsonPrimitive)
+ .map(it -> it.getAsJsonPrimitive().getAsString()).orElse(null);
+ }
+
+ static Set getStringSet(JsonObject jsonObject, String name) {
+ JsonArray array = Optional.ofNullable(jsonObject.get(name)).filter(JsonElement::isJsonArray)
+ .map(it -> it.getAsJsonArray()).orElse(null);
+ if (array != null) {
+ return array.asList().stream().map(it -> it.getAsString()).collect(Collectors.toSet());
+ }
+ return Collections.emptySet();
+ }
+
+ static long getLong(JsonObject jsonObject, String name) {
+ return Optional.ofNullable(jsonObject.get(name)).filter(JsonElement::isJsonPrimitive)
+ .map(it -> it.getAsJsonPrimitive().getAsLong()).orElse(Long.MIN_VALUE);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/curity/oauth/JsonWebKey.java b/src/main/java/io/curity/oauth/JsonWebKey.java
index 7ae67ca..7778973 100644
--- a/src/main/java/io/curity/oauth/JsonWebKey.java
+++ b/src/main/java/io/curity/oauth/JsonWebKey.java
@@ -16,76 +16,59 @@
package io.curity.oauth;
-import javax.json.JsonObject;
-import javax.json.JsonString;
-import javax.json.JsonValue;
-import java.util.Optional;
-
-class JsonWebKey
-{
- private final JsonObject _jsonObject;
-
- private JsonWebKeyType _keyType;
-
- JsonWebKey(JsonObject jsonObject)
- {
- _jsonObject = jsonObject;
-
- JsonValue jsonValue = jsonObject.get("kty");
-
- _keyType = JsonWebKeyType.from(jsonValue);
- }
-
- String getKeyId()
- {
- return getString("kid");
- }
-
- JsonWebKeyType getKeyType()
- {
- return _keyType;
- }
-
- String getUse()
- {
- return getString("use");
- }
-
- String getXCoordinate()
- {
- return getString("x");
- }
-
- String getYCoordinate()
- {
- return getString("y");
- }
-
- String getEllipticalCurve()
- {
- return getString("crv");
- }
-
- String getModulus()
- {
- return getString("n");
- }
-
- String getExponent()
- {
- return getString("e");
- }
-
- String getAlgorithm()
- {
- return getString("alg");
- }
-
- private String getString(String name)
- {
- return Optional.ofNullable(_jsonObject.get(name))
- .filter(it -> it.getValueType() == JsonValue.ValueType.STRING)
- .map(it -> ((JsonString) it).getString())
- .orElse(null);
- }
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+class JsonWebKey {
+ private final JsonObject _jsonObject;
+
+ private JsonWebKeyType _keyType;
+
+ JsonWebKey(JsonObject jsonObject) {
+ _jsonObject = jsonObject;
+
+ JsonElement jsonValue = jsonObject.get("kty");
+
+ _keyType = JsonWebKeyType.from(jsonValue);
+ }
+
+ String getKeyId() {
+ return getString("kid");
+ }
+
+ JsonWebKeyType getKeyType() {
+ return _keyType;
+ }
+
+ String getUse() {
+ return getString("use");
+ }
+
+ String getXCoordinate() {
+ return getString("x");
+ }
+
+ String getYCoordinate() {
+ return getString("y");
+ }
+
+ String getEllipticalCurve() {
+ return getString("crv");
+ }
+
+ String getModulus() {
+ return getString("n");
+ }
+
+ String getExponent() {
+ return getString("e");
+ }
+
+ String getAlgorithm() {
+ return getString("alg");
+ }
+
+ private String getString(String name) {
+ return _jsonObject.get(name).getAsString();
+ }
}
diff --git a/src/main/java/io/curity/oauth/JsonWebKeyNotFoundException.java b/src/main/java/io/curity/oauth/JsonWebKeyNotFoundException.java
index 2f4f722..a757d42 100644
--- a/src/main/java/io/curity/oauth/JsonWebKeyNotFoundException.java
+++ b/src/main/java/io/curity/oauth/JsonWebKeyNotFoundException.java
@@ -20,7 +20,9 @@
class JsonWebKeyNotFoundException extends IOException
{
- JsonWebKeyNotFoundException(String msg)
+ private static final long serialVersionUID = 6941054254935232366L;
+
+ JsonWebKeyNotFoundException(String msg)
{
super(msg);
}
diff --git a/src/main/java/io/curity/oauth/JsonWebKeyType.java b/src/main/java/io/curity/oauth/JsonWebKeyType.java
index 9d80050..2567a04 100644
--- a/src/main/java/io/curity/oauth/JsonWebKeyType.java
+++ b/src/main/java/io/curity/oauth/JsonWebKeyType.java
@@ -16,49 +16,39 @@
package io.curity.oauth;
-import javax.json.JsonString;
-import javax.json.JsonValue;
import java.util.logging.Logger;
-enum JsonWebKeyType {
- EC("EC"),
- OCT("oct"),
- OKP("OKP"),
- RSA("RSA"),
- UNSPECIFIED("UNSPECIFIED");
-
- private static final Logger _logger = Logger.getLogger(JsonWebKeyType.class.getName());
- String name;
-
- JsonWebKeyType(String name) {
- this.name = name;
- }
-
- static JsonWebKeyType from(JsonValue value) {
- if (value == null || value.toString().length() == 0) {
- return UNSPECIFIED;
- }
-
- if (value.getValueType() != JsonValue.ValueType.STRING) {
- _logger.warning(() -> String.format("Value '%s' is not a string, as required; it is %s",
- value, value.getValueType()));
- }
+import com.google.gson.JsonElement;
- switch (((JsonString) value).getString()) {
- case "RSA":
- return RSA;
- case "EC":
- return EC;
- case "OKP":
- return OKP;
- case "oct":
- return OCT;
- default:
-
- _logger.warning(() -> String.format("Unknown enumeration value '%s' given.", value));
-
- throw new IllegalArgumentException("value");
- }
- }
+enum JsonWebKeyType {
+ EC("EC"), OCT("oct"), OKP("OKP"), RSA("RSA"), UNSPECIFIED("UNSPECIFIED");
+
+ private static final Logger _logger = Logger.getLogger(JsonWebKeyType.class.getName());
+ String name;
+
+ JsonWebKeyType(String name) {
+ this.name = name;
+ }
+
+ static JsonWebKeyType from(JsonElement value) {
+ if (value == null || value.toString().length() == 0) {
+ return UNSPECIFIED;
+ }
+
+ switch (value.getAsString()) {
+ case "RSA":
+ return RSA;
+ case "EC":
+ return EC;
+ case "OKP":
+ return OKP;
+ case "oct":
+ return OCT;
+ default:
+
+ _logger.warning(() -> String.format("Unknown enumeration value '%s' given.", value));
+
+ throw new IllegalArgumentException("value");
+ }
+ }
}
-
diff --git a/src/main/java/io/curity/oauth/JwkManager.java b/src/main/java/io/curity/oauth/JwkManager.java
index 808a65e..0821fbb 100644
--- a/src/main/java/io/curity/oauth/JwkManager.java
+++ b/src/main/java/io/curity/oauth/JwkManager.java
@@ -16,12 +16,8 @@
package io.curity.oauth;
-import javax.json.JsonObject;
-import javax.json.JsonReader;
-import javax.json.JsonReaderFactory;
import java.io.Closeable;
import java.io.IOException;
-import java.io.StringReader;
import java.time.Duration;
import java.time.Instant;
import java.util.Collections;
@@ -33,102 +29,89 @@
import java.util.logging.Level;
import java.util.logging.Logger;
-final class JwkManager implements Closeable
-{
- private static final Logger _logger = Logger.getLogger(JwkManager.class.getName());
- private static final String ACCEPT = "Accept";
-
- private final TimeBasedCache _jsonWebKeyByKID;
- private final WebKeysClient _webKeysClient;
- private final ScheduledExecutorService _executor = Executors.newSingleThreadScheduledExecutor();
- private final JsonReaderFactory _jsonReaderFactory;
-
- JwkManager(long minKidReloadTimeInSeconds, WebKeysClient webKeysClient, JsonReaderFactory jsonReaderFactory)
- {
- _jsonWebKeyByKID = new TimeBasedCache<>(Duration.ofSeconds(minKidReloadTimeInSeconds), this::reload);
- _webKeysClient = webKeysClient;
- _jsonReaderFactory = jsonReaderFactory;
-
- // invalidate the cache periodically to avoid stale state
- _executor.scheduleAtFixedRate(this::ensureCacheIsFresh, 5, 15, TimeUnit.MINUTES);
- }
-
- /**
- * checks if the JsonWebKey exists in the local cached, otherwise this
- * method will call the JsonWebKeyService to get the new keys.
- *
- * @param keyId keyId
- * @return JsonWebKey
- */
- JsonWebKey getJsonWebKeyForKeyId(String keyId) throws JsonWebKeyNotFoundException
- {
- JsonWebKey key = _jsonWebKeyByKID.get(keyId);
-
- if (key != null)
- {
- return key;
- }
-
- throw new JsonWebKeyNotFoundException("Json Web Key does not exist: keyid=" + keyId);
- }
-
- private Map reload()
- {
- Map newKeys = new HashMap<>();
-
- try
- {
- JwksResponse response = parseJwksResponse(_webKeysClient.getKeys());
-
- for (JsonWebKey key : response.getKeys())
- {
- newKeys.put(key.getKeyId(), key);
- }
-
- _logger.info(() -> String.format("Fetched JsonWebKeys: %s", newKeys));
-
- return Collections.unmodifiableMap(newKeys);
- }
- catch (IOException e)
- {
- _logger.log(Level.SEVERE, "Could not contact JWKS Server", e);
-
- return Collections.emptyMap();
- }
- }
-
- private JwksResponse parseJwksResponse(String response)
- {
- JsonReader jsonReader = _jsonReaderFactory.createReader(new StringReader(response));
- JsonObject jsonObject = jsonReader.readObject();
-
- return new JwksResponse(jsonObject);
- }
-
- private void ensureCacheIsFresh()
- {
- _logger.info("Called ensureCacheIsFresh");
-
- Instant lastLoading = _jsonWebKeyByKID.getLastReloadInstant().orElse(Instant.MIN);
- boolean cacheIsNotFresh = lastLoading.isBefore(Instant.now()
- .minus(_jsonWebKeyByKID.getMinTimeBetweenReloads()));
-
- if (cacheIsNotFresh)
- {
- _logger.info("Invalidating JSON WebKeyID cache");
-
- _jsonWebKeyByKID.clear();
- }
- }
-
- @Override
- public void close() throws IOException
- {
- _executor.shutdown();
-
- if (_webKeysClient instanceof Closeable)
- {
- ((Closeable) _webKeysClient).close();
- }
- }
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+
+final class JwkManager implements Closeable {
+ private static final Logger _logger = Logger.getLogger(JwkManager.class.getName());
+
+ private final TimeBasedCache _jsonWebKeyByKID;
+ private final WebKeysClient _webKeysClient;
+ private final ScheduledExecutorService _executor = Executors.newSingleThreadScheduledExecutor();
+ private final Gson _gson;
+
+ JwkManager(long minKidReloadTimeInSeconds, WebKeysClient webKeysClient, Gson gson) {
+ _gson = gson;
+ _jsonWebKeyByKID = new TimeBasedCache<>(Duration.ofSeconds(minKidReloadTimeInSeconds), this::reload);
+ _webKeysClient = webKeysClient;
+
+ // invalidate the cache periodically to avoid stale state
+ _executor.scheduleAtFixedRate(this::ensureCacheIsFresh, 5, 15, TimeUnit.MINUTES);
+ }
+
+ /**
+ * checks if the JsonWebKey exists in the local cached, otherwise this method
+ * will call the JsonWebKeyService to get the new keys.
+ *
+ * @param keyId keyId
+ * @return JsonWebKey
+ */
+ JsonWebKey getJsonWebKeyForKeyId(String keyId) throws JsonWebKeyNotFoundException {
+ JsonWebKey key = _jsonWebKeyByKID.get(keyId);
+
+ if (key != null) {
+ return key;
+ }
+
+ throw new JsonWebKeyNotFoundException("Json Web Key does not exist: keyid=" + keyId);
+ }
+
+ private Map reload() {
+ Map newKeys = new HashMap<>();
+
+ try {
+ JwksResponse response = parseJwksResponse(_webKeysClient.getKeys());
+
+ for (JsonWebKey key : response.getKeys()) {
+ newKeys.put(key.getKeyId(), key);
+ }
+
+ _logger.info(() -> String.format("Fetched JsonWebKeys: %s", newKeys));
+
+ return Collections.unmodifiableMap(newKeys);
+ } catch (IOException e) {
+ _logger.log(Level.SEVERE, "Could not contact JWKS Server", e);
+
+ return Collections.emptyMap();
+ }
+ }
+
+ private JwksResponse parseJwksResponse(String response) {
+ JsonObject jsonObject = _gson.fromJson(response, JsonObject.class);
+
+ return new JwksResponse(jsonObject);
+ }
+
+ private void ensureCacheIsFresh() {
+ _logger.info("Called ensureCacheIsFresh");
+
+ Instant lastLoading = _jsonWebKeyByKID.getLastReloadInstant().orElse(Instant.MIN);
+ boolean cacheIsNotFresh = lastLoading
+ .isBefore(Instant.now().minus(_jsonWebKeyByKID.getMinTimeBetweenReloads()));
+
+ if (cacheIsNotFresh) {
+ _logger.info("Invalidating JSON WebKeyID cache");
+
+ _jsonWebKeyByKID.clear();
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ _executor.shutdown();
+
+ if (_webKeysClient instanceof Closeable) {
+ ((Closeable) _webKeysClient).close();
+ }
+ }
}
diff --git a/src/main/java/io/curity/oauth/JwksResponse.java b/src/main/java/io/curity/oauth/JwksResponse.java
index 64d1c0b..2b547eb 100644
--- a/src/main/java/io/curity/oauth/JwksResponse.java
+++ b/src/main/java/io/curity/oauth/JwksResponse.java
@@ -1,51 +1,28 @@
-/*
- * Copyright (C) 2016 Curity AB.
- *
- * Licensed 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 io.curity.oauth;
-import javax.json.JsonObject;
-import javax.json.JsonValue;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
-class JwksResponse
-{
- private final List _keys;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
- JwksResponse(JsonObject jsonObject)
- {
- JsonValue keys = jsonObject.get("keys");
+class JwksResponse {
+ private final List _keys;
- if (keys.getValueType() != JsonValue.ValueType.ARRAY)
- {
- _keys = Collections.emptyList();
- }
- else
- {
- _keys = keys.asJsonArray().stream()
- .filter(it -> it.getValueType() == JsonValue.ValueType.OBJECT)
- .map(JsonValue::asJsonObject)
- .map(JsonWebKey::new)
- .collect(Collectors.toList());
- }
- }
+ JwksResponse(JsonObject jsonObject) {
+ JsonElement keys = jsonObject.get("keys");
- List getKeys()
- {
- return _keys;
- }
+ if (!keys.isJsonArray()) {
+ _keys = Collections.emptyList();
+ } else {
+ _keys = keys.getAsJsonArray().asList().stream().filter(it -> it.isJsonObject())
+ .map(JsonElement::getAsJsonObject).map(JsonWebKey::new).collect(Collectors.toList());
+ }
+ }
+
+ List getKeys() {
+ return _keys;
+ }
}
diff --git a/src/main/java/io/curity/oauth/JwtValidatorWithCert.java b/src/main/java/io/curity/oauth/JwtValidatorWithCert.java
index 35db2b8..ddfe0ee 100644
--- a/src/main/java/io/curity/oauth/JwtValidatorWithCert.java
+++ b/src/main/java/io/curity/oauth/JwtValidatorWithCert.java
@@ -16,34 +16,22 @@
package io.curity.oauth;
-import javax.json.JsonReaderFactory;
import java.security.PublicKey;
import java.util.Map;
import java.util.Optional;
-import java.util.logging.Logger;
-final class JwtValidatorWithCert extends AbstractJwtValidator
-{
- private static final Logger _logger = Logger.getLogger(JwtValidatorWithCert.class.getName());
+final class JwtValidatorWithCert extends AbstractJwtValidator {
- private final Map _keys;
+ private final Map _keys;
- JwtValidatorWithCert(String issuer, String audience, Map publicKeys)
- {
- this(issuer, audience, publicKeys, JsonUtils.createDefaultReaderFactory());
- }
+ JwtValidatorWithCert(String issuer, String audience, Map publicKeys) {
+ super(issuer, audience);
- JwtValidatorWithCert(String issuer, String audience, Map publicKeys,
- JsonReaderFactory jsonReaderFactory)
- {
- super(issuer, audience, jsonReaderFactory);
-
- _keys = publicKeys;
- }
+ _keys = publicKeys;
+ }
- @Override
- protected Optional getPublicKey(JwtHeader jwtHeader)
- {
- return Optional.ofNullable(_keys.get(jwtHeader.getString("x5t#S256")));
- }
+ @Override
+ protected Optional getPublicKey(JwtHeader jwtHeader) {
+ return Optional.ofNullable(_keys.get(jwtHeader.getString("x5t#S256")));
+ }
}
diff --git a/src/main/java/io/curity/oauth/JwtValidatorWithJwk.java b/src/main/java/io/curity/oauth/JwtValidatorWithJwk.java
index 8260a6a..12789d7 100644
--- a/src/main/java/io/curity/oauth/JwtValidatorWithJwk.java
+++ b/src/main/java/io/curity/oauth/JwtValidatorWithJwk.java
@@ -16,7 +16,6 @@
package io.curity.oauth;
-import javax.json.JsonReaderFactory;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
@@ -25,68 +24,63 @@
import java.util.logging.Level;
import java.util.logging.Logger;
-final class JwtValidatorWithJwk extends AbstractJwtValidator
-{
- private static final Logger _logger = Logger.getLogger(JwtValidatorWithJwk.class.getName());
+import com.google.gson.Gson;
- private final JwkManager _jwkManager;
+final class JwtValidatorWithJwk extends AbstractJwtValidator {
+ private static final Logger _logger = Logger.getLogger(JwtValidatorWithJwk.class.getName());
- JwtValidatorWithJwk(long minKidReloadTime, WebKeysClient webKeysClient, String audience, String issuer,
- JsonReaderFactory jsonReaderFactory)
- {
- super(issuer, audience, jsonReaderFactory);
-
- _jwkManager = new JwkManager(minKidReloadTime, webKeysClient, jsonReaderFactory);
- }
+ private final JwkManager _jwkManager;
- @Override
- protected Optional getPublicKey(JwtHeader jwtHeader)
- {
- Optional result = Optional.empty();
+ JwtValidatorWithJwk(long minKidReloadTime, WebKeysClient webKeysClient, String audience, String issuer, Gson gson) {
+ super(issuer, audience);
- try
- {
- JsonWebKey jsonWebKeyType = _jwkManager.getJsonWebKeyForKeyId(jwtHeader.getKeyId());
+ _jwkManager = new JwkManager(minKidReloadTime, webKeysClient, gson);
+ }
- switch (jsonWebKeyType.getKeyType()) {
- case RSA :
- result = Optional.of(RsaPublicKeyCreator.createPublicKey(jsonWebKeyType.getModulus(),
- jsonWebKeyType.getExponent()));
- break;
- case OKP :
- if (isEdDSAKey(jsonWebKeyType)) {
- result = Optional.of(EdDSAPublicKeyCreator.createPublicKey(jsonWebKeyType.getEllipticalCurve(), jsonWebKeyType.getXCoordinate()));
- } else {
- throw new NoSuchAlgorithmException(String.format("Unsupported curve %s for key %s", jsonWebKeyType.getEllipticalCurve(), jsonWebKeyType.getKeyId()));
- }
- break;
- case EC :
- case OCT :
- default:
- throw new NoSuchAlgorithmException(String.format("Unsupported key type %s for key %s", jsonWebKeyType.getKeyType(), jsonWebKeyType.getKeyId()));
- }
- }
- catch (JsonWebKeyNotFoundException e)
- {
- // this is not a very exceptional occurrence, so let's not log a stack-trace
- _logger.info(() -> String.format("Could not find requested JsonWebKey: %s", e));
- }
- catch (NoSuchAlgorithmException | InvalidKeySpecException e)
- {
- _logger.log(Level.WARNING, "Could not create public key", e);
- }
+ @Override
+ protected Optional getPublicKey(JwtHeader jwtHeader) {
+ Optional result = Optional.empty();
- return result;
- }
+ try {
+ JsonWebKey jsonWebKeyType = _jwkManager.getJsonWebKeyForKeyId(jwtHeader.getKeyId());
- private boolean isEdDSAKey(JsonWebKey jsonWebKey) {
- String curve = jsonWebKey.getEllipticalCurve();
- return curve != null && (curve.equals("Ed25519") || curve.equals("Ed448"));
- }
+ switch (jsonWebKeyType.getKeyType()) {
+ case RSA:
+ result = Optional.of(
+ RsaPublicKeyCreator.createPublicKey(jsonWebKeyType.getModulus(), jsonWebKeyType.getExponent()));
+ break;
+ case OKP:
+ if (isEdDSAKey(jsonWebKeyType)) {
+ result = Optional.of(EdDSAPublicKeyCreator.createPublicKey(jsonWebKeyType.getEllipticalCurve(),
+ jsonWebKeyType.getXCoordinate()));
+ } else {
+ throw new NoSuchAlgorithmException(String.format("Unsupported curve %s for key %s",
+ jsonWebKeyType.getEllipticalCurve(), jsonWebKeyType.getKeyId()));
+ }
+ break;
+ case EC:
+ case OCT:
+ default:
+ throw new NoSuchAlgorithmException(String.format("Unsupported key type %s for key %s",
+ jsonWebKeyType.getKeyType(), jsonWebKeyType.getKeyId()));
+ }
+ } catch (JsonWebKeyNotFoundException e) {
+ // this is not a very exceptional occurrence, so let's not log a stack-trace
+ _logger.info(() -> String.format("Could not find requested JsonWebKey: %s", e));
+ } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
+ _logger.log(Level.WARNING, "Could not create public key", e);
+ }
- @Override
- public void close() throws IOException
- {
- _jwkManager.close();
- }
+ return result;
+ }
+
+ private boolean isEdDSAKey(JsonWebKey jsonWebKey) {
+ String curve = jsonWebKey.getEllipticalCurve();
+ return curve != null && (curve.equals("Ed25519") || curve.equals("Ed448"));
+ }
+
+ @Override
+ public void close() throws IOException {
+ _jwkManager.close();
+ }
}
diff --git a/src/main/java/io/curity/oauth/OAuthIntrospectResponse.java b/src/main/java/io/curity/oauth/OAuthIntrospectResponse.java
index effa3f7..d664935 100644
--- a/src/main/java/io/curity/oauth/OAuthIntrospectResponse.java
+++ b/src/main/java/io/curity/oauth/OAuthIntrospectResponse.java
@@ -16,24 +16,20 @@
package io.curity.oauth;
-import javax.json.JsonObject;
+import com.google.gson.JsonObject;
-class OAuthIntrospectResponse
-{
- private final JsonObject _jsonObject;
+class OAuthIntrospectResponse {
+ private final JsonObject _jsonObject;
- OAuthIntrospectResponse(JsonObject jsonObject)
- {
- _jsonObject = jsonObject;
- }
+ OAuthIntrospectResponse(JsonObject jsonObject) {
+ _jsonObject = jsonObject;
+ }
- boolean isActive()
- {
- return _jsonObject.getBoolean("active");
- }
+ boolean isActive() {
+ return _jsonObject.get("active").getAsBoolean();
+ }
- JsonObject getJsonObject()
- {
- return _jsonObject;
- }
+ JsonObject getJsonObject() {
+ return _jsonObject;
+ }
}
diff --git a/src/main/java/io/curity/oauth/OAuthJwtFilter.java b/src/main/java/io/curity/oauth/OAuthJwtFilter.java
index b574cf7..60d5817 100644
--- a/src/main/java/io/curity/oauth/OAuthJwtFilter.java
+++ b/src/main/java/io/curity/oauth/OAuthJwtFilter.java
@@ -16,13 +16,15 @@
package io.curity.oauth;
-import javax.json.JsonReaderFactory;
-import javax.json.spi.JsonProvider;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.UnavailableException;
-import java.util.Map;
-import java.util.logging.Logger;
public class OAuthJwtFilter extends OAuthFilter
{
@@ -69,13 +71,13 @@ protected TokenValidator createTokenValidator(Map filterConfig) throw
// Pass all of the filter's config to the ReaderFactory factory method. It'll ignore anything it doesn't
// understand (per JSR 353). This way, clients can change the provider using the service locator and configure
// the ReaderFactory using the filter's config.
- JsonReaderFactory jsonReaderFactory = JsonProvider.provider().createReaderFactory(filterConfig);
+ Gson gson = new GsonBuilder().create();
WebKeysClient webKeysClient = HttpClientProvider.provider().createWebKeysClient(filterConfig);
String audience = FilterHelper.getInitParamValue(InitParams.AUDIENCE, filterConfig);
String issuer = FilterHelper.getInitParamValue(InitParams.ISSUER, filterConfig);
return _jwtValidator = new JwtValidatorWithJwk(_minKidReloadTimeInSeconds, webKeysClient, audience, issuer,
- jsonReaderFactory);
+ gson);
}
@Override
diff --git a/src/main/java/io/curity/oauth/OAuthOpaqueFilter.java b/src/main/java/io/curity/oauth/OAuthOpaqueFilter.java
index f09f724..7510f44 100644
--- a/src/main/java/io/curity/oauth/OAuthOpaqueFilter.java
+++ b/src/main/java/io/curity/oauth/OAuthOpaqueFilter.java
@@ -16,60 +16,51 @@
package io.curity.oauth;
-import javax.json.JsonReaderFactory;
-import javax.json.spi.JsonProvider;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import com.google.gson.Gson;
+
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.UnavailableException;
-import java.util.Map;
-import java.util.logging.Logger;
-public class OAuthOpaqueFilter extends OAuthFilter
-{
- private static final Logger _logger = Logger.getLogger(OAuthOpaqueFilter.class.getName());
+public class OAuthOpaqueFilter extends OAuthFilter {
+ private static final Logger _logger = Logger.getLogger(OAuthOpaqueFilter.class.getName());
- private TokenValidator _opaqueTokenValidator = null;
+ private TokenValidator _opaqueTokenValidator = null;
- private interface InitParams
- {
- String SCOPE = "scope";
- }
+ private interface InitParams {
+ String SCOPE = "scope";
+ }
- @Override
- public void init(FilterConfig filterConfig) throws ServletException
- {
- super.init(filterConfig);
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ super.init(filterConfig);
- synchronized (this)
- {
- if (_opaqueTokenValidator == null)
- {
- _opaqueTokenValidator = createTokenValidator(getFilterConfiguration());
+ synchronized (this) {
+ if (_opaqueTokenValidator == null) {
+ _opaqueTokenValidator = createTokenValidator(getFilterConfiguration());
- _logger.info(() -> String.format("%s successfully initialized", OAuthFilter.class.getSimpleName()));
- }
- else
- {
- _logger.warning("Attempted to set introspect URI more than once! Ignoring further attempts.");
- }
- }
- }
+ _logger.info(() -> String.format("%s successfully initialized", OAuthFilter.class.getSimpleName()));
+ } else {
+ _logger.warning("Attempted to set introspect URI more than once! Ignoring further attempts.");
+ }
+ }
+ }
- @Override
- protected TokenValidator getTokenValidator()
- {
- return _opaqueTokenValidator;
- }
+ @Override
+ protected TokenValidator getTokenValidator() {
+ return _opaqueTokenValidator;
+ }
- @Override
- protected TokenValidator createTokenValidator(Map initParams) throws UnavailableException
- {
- // Like in the OAuthJwtFilter, we'll reuse the config of this filter + the service locator to
- // get a JsonReaderFactory
- JsonReaderFactory jsonReaderFactory = JsonProvider.provider().createReaderFactory(initParams);
- IntrospectionClient introspectionClient = HttpClientProvider.provider()
- .createIntrospectionClient(initParams);
+ @Override
+ protected TokenValidator createTokenValidator(Map initParams) throws UnavailableException {
+ // Like in the OAuthJwtFilter, we'll reuse the config of this filter + the
+ // service locator to
+ // get a JsonReaderFactory
+ IntrospectionClient introspectionClient = HttpClientProvider.provider().createIntrospectionClient(initParams);
- return new OpaqueTokenValidator(introspectionClient, jsonReaderFactory);
- }
+ return new OpaqueTokenValidator(introspectionClient, new Gson());
+ }
}
diff --git a/src/main/java/io/curity/oauth/OpaqueTokenValidator.java b/src/main/java/io/curity/oauth/OpaqueTokenValidator.java
index e50c88c..df232e0 100644
--- a/src/main/java/io/curity/oauth/OpaqueTokenValidator.java
+++ b/src/main/java/io/curity/oauth/OpaqueTokenValidator.java
@@ -16,86 +16,69 @@
package io.curity.oauth;
-import javax.json.JsonObject;
-import javax.json.JsonReader;
-import javax.json.JsonReaderFactory;
import java.io.Closeable;
import java.io.IOException;
-import java.io.StringReader;
import java.time.Instant;
import java.util.Optional;
-public class OpaqueTokenValidator implements Closeable, TokenValidator
-{
- private final IntrospectionClient _introspectionClient;
- private final ExpirationBasedCache _tokenCache;
- private final JsonReaderFactory _jsonReaderFactory;
-
- OpaqueTokenValidator(IntrospectionClient introspectionClient, JsonReaderFactory jsonReaderFactory)
- {
- _introspectionClient = introspectionClient;
- _tokenCache = new ExpirationBasedCache<>();
- _jsonReaderFactory = jsonReaderFactory;
- }
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
- public JsonData validate(String token) throws TokenValidationException
- {
- Optional cachedValue = _tokenCache.get(token);
+public class OpaqueTokenValidator implements Closeable, TokenValidator {
+ private final IntrospectionClient _introspectionClient;
+ private final ExpirationBasedCache _tokenCache;
+ private final Gson _gson;
- if (cachedValue.isPresent())
- {
- return cachedValue.get();
- }
+ OpaqueTokenValidator(IntrospectionClient introspectionClient, Gson gson) {
+ _introspectionClient = introspectionClient;
+ _tokenCache = new ExpirationBasedCache<>();
+ _gson = gson;
+ }
- String introspectJson;
+ public JsonData validate(String token) throws TokenValidationException {
+ Optional cachedValue = _tokenCache.get(token);
- try
- {
- introspectJson = _introspectionClient.introspect(token);
- }
- catch (Exception e)
- {
- // TODO: Add logging
- throw new TokenValidationException("Failed to introspect token", e);
- }
+ if (cachedValue.isPresent()) {
+ return cachedValue.get();
+ }
- OAuthIntrospectResponse response = parseIntrospectResponse(introspectJson);
+ String introspectJson;
- if (response.isActive())
- {
- JsonData newToken = new JsonData(response.getJsonObject());
+ try {
+ introspectJson = _introspectionClient.introspect(token);
+ } catch (Exception e) {
+ // TODO: Add logging
+ throw new TokenValidationException("Failed to introspect token", e);
+ }
- if (newToken.getExpiresAt().isAfter(Instant.now()))
- {
- //Note: If this cache is backed by some persistent storage, the token should be hashed and not stored
- // in clear text
- _tokenCache.put(token, newToken);
+ OAuthIntrospectResponse response = parseIntrospectResponse(introspectJson);
- return newToken;
- }
- else
- {
- throw new ExpiredTokenException();
- }
- }
- else
- {
- throw new RevokedTokenException();
- }
- }
+ if (response.isActive()) {
+ JsonData newToken = new JsonData(response.getJsonObject());
- private OAuthIntrospectResponse parseIntrospectResponse(String introspectJson)
- {
- JsonReader jsonReader = _jsonReaderFactory.createReader(new StringReader(introspectJson));
- JsonObject jsonObject = jsonReader.readObject();
+ if (newToken.getExpiresAt().isAfter(Instant.now())) {
+ // Note: If this cache is backed by some persistent storage, the token should be
+ // hashed and not stored
+ // in clear text
+ _tokenCache.put(token, newToken);
- return new OAuthIntrospectResponse(jsonObject);
- }
+ return newToken;
+ } else {
+ throw new ExpiredTokenException();
+ }
+ } else {
+ throw new RevokedTokenException();
+ }
+ }
- @Override
- public void close() throws IOException
- {
- _introspectionClient.close();
- _tokenCache.clear();
- }
+ private OAuthIntrospectResponse parseIntrospectResponse(String introspectJson) {
+ JsonObject jsonObject = _gson.fromJson(introspectJson, JsonObject.class);
+ return new OAuthIntrospectResponse(jsonObject);
+ }
+
+ @Override
+ public void close() throws IOException {
+ _introspectionClient.close();
+ _tokenCache.clear();
+ }
}
diff --git a/src/main/java/io/curity/oauth/TokenValidationException.java b/src/main/java/io/curity/oauth/TokenValidationException.java
index 7015fff..0327f46 100644
--- a/src/main/java/io/curity/oauth/TokenValidationException.java
+++ b/src/main/java/io/curity/oauth/TokenValidationException.java
@@ -1,5 +1,4 @@
/*
- * Copyright (C) 2017 Curity AB.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +17,9 @@
public class TokenValidationException extends Exception
{
- public TokenValidationException(String msg)
+ private static final long serialVersionUID = 2986832328622504264L;
+
+ public TokenValidationException(String msg)
{
super(msg);
}
diff --git a/src/test/java/io/curity/oauth/AuthenticatedUserRequestWrapperTest.java b/src/test/java/io/curity/oauth/AuthenticatedUserRequestWrapperTest.java
index 3daafae..0779f3a 100644
--- a/src/test/java/io/curity/oauth/AuthenticatedUserRequestWrapperTest.java
+++ b/src/test/java/io/curity/oauth/AuthenticatedUserRequestWrapperTest.java
@@ -16,22 +16,23 @@
package io.curity.oauth;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Collection;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
-import javax.json.Json;
-import javax.json.JsonObject;
+import com.google.gson.JsonObject;
+
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
-import java.util.Arrays;
-import java.util.Collection;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
public class AuthenticatedUserRequestWrapperTest
{
@@ -39,7 +40,8 @@ public class AuthenticatedUserRequestWrapperTest
public void testCanAuthenticate() throws Exception
{
// GIVEN: an authenticated user
- JsonObject json = Json.createObjectBuilder().add("sub", "test-user").build();
+ JsonObject json = new JsonObject();
+ json.addProperty("sub", "test-user");
JsonData jsonData = new JsonData(json);
AuthenticatedUser user = AuthenticatedUser.from(jsonData);
diff --git a/src/test/java/io/curity/oauth/JwtWithCertTest.java b/src/test/java/io/curity/oauth/JwtWithCertTest.java
index 60004f2..521ffa2 100644
--- a/src/test/java/io/curity/oauth/JwtWithCertTest.java
+++ b/src/test/java/io/curity/oauth/JwtWithCertTest.java
@@ -16,16 +16,12 @@
package io.curity.oauth;
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
-import javax.json.JsonObject;
-import javax.json.JsonString;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
@@ -39,9 +35,17 @@
import java.util.HashMap;
import java.util.Map;
-import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertNotNull;
-import static junit.framework.TestCase.assertTrue;
+
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
@RunWith(Parameterized.class)
public class JwtWithCertTest
@@ -108,7 +112,7 @@ public void testFindAndValidateWithOneCert() throws Exception
assertNotNull(validatedToken);
}
-
+
@Test
public void testValidContentInToken() throws Exception
{
@@ -122,12 +126,29 @@ public void testValidContentInToken() throws Exception
JsonObject jsonObject = result.getJsonObject();
- assertTrue(jsonObject.containsKey("sub"));
- assertTrue(jsonObject.containsKey(EXTRA_CLAIM));
+ assertTrue(jsonObject.keySet().contains("sub"));
+ assertTrue(jsonObject.keySet().contains(EXTRA_CLAIM));
- assertEquals(SUBJECT, ((JsonString) jsonObject.get("sub")).getString());
- assertEquals(EXTRA_CLAIM_VALUE, ((JsonString) jsonObject.get(EXTRA_CLAIM)).getString());
+ assertEquals(SUBJECT, jsonObject.get("sub").getAsString());
+ assertEquals(EXTRA_CLAIM_VALUE, jsonObject.get(EXTRA_CLAIM).getAsString());
}
+
+ @Test
+ public void testValidContentInTokenAudienceArray() throws Exception {
+ JwtTokenIssuer issuer = new JwtTokenIssuer(ISSUER, _algorithm, getPrivateKey(), getCertificate());
+ Map attributes = new HashMap<>();
+ attributes.put(EXTRA_CLAIM, EXTRA_CLAIM_VALUE);
+ _testToken = issuer.issueToken(SUBJECT, AUDIENCE+" bar:audience", EXPIRATION, attributes);
+
+ JwtValidator validator = new JwtValidatorWithCert(ISSUER, AUDIENCE, prepareKeyMap());
+
+ _logger.info("test token = {}", _testToken);
+
+ JsonData validatedToken = validator.validate(_testToken);
+
+ assertNotNull(validatedToken);
+
+ }
/**
* Load the private Keymap with the x5t256 thumbprint and the public key
diff --git a/src/test/java/io/curity/oauth/JwtWithJwksTest.java b/src/test/java/io/curity/oauth/JwtWithJwksTest.java
index 5e59676..a457e01 100644
--- a/src/test/java/io/curity/oauth/JwtWithJwksTest.java
+++ b/src/test/java/io/curity/oauth/JwtWithJwksTest.java
@@ -16,17 +16,12 @@
package io.curity.oauth;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
-import javax.json.JsonObject;
-import javax.json.JsonReaderFactory;
-import javax.json.JsonString;
-import javax.json.spi.JsonProvider;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
@@ -36,154 +31,171 @@
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.interfaces.EdECPrivateKey;
-import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
-import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertNotNull;
-import static junit.framework.TestCase.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
@RunWith(Parameterized.class)
-public class JwtWithJwksTest
-{
- private static final Logger _logger = LogManager.getLogger(JwtWithJwksTest.class);
-
- private final String SUBJECT = "testsubject";
- private final String AUDIENCE = "foo:audience";
- private final String ISSUER = "test:issuer";
- private final int EXPIRATION = 200;
- private final String EXTRA_CLAIM = "TEST_KEY";
- private final String EXTRA_CLAIM_VALUE = "TEST_VALUE";
-
- // Used for signing tokens
- private final String PATH_TO_KEY = "/Se.Curity.Test.p12";
- private final String KEY_PWD = "Password1";
-
- private String _testToken;
- private KeyStore _keyStore;
-
- @Parameterized.Parameter()
- public String _keyAlias;
-
- @Parameterized.Parameter(1)
- public String _algorithm;
-
- @Parameterized.Parameter(2)
- public String _keyId;
-
- @Parameterized.Parameters
- public static Object[] keysToTest() {
- return new Object[][] { {"se.curity.test", "RS256", "-38074812"}, {"se.curity.test.ed25519", "EdDSA", "-1909572257"}, {"se.curity.test.ed448", "EdDSA", "1716999904"} };
- }
-
- @Before
- public void before() throws Exception
- {
- loadKeyStore();
-
- PrivateKey key = getPrivateKey();
-
- if (!_algorithm.equals("EdDSA")) {
- // Create test token on the fly
- JwtTokenIssuer issuer = new JwtTokenIssuer(ISSUER, _algorithm, key, _keyId);
- Map attributes = new HashMap<>();
- attributes.put(EXTRA_CLAIM, EXTRA_CLAIM_VALUE);
- _testToken = issuer.issueToken(SUBJECT, AUDIENCE, EXPIRATION, attributes);
- } else {
- // Use hardcoded values until jose4j supports EdDSA
- String curveName = ((EdECPrivateKey) key).getParams().getName();
- if ("Ed25519".equals(curveName)) {
- _testToken ="eyJraWQiOiItMTkwOTU3MjI1NyIsIng1dCI6IlNIZDRIQ1VkQThISlZHTTJVV3o1Tm1JUFRHMCIsIng1dCNTMjU2IjoiS0lZVnBHXzVXSnh0ZUdOUTVLR043M0xlQWNHS0w4MmMyWFhaR0M5RUNKVSIsImFsZyI6IkVkRFNBIn0.eyJqdGkiOiJlMzE2YjBmOS1mN2JlLTQ3M2QtOGMzNi05NGMwNzRlMjMzNjEiLCJkZWxlZ2F0aW9uSWQiOiIzZDE2NzM5Ni02NGEzLTQ2MmYtOGMyZS02MzdhYzM0NzdkMTMiLCJleHAiOjE5Njg0MDkwNzMsIm5iZiI6MTY1MzA0OTA3Mywic2NvcGUiOiJyZWFkIG9wZW5pZCIsImlzcyI6InRlc3Q6aXNzdWVyIiwic3ViIjoidGVzdHN1YmplY3QiLCJhdWQiOiJmb286YXVkaWVuY2UiLCJpYXQiOjE2NTMwNDkwNzMsInB1cnBvc2UiOiJhY2Nlc3NfdG9rZW4iLCJURVNUX0tFWSI6IlRFU1RfVkFMVUUifQ.NGWCDwzCPOx50-WBJRqKFvPy2562rqFjNS3Q9zmJqNhdxtZK3s7g7JWtgI_AwnJBnaPeC1ATMYyxKjionwzQAA";
- } else {
- _testToken ="eyJraWQiOiIxNzE2OTk5OTA0IiwieDV0IjoiMUlSVEJMTFFlaUwyWVpMQjFWRER2Q1RHb3pjIiwieDV0I1MyNTYiOiJTbGVDbTlwRVI5a2ZiTjBYeGlqa1g4MmdyR0hUYXhOTkNCRHNUMHR1M3lBIiwiYWxnIjoiRWREU0EifQ.eyJqdGkiOiIyNjNiNmM2OS02NTExLTQ5YjktYWVlYi0yY2JkOGMyMGE3NGUiLCJkZWxlZ2F0aW9uSWQiOiIwY2NjZmMyZi1mY2EzLTRlOGQtOTgxYy05ZjU5MzIyNmYyNTEiLCJleHAiOjE5Njg0MDg5NzUsIm5iZiI6MTY1MzA0ODk3NSwic2NvcGUiOiJyZWFkIG9wZW5pZCIsImlzcyI6InRlc3Q6aXNzdWVyIiwic3ViIjoidGVzdHN1YmplY3QiLCJhdWQiOiJmb286YXVkaWVuY2UiLCJpYXQiOjE2NTMwNDg5NzUsInB1cnBvc2UiOiJhY2Nlc3NfdG9rZW4iLCJURVNUX0tFWSI6IlRFU1RfVkFMVUUifQ.2gcRnLTFnCsdkElgcecSjxvrKA3bKAFuUf5vhVapdLqxZvx6E1BblTzjaVjqy3OT0OzdN3p1q5kApJ5EjVUT0tdjHVxZMBtkosviYM5EL2UkJO_T3tA-on7h0lfcufxnhd_TUOlM_YTkJxFGSkOtLg4A";
- }
- }
- }
-
- @Test
- public void testFindAndValidateWithOneJwk() throws Exception
- {
- JsonReaderFactory jsonReaderFactory = JsonProvider.provider().createReaderFactory(Collections.emptyMap());
- WebKeysClient webKeysClient = mock(WebKeysClient.class);
-
- JwtValidatorWithJwk validator = new JwtValidatorWithJwk(0, webKeysClient, AUDIENCE, ISSUER,jsonReaderFactory);
- when(webKeysClient.getKeys()).thenReturn(prepareKeyMap().get(_keyId));
- _logger.info("test token = {}", _testToken);
-
- JsonData validatedToken = validator.validate(_testToken);
-
- assertNotNull(validatedToken);
- }
-
- @Test
- public void testValidContentInToken() throws Exception
- {
- JsonReaderFactory jsonReaderFactory = JsonProvider.provider().createReaderFactory(Collections.emptyMap());
- WebKeysClient webKeysClient = mock(WebKeysClient.class);
-
- JwtValidatorWithJwk validator = new JwtValidatorWithJwk(0, webKeysClient, AUDIENCE, ISSUER,jsonReaderFactory);
- when(webKeysClient.getKeys()).thenReturn(prepareKeyMap().get(_keyId));
- _logger.info("test token = {}", _testToken);
-
- JsonData result = validator.validate(_testToken);
-
- _logger.info("test token = {}", _testToken);
-
- assertNotNull(result);
-
- JsonObject jsonObject = result.getJsonObject();
-
- assertTrue(jsonObject.containsKey("sub"));
- assertTrue(jsonObject.containsKey(EXTRA_CLAIM));
-
- assertEquals(SUBJECT, ((JsonString) jsonObject.get("sub")).getString());
- assertEquals(EXTRA_CLAIM_VALUE, ((JsonString) jsonObject.get(EXTRA_CLAIM)).getString());
- }
-
- /**
- * Load the private keymap with the kid and the jwks
- * The map only contains a single key
- * @return a map with a single entry representing a JWKS that contains the key with the keyid
- */
- private Map prepareKeyMap()
- {
- Map keys = new HashMap<>();
-
- keys.put("-38074812","{\"keys\":[{\"kty\":\"RSA\",\"kid\":\"-38074812\",\"use\":\"sig\",\"alg\":\"RS256\",\"n\":\"yMAHZiIfbAgmZJ-_4Gj-wdS8rvaKNBbnHz_krmd-kkX51bA1EsUc0CN672-xnUb_-E_-u_GoWhJzdjiBuz9XasSfQK8WyAwbc7MLkw40A7Zxl2sfsxGTod3qi1u8mjguoc9CbVqPdYe_9YPVxoK4CeJz6V8AsPcxVJxYq6os1rI9qFx_6a1JdQEhetGtkHLFvwo80UTzKXKhGXSu96WrXnkDE8Kw5TSKvh2gI_BX4QHXjE82xldJRJ8QIXGpRNbdyzGkUdjsrhmZl3ARC9IUlxmowkcEEIzjfbOKBVGrVcJ7rHb0GYNaKtMB_MlH1uAPDxl6qKeXOAZ8YEZ1r0ToPw\",\"e\":\"AQAB\",\"x5t\":\"MR-pGTa866RdZLjN6Vwrfay907g\"}]}");
- keys.put("-1909572257", "{\"keys\":[{\"kty\":\"OKP\",\"kid\":\"-1909572257\",\"use\":\"sig\",\"alg\":\"EdDSA\",\"crv\":\"Ed25519\",\"x\":\"XWxGtApfcqmKI7p0OKnF5JSEWMVoLsytFXLEP7xZ_l8\",\"x5t\":\"SHd4HCUdA8HJVGM2UWz5NmIPTG0\"}]}");
- keys.put("1716999904","{\"keys\":[{\"kty\":\"OKP\",\"kid\":\"1716999904\",\"use\":\"sig\",\"alg\":\"EdDSA\",\"crv\":\"Ed448\",\"x\":\"lDc565Rydl9MUCoOB9JpGV3pUSHm7FvuiuEMvrvRkS7PeYL41rPU6s2rMdLeHiXfSxvR1veh4C0A\",\"x5t\":\"1IRTBLLQeiL2YZLB1VDDvCTGozc\"}]}");
- return keys;
- }
-
- private void loadKeyStore()
- throws Exception
- {
- URL url = getClass().getResource(PATH_TO_KEY);
- assert url != null;
- File certFile = new File(url.getFile());
-
- InputStream keyIS = new FileInputStream(certFile);
- KeyStore keyStore = KeyStore.getInstance("PKCS12");
- keyStore.load(keyIS, KEY_PWD.toCharArray());
-
- keyIS.close();
-
- this._keyStore=keyStore;
- }
-
- private PrivateKey getPrivateKey()
- throws Exception
- {
- return (PrivateKey)this._keyStore.getKey(_keyAlias, KEY_PWD.toCharArray());
-
- }
-
- private Certificate getCertificate() throws KeyStoreException {
- //Get key by alias (found in the p12 file using:
- //keytool -list -keystore test-root-ca.p12 -storepass foobar -storetype PKCS12
- return this._keyStore.getCertificate(_keyAlias);
- }
+public class JwtWithJwksTest {
+ private static final Logger _logger = LogManager.getLogger(JwtWithJwksTest.class);
+
+ private final String SUBJECT = "testsubject";
+ private final String AUDIENCE = "foo:audience";
+ private final String ISSUER = "test:issuer";
+ private final int EXPIRATION = 200;
+ private final String EXTRA_CLAIM = "TEST_KEY";
+ private final String EXTRA_CLAIM_VALUE = "TEST_VALUE";
+
+ // Used for signing tokens
+ private final String PATH_TO_KEY = "/Se.Curity.Test.p12";
+ private final String KEY_PWD = "Password1";
+
+ private String _testToken;
+ private KeyStore _keyStore;
+
+ @Parameterized.Parameter()
+ public String _keyAlias;
+
+ @Parameterized.Parameter(1)
+ public String _algorithm;
+
+ @Parameterized.Parameter(2)
+ public String _keyId;
+
+ @Parameterized.Parameters
+ public static Object[] keysToTest() {
+ return new Object[][] { { "se.curity.test", "RS256", "-38074812" },
+ { "se.curity.test.ed25519", "EdDSA", "-1909572257" },
+ { "se.curity.test.ed448", "EdDSA", "1716999904" } };
+ }
+
+ @Before
+ public void before() throws Exception {
+ loadKeyStore();
+
+ PrivateKey key = getPrivateKey();
+
+ if (!_algorithm.equals("EdDSA")) {
+ // Create test token on the fly
+ JwtTokenIssuer issuer = new JwtTokenIssuer(ISSUER, _algorithm, key, _keyId);
+ Map attributes = new HashMap<>();
+ attributes.put(EXTRA_CLAIM, EXTRA_CLAIM_VALUE);
+ _testToken = issuer.issueToken(SUBJECT, AUDIENCE, EXPIRATION, attributes);
+ } else {
+ // Use hardcoded values until jose4j supports EdDSA
+ String curveName = ((EdECPrivateKey) key).getParams().getName();
+ if ("Ed25519".equals(curveName)) {
+ _testToken = "eyJraWQiOiItMTkwOTU3MjI1NyIsIng1dCI6IlNIZDRIQ1VkQThISlZHTTJVV3o1Tm1JUFRHMCIsIng1dCNTMjU2IjoiS0lZVnBHXzVXSnh0ZUdOUTVLR043M0xlQWNHS0w4MmMyWFhaR0M5RUNKVSIsImFsZyI6IkVkRFNBIn0.eyJqdGkiOiJlMzE2YjBmOS1mN2JlLTQ3M2QtOGMzNi05NGMwNzRlMjMzNjEiLCJkZWxlZ2F0aW9uSWQiOiIzZDE2NzM5Ni02NGEzLTQ2MmYtOGMyZS02MzdhYzM0NzdkMTMiLCJleHAiOjE5Njg0MDkwNzMsIm5iZiI6MTY1MzA0OTA3Mywic2NvcGUiOiJyZWFkIG9wZW5pZCIsImlzcyI6InRlc3Q6aXNzdWVyIiwic3ViIjoidGVzdHN1YmplY3QiLCJhdWQiOiJmb286YXVkaWVuY2UiLCJpYXQiOjE2NTMwNDkwNzMsInB1cnBvc2UiOiJhY2Nlc3NfdG9rZW4iLCJURVNUX0tFWSI6IlRFU1RfVkFMVUUifQ.NGWCDwzCPOx50-WBJRqKFvPy2562rqFjNS3Q9zmJqNhdxtZK3s7g7JWtgI_AwnJBnaPeC1ATMYyxKjionwzQAA";
+ } else {
+ _testToken = "eyJraWQiOiIxNzE2OTk5OTA0IiwieDV0IjoiMUlSVEJMTFFlaUwyWVpMQjFWRER2Q1RHb3pjIiwieDV0I1MyNTYiOiJTbGVDbTlwRVI5a2ZiTjBYeGlqa1g4MmdyR0hUYXhOTkNCRHNUMHR1M3lBIiwiYWxnIjoiRWREU0EifQ.eyJqdGkiOiIyNjNiNmM2OS02NTExLTQ5YjktYWVlYi0yY2JkOGMyMGE3NGUiLCJkZWxlZ2F0aW9uSWQiOiIwY2NjZmMyZi1mY2EzLTRlOGQtOTgxYy05ZjU5MzIyNmYyNTEiLCJleHAiOjE5Njg0MDg5NzUsIm5iZiI6MTY1MzA0ODk3NSwic2NvcGUiOiJyZWFkIG9wZW5pZCIsImlzcyI6InRlc3Q6aXNzdWVyIiwic3ViIjoidGVzdHN1YmplY3QiLCJhdWQiOiJmb286YXVkaWVuY2UiLCJpYXQiOjE2NTMwNDg5NzUsInB1cnBvc2UiOiJhY2Nlc3NfdG9rZW4iLCJURVNUX0tFWSI6IlRFU1RfVkFMVUUifQ.2gcRnLTFnCsdkElgcecSjxvrKA3bKAFuUf5vhVapdLqxZvx6E1BblTzjaVjqy3OT0OzdN3p1q5kApJ5EjVUT0tdjHVxZMBtkosviYM5EL2UkJO_T3tA-on7h0lfcufxnhd_TUOlM_YTkJxFGSkOtLg4A";
+ }
+ }
+ }
+
+ @Test
+ public void testFindAndValidateWithOneJwk() throws Exception {
+ WebKeysClient webKeysClient = mock(WebKeysClient.class);
+
+ JwtValidatorWithJwk validator = new JwtValidatorWithJwk(0, webKeysClient, AUDIENCE, ISSUER, new Gson());
+ when(webKeysClient.getKeys()).thenReturn(prepareKeyMap().get(_keyId));
+ _logger.info("test token = {}", _testToken);
+
+ JsonData validatedToken = validator.validate(_testToken);
+
+ assertNotNull(validatedToken);
+ }
+
+ @Test
+ public void testValidContentInToken() throws Exception {
+ WebKeysClient webKeysClient = mock(WebKeysClient.class);
+
+ JwtValidatorWithJwk validator = new JwtValidatorWithJwk(0, webKeysClient, AUDIENCE, ISSUER, new Gson());
+ when(webKeysClient.getKeys()).thenReturn(prepareKeyMap().get(_keyId));
+ _logger.info("test token = {}", _testToken);
+
+ JsonData result = validator.validate(_testToken);
+
+ _logger.info("test token = {}", _testToken);
+
+ assertNotNull(result);
+
+ JsonObject jsonObject = result.getJsonObject();
+
+ assertTrue(jsonObject.keySet().contains("sub"));
+ assertTrue(jsonObject.keySet().contains(EXTRA_CLAIM));
+
+ assertEquals(SUBJECT, jsonObject.get("sub").getAsString());
+ assertEquals(EXTRA_CLAIM_VALUE, jsonObject.get(EXTRA_CLAIM).getAsString());
+ }
+
+ @Test
+ public void testValidContentInTokenAudienceArray() throws Exception {
+ JwtTokenIssuer issuer = new JwtTokenIssuer(ISSUER, _algorithm, getPrivateKey(), _keyId);
+ Map attributes = new HashMap<>();
+ attributes.put(EXTRA_CLAIM, EXTRA_CLAIM_VALUE);
+ _testToken = issuer.issueToken(SUBJECT, AUDIENCE+" bar:audience", EXPIRATION, attributes);
+
+ WebKeysClient webKeysClient = mock(WebKeysClient.class);
+
+ JwtValidatorWithJwk validator = new JwtValidatorWithJwk(0, webKeysClient, AUDIENCE, ISSUER, new Gson());
+ when(webKeysClient.getKeys()).thenReturn(prepareKeyMap().get(_keyId));
+ _logger.info("test token = {}", _testToken);
+
+ JsonData validatedToken = validator.validate(_testToken);
+
+ assertNotNull(validatedToken);
+ }
+
+ /**
+ * Load the private keymap with the kid and the jwks The map only contains a
+ * single key
+ *
+ * @return a map with a single entry representing a JWKS that contains the key
+ * with the keyid
+ */
+ private Map prepareKeyMap() {
+ Map keys = new HashMap<>();
+
+ keys.put("-38074812",
+ "{\"keys\":[{\"kty\":\"RSA\",\"kid\":\"-38074812\",\"use\":\"sig\",\"alg\":\"RS256\",\"n\":\"yMAHZiIfbAgmZJ-_4Gj-wdS8rvaKNBbnHz_krmd-kkX51bA1EsUc0CN672-xnUb_-E_-u_GoWhJzdjiBuz9XasSfQK8WyAwbc7MLkw40A7Zxl2sfsxGTod3qi1u8mjguoc9CbVqPdYe_9YPVxoK4CeJz6V8AsPcxVJxYq6os1rI9qFx_6a1JdQEhetGtkHLFvwo80UTzKXKhGXSu96WrXnkDE8Kw5TSKvh2gI_BX4QHXjE82xldJRJ8QIXGpRNbdyzGkUdjsrhmZl3ARC9IUlxmowkcEEIzjfbOKBVGrVcJ7rHb0GYNaKtMB_MlH1uAPDxl6qKeXOAZ8YEZ1r0ToPw\",\"e\":\"AQAB\",\"x5t\":\"MR-pGTa866RdZLjN6Vwrfay907g\"}]}");
+ keys.put("-1909572257",
+ "{\"keys\":[{\"kty\":\"OKP\",\"kid\":\"-1909572257\",\"use\":\"sig\",\"alg\":\"EdDSA\",\"crv\":\"Ed25519\",\"x\":\"XWxGtApfcqmKI7p0OKnF5JSEWMVoLsytFXLEP7xZ_l8\",\"x5t\":\"SHd4HCUdA8HJVGM2UWz5NmIPTG0\"}]}");
+ keys.put("1716999904",
+ "{\"keys\":[{\"kty\":\"OKP\",\"kid\":\"1716999904\",\"use\":\"sig\",\"alg\":\"EdDSA\",\"crv\":\"Ed448\",\"x\":\"lDc565Rydl9MUCoOB9JpGV3pUSHm7FvuiuEMvrvRkS7PeYL41rPU6s2rMdLeHiXfSxvR1veh4C0A\",\"x5t\":\"1IRTBLLQeiL2YZLB1VDDvCTGozc\"}]}");
+ return keys;
+ }
+
+ private void loadKeyStore() throws Exception {
+ URL url = getClass().getResource(PATH_TO_KEY);
+ assert url != null;
+ File certFile = new File(url.getFile());
+
+ InputStream keyIS = new FileInputStream(certFile);
+ KeyStore keyStore = KeyStore.getInstance("PKCS12");
+ keyStore.load(keyIS, KEY_PWD.toCharArray());
+
+ keyIS.close();
+
+ this._keyStore = keyStore;
+ }
+
+ private PrivateKey getPrivateKey() throws Exception {
+ return (PrivateKey) this._keyStore.getKey(_keyAlias, KEY_PWD.toCharArray());
+
+ }
+
+ private Certificate getCertificate() throws KeyStoreException {
+ // Get key by alias (found in the p12 file using:
+ // keytool -list -keystore test-root-ca.p12 -storepass foobar -storetype PKCS12
+ return this._keyStore.getCertificate(_keyAlias);
+ }
}