Skip to content
This repository was archived by the owner on Sep 2, 2020. It is now read-only.

Commit 8075b45

Browse files
committed
fix(SecuredEventInterceptor): Relocate by default for non-ajax events
For non-ajax events, `relocate` instead of `overrideEvent` to allow for preProcess events and the like to fire completely when loading the login page (or whatever page is the target of the redirect). For ajax events, `overrideEvent` is still used. This behavior can be adjusted in the module settings. BREAKING CHANGE: Non-ajax events now relocate instead of override the event.
1 parent b199f66 commit 8075b45

File tree

6 files changed

+136
-35
lines changed

6 files changed

+136
-35
lines changed

ModuleConfig.cfc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ component {
3737

3838
function onLoad() {
3939
controller.getInterceptorService().registerInterceptor(
40+
interceptorName = "SecuredEventInterceptor",
4041
interceptorClass = "#moduleMapping#.interceptors.SecuredEventInterceptor",
4142
interceptorProperties = settings
4243
);

README.md

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
## Annotation driven guards for authentication and authorization in ColdBox
66

7-
87
### Usage
98

109
`cbguard` lets us lock down methods to logged in users and users with specific permissions using one annotation — `secured`. Just sticking the secured annotation on a handler or action is enough to require a user to log in before executing those events.
@@ -41,7 +40,7 @@ You can further lock down handlers and actions to a list of specific permissions
4140

4241
```cfc
4342
component secured="admin" {
44-
43+
4544
function index( event, rc, prc ) {
4645
// ...
4746
}
@@ -57,7 +56,7 @@ In the above component, the user must have the `admin` permission to access the
5756

5857
```cfc
5958
component {
60-
59+
6160
function show( event, rc, prc ) secured="admin,reviews_posts" {
6261
// ...
6362
}
@@ -176,3 +175,23 @@ moduleSettings = {
176175
}
177176
};
178177
```
178+
179+
Additionally, you can modify the override action for each of the event types:
180+
181+
```cfc
182+
moduleSettings = {
183+
cbguard = {
184+
overrideActions = {
185+
authenticationOverrideEvent = "relocate",
186+
authenticationAjaxOverrideEvent = "override",
187+
authorizationOverrideEvent = "relocate",
188+
authorizationAjaxOverrideEvent = "override"
189+
}
190+
}
191+
};
192+
```
193+
194+
`relocate` refers to calling `relocate` on the controller. The user will be redirected to the new page.
195+
`override` refers to `event.overrideEvent`. This will not redirect but simply change the running event.
196+
197+
`

interceptors/SecuredEventInterceptor.cfc

Lines changed: 65 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ component extends="coldbox.system.Interceptor"{
1616
* the event is overridden to the event specified in module settings.
1717
*/
1818
function preProcess( event, rc, prc, interceptData, buffer ) {
19-
20-
if ( isNull( variables.authenticationService ) ) {
19+
if ( isNull( variables.authenticationService ) ) {
2120
variables.authenticationService = wirebox.getInstance( getProperty( "AuthenticationService" ) );
2221
}
2322

@@ -56,11 +55,22 @@ component extends="coldbox.system.Interceptor"{
5655
}
5756

5857
if ( ! invoke( authenticationService, getProperty( "methodNames" )[ "isLoggedIn" ] ) ) {
59-
event.overrideEvent(
60-
event.isAjax() ?
61-
getProperty( "authenticationAjaxOverrideEvent", getProperty( "authenticationOverrideEvent", "" ) ) :
62-
getProperty( "authenticationOverrideEvent", "" )
63-
);
58+
var eventType = event.isAjax() ? "authenticationAjaxOverrideEvent" : "authenticationOverrideEvent";
59+
var relocateEvent = getProperty( eventType );
60+
var overrideAction = getProperty( "overrideActions" )[ eventType ];
61+
switch ( overrideAction ) {
62+
case "relocate":
63+
relocate( relocateEvent );
64+
break;
65+
case "override":
66+
event.overrideEvent( relocateEvent );
67+
break;
68+
default:
69+
throw(
70+
type = "InvalidOverideActionType",
71+
message = "The type [#overrideAction#] is not a valid override action. Valid types are ['relocate', 'override']."
72+
);
73+
}
6474
return true;
6575
}
6676

@@ -81,11 +91,22 @@ component extends="coldbox.system.Interceptor"{
8191
}
8292
}
8393

84-
event.overrideEvent(
85-
event.isAjax() ?
86-
getProperty( "authorizationAjaxOverrideEvent", getProperty( "authorizationOverrideEvent", "" ) ) :
87-
getProperty( "authorizationOverrideEvent", "" )
88-
);
94+
var eventType = event.isAjax() ? "authorizationAjaxOverrideEvent" : "authorizationOverrideEvent";
95+
var relocateEvent = getProperty( eventType );
96+
var overrideAction = getProperty( "overrideActions" )[ eventType ];
97+
switch ( overrideAction ) {
98+
case "relocate":
99+
relocate( relocateEvent );
100+
break;
101+
case "override":
102+
event.overrideEvent( relocateEvent );
103+
break;
104+
default:
105+
throw(
106+
type = "InvalidOverideActionType",
107+
message = "The type [#overrideAction#] is not a valid override action. Valid types are ['relocate', 'override']."
108+
);
109+
}
89110
return true;
90111
}
91112

@@ -117,11 +138,22 @@ component extends="coldbox.system.Interceptor"{
117138
}
118139

119140
if ( ! invoke( authenticationService, getProperty( "methodNames" )[ "isLoggedIn" ] ) ) {
120-
event.overrideEvent(
121-
event.isAjax() ?
122-
getProperty( "authenticationAjaxOverrideEvent", getProperty( "authenticationOverrideEvent", "" ) ) :
123-
getProperty( "authenticationOverrideEvent", "" )
124-
);
141+
var eventType = event.isAjax() ? "authenticationAjaxOverrideEvent" : "authenticationOverrideEvent";
142+
var relocateEvent = getProperty( eventType );
143+
var overrideAction = getProperty( "overrideActions" )[ eventType ];
144+
switch ( overrideAction ) {
145+
case "relocate":
146+
relocate( relocateEvent );
147+
break;
148+
case "override":
149+
event.overrideEvent( relocateEvent );
150+
break;
151+
default:
152+
throw(
153+
type = "InvalidOverideActionType",
154+
message = "The type [#overrideAction#] is not a valid override action. Valid types are ['relocate', 'override']."
155+
);
156+
}
125157
return true;
126158
}
127159

@@ -142,11 +174,22 @@ component extends="coldbox.system.Interceptor"{
142174
}
143175
}
144176

145-
event.overrideEvent(
146-
event.isAjax() ?
147-
getProperty( "authorizationAjaxOverrideEvent", getProperty( "authorizationOverrideEvent", "" ) ) :
148-
getProperty( "authorizationOverrideEvent", "" )
149-
);
177+
var eventType = event.isAjax() ? "authorizationAjaxOverrideEvent" : "authorizationOverrideEvent";
178+
var relocateEvent = getProperty( eventType );
179+
var overrideAction = getProperty( "overrideActions" )[ eventType ];
180+
switch ( overrideAction ) {
181+
case "relocate":
182+
relocate( relocateEvent );
183+
break;
184+
case "override":
185+
event.overrideEvent( relocateEvent );
186+
break;
187+
default:
188+
throw(
189+
type = "InvalidOverideActionType",
190+
message = "The type [#overrideAction#] is not a valid override action. Valid types are ['relocate', 'override']."
191+
);
192+
}
150193
return true;
151194
}
152195

tests/resources/ModuleIntegrationSpec.cfc

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ component extends="coldbox.system.testing.BaseTestCase" {
22

33
function beforeAll() {
44
super.beforeAll();
5-
5+
66
getController().getModuleService()
77
.registerAndActivateModule( "cbguard", "testingModuleRoot" );
88
}
@@ -14,4 +14,18 @@ component extends="coldbox.system.testing.BaseTestCase" {
1414
setup();
1515
}
1616

17+
function withSwappedSettings( applyOverrides, callback ) {
18+
var newSettings = duplicate( getController().getConfigSettings().modules.cbguard.settings );
19+
applyOverrides( newSettings );
20+
var interceptor = getController().getInterceptorService().getInterceptor( "SecuredEventInterceptor" );
21+
interceptor.setProperties( newSettings );
22+
try {
23+
callback();
24+
} catch ( any e ) {
25+
rethrow;
26+
} finally {
27+
interceptor.setProperties( getController().getConfigSettings().modules.cbguard.settings );
28+
}
29+
}
30+
1731
}

tests/specs/integration/AuthenticationSpec.cfc

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,19 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" {
2020

2121
it( "redirects the user if the component has a secured annotation and the user is not logged in", function() {
2222
var event = execute( event = "Secured.index" );
23-
expect( event.getValue( "event", "" ) ).toBe( "Main.onAuthenticationFailure" );
23+
expect( event.getValue( "relocate_EVENT", "" ) ).toBe( "Main.onAuthenticationFailure" );
24+
} );
25+
26+
it( "overrides the event if the component has a secured annotation and the user is not logged in with specific settings", function() {
27+
withSwappedSettings(
28+
function( settings ) {
29+
settings.overrideActions.authenticationOverrideEvent = "override";
30+
},
31+
function() {
32+
var event = execute( event = "Secured.index" );
33+
expect( event.getValue( "event", "" ) ).toBe( "Main.onAuthenticationFailure" );
34+
}
35+
);
2436
} );
2537

2638
it( "does not redirect the user if the component has a secured annotation and the user is logged in", function() {
@@ -31,7 +43,19 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" {
3143

3244
it( "redirects the user if the action has a secured annotation and the user is not logged in", function() {
3345
var event = execute( event = "PartiallySecured.secured" );
34-
expect( event.getValue( "event", "" ) ).toBe( "Main.onAuthenticationFailure" );
46+
expect( event.getValue( "relocate_EVENT", "" ) ).toBe( "Main.onAuthenticationFailure" );
47+
} );
48+
49+
it( "overrides the event if the action has a secured annotation and the user is not logged in with specific settings", function() {
50+
withSwappedSettings(
51+
function( settings ) {
52+
settings.overrideActions.authenticationOverrideEvent = "override";
53+
},
54+
function() {
55+
var event = execute( event = "PartiallySecured.secured" );
56+
expect( event.getValue( "event", "" ) ).toBe( "Main.onAuthenticationFailure" );
57+
}
58+
);
3559
} );
3660

3761
it( "does not redirect the user if the action has a secured annotation and the user is logged in", function() {

tests/specs/integration/AuthorizationSpec.cfc

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,19 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" {
1515

1616
it( "redirects the user if the component has a secured annotation with a list of permissions and the user is not logged in", function() {
1717
var event = execute( event = "PermissionSecured.fooPermissionAction" );
18-
expect( event.getValue( "event", "" ) ).toBe( "Main.onAuthenticationFailure" );
18+
expect( event.getValue( "relocate_EVENT", "" ) ).toBe( "Main.onAuthenticationFailure" );
1919
} );
2020

2121
it( "redirects the user if the component has a secured annotation with a list of permissions and the user does not have any permissions", function() {
2222
authenticationService.login( createUser( { permissions = [] } ) );
2323
var event = execute( event = "PermissionSecured.fooPermissionAction" );
24-
expect( event.getValue( "event", "" ) ).toBe( "Main.onAuthorizationFailure" );
24+
expect( event.getValue( "relocate_EVENT", "" ) ).toBe( "Main.onAuthorizationFailure" );
2525
} );
2626

2727
it( "redirects the user if the component has a secured annotation with a list of permissions and the user does not have any of the required permissions", function() {
2828
authenticationService.login( createUser( { permissions = [ "bar" ] } ) );
2929
var event = execute( event = "PermissionSecured.fooPermissionAction" );
30-
expect( event.getValue( "event", "" ) ).toBe( "Main.onAuthorizationFailure" );
30+
expect( event.getValue( "relocate_EVENT", "" ) ).toBe( "Main.onAuthorizationFailure" );
3131
} );
3232

3333
it( "does not redirect the user if the component has a secured annotation with a list of permissions and the user has at least one of the required permissions", function() {
@@ -38,19 +38,19 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" {
3838

3939
it( "redirects the user if the action has a secured annotation with a list of permissions and the user is not logged in", function() {
4040
var event = execute( event = "PermissionActionSecured.fooPermissionAction" );
41-
expect( event.getValue( "event", "" ) ).toBe( "Main.onAuthenticationFailure" );
41+
expect( event.getValue( "relocate_EVENT", "" ) ).toBe( "Main.onAuthenticationFailure" );
4242
} );
4343

4444
it( "redirects the user if the action has a secured annotation with a list of permissions and the user does not have any permissions", function() {
4545
authenticationService.login( createUser( { permissions = [] } ) );
4646
var event = execute( event = "PermissionActionSecured.fooPermissionAction" );
47-
expect( event.getValue( "event", "" ) ).toBe( "Main.onAuthorizationFailure" );
47+
expect( event.getValue( "relocate_EVENT", "" ) ).toBe( "Main.onAuthorizationFailure" );
4848
} );
4949

5050
it( "redirects the user if the action has a secured annotation with a list of permissions and the user does not have any of the required permissions", function() {
5151
authenticationService.login( createUser( { permissions = [ "bar" ] } ) );
5252
var event = execute( event = "PermissionActionSecured.fooPermissionAction" );
53-
expect( event.getValue( "event", "" ) ).toBe( "Main.onAuthorizationFailure" );
53+
expect( event.getValue( "relocate_EVENT", "" ) ).toBe( "Main.onAuthorizationFailure" );
5454
} );
5555

5656
it( "does not redirect the user if the action has a secured annotation with a list of permissions and the user has at least one of the required permissions", function() {
@@ -62,7 +62,7 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" {
6262
it( "redirects the user if the component has a secured annotatoin with a list of permissions and the user has at least one of the required permissions but the action also has a secured annotation with a list of permissions and the user does not have any of the required permissions", function() {
6363
authenticationService.login( createUser( { permissions = [ "one" ] } ) );
6464
var event = execute( event = "DoubleSecured.securedAction" );
65-
expect( event.getValue( "event", "" ) ).toBe( "Main.onAuthorizationFailure" );
65+
expect( event.getValue( "relocate_EVENT", "" ) ).toBe( "Main.onAuthorizationFailure" );
6666
} );
6767

6868
it( "does not redirect the user if the component has a secured annotatoin with a list of permissions and the user has at least one of the required permissions and the action also has a secured annotation with a list of permissions and the user has at least one of the required permissions", function() {

0 commit comments

Comments
 (0)