-
Notifications
You must be signed in to change notification settings - Fork 682
/
JwtGenerator.java
215 lines (178 loc) · 7.26 KB
/
JwtGenerator.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
package org.pac4j.jwt.profile;
import com.nimbusds.jose.EncryptionMethod;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWEAlgorithm;
import com.nimbusds.jose.JWEHeader;
import com.nimbusds.jose.JWEObject;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSSigner;
import com.nimbusds.jose.Payload;
import com.nimbusds.jose.crypto.DirectEncrypter;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.PlainJWT;
import com.nimbusds.jwt.SignedJWT;
import org.pac4j.core.exception.TechnicalException;
import org.pac4j.core.profile.CommonProfile;
import org.pac4j.core.util.CommonHelper;
import org.pac4j.jwt.JwtConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.Map;
/**
* Generates a JWT token from a user profile.
*
* @author Jerome Leleu
* @since 1.8.0
*/
public class JwtGenerator<U extends CommonProfile> {
public static final String INTERNAL_ROLES = "$int_roles";
public static final String INTERNAL_PERMISSIONS = "$int_perms";
protected final Logger logger = LoggerFactory.getLogger(getClass());
private String signingSecret;
private String encryptionSecret;
private JWSAlgorithm jwsAlgorithm = JWSAlgorithm.HS256;
private JWEAlgorithm jweAlgorithm = JWEAlgorithm.DIR;
private EncryptionMethod encryptionMethod = EncryptionMethod.A256GCM;
public JwtGenerator(final String secret) {
this(secret, true);
}
public JwtGenerator(final String secret, final boolean encrypted) {
this.signingSecret = secret;
if (encrypted) {
this.encryptionSecret = secret;
logger.warn("Using the same key for signing and encryption may lead to security vulnerabilities. Consider using different keys");
}
}
/**
* Initializes the generator that will create JWT tokens that is signed and optionally encrypted.
*
* @param signingSecret The signingSecret. Must be at least 256 bits long and not {@code null}
* @param encryptionSecret The encryptionSecret. Must be at least 256 bits long and not {@code null} if you want encryption
* @since 1.8.2
*/
public JwtGenerator(final String signingSecret, final String encryptionSecret) {
this.signingSecret = signingSecret;
this.encryptionSecret = encryptionSecret;
}
/**
* Generates a JWT from a user profile.
*
* @param profile the given user profile
* @return the created JWT
*/
public String generate(final U profile) {
try {
// Create HMAC signer
final JWSSigner signer = new MACSigner(this.signingSecret);
return generate(profile, signer, this.jwsAlgorithm);
} catch (JOSEException e) {
throw new RuntimeException(e);
}
}
/**
* Generates a JWT from a user profile.
*
* @param profile the given user profile
* @return the created JWT
*/
public String generate(final U profile, JWSSigner signer, JWSAlgorithm jwsAlgorithm) {
verifyProfile(profile);
try {
final JWTClaimsSet claims = buildJwtClaimsSet(profile);
if (CommonHelper.isNotBlank(this.signingSecret)) {
CommonHelper.assertNotNull("jwsAlgorithm", jwsAlgorithm);
final SignedJWT signedJWT = signJwt(claims, signer, jwsAlgorithm);
if (CommonHelper.isNotBlank(this.encryptionSecret)) {
CommonHelper.assertNotNull("jweAlgorithm", jweAlgorithm);
CommonHelper.assertNotNull("encryptionMethod", encryptionMethod);
return encryptJwt(signedJWT);
}
return signedJWT.serialize();
}
return new PlainJWT(claims).serialize();
} catch (final Exception e) {
throw new TechnicalException("Cannot generate JWT", e);
}
}
protected String encryptJwt(final SignedJWT signedJWT) throws Exception {
// Create JWE object with signed JWT as payload
final JWEObject jweObject = new JWEObject(
new JWEHeader.Builder(jweAlgorithm, encryptionMethod).contentType("JWT").build(),
new Payload(signedJWT));
// Perform encryption
jweObject.encrypt(new DirectEncrypter(this.encryptionSecret.getBytes("UTF-8")));
// Serialise to JWE compact form
return jweObject.serialize();
}
protected SignedJWT signJwt(final JWTClaimsSet claims) throws JOSEException {
// Create HMAC signer
final JWSSigner signer = new MACSigner(this.signingSecret);
return signJwt(claims, signer, this.jwsAlgorithm);
}
protected SignedJWT signJwt(final JWTClaimsSet claims, JWSSigner signer, JWSAlgorithm jwsAlgorithm) throws JOSEException {
final SignedJWT signedJWT = new SignedJWT(new JWSHeader(jwsAlgorithm), claims);
// Apply the HMAC
signedJWT.sign(signer);
return signedJWT;
}
protected JWTClaimsSet buildJwtClaimsSet(final U profile) {
// Build claims
final JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder()
.subject(profile.getTypedId())
.issueTime(new Date());
// add attributes
final Map<String, Object> attributes = profile.getAttributes();
for (final Map.Entry<String, Object> entry : attributes.entrySet()) {
builder.claim(entry.getKey(), entry.getValue());
}
builder.claim(INTERNAL_ROLES, profile.getRoles());
builder.claim(INTERNAL_PERMISSIONS, profile.getPermissions());
// claims
return builder.build();
}
private void verifyProfile(final U profile) {
CommonHelper.assertNotNull("profile", profile);
CommonHelper.assertNull("profile.sub", profile.getAttribute(JwtConstants.SUBJECT));
CommonHelper.assertNull("profile.iat", profile.getAttribute(JwtConstants.ISSUE_TIME));
CommonHelper.assertNull(INTERNAL_ROLES, profile.getAttribute(INTERNAL_ROLES));
CommonHelper.assertNull(INTERNAL_PERMISSIONS, profile.getAttribute(INTERNAL_PERMISSIONS));
}
public String getSigningSecret() {
return signingSecret;
}
public void setSigningSecret(final String signingSecret) {
this.signingSecret = signingSecret;
}
public String getEncryptionSecret() {
return encryptionSecret;
}
public void setEncryptionSecret(final String encryptionSecret) {
this.encryptionSecret = encryptionSecret;
}
public JWSAlgorithm getJwsAlgorithm() {
return jwsAlgorithm;
}
/**
* Only the HS256, HS384 and HS512 are currently supported.
*
* @param jwsAlgorithm the signing algorithm
*/
public void setJwsAlgorithm(final JWSAlgorithm jwsAlgorithm) {
this.jwsAlgorithm = jwsAlgorithm;
}
public JWEAlgorithm getJweAlgorithm() {
return jweAlgorithm;
}
public void setJweAlgorithm(final JWEAlgorithm jweAlgorithm) {
this.jweAlgorithm = jweAlgorithm;
}
public EncryptionMethod getEncryptionMethod() {
return encryptionMethod;
}
public void setEncryptionMethod(final EncryptionMethod encryptionMethod) {
this.encryptionMethod = encryptionMethod;
}
}