Skip to content

Commit cd6223c

Browse files
committed
refactor Algorithm into subclasses
1 parent 918ec0b commit cd6223c

10 files changed

Lines changed: 231 additions & 165 deletions

File tree

lib/src/main/java/com/auth0/jwtdecodejava/Utils.java

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.auth0.jwtdecodejava;
22

3-
import com.auth0.jwtdecodejava.enums.Algorithm;
3+
import com.auth0.jwtdecodejava.enums.HSAlgorithm;
4+
import com.auth0.jwtdecodejava.enums.RSAlgorithm;
45
import com.auth0.jwtdecodejava.exceptions.JWTException;
56
import org.apache.commons.codec.binary.Base64;
67
import org.apache.commons.codec.binary.StringUtils;
@@ -31,20 +32,6 @@ public static String base64Encode(String string) throws JWTException {
3132
return encoded;
3233
}
3334

34-
public static boolean verifyHS(String[] jwtParts, String secret, Algorithm algorithm) throws NoSuchAlgorithmException, InvalidKeyException {
35-
if (secret == null) {
36-
throw new IllegalArgumentException("The Secret cannot be null");
37-
}
38-
if (algorithm != Algorithm.HS256 && algorithm != Algorithm.HS384 && algorithm != Algorithm.HS512) {
39-
throw new IllegalArgumentException("The Algorithm must be one of HS256, HS384, or HS512.");
40-
}
41-
Mac mac = Mac.getInstance(algorithm.toString());
42-
mac.init(new SecretKeySpec(secret.getBytes(), algorithm.toString()));
43-
String message = String.format("%s.%s", jwtParts[0], jwtParts[1]);
44-
byte[] result = mac.doFinal(message.getBytes());
45-
return MessageDigest.isEqual(result, Base64.decodeBase64(jwtParts[2]));
46-
}
47-
4835
public static String[] splitToken(String token) {
4936
String[] parts = token.split("\\.");
5037
if (parts.length == 2 && token.endsWith(".")) {
@@ -57,16 +44,31 @@ public static String[] splitToken(String token) {
5744
return parts;
5845
}
5946

60-
public static boolean verifyRS(String[] jwtParts, PublicKey publicKey, Algorithm algorithm) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException {
47+
public static boolean verifyHS(HSAlgorithm algorithm, String[] jwtParts, String secret) throws NoSuchAlgorithmException, InvalidKeyException {
48+
if (secret == null) {
49+
throw new IllegalArgumentException("The Secret cannot be null");
50+
}
51+
if (algorithm == null) {
52+
throw new IllegalArgumentException("The Algorithm must be one of HS256, HS384, or HS512.");
53+
}
54+
55+
Mac mac = Mac.getInstance(algorithm.describe());
56+
mac.init(new SecretKeySpec(secret.getBytes(), algorithm.describe()));
57+
String message = String.format("%s.%s", jwtParts[0], jwtParts[1]);
58+
byte[] result = mac.doFinal(message.getBytes());
59+
return MessageDigest.isEqual(result, Base64.decodeBase64(jwtParts[2]));
60+
}
61+
62+
public static boolean verifyRS(RSAlgorithm algorithm, String[] jwtParts, PublicKey publicKey) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException {
6163
if (publicKey == null) {
6264
throw new IllegalArgumentException("The PublicKey cannot be null");
6365
}
64-
if (algorithm != Algorithm.RS256 && algorithm != Algorithm.RS384 && algorithm != Algorithm.RS512) {
66+
if (algorithm == null) {
6567
throw new IllegalArgumentException("The Algorithm must be one of RS256, RS384, or RS512.");
6668
}
6769

6870
final String content = String.format("%s.%s", jwtParts[0], jwtParts[1]);
69-
Signature s = Signature.getInstance(algorithm.toString());
71+
Signature s = Signature.getInstance(algorithm.describe());
7072
s.initVerify(publicKey);
7173
s.update(content.getBytes());
7274
return s.verify(Base64.decodeBase64(jwtParts[2]));
Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,9 @@
11
package com.auth0.jwtdecodejava.enums;
22

3-
import org.apache.commons.codec.digest.HmacAlgorithms;
3+
public interface Algorithm {
44

5-
public enum Algorithm {
6-
none(null),
7-
HS256(HmacAlgorithms.HMAC_SHA_256.toString()),
8-
HS384(HmacAlgorithms.HMAC_SHA_384.toString()),
9-
HS512(HmacAlgorithms.HMAC_SHA_512.toString()),
10-
RS256("SHA256withRSA"),
11-
RS384("SHA384withRSA"),
12-
RS512("SHA512withRSA");
5+
String describe();
136

14-
private final String description;
7+
String name();
158

16-
Algorithm(String description) {
17-
this.description = description;
18-
}
19-
20-
@Override
21-
public String toString() {
22-
return description;
23-
}
24-
25-
public static Algorithm parseFrom(String algorithmName) {
26-
try {
27-
return Algorithm.valueOf(algorithmName);
28-
} catch (IllegalArgumentException ignored) {
29-
return null;
30-
}
31-
}
329
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.auth0.jwtdecodejava.enums;
2+
3+
import org.apache.commons.codec.digest.HmacAlgorithms;
4+
5+
public enum HSAlgorithm implements Algorithm {
6+
HS256(HmacAlgorithms.HMAC_SHA_256.toString()),
7+
HS384(HmacAlgorithms.HMAC_SHA_384.toString()),
8+
HS512(HmacAlgorithms.HMAC_SHA_512.toString());
9+
10+
private final String description;
11+
12+
HSAlgorithm(String description) {
13+
this.description = description;
14+
}
15+
16+
@Override
17+
public String describe() {
18+
return description;
19+
}
20+
21+
public static Algorithm resolveFrom(String name) {
22+
try {
23+
return valueOf(name);
24+
} catch (IllegalArgumentException ignored) {
25+
return null;
26+
}
27+
}
28+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.auth0.jwtdecodejava.enums;
2+
3+
public enum NoneAlgorithm implements Algorithm {
4+
none("none");
5+
6+
private final String description;
7+
8+
NoneAlgorithm(String description) {
9+
this.description = description;
10+
}
11+
12+
@Override
13+
public String describe() {
14+
return description;
15+
}
16+
17+
public static Algorithm resolveFrom(String name) {
18+
try {
19+
return valueOf(name);
20+
} catch (IllegalArgumentException ignored) {
21+
return null;
22+
}
23+
}
24+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.auth0.jwtdecodejava.enums;
2+
3+
public enum RSAlgorithm implements Algorithm {
4+
RS256("SHA256withRSA"),
5+
RS384("SHA384withRSA"),
6+
RS512("SHA512withRSA");
7+
8+
private final String description;
9+
10+
RSAlgorithm(String description) {
11+
this.description = description;
12+
}
13+
14+
@Override
15+
public String describe() {
16+
return description;
17+
}
18+
19+
public static Algorithm resolveFrom(String name) {
20+
try {
21+
return valueOf(name);
22+
} catch (IllegalArgumentException ignored) {
23+
return null;
24+
}
25+
}
26+
}

lib/src/main/java/com/auth0/jwtdecodejava/impl/HeaderImpl.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package com.auth0.jwtdecodejava.impl;
22

33
import com.auth0.jwtdecodejava.enums.Algorithm;
4+
import com.auth0.jwtdecodejava.enums.HSAlgorithm;
5+
import com.auth0.jwtdecodejava.enums.NoneAlgorithm;
6+
import com.auth0.jwtdecodejava.enums.RSAlgorithm;
47
import com.auth0.jwtdecodejava.interfaces.Header;
58
import com.fasterxml.jackson.databind.JsonNode;
69

@@ -19,7 +22,7 @@ class HeaderImpl implements Header {
1922
@Override
2023
public Algorithm getAlgorithm() {
2124
String alg = extractClaim(ALGORITHM, tree).asString();
22-
return Algorithm.parseFrom(alg);
25+
return parseFrom(alg);
2326
}
2427

2528
@Override
@@ -31,4 +34,16 @@ public String getType() {
3134
public String getContentType() {
3235
return extractClaim(CONTENT_TYPE, tree).asString();
3336
}
37+
38+
39+
private Algorithm parseFrom(String algorithmName) {
40+
Algorithm algorithm = RSAlgorithm.resolveFrom(algorithmName);
41+
if (algorithm == null) {
42+
algorithm = HSAlgorithm.resolveFrom(algorithmName);
43+
}
44+
if (algorithm == null) {
45+
algorithm = NoneAlgorithm.resolveFrom(algorithmName);
46+
}
47+
return algorithm;
48+
}
3449
}

lib/src/main/java/com/auth0/jwtdecodejava/impl/JWTVerifier.java

Lines changed: 36 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
import com.auth0.jwtdecodejava.JWTDecoder;
44
import com.auth0.jwtdecodejava.Utils;
55
import com.auth0.jwtdecodejava.enums.Algorithm;
6+
import com.auth0.jwtdecodejava.enums.HSAlgorithm;
7+
import com.auth0.jwtdecodejava.enums.NoneAlgorithm;
8+
import com.auth0.jwtdecodejava.enums.RSAlgorithm;
69
import com.auth0.jwtdecodejava.exceptions.AlgorithmMismatchException;
710
import com.auth0.jwtdecodejava.exceptions.InvalidClaimException;
811
import com.auth0.jwtdecodejava.exceptions.JWTException;
@@ -18,6 +21,8 @@
1821
import java.util.HashMap;
1922
import java.util.Map;
2023

24+
import static com.auth0.jwtdecodejava.enums.NoneAlgorithm.none;
25+
2126
public class JWTVerifier {
2227
private final Algorithm algorithm;
2328
private final String secret;
@@ -32,28 +37,28 @@ private JWTVerifier(Algorithm algorithm, String secret, PublicKey key) {
3237
}
3338

3439
public static JWTVerifier init() throws IllegalArgumentException {
35-
return init(Algorithm.none, null);
40+
return init(none, null, null);
41+
}
42+
43+
public static JWTVerifier init(HSAlgorithm algorithm, String secret) throws IllegalArgumentException {
44+
return init(algorithm, null, secret);
45+
}
46+
47+
public static JWTVerifier init(RSAlgorithm algorithm, PublicKey publicKey) throws IllegalArgumentException {
48+
return init(algorithm, publicKey, null);
3649
}
3750

38-
public static JWTVerifier init(Algorithm algorithm, String secret) throws IllegalArgumentException {
51+
private static JWTVerifier init(Algorithm algorithm, PublicKey publicKey, String secret) throws IllegalArgumentException {
3952
if (algorithm == null) {
4053
throw new IllegalArgumentException("The Algorithm cannot be null.");
4154
}
42-
switch (algorithm) {
43-
case HS256:
44-
case HS384:
45-
case HS512:
46-
if (secret == null) {
47-
throw new IllegalArgumentException(String.format("You can't use the %s algorithm without providing a valid Secret.", algorithm.name()));
48-
}
49-
break;
50-
case none:
51-
if (secret != null) {
52-
throw new IllegalArgumentException("You can't use the Algorithm 'none' with a non-null Secret.");
53-
}
54-
default:
55+
if (algorithm instanceof HSAlgorithm && secret == null) {
56+
throw new IllegalArgumentException(String.format("You can't use the %s algorithm without providing a valid Secret.", algorithm.name()));
57+
}
58+
if (algorithm instanceof RSAlgorithm && publicKey == null) {
59+
throw new IllegalArgumentException(String.format("You can't use the %s algorithm without providing a valid PublicKey.", algorithm.name()));
5560
}
56-
return new JWTVerifier(algorithm, secret, null);
61+
return new JWTVerifier(algorithm, secret, publicKey);
5762
}
5863

5964
public JWTVerifier withIssuer(String issuer) {
@@ -93,37 +98,27 @@ public JWTVerifier withJWTId(String jwtId) {
9398

9499
public JWT verify(String token) throws JWTException {
95100
JWT jwt = JWTDecoder.decode(token);
96-
verifyClaims(jwt, claims);
97101
verifyAlgorithm(jwt, algorithm);
98102
verifySignature(Utils.splitToken(token));
103+
verifyClaims(jwt, claims);
99104
return jwt;
100105
}
101106

102107
private void verifySignature(String[] parts) {
103-
switch (algorithm) {
104-
case HS256:
105-
case HS384:
106-
case HS512:
107-
try {
108-
Utils.verifyHS(parts, secret, algorithm);
109-
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
110-
throw new SignatureVerificationException(algorithm, e);
111-
}
112-
break;
113-
case RS256:
114-
case RS384:
115-
case RS512:
116-
try {
117-
Utils.verifyRS(parts, key, algorithm);
118-
} catch (InvalidKeyException | NoSuchAlgorithmException | SignatureException e) {
119-
throw new SignatureVerificationException(algorithm, e);
120-
}
121-
break;
122-
case none:
123-
if (!parts[2].isEmpty()) {
124-
throw new SignatureVerificationException(algorithm);
125-
}
126-
default:
108+
if (algorithm instanceof HSAlgorithm) {
109+
try {
110+
Utils.verifyHS((HSAlgorithm) algorithm, parts, secret);
111+
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
112+
throw new SignatureVerificationException(algorithm, e);
113+
}
114+
} else if (algorithm instanceof RSAlgorithm) {
115+
try {
116+
Utils.verifyRS((RSAlgorithm) algorithm, parts, key);
117+
} catch (InvalidKeyException | NoSuchAlgorithmException | SignatureException e) {
118+
throw new SignatureVerificationException(algorithm, e);
119+
}
120+
} else if (algorithm instanceof NoneAlgorithm && !parts[2].isEmpty()) {
121+
throw new SignatureVerificationException(algorithm);
127122
}
128123
}
129124

lib/src/test/java/com/auth0/jwtdecodejava/JWTDecoderTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.auth0.jwtdecodejava;
22

3-
import com.auth0.jwtdecodejava.enums.Algorithm;
3+
import com.auth0.jwtdecodejava.enums.HSAlgorithm;
44
import com.auth0.jwtdecodejava.exceptions.JWTException;
55
import com.auth0.jwtdecodejava.impl.BaseClaim;
66
import com.auth0.jwtdecodejava.interfaces.Claim;
@@ -76,7 +76,7 @@ public void shouldGetStringToken() throws Exception {
7676
public void shouldGetHeader() throws Exception {
7777
JWT jwt = JWTDecoder.decode("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ");
7878
assertThat(jwt, is(notNullValue()));
79-
assertThat(jwt.getAlgorithm(), is(Algorithm.HS256));
79+
assertThat(jwt.getAlgorithm(), is(HSAlgorithm.HS256));
8080
}
8181

8282
@Test

0 commit comments

Comments
 (0)