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

Commit 731113b

Browse files
committed
feat: Add _securedUrl to flash scope on overrides
1 parent c9f9c4d commit 731113b

File tree

5 files changed

+119
-65
lines changed

5 files changed

+119
-65
lines changed

.travis.yml

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
11
language: java
22
sudo: required
33
jdk:
4-
- openjdk8
4+
- openjdk8
55
env:
6-
matrix:
7-
- ENGINE=lucee@5 COLDBOX_VERSION=stable
8-
- ENGINE=adobe@2018 COLDBOX_VERSION=stable
9-
- ENGINE=adobe@2016 COLDBOX_VERSION=stable
10-
- ENGINE=lucee@5 COLDBOX_VERSION=be
11-
- ENGINE=adobe@2018 COLDBOX_VERSION=be
12-
- ENGINE=adobe@2016 COLDBOX_VERSION=be
6+
matrix:
7+
- ENGINE=lucee@5 COLDBOX_VERSION=stable
8+
- ENGINE=adobe@2018 COLDBOX_VERSION=stable
9+
- ENGINE=adobe@2016 COLDBOX_VERSION=stable
10+
- ENGINE=lucee@5 COLDBOX_VERSION=be
11+
- ENGINE=adobe@2018 COLDBOX_VERSION=be
12+
- ENGINE=adobe@2016 COLDBOX_VERSION=be
1313
before_install:
14-
- curl -fsSl https://downloads.ortussolutions.com/debs/gpg | sudo apt-key add -
15-
- sudo echo "deb http://downloads.ortussolutions.com/debs/noarch /" | sudo tee -a /etc/apt/sources.list.d/commandbox.list
14+
- curl -fsSl https://downloads.ortussolutions.com/debs/gpg | sudo apt-key add -
15+
- sudo echo "deb http://downloads.ortussolutions.com/debs/noarch /" | sudo tee -a /etc/apt/sources.list.d/commandbox.list
1616
install:
17-
- sudo apt update && sudo apt --assume-yes install commandbox
18-
- box install commandbox-cfformat
19-
- box install
20-
- box install coldbox@${COLDBOX_VERSION} --force
17+
- sudo apt update && sudo apt --assume-yes install commandbox
18+
- box install commandbox-cfformat
19+
- box install
20+
- box install coldbox@${COLDBOX_VERSION} --force --!save
2121
before_script:
22-
- box server start cfengine=$ENGINE port=8500
22+
- box server start cfengine=$ENGINE port=8500
2323
script:
24-
- box testbox run verbose=false
25-
- box run-script format:check
24+
- box testbox run verbose=false
25+
- box run-script format:check
2626
after_success:
27-
- box install commandbox-semantic-release
28-
- box config set endpoints.forgebox.APIToken=${FORGEBOX_TOKEN}
29-
- box semantic-release
27+
- box install commandbox-semantic-release
28+
- box config set endpoints.forgebox.APIToken=${FORGEBOX_TOKEN}
29+
- box semantic-release
3030
notifications:
31-
email: false
31+
email: false

README.md

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
### Usage
88

9-
`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.
9+
`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.
1010

1111
Here's an example of how to lock down an entire handler:
1212

