Skip to content

Commit 8f594f4

Browse files
Merge pull request #3 from BastiaanJansen/dev
V1.2.0
2 parents 9fd4dcf + 558c65f commit 8f594f4

25 files changed

+309
-291
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,13 @@ To create the signature part you have to take the Base64URL encoded header, the
7979
<dependency>
8080
<groupId>com.github.bastiaanjansen</groupId>
8181
<artifactId>jwt-java</artifactId>
82-
<version>1.1.0</version>
82+
<version>1.2.0</version>
8383
</dependency>
8484
```
8585

8686
### Gradle
8787
```gradle
88-
implementation 'com.github.bastiaanjansen:jwt-java:1.1.0'
88+
implementation 'com.github.bastiaanjansen:jwt-java:1.2.0'
8989
```
9090

9191
## Usage
@@ -208,7 +208,7 @@ Date exp = payload.getExpirationTime();
208208
Date nbf = payload.getNotBefore();
209209
String[] audience = payload.getAudience();
210210

211-
Object customClaim = payload.get("username");
211+
String customClaim = payload.getClaim("username", String.class);
212212

213213
boolean hasClaim = payload.containsClaim("key");
214214
```
@@ -245,7 +245,7 @@ JWTValidator validator = new DefaultJWTValidator.Builder()
245245
.withIssuer("issuer")
246246
.withID("id")
247247
.withOneOfAudience("aud1", "aud2") // Enforce audience has "aud1" or "aud2"
248-
.withCLaim("username", "BastiaanJansen") // Enforce custom claim value
248+
.withClaim("username", "BastiaanJansen") // Enforce custom claim value
249249
.build();
250250

