34
34
import io .netty .handler .codec .http .HttpHeaders ;
35
35
import io .netty .handler .codec .http .HttpResponseStatus ;
36
36
import org .apache .commons .lang3 .StringUtils ;
37
+ import org .summerboot .jexpress .boot .BootConstant ;
37
38
import org .summerboot .jexpress .boot .BootErrorCode ;
38
39
import org .summerboot .jexpress .boot .BootPOI ;
39
40
import org .summerboot .jexpress .integration .cache .AuthTokenCache ;
42
43
import org .summerboot .jexpress .nio .server .domain .Err ;
43
44
import org .summerboot .jexpress .nio .server .domain .ServiceContext ;
44
45
import org .summerboot .jexpress .security .JwtUtil ;
46
+ import org .summerboot .jexpress .util .FormatterUtil ;
45
47
46
48
import javax .naming .NamingException ;
47
49
import java .security .Key ;
48
50
import java .time .Duration ;
49
51
import java .util .Date ;
52
+ import java .util .Map ;
50
53
import java .util .Set ;
51
54
52
55
/**
@@ -81,28 +84,27 @@ public String signJWT(String username, String pwd, E metaData, int validForMinut
81
84
context .poi (BootPOI .LDAP_BEGIN );
82
85
Caller caller = authenticate (username , pwd , (E ) metaData , authenticatorListener , context );
83
86
context .poi (BootPOI .LDAP_END );
87
+
88
+ return signJWT (caller , validForMinutes , context );
89
+ }
90
+
91
+ @ Override
92
+ public String signJWT (Caller caller , int validForMinutes , final ServiceContext context ) {
84
93
if (caller == null ) {
85
94
context .status (HttpResponseStatus .UNAUTHORIZED );
86
95
return null ;
87
96
}
88
97
89
- // get token TTL from caller, otherwise use default
90
- Long tokenTtlSec = caller .getTokenTtlSec ();
91
- Duration tokenTTL ;
92
- if (tokenTtlSec != null ) {
93
- tokenTTL = Duration .ofSeconds (tokenTtlSec );
94
- } else {
95
- tokenTTL = Duration .ofMinutes (validForMinutes );
96
- }
97
-
98
- //3. format JWT
99
- JwtBuilder builder = toJwt (caller );
98
+ //3. format JWT and set token TTL from caller
99
+ JwtBuilder builder = toJwt (caller , context .txId ());
100
100
101
- //4 . create JWT
101
+ //5 . create JWT
102
102
Key signingKey = AuthConfig .cfg .getJwtSigningKey ();
103
103
if (signingKey == null ) {
104
104
throw new UnsupportedOperationException (ERROR_NO_CFG );
105
105
}
106
+ // override caller TTL if validForMinutes is greater than 0
107
+ Duration tokenTTL = Duration .ofMinutes (validForMinutes );
106
108
String token = JwtUtil .createJWT (signingKey , builder , tokenTTL );
107
109
if (authenticatorListener != null ) {
108
110
authenticatorListener .onLoginSuccess (caller .getUid (), token );
@@ -127,11 +129,12 @@ public String signJWT(String username, String pwd, E metaData, int validForMinut
127
129
* customized token format
128
130
*
129
131
* @param caller
132
+ * @param txId
130
133
* @return formatted auth token builder
131
134
*/
132
135
@ Override
133
- public JwtBuilder toJwt (Caller caller ) {
134
- String jti = caller .getTenantId () + ". " + caller .getId () + "_ " + caller . getUid () + "_" + System . currentTimeMillis ();
136
+ public JwtBuilder toJwt (Caller caller , String txId ) {
137
+ String jti = caller .getTenantId () + "- " + caller .getId () + "@ " + txId ; // tenantId-userId@txId
135
138
String issuer = AuthConfig .cfg .getJwtIssuer ();
136
139
String userName = caller .getUid ();
137
140
Set <String > groups = caller .getGroups ();
@@ -145,24 +148,31 @@ public JwtBuilder toJwt(Caller caller) {
145
148
.issuer (issuer )
146
149
.subject (userName )
147
150
.audience ().add (groups );
148
- if (caller .getId () != null ) {
149
- builder .claim ("callerId" , caller .getId ());
151
+ // if (caller.getId() != null) {
152
+ // builder.claim(KEY_CALLERID, caller.getId());
153
+ // }
154
+ // if (caller.getTenantId() != null) {
155
+ // builder.claim(KEY_TENANTID, caller.getTenantId());
156
+ // }
157
+ if (StringUtils .isNotBlank (caller .getTenantName ())) {
158
+ builder .claim (KEY_TENANTNAME , caller .getTenantName ());
150
159
}
151
- if (caller .getTenantId () != null ) {
152
- builder .claim ("tenantId" , caller .getTenantId ());
153
- }
154
- if (caller .getTenantName () != null ) {
155
- builder .claim ("tenantName" , caller .getTenantName ());
156
- }
157
- Set <String > keys = caller .propKeySet ();
158
- if (keys != null ) {
159
- for (String key : keys ) {
160
- Object v = caller .getProp (key , Object .class );
161
- builder .claim (key , v );
160
+ Set <Map .Entry <String , Object >> callerCustomizedFields = caller .customizedFields ();
161
+ if (callerCustomizedFields != null ) {
162
+ for (Map .Entry <String , Object > entry : callerCustomizedFields ) {
163
+ if (StringUtils .isBlank (entry .getKey ()) || entry .getValue () == null ) {
164
+ continue ;
165
+ }
166
+ builder .claim (entry .getKey (), entry .getValue ());
162
167
}
163
168
}
164
169
165
170
//JwtBuilder builder = Jwts.builder().setClaims(claims);
171
+ Long tokenTtlSec = caller .getTokenTtlSec ();
172
+ if (tokenTtlSec != null ) {
173
+ Duration tokenTTL = Duration .ofSeconds (tokenTtlSec );
174
+ JwtUtil .setJwtExpireTime (builder , tokenTTL );
175
+ }
166
176
return builder ;
167
177
}
168
178
@@ -174,6 +184,10 @@ protected Claims parseJWT(String jwt) {
174
184
return JwtUtil .parseJWT (jwtParser , jwt ).getPayload ();
175
185
}
176
186
187
+ // private static final String KEY_CALLERID = "callerId";
188
+ // private static final String KEY_TENANTID = "tenantId";
189
+ private static final String KEY_TENANTNAME = "tenantName" ;
190
+
177
191
/**
178
192
* Convert Caller back from auth token, override this method to implement
179
193
* customized token format
@@ -182,39 +196,61 @@ protected Claims parseJWT(String jwt) {
182
196
* @return Caller
183
197
*/
184
198
protected Caller fromJwt (Claims claims ) {
185
- //String jti = claims.getId();
186
199
//String issuer = claims.getIssuer();
187
200
String userName = claims .getSubject ();
188
201
Set <String > audience = claims .getAudience ();
189
- Long userId = claims .get ("callerId" , Long .class );
190
- Long tenantId = claims .get ("tenantId" , Long .class );
191
- String tenantName = claims .get ("tenantName" , String .class );
202
+ // Long userId = claims.get(KEY_CALLERID, Long.class);
203
+ // Long tenantId = claims.get(KEY_TENANTID, Long.class);
204
+ String jti = claims .getId (); // tenantId-userId@txId
205
+ Long tenantId = 0L , userId = 0L ;
206
+ // parse jti into tenantId and userId
207
+ try {
208
+ String [] arr0 = FormatterUtil .parseDsv (jti , "-" );
209
+ if (arr0 != null && arr0 .length > 1 ) {
210
+ tenantId = Long .parseLong (arr0 [0 ]);
211
+ String [] arr1 = FormatterUtil .parseDsv (arr0 [1 ], "@" );
212
+ userId = Long .parseLong (arr1 [0 ]);
213
+ }
214
+ } catch (Exception ex ) {
215
+ //ignore
216
+ }
217
+ String tenantName = claims .get (KEY_TENANTNAME , String .class );
192
218
193
219
User caller = new User (tenantId , tenantName , userId , userName );
194
220
195
221
if (audience != null ) {
196
222
for (String group : audience ) {
197
223
caller .addGroup (group );
224
+ if (BootConstant .CFG_JWT_AUD_AS_CSV && audience .size () == 1 ) {
225
+ String [] arr = FormatterUtil .parseCsv (group );
226
+ if (arr != null ) {
227
+ for (String g : arr ) {
228
+ if (StringUtils .isNotBlank (g )) {
229
+ caller .addGroup (g );
230
+ }
231
+ }
232
+ }
233
+ }
198
234
}
199
235
}
200
236
201
237
Set <String > keys = claims .keySet ();
202
238
if (keys != null ) {
203
239
for (String key : keys ) {
204
240
Object v = claims .get (key );
205
- caller .putProp (key , v );
241
+ caller .setCustomizedField (key , v );
206
242
}
207
243
}
208
- caller .remove (Claims .AUDIENCE );
209
- caller .remove (Claims .EXPIRATION );
210
- caller .remove (Claims .ID );
211
- caller .remove (Claims .ISSUED_AT );
212
- caller .remove (Claims .ISSUER );
213
- caller .remove (Claims .NOT_BEFORE );
214
- caller .remove (Claims .SUBJECT );
215
- caller .remove ( "callerId" );
216
- caller .remove ( "tenantId" );
217
- caller .remove ( "tenantName" );
244
+ caller .removeCustomizedField (Claims .AUDIENCE );
245
+ caller .removeCustomizedField (Claims .EXPIRATION );
246
+ caller .removeCustomizedField (Claims .ID );
247
+ caller .removeCustomizedField (Claims .ISSUED_AT );
248
+ caller .removeCustomizedField (Claims .ISSUER );
249
+ caller .removeCustomizedField (Claims .NOT_BEFORE );
250
+ caller .removeCustomizedField (Claims .SUBJECT );
251
+ // caller.removeCustomizedField(KEY_CALLERID );
252
+ // caller.removeCustomizedField(KEY_TENANTID );
253
+ caller .removeCustomizedField ( KEY_TENANTNAME );
218
254
219
255
return caller ;
220
256
}
0 commit comments