@@ -36,7 +36,7 @@ component {
3636
}
3737
```
3838

39-
You can further lock down handlers and actions to a list of specific permissions. If specified, the logged in user must have one of the permissions in the list specified.
39+
You can further lock down handlers and actions to a list of specific permissions. If specified, the logged in user must have one of the permissions in the list specified.
4040

4141
```cfc
4242
component secured="admin" {
@@ -64,7 +64,7 @@ component {
6464
}
6565
```
6666

67-
Individual actions can be secured in the same way. Above, the `show` action requires the logged in user to have either the `admin` or the `reviews_posts` permission.
67+
Individual actions can be secured in the same way. Above, the `show` action requires the logged in user to have either the `admin` or the `reviews_posts` permission.
6868

6969
These two approaches can be combined and both handler and actions can be secured together:
7070

@@ -118,7 +118,7 @@ public void function authorize( required any permissions, struct additionalArgs
118118
In all cases `permissions` can be either a string, a list of strings, or an array of strings.
119119

120120
In the case of `authorize` the `errorMessage` replaces the thrown error message
121-
in the `NotAuthorized`. exception. It can also be a closure that takes the following shape:
121+
in the `NotAuthorized`. exception. It can also be a closure that takes the following shape:
122122

123123
```cfc
124124
string function errorMessage( array permissions, any user, struct additionalArgs );
@@ -127,14 +127,14 @@ string function errorMessage( array permissions, any user, struct additionalArgs
127127
#### Defining Custom Guards
128128

129129
While handling all of your guard clauses inside the `hasPermission` method on your user
130-
works fine, you may want to define a different way to handle permissions. You
131-
can do this by declaring custom guards using the `guard.define` method. Here's the signature:
130+
works fine, you may want to define a different way to handle permissions. You
131+
can do this by declaring custom guards using the `guard.define` method. Here's the signature:
132132

133133
```cfc
134134
public Guard function define( required string name, required any callback );
135135
```
136136

137-
The `name` will match against a permission name. If it matches, the guard is
137+
The `name` will match against a permission name. If it matches, the guard is
138138
called instead of calling `hasPermission` on the `User` model. (You can always
139139
call `hasPermission` on the `User` inside your guard callback if you need.)
140140

@@ -149,7 +149,7 @@ public boolean function authorize( required any user, struct additionalArgs = {}
149149
```
150150

151151
Using this approach, you can define custom guards anywhere in your application:
152-
`config/ColdBox.cfc`, `ModuleConfig.cfc` of your custom modules, etc. The
152+
`config/ColdBox.cfc`, `ModuleConfig.cfc` of your custom modules, etc. The
153153
`Guard` component is registered as a singleton, so it will keep track of all the
154154
guards registered, even from different sources.
155155

@@ -161,7 +161,7 @@ public Guard function removeDefinition( required string name );
161161

162162
### Redirects
163163

164-
When a user is denied access to a action, an event of your choosing is executed instead. There are four keys that can be set in the `moduleSettings` struct that all come with good defaults.
164+
When a user is denied access to a action, an event of your choosing is executed instead. There are four keys that can be set in the `moduleSettings` struct that all come with good defaults.
165165

166166
1. `authenticationOverrideEvent` (Default: `Main.onAuthenticationFailure`)
167167

@@ -173,12 +173,16 @@ This is the event that is executed when the user is logged in and is attempting
173173

174174
3. `authenticationAjaxOverrideEvent` (Default: `Main.onAuthenticationFailure`)
175175

176-
This is the event that is executed when the user is not logged in and is attempting to execute a secured action via ajax (`event.isAjax()`), whether or not that handler or action has permissions. By default, this will execute the same action that is configured for `authenticationOverrideEvent`.
176+
This is the event that is executed when the user is not logged in and is attempting to execute a secured action via ajax (`event.isAjax()`), whether or not that handler or action has permissions. By default, this will execute the same action that is configured for `authenticationOverrideEvent`.
177177

178178
4. `authorizationAjaxOverrideEvent` (Default: same as `authorizationOverrideEvent`)
179179

180180
This is the event that is executed when the user is logged in and is attempting to execute a secured action via ajax (`event.isAjax()`) but does not have the requisite permissions. By default, this will execute the same action that is configured for `authorizationOverrideEvent`.
181181

182+
### \_securedUrl
183+
184+
When an override event is used, the url the user was trying to access is stored in the `flash` scope as `_securedUrl`.
185+
You can make use of this in your login actions to send the user back where they intended after logging in.
182186

183187
### Setup
184188

@@ -234,12 +238,11 @@ moduleSettings = {
234238
};
235239
```
236240

237-
The default `authenticationService` for `cbguard` is `AuthenticationService@cbauth`. `cbauth` follows the `AuthenticationServiceInterface` out of the box.
238-
241+
The default `authenticationService` for `cbguard` is `AuthenticationService@cbauth`. `cbauth` follows the `AuthenticationServiceInterface` out of the box.
239242

240243
### config/ColdBox.cfc Settings
241244

242-
You can change the method names called on the `AuthenticationService` and the returned `User` if you need to. We highly discourage this use case, as it makes it harder to utilize the `cbguard` conventions across projects. However, should the need arise, you can modify the method names as follows:
245+
You can change the method names called on the `AuthenticationService` and the returned `User` if you need to. We highly discourage this use case, as it makes it harder to utilize the `cbguard` conventions across projects. However, should the need arise, you can modify the method names as follows:
243246

244247
```cfc
245248
moduleSettings = {
@@ -271,10 +274,9 @@ moduleSettings = {
271274
`relocate` refers to calling `relocate` on the controller. The user will be redirected to the new page.
272275
`override` refers to `event.overrideEvent`. This will not redirect but simply change the running event.
273276

274-
275277
### Module Overrides
276278

277-
All of the `cbguard` settings can be overriden inside a module. This allows modules, such as an API module, to provide
279+
All of the `cbguard` settings can be overriden inside a module. This allows modules, such as an API module, to provide
278280
their own authentication services as well as redirect events.
279281

280282
To specify some overrides, create a `cbguard` struct in your desired module's `settings` in that module's `ModuleConfig.cfc`.
@@ -327,7 +329,9 @@ component secured {
327329
```
328330

329331
### Override Order
332+
330333
cbguard will process your authorization and authentication failures in the following order:
334+
331335
1. Inline handler methods (`onAuthenticationFailure` & `onAuthorizationFailure` within your handlers).
332336
2. cbguard settings in the ModuleConfig of the handler's module. (Overrides in `modules_app/api/ModuleConfig.cfc` when the handler is in the module, i.e. `modules_app/api/handlers/Main.cfc`.)
333337
3. Overrides in `config/ColdBox.cfc` using `moduleSettings`.

box.json

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,33 @@
11
{
2-
"name":"cbguard",
3-
"version":"4.1.1",
4-
"author":"",
5-
"location":"forgeboxStorage",
6-
"homepage":"https://github.com/coldbox-modules/cbguard",
7-
"documentation":"https://github.com/coldbox-modules/cbguard",
8-
"repository":{
9-
"type":"git",
10-
"URL":"https://github.com/coldbox-modules/cbguard"
2+
"name": "cbguard",
3+
"version": "4.1.1",
4+
"author": "",
5+
"location": "forgeboxStorage",
6+
"homepage": "https://github.com/coldbox-modules/cbguard",
7+
"documentation": "https://github.com/coldbox-modules/cbguard",
8+
"repository": {
9+
"type": "git",
10+
"URL": "https://github.com/coldbox-modules/cbguard"
1111
},
12-
"bugs":"https://github.com/coldbox-modules/cbguard/issues",
13-
"slug":"cbguard",
14-
"shortDescription":"Annotation driven guards for authentication and authorization in ColdBox apps",
15-
"description":"Annotation driven guards for authentication and authorization in ColdBox apps",
16-
"type":"modules",
17-
"dependencies":{
18-
"coldbox":"stable"
12+
"bugs": "https://github.com/coldbox-modules/cbguard/issues",
13+
"slug": "cbguard",
14+
"shortDescription": "Annotation driven guards for authentication and authorization in ColdBox apps",
15+
"description": "Annotation driven guards for authentication and authorization in ColdBox apps",
16+
"type": "modules",
17+
"dependencies": {},
18+
"devDependencies": {
19+
"coldbox": "^5.6.0",
20+
"testbox": "^2.4.0+80"
1921
},
20-
"devDependencies":{
21-
"coldbox":"^5.6.0",
22-
"testbox":"^2.4.0+80"
22+
"installPaths": {
23+
"testbox": "testbox/",
24+
"coldbox": "tests/resources/app/coldbox/"
2325
},
24-
"installPaths":{
25-
"testbox":"testbox/",
26-
"coldbox":"tests/resources/app/coldbox/"
26+
"scripts": {
27+
"format": "cfformat run interceptors/**/*.cfc,interfaces/**/*.cfc,models/**/*.cfc,tests/specs/**/*.cfc --overwrite",
28+
"format:check": "cfformat check interceptors/**/*.cfc,interfaces/**/*.cfc,models/**/*.cfc,tests/specs/**/*.cfc"
2729
},
28-
"scripts":{
29-
"format":"cfformat run interceptors/**/*.cfc,interfaces/**/*.cfc,models/**/*.cfc,tests/specs/**/*.cfc --overwrite",
30-
"format:check":"cfformat check interceptors/**/*.cfc,interfaces/**/*.cfc,models/**/*.cfc,tests/specs/**/*.cfc"
31-
},
32-
"ignore":[
30+
"ignore": [
3331
"**/.*",
3432
"test",
3533
"tests"

interceptors/SecuredEventInterceptor.cfc

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
component extends="coldbox.system.Interceptor" {
22

3-
property name="coldboxVersion" inject="coldbox:fwSetting:version";
4-
property name="handlerService" inject="coldbox:handlerService";
3+
property name="flash" inject="coldbox:flash";
54
property name="moduleService" inject="coldbox:moduleService";
5+
property name="handlerService" inject="coldbox:handlerService";
6+
property name="coldboxVersion" inject="coldbox:fwSetting:version";
67
property name="invalidEventHandler" inject="coldbox:setting:invalidEventHandler";
78

89
void function configure() {
@@ -100,6 +101,8 @@ component extends="coldbox.system.Interceptor" {
100101
}
101102

102103
if ( !invoke( props.authenticationService, props.methodNames[ "isLoggedIn" ] ) ) {
104+
saveSecuredUrl( event );
105+
103106
// Override the coldbox.cfc global onAuthenticationFailure if it exists in the handler.
104107
// Per docs, they will override for Ajax requests also.
105108
var eventType = event.isAjax() ? "authenticationAjaxOverrideEvent" : "authenticationOverrideEvent";
@@ -147,6 +150,8 @@ component extends="coldbox.system.Interceptor" {
147150
}
148151
}
149152

153+
saveSecuredUrl( event );
154+
150155
// At this point, we know the user did NOT have any of the required permissions,
151156
// so we will fire the appropriate authorization failure events
152157
var eventType = event.isAjax() ? "authorizationAjaxOverrideEvent" : "authorizationOverrideEvent";
@@ -217,7 +222,10 @@ component extends="coldbox.system.Interceptor" {
217222
if ( !structKeyExists( targetActionMetadata, "secured" ) || targetActionMetadata.secured == false ) {
218223
return false;
219224
}
225+
220226
if ( !invoke( props.authenticationService, props.methodNames[ "isLoggedIn" ] ) ) {
227+
saveSecuredUrl( event );
228+
221229
var eventType = event.isAjax() ? "authenticationAjaxOverrideEvent" : "authenticationOverrideEvent";
222230
var relocateEvent = getOverrideEvent(
223231
handlerMetadata,
@@ -257,6 +265,8 @@ component extends="coldbox.system.Interceptor" {
257265
}
258266
}
259267

268+
saveSecuredUrl( event );
269+
260270
// Override the coldbox.cfc global onAuthorizationFailure if it exists in the handler.
261271
// Per docs, they will override for Ajax requests also.
262272
var eventType = event.isAjax() ? "authorizationAjaxOverrideEvent" : "authorizationOverrideEvent";
@@ -323,4 +333,25 @@ component extends="coldbox.system.Interceptor" {
323333
);
324334
}
325335

336+
/**
337+
* Flash the incoming secured Url so we can redirect to it or use it in the next request.
338+
*
339+
* @event The event object
340+
*/
341+
private function saveSecuredUrl( required event ) {
342+
var securedUrl = arguments.event.getFullUrl();
343+
344+
if ( arguments.event.isSES() ) {
345+
securedURL = arguments.event.buildLink(
346+
to = event.getCurrentRoutedURL(),
347+
queryString = CGI.QUERY_STRING,
348+
translate = false
349+
);
350+
}
351+
352+
// Flash it and place it in RC as well
353+
flash.put( "_securedUrl", securedUrl );
354+
arguments.event.setValue( "_securedUrl", securedUrl );
355+
}
356+
326357
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" {
2+
3+
property name="interceptorService" inject="coldbox:interceptorService";
4+
property name="flash" inject="coldbox:flash";
5+
6+
function run() {
7+
describe( "Secured Url Spec", function() {
8+
beforeEach( function() {
9+
flash.clear();
10+
} );
11+
12+
it( "puts the _securedUrl in the flash scope when relocating", function() {
13+
var event = execute( event = "Secured.index" );
14+
expect( event.getValue( "relocate_EVENT", "" ) ).toBe( "Main.onAuthenticationFailure" );
15+
expect( flash.exists( "_securedUrl" ) ).toBeTrue( "_securedUrl should exist in the flash scope" );
16+
expect( flash.get( "_securedUrl" ) ).toBe( event.getFullUrl() );
17+
} );
18+
} );
19+
}
20+
21+
}

0 commit comments

Comments
 (0)