forked from auth0/java-jwt
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathJwtSigner.java
More file actions
141 lines (112 loc) · 3.5 KB
/
Copy pathJwtSigner.java
File metadata and controls
141 lines (112 loc) · 3.5 KB
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
package com.auth0.jwt;
import java.util.ArrayList;
import java.util.List;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.naming.OperationNotSupportedException;
import org.apache.commons.codec.binary.Base64;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
/**
* JwtSigner implementation based on the Ruby implementation from http://jwt.io
* No support for RSA encryption at present
*/
public class JwtSigner {
/**
* Generate a JSON web token based on a payload, secret key and claim set
*/
public String encode(Algorithm algorithm, String payload, String payloadId, String key,
ClaimSet claimSet) throws Exception {
List<String> segments = new ArrayList<String>();
segments.add(encodedHeader(algorithm));
segments.add(encodedPayload(payload, payloadId, claimSet));
segments.add(encodedSignature(join(segments, "."), key, algorithm));
return join(segments, ".");
}
/**
* Generate the header part of a JSON web token
*/
private String encodedHeader(Algorithm algorithm)
throws Exception {
if (algorithm == null) { // default the algorithm if not specified
algorithm = Algorithm.HS256;
}
// create the header
ObjectNode header = JsonNodeFactory.instance.objectNode();
header.put("type", "JWT");
header.put("alg", algorithm.name());
return base64UrlEncode(header.toString().getBytes());
}
/**
* Generate the JSON web token payload, merging it with the claim set
*/
private String encodedPayload(String payload, String payloadId, ClaimSet claimSet) throws Exception {
ObjectNode localClaimSet = JsonNodeFactory.instance.objectNode();
ObjectNode localPayload = JsonNodeFactory.instance.objectNode();
localPayload.put(payloadId, payload);
if(claimSet != null) {
if(claimSet.getExp() > 0) {
localClaimSet.put("exp", claimSet.getExp());
}
localPayload.putAll(localClaimSet);
}
return base64UrlEncode(localPayload.toString().getBytes());
}
/**
* Sign the header and payload
*/
private String encodedSignature(String signingInput, String key,
Algorithm algorithm) throws Exception {
byte[] signature = sign(algorithm, signingInput, key);
return base64UrlEncode(signature);
}
/**
* Safe URL encode a byte array to a String
*/
private String base64UrlEncode(byte[] str) throws Exception {
return new String(Base64.encodeBase64URLSafe(str));
}
/**
* Switch the signing algorithm based on input, RSA not supported
*/
private byte[] sign(Algorithm algorithm, String msg, String key)
throws Exception {
switch (algorithm) {
case HS256:
case HS384:
case HS512:
return signHmac(algorithm, msg, key);
case RS256:
case RS384:
case RS512:
default:
throw new OperationNotSupportedException(
"Unsupported signing method");
}
}
/**
* Sign an input string using HMAC and return the encrypted bytes
*/
private byte[] signHmac(Algorithm algorithm, String msg, String key)
throws Exception {
Mac mac = Mac.getInstance(algorithm.getValue());
mac.init(new SecretKeySpec(key.getBytes(), algorithm.getValue()));
return mac.doFinal(msg.getBytes());
}
/**
* Mimick the ruby array.join function
*/
private String join(List<String> input, String on) {
int size = input.size();
int count = 1;
StringBuilder joined = new StringBuilder();
for (String string : input) {
joined.append(string);
if (count < size) {
joined.append(on);
}
count++;
}
return joined.toString();
}
}