Skip to content

Commit 2e7e935

Browse files
committed
## Changed
* `CBAuthValidator` has been renamed to just `AuthValidator` this way it can be used with ANY authentication service instead of binding it to just `cbauth`. This validator just relies on the `IAuthUser` interface now. ### Added * New `AuthValidator` now can validate permissions and roles according to our `IAuthUser` interface but can be used on ANY authentication service that implements `IAuthService`
1 parent 8f0758d commit 2e7e935

File tree

7 files changed

+132
-81
lines changed

7 files changed

+132
-81
lines changed

changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616
* **COMPAT** New `JwtAuthValidator` instead of mixing concerns with the `JwtService`. You will have to update your configuration to use this `validator` instead of the `JwtService`
1717
* `useSSL` is now defaulted to `true` for all security relocations as the default
1818
* Encapsulation of `jwt` settings from the `ModuleConfig` to the `JwtService`
19+
* `CBAuthValidator` has been renamed to just `AuthValidator` this way it can be used with ANY authentication service instead of binding it to just `cbauth`. This validator just relies on the `IAuthUser` interface now.
1920

2021
### Added
2122

23+
* New `AuthValidator` now can validate permissions and roles according to our `IAuthUser` interface but can be used on ANY authentication service that implements `IAuthService`
2224
* New authorization and authentication delegates for usage in cb7
2325
* New ability for the firewall to log all action events to a database table.
2426
* New visualizer that can visualize all settings and all firewall events via the log table if enabled.

