Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support specifying the Cryptography Provider by name and instance #610

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
472a5b7
#597 Add support for specifying provider without breaking changes
aps-augentictech Jul 12, 2022
82c6496
Merge branch '#597'
aps-augentictech Jul 12, 2022
2cdcf64
publish maven artifact to private maven repository
aps-augentictech Jul 12, 2022
fe74885
Formatting rules check
aps-augentictech Jul 12, 2022
42818c4
Ignore failing tests. Have no clue why, maybe a bad merge
aps-augentictech Jul 12, 2022
665752e
enable maven publishing to INCM
aps-augentictech Jul 12, 2022
5e10a40
Merge branch 'auth0:master' into master
aps-augentictech Sep 25, 2022
7b901d4
Treble all sign and verify methods to accept the provider name or a j…
aps-augentictech Sep 26, 2022
52e2ab8
Merge branch 'master' of github.com:DNXT-S-A/java-jwt
aps-augentictech Sep 26, 2022
3fc6a62
fixed comments that were failing CicrleCI pipeline
aps-augentictech Sep 26, 2022
dff64ea
Fix source formatting
aps-augentictech Sep 26, 2022
a3b2d87
Fix source formatting according to the rules this time
aps-augentictech Sep 26, 2022
d051f8d
Revert "enable maven publishing to INCM"
aps-augentictech Sep 26, 2022
1f29432
Revert "Ignore failing tests. Have no clue why, maybe a bad merge"
aps-augentictech Sep 26, 2022
b00787c
Revert "publish maven artifact to private maven repository"
aps-augentictech Sep 26, 2022
6b361dd
Reversed commits that affected the build scripts and ignored tests. F…
aps-augentictech Sep 26, 2022
19a2847
remove unnecessary overloads
aps-augentictech Sep 26, 2022
20331d3
Increase test coverage
aps-augentictech Sep 26, 2022
acc3723
increment test coverage
aps-augentictech Sep 26, 2022
c429db2
code rules
aps-augentictech Sep 26, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 109 additions & 60 deletions lib/src/main/java/com/auth0/jwt/JWTCreator.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,19 @@
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.SignatureGenerationException;
import com.auth0.jwt.impl.*;
import com.auth0.jwt.impl.HeaderClaimsHolder;
import com.auth0.jwt.impl.HeaderSerializer;
import com.auth0.jwt.impl.PayloadClaimsHolder;
import com.auth0.jwt.impl.PayloadSerializer;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;

