Skip to content

Commit 495d516

Browse files
homestar9elpete
authored andcommitted
feat(Login): Add new preLogin and postLogin interception points
Adding new interception points for `preLogin` and `postLogin` will allow applications which will log a user in by calling `auth().logIn()` explicitly instead of `auth().authenticate()` to perform important post-login actions. This would be especially useful for a site that has "remember me" functionality, where a user will be logged in based on a special cookie on their browser as opposed to them entering their username/password.
1 parent 99808ed commit 495d516

File tree

3 files changed

+73
-27
lines changed

3 files changed

+73
-27
lines changed

README.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,9 @@ If there is no logged in user, it throws a `NoUserLoggedIn` exception.
136136

137137
## Interception Points — (preAuthentication & postAuthentication)
138138

139-
cbauth announces two custom interception points — preAuthentication and postAuthentication. You can use these interception points to change request data or add additional values to session or request scopes.
139+
cbauth announces several custom interception points. You can use these interception points to change request data or add additional values to session or request scopes. The `preAuthentication` and `postAuthentication` events fire during the standard `authenticate()` method call with a username and password. The `preLogin` and `postLogin` events fire during the `login()` method call.
140+
141+
Note: the `preLogin` and `postLogin` interception points will be called during the course of `authenticate()`. The order of the calls then are `preAuthentication` -> `preLogin` -> `postLogin` -> `postAuthentication`.
140142

141143
### `preAuthentication`
142144

@@ -161,3 +163,25 @@ interceptData
161163
| requestStorage | The requestStorage object to store additional values if needed. |
162164

163165
This is the prime time to store additional values based on the user returned.
166+
167+
### `preLogin`
168+
169+
interceptData
170+
171+
| name | description |
172+
| --- | --- |
173+
| user | The user component to be logged in. |
174+
175+
176+
### `postLogin`
177+
178+
interceptData
179+
180+
| name | description |
181+
| --- | --- |
182+
| user | The user component to be logged in. |
183+
| sessionStorage | The sessionStorage object to store additional values if needed. |
184+
| requestStorage | The requestStorage object to store additional values if needed. |
185+
186+
187+
This is a good opportunity to store additional data if your application logged the user in manually without authenticating via a username/password like a "remember me" system.