models/CBSecurity.cfc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ component threadsafe singleton accessors="true" {
7575
// Auto load the global security firewall automatically, else you can load it a-la-carte via the `Security` interceptor
7676
"autoLoadFirewall" : true,
7777
// The validator is an object that will validate the firewall rules and annotations and provide feedback on either authentication or authorization issues.
78-
"validator" : "CBAuthValidator@cbsecurity",
78+
"validator" : "AuthValidator@cbsecurity",
7979
// Activate handler/action based annotation security
8080
"handlerAnnotationSecurity" : true,
8181
// The global invalid authentication event or URI or URL to go if an invalid authentication occurs
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/**
2+
* Copyright since 2016 by Ortus Solutions, Corp
3+
* www.ortussolutions.com
4+
* ---
5+
* This is the core validator which leverages any Authentication Service
6+
* that implements cbsecurity.models.interfaces.IAuthService and any User
7+
* that implements cbsecurity.models.interfaces.IAuthUser
8+
*/
9+
component singleton threadsafe {
10+
11+
// DI
12+
property name="cbSecurity" inject="CBSecurity@cbSecurity";
13+
property name="log" inject="logbox:logger:{this}";
14+
15+
/**
16+
* This function is called once an incoming event matches a security rule.
17+
* You will receive the security rule that matched and an instance of the
18+
* ColdBox controller.
19+
*
20+
* You must return a struct with three keys:
21+
* - allow:boolean True, user can continue access, false, invalid access actions will ensue
22+
* - type:string(authentication|authorization) The type of block that ocurred. Either an authentication or an authorization issue.
23+
* - messages:string Info/debug messages
24+
*
25+
* @return { allow:boolean, type:string(authentication|authorization), messages:string }
26+
*/
27+
struct function ruleValidator( required rule, required controller ){
28+
return validateSecurity( permissions: arguments.rule.permissions, roles: arguments.rule.roles );
29+
}
30+
31+
/**
32+
* This function is called once access to a handler/action is detected.
33+
* You will receive the secured annotation value and an instance of the ColdBox Controller
34+
*
35+
* You must return a struct with three keys:
36+
* - allow:boolean True, user can continue access, false, invalid access actions will ensue
37+
* - type:string(authentication|authorization) The type of block that ocurred. Either an authentication or an authorization issue.
38+
* - messages:string Info/debug messages
39+
*
40+
* @return { allow:boolean, type:string(authentication|authorization), messages:string }
41+
*/
42+
struct function annotationValidator( required securedValue, required controller ){
43+
return validateSecurity( permissions = arguments.securedValue );
44+
}
45+
46+
/**
47+
* Validate Security on the user
48+
*
49+
* @permissions The secured value of the annotation or the rule permissions
50+
* @roles Rule roles
51+
*
52+
* @return Security Results Struct: { allow : boolean, type : (authentication|authorization), messages : "" }
53+
*/
54+
private function validateSecurity( string permissions = "", string roles = "" ){
55+
var results = {
56+
"allow" : false,
57+
"type" : "authentication",
58+
"messages" : ""
59+
};
60+
var authService = variables.cbSecurity.getAuthService();
61+
62+
// Normalize roles + perms
63+
arguments.roles = arguments.roles.listToArray();
64+
arguments.permissions = arguments.permissions.listToArray();
65+
66+
if ( authService.isLoggedIn() ) {
67+
// If we are here, we are logged in, verify authorizations
68+
var oUser = authService.getUser();
69+
// Authentication passed, we are on to authorization now
70+
results.type = "authorization";
71+
// Default to block, unless we validate either roles or permissions
72+
results.allow = arrayLen( arguments.roles ) || arrayLen( arguments.permissions ) ? false : true;
73+
74+
// Validate new interface if not, just warn
75+
// TODO: Change to just use the hasRole() by vNext : Compat for now.
76+
if ( !structKeyExists( oUser, "hasRole" ) ) {
77+
variables.log.warn( "CBSecurity User object does not implement the `hasRole()` method. Please add it." );
78+
}
79+
80+
// Check roles
81+
if ( arrayLen( arguments.roles ) && structKeyExists( oUser, "hasRole" ) ) {
82+
for ( var thisRole in arguments.roles ) {
83+
if ( oUser.hasRole( thisRole ) ) {
84+
results.allow = true;
85+
break;
86+
}
87+
}
88+
}
89+
90+
// Check Perms
91+
if ( listLen( arguments.permissions ) ) {
92+
for ( var thisPermission in arguments.permissions ) {
93+
if ( oUser.hasPermission( thisPermission ) ) {
94+
results.allow = true;
95+
break;
96+
}
97+
}
98+
}
99+
}
100+
101+
return results;
102+
}
103+
104+
}

models/validators/BasicAuthValidator.cfc

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
*/
88
component singleton threadsafe {
99

10-
// Injection
10+
// DI
1111
property name="cbSecurity" inject="CBSecurity@cbSecurity";
12+
property name="log" inject="logbox:logger:{this}";
1213

1314
/**
1415
* This function is called once an incoming event matches a security rule.
@@ -79,32 +80,40 @@ component singleton threadsafe {
7980
results.allow = true;
8081
} catch ( "InvalidCredentials" e ) {
8182
// Not secure! Basic Auth Prompt
82-
event.setHTTPHeader(
83-
name = "WWW-Authenticate",
84-
value = "basic realm='Please enter your credentials'"
85-
).setHTTPHeader( name = "Cache-Control", value = "no-cache, must-revalidate, max-age=0" );
83+
event
84+
.setHTTPHeader(
85+
name = "WWW-Authenticate",
86+
value = "basic realm='Please enter your credentials'"
87+
)
88+
.setHTTPHeader( name = "Cache-Control", value = "no-cache, must-revalidate, max-age=0" );
8689
results.processactions = false;
8790
return results;
8891
}
8992
}
9093

9194
// If we are here, we are logged in, verify authorizations
92-
var user = authService.getUser();
95+
var oUser = authService.getUser();
9396
// Authentication passed, we are on to authorization now
9497
results.type = "authorization";
9598
// Default to block, unless we validate either roles or permissions
9699
results.allow = arrayLen( arguments.roles ) || arrayLen( arguments.permissions ) ? false : true;
97100

98-
// Check if the access requires roles
101+
// Validate new interface if not, just warn
102+
// TODO: Change to just use the hasRole() by vNext : Compat for now.
103+
if ( !structKeyExists( oUser, "hasRole" ) ) {
104+
variables.log.warn( "CBSecurity User object does not implement the `hasRole()` method. Please add it." );
105+
}
106+
107+
// Check roles
99108
if ( arrayLen( arguments.roles ) && structKeyExists( user, "hasRole" ) ) {
100-
if ( user.hasRole( arguments.roles ) ) {
109+
if ( oUser.hasRole( arguments.roles ) ) {
101110
results.allow = true;
102111
}
103112
}
104113

105-
// Check if the access requires permissions
114+
// Check perms
106115
if ( arrayLen( arguments.permissions ) ) {
107-
if ( user.hasPermission( arguments.permissions ) ) {
116+
if ( oUser.hasPermission( arguments.permissions ) ) {
108117
results.allow = true;
109118
}
110119
}
Lines changed: 3 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,7 @@
1-
/**
2-
* Copyright since 2016 by Ortus Solutions, Corp
3-
* www.ortussolutions.com
4-
* ---
5-
* This is the core validator which leverages CBAuth
6-
* https://helpx.adobe.com/coldfusion/developing-applications/developing-cfml-applications/securing-applications/using-coldfusion-security-tags-and-functions.html
7-
*/
8-
component singleton threadsafe {
1+
component singleton threadsafe extends="AuthValidator"{
92

10-
// Injection
11-
property name="cbSecurity" inject="CBSecurity@cbSecurity";
12-
13-
/**
14-
* This function is called once an incoming event matches a security rule.
15-
* You will receive the security rule that matched and an instance of the
16-
* ColdBox controller.
17-
*
18-
* You must return a struct with three keys:
19-
* - allow:boolean True, user can continue access, false, invalid access actions will ensue
20-
* - type:string(authentication|authorization) The type of block that ocurred. Either an authentication or an authorization issue.
21-
* - messages:string Info/debug messages
22-
*
23-
* @return { allow:boolean, type:string(authentication|authorization), messages:string }
24-
*/
25-
struct function ruleValidator( required rule, required controller ){
26-
return validateSecurity( arguments.rule.permissions );
27-
}
28-
29-
/**
30-
* This function is called once access to a handler/action is detected.
31-
* You will receive the secured annotation value and an instance of the ColdBox Controller
32-
*
33-
* You must return a struct with three keys:
34-
* - allow:boolean True, user can continue access, false, invalid access actions will ensue
35-
* - type:string(authentication|authorization) The type of block that ocurred. Either an authentication or an authorization issue.
36-
* - messages:string Info/debug messages
37-
*
38-
* @return { allow:boolean, type:string(authentication|authorization), messages:string }
39-
*/
40-
struct function annotationValidator( required securedValue, required controller ){
41-
return validateSecurity( arguments.securedValue );
42-
}
43-
44-
/**
45-
* Validate Security via CBAuth
46-
*
47-
* @permissions
48-
*/
49-
private function validateSecurity( required permissions ){
50-
var results = {
51-
"allow" : false,
52-
"type" : "authentication",
53-
"messages" : ""
54-
};
55-
56-
// Are we logged in?
57-
if ( variables.cbSecurity.getAuthService().isLoggedIn() ) {
58-
// Do we have any permissions?
59-
if ( listLen( arguments.permissions ) ) {
60-
results.allow = variables.cbSecurity.has( arguments.permissions );
61-
results.type = "authorization";
62-
} else {
63-
// We are satisfied!
64-
results.allow = true;
65-
}
66-
}
67-
68-
return results;
3+
function onDIComplete(){
4+
variables.log.warn( "The CBAuthValidator has been deprecated, please change your references to just `AuthValidator@cbsecurity` " );
695
}
706

717
}

readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ moduleSettings = {
134134
// Auto load the global security firewall automatically, else you can load it a-la-carte via the `Security` interceptor
135135
"autoLoadFirewall" : true,
136136
// The Global validator is an object that will validate the firewall rules and annotations and provide feedback on either authentication or authorization issues.
137-
"validator" : "CBAuthValidator@cbsecurity",
137+
"validator" : "AuthValidator@cbsecurity",
138138
// Activate handler/action based annotation security
139139
"handlerAnnotationSecurity" : true,
140140
// The global invalid authentication event or URI or URL to go if an invalid authentication occurs

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ component extends="coldbox.system.testing.BaseTestCase" appMapping="/root" {
173173

174174
given( "A secured annotated handler and an annotated action and a valid access", function(){
175175
then( "it should allow access", function(){
176-
prepareMock( getInstance( "CBAuthValidator@cbSecurity" ) ).$(
176+
prepareMock( getInstance( "AuthValidator@cbSecurity" ) ).$(
177177
"annotationValidator",
178178
{ allow : true, type : "authentication" }
179179
);
@@ -184,7 +184,7 @@ component extends="coldbox.system.testing.BaseTestCase" appMapping="/root" {
184184

185185
given( "A secured annotated handler and an annotated action with invalid auth", function(){
186186
then( "it should allow access to handler but not to action", function(){
187-
prepareMock( getInstance( "CBAuthValidator@cbSecurity" ) )
187+
prepareMock( getInstance( "AuthValidator@cbSecurity" ) )
188188
.$( "annotationValidator" )
189189
.$results(
190190
{ allow : true, type : "authentication" },

0 commit comments

Comments
 (0)