import java.nio.charset.StandardCharsets;
import java.security.NoSuchProviderException;
import java.security.Provider;
import java.security.Security;
import java.time.Instant;
import java.util.*;
import java.util.Map.Entry;
Expand All @@ -23,10 +29,6 @@
@SuppressWarnings("WeakerAccess")
public final class JWTCreator {

private final Algorithm algorithm;
private final String headerJson;
private final String payloadJson;

private static final ObjectMapper mapper;
private static final SimpleModule module;

Expand All @@ -39,6 +41,10 @@ public final class JWTCreator {
mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
}

private final Algorithm algorithm;
private final String headerJson;
private final String payloadJson;

private JWTCreator(Algorithm algorithm, Map<String, Object> headerClaims, Map<String, Object> payloadClaims)
throws JWTCreationException {
this.algorithm = algorithm;
Expand All @@ -60,6 +66,19 @@ static JWTCreator.Builder init() {
return new Builder();
}

private String sign(Provider cryptoProvider) throws SignatureGenerationException {
String header = Base64.getUrlEncoder().withoutPadding()
.encodeToString(headerJson.getBytes(StandardCharsets.UTF_8));
String payload = Base64.getUrlEncoder().withoutPadding()
.encodeToString(payloadJson.getBytes(StandardCharsets.UTF_8));

byte[] signatureBytes = algorithm.sign(header.getBytes(StandardCharsets.UTF_8),
payload.getBytes(StandardCharsets.UTF_8), cryptoProvider);
String signature = Base64.getUrlEncoder().withoutPadding().encodeToString((signatureBytes));

return String.format("%s.%s.%s", header, payload, signature);
}

/**
* The Builder class holds the Claims that defines the JWT to be created.
*/
Expand All @@ -72,6 +91,55 @@ public static class Builder {
this.headerClaims = new HashMap<>();
}

private static boolean validateClaim(Map<?, ?> map) {
// do not accept null values in maps
for (Entry<?, ?> entry : map.entrySet()) {
Object value = entry.getValue();
if (!isSupportedType(value)) {
return false;
}

if (entry.getKey() == null || !(entry.getKey() instanceof String)) {
return false;
}
}
return true;
}

private static boolean validateClaim(List<?> list) {
// accept null values in list
for (Object object : list) {
if (!isSupportedType(object)) {
return false;
}
}
return true;
}

private static boolean isSupportedType(Object value) {
if (value instanceof List) {
return validateClaim((List<?>) value);
} else if (value instanceof Map) {
return validateClaim((Map<?, ?>) value);
} else {
return isBasicType(value);
}
}

private static boolean isBasicType(Object value) {
if (value == null) {
return true;
} else {
Class<?> c = value.getClass();

if (c.isArray()) {
return c == Integer[].class || c == Long[].class || c == String[].class;
}
return c == String.class || c == Integer.class || c == Long.class || c == Double.class
|| c == Date.class || c == Instant.class || c == Boolean.class;
}
}

/**
* Add specific Claims to set as the Header.
* If provided map is null then nothing is changed
Expand Down Expand Up @@ -481,65 +549,58 @@ private boolean validatePayload(Map<String, ?> payload) {
return true;
}

private static boolean validateClaim(Map<?, ?> map) {
// do not accept null values in maps
for (Entry<?, ?> entry : map.entrySet()) {
Object value = entry.getValue();
if (!isSupportedType(value)) {
return false;
}
/**
* Creates a new JWT and signs is with the given algorithm.
*
* @param algorithm used to sign the JWT
* @return a new JWT token
* @throws IllegalArgumentException if the provided algorithm is null.
* @throws JWTCreationException if the claims could not be converted to a valid JSON
* or there was a problem with the signing key.
*/
public String sign(Algorithm algorithm) throws IllegalArgumentException, JWTCreationException {

if (entry.getKey() == null || !(entry.getKey() instanceof String)) {
return false;
}
}
return true;
return this.sign(algorithm, (Provider) null);
}

private static boolean validateClaim(List<?> list) {
// accept null values in list
for (Object object : list) {
if (!isSupportedType(object)) {
return false;
}
/**
* Creates a new JWT and signs is with the given algorithm.
*
* @param algorithm used to sign the JWT
* @param providerName the provider to use for crypto operations
* @return a new JWT token
* @throws IllegalArgumentException if the provided algorithm is null.
* @throws JWTCreationException if the claims could not be converted to a valid JSON
* or there was a problem with the signing key.
* @throws NoSuchProviderException if a provider with providerName name cannot be found with
* {@link Security#getProvider(String)}
*/
public String sign(Algorithm algorithm, String providerName)
throws IllegalArgumentException, JWTCreationException, NoSuchProviderException {
if (providerName == null) {
throw new IllegalArgumentException("providerName cannot be null");
}
return true;
}

private static boolean isSupportedType(Object value) {
if (value instanceof List) {
return validateClaim((List<?>) value);
} else if (value instanceof Map) {
return validateClaim((Map<?, ?>) value);
} else {
return isBasicType(value);
Provider provider = Security.getProvider(providerName);
if (provider == null) {
throw new NoSuchProviderException(String.format("No provider named [%s] installed", providerName));
}
}

private static boolean isBasicType(Object value) {
if (value == null) {
return true;
} else {
Class<?> c = value.getClass();

if (c.isArray()) {
return c == Integer[].class || c == Long[].class || c == String[].class;
}
return c == String.class || c == Integer.class || c == Long.class || c == Double.class
|| c == Date.class || c == Instant.class || c == Boolean.class;
}
return new JWTCreator(algorithm, headerClaims, payloadClaims).sign(provider);
}

/**
* Creates a new JWT and signs is with the given algorithm.
*
* @param algorithm used to sign the JWT
* @param algorithm used to sign the JWT
* @param cryptoProvider the provider to use for crypto operations
* @return a new JWT token
* @throws IllegalArgumentException if the provided algorithm is null.
* @throws JWTCreationException if the claims could not be converted to a valid JSON
* or there was a problem with the signing key.
*/
public String sign(Algorithm algorithm) throws IllegalArgumentException, JWTCreationException {
public String sign(Algorithm algorithm, Provider cryptoProvider)
throws IllegalArgumentException, JWTCreationException {
if (algorithm == null) {
throw new IllegalArgumentException("The Algorithm cannot be null.");
}
Expand All @@ -551,7 +612,7 @@ public String sign(Algorithm algorithm) throws IllegalArgumentException, JWTCrea
if (signingKeyId != null) {
withKeyId(signingKeyId);
}
return new JWTCreator(algorithm, headerClaims, payloadClaims).sign();
return new JWTCreator(algorithm, headerClaims, payloadClaims).sign(cryptoProvider);
}

private void assertNonNull(String name) {
Expand All @@ -563,18 +624,6 @@ private void assertNonNull(String name) {
private void addClaim(String name, Object value) {
payloadClaims.put(name, value);
}
}

private String sign() throws SignatureGenerationException {
String header = Base64.getUrlEncoder().withoutPadding()
.encodeToString(headerJson.getBytes(StandardCharsets.UTF_8));
String payload = Base64.getUrlEncoder().withoutPadding()
.encodeToString(payloadJson.getBytes(StandardCharsets.UTF_8));

byte[] signatureBytes = algorithm.sign(header.getBytes(StandardCharsets.UTF_8),
payload.getBytes(StandardCharsets.UTF_8));
String signature = Base64.getUrlEncoder().withoutPadding().encodeToString((signatureBytes));

return String.format("%s.%s.%s", header, payload, signature);
}
}
Loading