models/AuthenticationService.cfc

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,44 @@ component singleton {
1010
variables.USER_KEY = "cbauth__user";
1111

1212
public void function logout() {
13-
sessionStorage.delete( USER_ID_KEY );
14-
requestStorage.delete( USER_KEY );
13+
variables.sessionStorage.delete( variables.USER_ID_KEY );
14+
variables.requestStorage.delete( variables.USER_KEY );
1515
}
1616

1717
public void function login( required user ) {
18-
sessionStorage.set( USER_ID_KEY, user.getId() );
19-
requestStorage.set( USER_KEY, user );
18+
variables.interceptorService.processState( "preLogin", {
19+
user = arguments.user
20+
} );
21+
22+
variables.sessionStorage.set( variables.USER_ID_KEY, arguments.user.getId() );
23+
variables.requestStorage.set( variables.USER_KEY, arguments.user );
24+
25+
variables.interceptorService.processState( "postLogin", {
26+
user = arguments.user,
27+
sessionStorage = variables.sessionStorage,
28+
requestStorage = variables.requestStorage
29+
} );
2030
}
2131

2232
public boolean function authenticate( required string username, required string password ) {
23-
var args = {
24-
username = username,
25-
password = password
26-
};
27-
28-
interceptorService.processState( "preAuthentication", args );
33+
variables.interceptorService.processState( "preAuthentication", {
34+
"username" = arguments.username,
35+
"password" = arguments.password
36+
} );
2937

30-
if ( NOT getUserService().isValidCredentials( args.username, args.password ) ) {
31-
throw( "Incorrect Credentials Entered", "InvalidCredentials" );
38+
if ( ! getUserService().isValidCredentials( arguments.username, arguments.password ) ) {
39+
throw(
40+
type = "InvalidCredentials",
41+
message = "Incorrect Credentials Entered"
42+
);
3243
}
3344

34-
var user = getUserService().retrieveUserByUsername( args.username );
45+
var user = getUserService().retrieveUserByUsername( arguments.username );
3546

36-
interceptorService.processState( "postAuthentication", {
47+
variables.interceptorService.processState( "postAuthentication", {
3748
user = user,
38-
sessionStorage = sessionStorage,
39-
requestStorage = requestStorage
49+
sessionStorage = variables.sessionStorage,
50+
requestStorage = variables.requestStorage
4051
} );
4152

4253
login( user );
@@ -45,7 +56,7 @@ component singleton {
4556
}
4657

4758
public boolean function isLoggedIn() {
48-
return sessionStorage.exists( USER_ID_KEY );
59+
return variables.sessionStorage.exists( variables.USER_ID_KEY );
4960
}
5061

5162
public boolean function check() {
@@ -57,12 +68,12 @@ component singleton {
5768
}
5869

5970
public any function getUser() {
60-
if ( ! requestStorage.exists( USER_KEY ) ) {
71+
if ( ! variables.requestStorage.exists( variables.USER_KEY ) ) {
6172
var userBean = getUserService().retrieveUserById( getUserId() );
62-
requestStorage.set( USER_KEY, userBean );
73+
variables.requestStorage.set( variables.USER_KEY, userBean );
6374
}
6475

65-
return requestStorage.get( USER_KEY );
76+
return variables.requestStorage.get( variables.USER_KEY );
6677
}
6778

6879
public any function user() {
@@ -71,19 +82,25 @@ component singleton {
7182

7283
public any function getUserId() {
7384
if ( ! isLoggedIn() ) {
74-
throw( "No user is currently logged in.", "NoUserLoggedIn" );
85+
throw(
86+
type = "NoUserLoggedIn",
87+
message = "No user is currently logged in."
88+
);
7589
}
7690

77-
return sessionStorage.get( USER_ID_KEY );
91+
return variables.sessionStorage.get( variables.USER_ID_KEY );
7892
}
7993

8094
private any function getUserService() {
8195
if ( ! structKeyExists( variables, "userService" ) ) {
82-
if ( userServiceClass == "" ) {
83-
throw( "No [userServiceClass] provided. Please set in `config/ColdBox.cfc` under `moduleSettings.cbauth.userServiceClass`.", "IncompleteConfiguration" );
96+
if ( variables.userServiceClass == "" ) {
97+
throw(
98+
type = "IncompleteConfiguration",
99+
message = "No [userServiceClass] provided. Please set in `config/ColdBox.cfc` under `moduleSettings.cbauth.userServiceClass`."
100+
);
84101
}
85102

86-
variables.userService = wirebox.getInstance( userServiceClass );
103+
variables.userService = variables.wirebox.getInstance( variables.userServiceClass );
87104
}
88105

89106
return variables.userService;

tests/specs/AuthenticationSpec.cfc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,11 +269,16 @@ component extends="testbox.system.BaseSpec" {
269269
var processStateCallLog = interceptorServiceMock.$callLog().processState;
270270

271271
expect( processStateCallLog )
272-
.toHaveLength( 2, "Two events should have been announced" );
272+
.toHaveLength( 4, "Four events should have been announced" );
273273
expect( processStateCallLog[1][1] )
274274
.toBe( "preAuthentication", "[preAuthentication] should have been announced." );
275275
expect( processStateCallLog[2][1] )
276276
.toBe( "postAuthentication", "[postAuthentication] should have been announced." );
277+
expect( processStateCallLog[3][1] )
278+
.toBe( "preLogin", "[preLogin] should have been announced." );
279+
expect( processStateCallLog[4][1] )
280+
.toBe( "postLogin", "[postLogin] should have been announced." );
281+
277282
} );
278283
} );
279284

0 commit comments

Comments
 (0)