Skip to content

Commit 233757b

Browse files
committed
migration complete
1 parent 166957a commit 233757b

File tree

9 files changed

+117
-35
lines changed

9 files changed

+117
-35
lines changed

ModuleConfig.cfc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ component {
1919
// Helpers
2020
this.applicationHelper = [ "helpers/mixins.cfm" ];
2121
// Dependencies
22-
this.dependencies = [ "cbauth", "jwt" ];
22+
this.dependencies = [ "cbauth", "jwtcfml" ];
2323

2424
/**
2525
* Module Config

box.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"*/.md"
2929
],
3030
"dependencies":{
31-
"jwt":"^1.1.0",
31+
"jwt-cfml":"^1.0.0",
3232
"cbauth":"^4.0.0"
3333
},
3434
"scripts":{

changelog.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,19 @@
22

33
## 2.2.0
44

5+
* `Feature` : Migrated from the jwt to the `jwtcfml` (https://forgebox.io/view/jwt-cfml) library to expand encoding/decoding capabilities to support `RS` and `ES` algorithms:
6+
* HS256
7+
* HS384
8+
* HS512
9+
* RS256
10+
* RS384
11+
* RS512
12+
* ES256
13+
* ES384
14+
* ES512
515
* `Feature` : Added a new convenience method on the JWT Service: `isTokenInStorage( token )` to verify if a token still exists in the token storage
16+
* `Feature` : If no jwt secret is given in the settings, we will dynamically generate one that will last for the duration of the application scope.
17+
* `Improve` : Ability to have defaults for all JWT settings instead of always typing them in the configs
618
* `Improve` : More cfformating goodness!
719
* `Bug` : Invalidation of tokens was not happening due to not using the actual key for the storage
820

models/jwt/JwtService.cfc

Lines changed: 87 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,21 @@
77
*/
88
component accessors="true" singleton {
99

10-
// DI
11-
property name="jwt" inject="provider:JWTService@jwt";
10+
/*********************************************************************************************/
11+
/** DI **/
12+
/*********************************************************************************************/
13+
14+
property name="jwt" inject="provider:jwt@jwtcfml";
1215
property name="wirebox" inject="wirebox";
1316
property name="settings" inject="coldbox:moduleSettings:cbSecurity";
1417
property name="interceptorService" inject="coldbox:interceptorService";
1518
property name="requestService" inject="coldbox:requestService";
1619
property name="log" inject="logbox:logger:{this}";
1720

21+
/*********************************************************************************************/
22+
/** PROPERTIES **/
23+
/*********************************************************************************************/
24+
1825
/**
1926
* The auth service in use
2027
*/
@@ -30,6 +37,10 @@ component accessors="true" singleton {
3037
*/
3138
property name="tokenStorage";
3239

40+
/*********************************************************************************************/
41+
/** STATIC PROPERTIES **/
42+
/*********************************************************************************************/
43+
3344
// Required Claims
3445
variables.REQUIRED_CLAIMS = [
3546
"jti",
@@ -40,6 +51,41 @@ component accessors="true" singleton {
4051
"scopes"
4152
];
4253

54+
// Default Settings
55+
variables.DEFAULT_SETTINGS = {
56+
// The jwt secret encoding key
57+
"secretKey" : "",
58+
// The Custom header to inspect for tokens
59+
"customAuthHeader" : "x-auth-token",
60+
// The expiration in minutes for the jwt tokens
61+
"expiration" : 60,
62+
// If true, enables refresh tokens, longer lived tokens (not implemented yet)
63+
"enableRefreshTokens" : false,
64+
// The default expiration for refresh tokens, defaults to 30 days
65+
"refreshExpiration" : 43200,
66+
// encryption algorithm to use, valid algorithms are: HS256, HS384, and HS512
67+
"algorithm" : "HS512",
68+
// Which claims neds to be present on the jwt token or `TokenInvalidException` upon verification and decoding
69+
"requiredClaims" : [] ,
70+
// The token storage settings
71+
"tokenStorage" : {
72+
// enable or not, default is true
73+
"enabled" : true,
74+
// A cache key prefix to use when storing the tokens
75+
"keyPrefix" : "cbjwt_",
76+
// The driver to use: db, cachebox or a WireBox ID
77+
"driver" : "cachebox",
78+
// Driver specific properties
79+
"properties" : {
80+
"cacheName" : "default"
81+
}
82+
}
83+
};
84+
85+
/*********************************************************************************************/
86+
/** CONSTRUCTOR & STARTUP **/
87+
/*********************************************************************************************/
88+
4389
/**
4490
* Constructor
4591
*/
@@ -48,17 +94,24 @@ component accessors="true" singleton {
4894
}
4995

5096
/**
51-
* Runs after DI
97+
* Runs after DI, here is where we setup the jwt settings for operation
5298
*/
5399
function onDIComplete(){
54-
// Verify a few settings just in case
100+
// If no settings defined, use the defaults
101+
if( !structKeyExists( variables.settings, "jwt" ) ){
102+
variables.settings.jwt = variables.DEFAULT_SETTINGS;
103+
}
104+
105+
// Incorporate defaults into incoming data
106+
structAppend( variables.settings.jwt, variables.DEFAULT_SETTINGS, false );
107+
structAppend( variables.settings.jwt.tokenStorage, variables.DEFAULT_SETTINGS.tokenStorage, false );
108+
109+
// If no secret is defined, then let's create one dynamically
55110
if ( isNull( variables.settings.jwt.secretKey ) || !len( variables.settings.jwt.secretKey ) ) {
56-
throw(
57-
message = "The JWT secret key cannot be empty, please fill this out in your `config/ColdBox.cfc` under your cbsecurity settings",
58-
detail = "cbsecurity.jwt.secretKey",
59-
type = "InvalidSecretKey"
60-
)
111+
variables.settings.jwt.secretKey = generateSecretKey( "blowfish", 448 );
112+
variables.log.warn( "No jwt secret key setting found, automatically generating one" );
61113
}
114+
62115
}
63116

64117
/************************************************************************************/
@@ -326,8 +379,14 @@ component accessors="true" singleton {
326379
}
327380
} );
328381

382+
329383
// Verify Expiration first
330-
if ( dateCompare( fromEpoch( decodedToken.exp ), now() ) < 0 ) {
384+
if (
385+
dateCompare(
386+
( isDate( decodedToken.exp ) ? decodedToken.exp : fromEpoch( decodedToken.exp ) ),
387+
now()
388+
) < 0
389+
) {
331390
if ( variables.log.canWarn() ) {
332391
variables.log.warn( "Token rejected, it has expired", decodedToken );
333392
}
@@ -477,11 +536,17 @@ component accessors="true" singleton {
477536
* @token The token to validate
478537
*/
479538
boolean function verify( required token ){
480-
return variables.jwt.verify(
481-
arguments.token,
482-
variables.settings.jwt.secretKey,
483-
variables.settings.jwt.algorithm
484-
);
539+
try{
540+
variables.jwt.decode(
541+
token = arguments.token,
542+
key = variables.settings.jwt.secretKey,
543+
algorithms = variables.settings.jwt.algorithm,
544+
verify = false
545+
);
546+
return true;
547+
} catch( Any e ){
548+
return false;
549+
}
485550
}
486551

487552
/**
@@ -494,9 +559,9 @@ component accessors="true" singleton {
494559
struct function decode( required token ){
495560
try {
496561
return variables.jwt.decode(
497-
arguments.token,
498-
variables.settings.jwt.secretKey,
499-
variables.settings.jwt.algorithm
562+
token = arguments.token,
563+
key = variables.settings.jwt.secretKey,
564+
algorithms = variables.settings.jwt.algorithm
500565
);
501566
} catch ( any e ) {
502567
throw(
@@ -567,7 +632,9 @@ component accessors="true" singleton {
567632
}
568633

569634
/**
570-
* Get the appropriate token storage
635+
* Get the appropriate token storage provider
636+
*
637+
* @return cbsecurity.interfaces.jwt.IJwtStorage
571638
*/
572639
function getTokenStorage(){
573640
// If loaded, use it!
@@ -725,4 +792,4 @@ component accessors="true" singleton {
725792
.len();
726793
}
727794

728-
}
795+
}

test-harness/box.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,27 @@
77
"dependencies":{
88
"coldbox":"^5.0.0",
99
"testbox":"be",
10-
"jwt":"^1.1.0",
1110
"cbauth":"^4.0.0",
12-
"BCrypt":"^2.5.0-snapshot"
11+
"BCrypt":"^2.5.0-snapshot",
12+
"jwt-cfml":"^1.0.0"
1313
},
1414
"devDependencies":{
1515
"route-visualizer":"^1.2.0+4"
1616
},
1717
"installPaths":{
1818
"coldbox":"coldbox/",
1919
"testbox":"testbox/",
20-
"jwt":"modules/jwt/",
2120
"cbauth":"modules/cbauth/",
2221
"BCrypt":"modules/BCrypt/",
23-
"route-visualizer":"modules/route-visualizer/"
22+
"route-visualizer":"modules/route-visualizer/",
23+
"jwt-cfml":"modules/jwtcfml/"
2424
},
2525
"testbox":{
2626
"runner":"http://localhost:60299/tests/runner.cfm"
2727
},
2828
"scripts":{
29-
"format":"cfformat config/**.cfc,handlers/**.cfc,models/**.cfc,modules_app/**.cfc,tests/specs/**/*.cfc --overwrite",
30-
"format:watch":"cfformat config/**.cfc,handlers/**.cfc,models/**.cfc,modules_app/**.cfc,tests/specs/**/*.cfc --watch",
31-
"format:check":"cfformat config/**.cfc,handlers/**.cfc,models/**.cfc,modules_app/**.cfc,tests/specs/**/*.cfc --check"
29+
"format":"cfformat run config/**.cfc,handlers/**.cfc,models/**.cfc,modules_app/**.cfc,tests/specs/**/*.cfc --overwrite",
30+
"format:watch":"cfformat run config/**.cfc,handlers/**.cfc,models/**.cfc,modules_app/**.cfc,tests/specs/**/*.cfc --watch",
31+
"format:check":"cfformat run config/**.cfc,handlers/**.cfc,models/**.cfc,modules_app/**.cfc,tests/specs/**/*.cfc --check"
3232
}
3333
}

test-harness/config/Coldbox.cfc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,9 @@
118118
"jwt" : {
119119
"secretKey" : "C3D4AF35-8FCD-49AB-943A39AEFFB584EE",
120120
"customAuthHeader" : "x-auth-token",
121-
"expiration" : 60,
122-
"enableRefreshTokens" : false,
123-
"refreshExpiration" : 43200,
121+
//"expiration" : 60,
122+
//"enableRefreshTokens" : false,
123+
//"refreshExpiration" : 43200,
124124
"algorithm" : "HS512",
125125
"requiredClaims" : [ "role" ],
126126
"tokenStorage" : {

test-harness/[email protected]

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
},
1111
"rewrites":{
1212
"enable":"true"
13-
},
14-
"aliases":{
13+
},
14+
"aliases":{
1515
"/moduleroot/cbsecurity":"../"
1616
}
1717
},

test-harness/tests/Application.cfc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ component {
3232

3333
// request start
3434
public boolean function onRequestStart( String targetPage ){
35+
if( server.keyExists( "lucee" ) ){
36+
pagePoolClear();
37+
}
3538
return true;
3639
}
3740

test-harness/tests/specs/integration/JWTSpec.cfc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ component extends="coldbox.system.testing.BaseTestCase" appMapping="/root" {
8282
expect( event.getCurrentEvent() ).toBe( "api:Home.onInvalidAuth" );
8383
expect( event.valueExists( "relocate_event" ) ).toBeFalse();
8484
expect( event.getPrivateValue( "cbsecurity_validatorResults" ).messages ).toInclude(
85-
"TokenExpiredException"
85+
"Token has expired"
8686
);
8787
} );
8888
} );

0 commit comments

Comments
 (0)