251251
try {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.bastiaanjansen.jwt;
2+
3+
public interface ClaimConverter<T> {
4+
T convert(Object value);
5+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package com.bastiaanjansen.jwt;
2+
3+
import com.bastiaanjansen.jwt.utils.Base64Utils;
4+
import org.json.JSONObject;
5+
6+
import java.util.*;
7+
import java.util.stream.Collectors;
8+
9+
public class Claims {
10+
private final Registered[] registeredDateClaims = { Registered.EXPIRATION_TIME, Registered.ISSUED_AT, Registered.NOT_BEFORE };
11+
protected final Map<String, Object> claims;
12+
13+
protected Claims() {
14+
claims = new HashMap<>();
15+
}
16+
17+
public boolean containsClaim(String name) {
18+
return claims.containsKey(name);
19+
}
20+
21+
public Map<String, Object> getAsMap() {
22+
return new HashMap<>(claims);
23+
}
24+
25+
public String base64Encoded() {
26+
String json = new JSONObject(claims).toString();
27+
return Base64Utils.encodeBase64URL(json);
28+
}
29+
30+
/**
31+
* Get a claim by name and cast it to a specific type
32+
*
33+
* @param name of the claim
34+
* @param type of the claim
35+
* @param <T> type of the claim
36+
* @return claim value cast to specified type
37+
*/
38+
@SuppressWarnings("unchecked")
39+
public <T> T getClaim(String name, Class<T> type) {
40+
Object value = claims.get(name);
41+
42+
boolean isDateClaim = Arrays.stream(registeredDateClaims)
43+
.map(Claims.Registered::getValue)
44+
.collect(Collectors.toList())
45+
.contains(name);
46+
47+
if (isDateClaim) {
48+
long millisSinceEpoch = Long.parseLong(String.valueOf(value));
49+
return (T) new Date(millisSinceEpoch);
50+
}
51+
52+
return type.cast(value);
53+
}
54+
55+
public <T> T getClaim(String name, ClaimConverter<T> converter) {
56+
Object value = claims.get(name);
57+
return converter.convert(value);
58+
}
59+
60+
public void addClaim(String name, Object value) {
61+
if (name == null) throw new IllegalArgumentException("name cannot be null");
62+
if (value == null) throw new IllegalArgumentException("value cannot be null");
63+
claims.put(name, value);
64+
}
65+
66+
public enum Registered {
67+
ISSUER("iss"),
68+
SUBJECT("sub"),
69+
AUDIENCE("aud"),
70+
EXPIRATION_TIME("exp"),
71+
NOT_BEFORE("nbf"),
72+
ISSUED_AT("iat"),
73+
JWT_ID("jti"),
74+
TYPE("typ"),
75+
CONTENT_TYPE("cty"),
76+
ALGORITHM("alg");
77+
78+
private final String value;
79+
80+
Registered(String value) {
81+
this.value = value;
82+
}
83+
84+
public String getValue() {
85+
return value;
86+
}
87+
}
88+
}

src/main/java/com/bastiaanjansen/jwt/DefaultJWTValidator.java

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.bastiaanjansen.jwt;
22

3-
import com.bastiaanjansen.jwt.Exceptions.JWTExpiredException;
4-
import com.bastiaanjansen.jwt.Exceptions.JWTValidationException;
3+
import com.bastiaanjansen.jwt.exceptions.JWTExpiredException;
4+
import com.bastiaanjansen.jwt.exceptions.JWTValidationException;
55

66
import java.nio.charset.StandardCharsets;
77
import java.util.*;
@@ -68,15 +68,15 @@ private void verifyPayload(Payload payload) throws JWTValidationException {
6868

6969
private void validateNotBefore(Payload payload, Date currentDate) throws JWTValidationException {
7070
// Checks that if the not-before (nbf) claim is set, the current date is after or equal to the not-before date.
71-
if (payload.containsClaim(Payload.Registered.NOT_BEFORE)) {
71+
if (payload.containsClaim(Claims.Registered.NOT_BEFORE.getValue())) {
7272
Date notBefore = payload.getNotBefore();
7373
if (currentDate.getTime() <= notBefore.getTime())
7474
throw new JWTValidationException("JWT is only valid after " + notBefore);
7575
}
7676
}
7777

7878
private void validateExpirationTime(Payload payload, Date currentDate) throws JWTExpiredException {
79-
if (payload.containsClaim(Payload.Registered.EXPIRATION_TIME)) {
79+
if (payload.containsClaim(Claims.Registered.EXPIRATION_TIME.getValue())) {
8080
Date expirationTime = payload.getExpirationTime();
8181
if (currentDate.getTime() > expirationTime.getTime())
8282
throw new JWTExpiredException("JWT expired on " + expirationTime);
@@ -93,73 +93,83 @@ public Builder() {
9393
}
9494

9595
public Builder withType(String type) {
96-
withHeader(Header.Registered.TYPE, type::equals);
96+
withHeader(Claims.Registered.TYPE.getValue(), type::equals);
9797
return this;
9898
}
9999

100100
public Builder withContentType(String type) {
101-
withHeader(Header.Registered.CONTENT_TYPE, type::equals);
101+
withHeader(Claims.Registered.CONTENT_TYPE.getValue(), type::equals);
102102
return this;
103103
}
104104

105105
public Builder withAlgorithm(String algorithm) {
106-
withHeader(Header.Registered.ALGORITHM, algorithm::equals);
106+
withHeader(Claims.Registered.ALGORITHM.getValue(), algorithm::equals);
107107
return this;
108108
}
109109

110110
public Builder withIssuer(String issuer) {
111-
withClaim(Payload.Registered.ISSUER, issuer::equals);
111+
withClaim(Claims.Registered.ISSUER.getValue(), issuer::equals);
112112
return this;
113113
}
114114

115115
public Builder withSubject(String subject) {
116-
withClaim(Payload.Registered.SUBJECT, subject::equals);
116+
withClaim(Claims.Registered.SUBJECT.getValue(), subject::equals);
117117
return this;
118118
}
119119

120120
public Builder withOneOfAudience(String... audience) {
121-
withClaim(Payload.Registered.AUDIENCE, value -> {
121+
withClaim(Claims.Registered.AUDIENCE.getValue(), value -> {
122122
for (String audienceItem: audience) {
123123
if (Arrays.asList((Object[]) value).contains(audienceItem))
124124
return true;
125125
}
126126
return false;
127127
});
128+
129+
return this;
130+
}
131+
132+
public Builder withAllOfAudience(String... audience) {
133+
withClaim(Claims.Registered.AUDIENCE.getValue(), value -> {
134+
String[] values = (String[]) value;
135+
return Arrays.asList(values).containsAll(Arrays.asList(audience));
136+
});
137+
128138
return this;
129139
}
130140

131141
public Builder withExpirationTime(Date expirationTime) {
132-
withClaim(Payload.Registered.EXPIRATION_TIME, value -> value.equals(expirationTime.getTime()));
142+
withClaim(Claims.Registered.EXPIRATION_TIME.getValue(), value -> value.equals(expirationTime.getTime()));
133143
return this;
134144
}
135145

136146
public Builder withExpirationTime(long timeSinceEpoch) {
137-
withClaim(Payload.Registered.EXPIRATION_TIME, value -> value.equals(timeSinceEpoch));
147+
withClaim(Claims.Registered.EXPIRATION_TIME.getValue(), value -> value.equals(timeSinceEpoch));
138148
return this;
139149
}
140150

141151
public Builder withNotBefore(Date notBefore) {
142-
withClaim(Payload.Registered.NOT_BEFORE, value -> value.equals(notBefore.getTime()));
152+
withClaim(Claims.Registered.NOT_BEFORE.getValue(), value -> value.equals(notBefore.getTime()));
143153
return this;
144154
}
145155

146156
public Builder withNotBefore(long timeSinceEpoch) {
147-
withClaim(Payload.Registered.NOT_BEFORE, value -> value.equals(timeSinceEpoch));
157+
withClaim(Claims.Registered.NOT_BEFORE.getValue(), value -> value.equals(timeSinceEpoch));
148158
return this;
149159
}
150160

151161
public Builder withIssuedAt(Date issuedAt) {
152-
withClaim(Payload.Registered.ISSUED_AT, value -> value.equals(issuedAt.getTime()));
162+
withClaim(Claims.Registered.ISSUED_AT.getValue(), value -> value.equals(issuedAt.getTime()));
153163
return this;
154164
}
155165

156166
public Builder withIssuedAt(long timeSinceEpoch) {
157-
withClaim(Payload.Registered.ISSUED_AT, value -> value.equals(timeSinceEpoch));
167+
withClaim(Claims.Registered.ISSUED_AT.getValue(), value -> value.equals(timeSinceEpoch));
158168
return this;
159169
}
160170

161171
public Builder withID(String id) {
162-
withClaim(Payload.Registered.JWT_ID, id::equals);
172+
withClaim(Claims.Registered.JWT_ID.getValue(), id::equals);
163173
return this;
164174
}
165175

@@ -195,10 +205,10 @@ public DefaultJWTValidator build() {
195205
}
196206

197207
public Map<String, ClaimValidator> getHeaderValidators() {
198-
return headerValidators;
208+
return new HashMap<>(headerValidators);
199209
}
200210

201211
public Map<String, ClaimValidator> getPayloadValidators() {
202-
return payloadValidators;
212+
return new HashMap<>(payloadValidators);
203213
}
204214
}
Lines changed: 8 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,13 @@
11
package com.bastiaanjansen.jwt;
22

3-
import com.bastiaanjansen.jwt.Utils.Base64Utils;
3+
import com.bastiaanjansen.jwt.utils.Base64Utils;
44
import org.json.JSONObject;
55

6-
import java.util.HashMap;
76
import java.util.Map;
87

9-
public class Header {
10-
public static class Registered {
11-
static String TYPE = "typ";
12-
static String CONTENT_TYPE = "cty";
13-
static String ALGORITHM = "alg";
14-
}
15-
16-
private final Map<String, Object> claims;
8+
public final class Header extends Claims {
179

1810
public Header() {
19-
claims = new HashMap<>();
2011
setType("JWT");
2112
}
2213

@@ -32,56 +23,26 @@ public static Header fromBase64EncodedJSON(String encodedJSON) {
3223
}
3324

3425
public void setType(String type) {
35-
addClaim(Registered.TYPE, type);
26+
addClaim(Registered.TYPE.getValue(), type);
3627
}
3728

3829
public String getType() {
39-
Object type = claims.get(Registered.TYPE);
40-
return getString(type);
30+
return getClaim(Registered.TYPE.getValue(), String.class);
4131
}
4232

4333
public void setContentType(String value) {
44-
addClaim(Registered.CONTENT_TYPE, value);
34+
addClaim(Registered.CONTENT_TYPE.getValue(), value);
4535
}
4636

4737
public String getContentType() {
48-
Object contentType = claims.get(Registered.CONTENT_TYPE);
49-
return getString(contentType);
38+
return getClaim(Registered.CONTENT_TYPE.getValue(), String.class);
5039
}
5140

5241
public void setAlgorithm(String algorithm) {
53-
addClaim(Registered.ALGORITHM, algorithm);
42+
addClaim(Registered.ALGORITHM.getValue(), algorithm);
5443
}
5544

5645
public String getAlgorithm() {
57-
Object algorithm = claims.get(Registered.ALGORITHM);
58-
return getString(algorithm);
59-
}
60-
61-
public boolean containsClaim(String name) {
62-
return claims.containsKey(name);
63-
}
64-
65-
public Map<String, Object> getAsMap() {
66-
return new HashMap<>(claims);
67-
}
68-
69-
public String base64Encoded() {
70-
return Base64Utils.encodeBase64URL(new JSONObject(claims).toString());
71-
}
72-
73-
public Object get(String name) {
74-
return claims.get(name);
75-
}
76-
77-
public void addClaim(String name, Object value) {
78-
if (name == null) throw new IllegalArgumentException("name cannot be null");
79-
if (value == null) throw new IllegalArgumentException("value cannot be null");
80-
81-
claims.put(name, value);
82-
}
83-
84-
private String getString(Object object) {
85-
return object != null ? String.valueOf(object) : null;
46+
return getClaim(Registered.ALGORITHM.getValue(), String.class);
8647
}
8748
}

0 commit comments

Comments
 (0)