[cbsecurity 3.4.2] CBSecrurity and the RememberMe Module

I developed the RememberMe Forgebox module to give developers a simple API for “remembering” users across sessions and automatically logging them in using their favorite auth library, like cbAuth. I would like for the RememberMe module to also play nicely with cbSecurity.

My recommended implementation of RememberMe, was to use the preProcess() interceptor method to check if the user is logged in, and if not, recall them, like this:

function preProcess( event, interceptData, buffer, rc, prc ) {
    
    // if the user is not logged in, and the rememberMe cookie exists, attempt to recall the user
    if ( 
        !auth().isLoggedIn() && // <-- cbAuth method
        remember().cookieExists() 
    ) {
        
        try {
            
            // attempt to recall the user 
            // if successful, returns a user object from your `userServiceClass`
            var user = remember().recallMe();

            // verify the user exists and log them in using cbauth
            if ( user.isLoaded() ) {
                auth().login( user ); // <-- cbAuth method
            }

        // if the token is invalid, forget the user and cleanup bad cookies
        } catch( InvalidToken e ) {
            remember().forgetMe();
        }

    }

Unfortunately, under certain circumstances, cbSecurity’s preProcess() interceptor method fires before RememberMe, so the firewall check occurs before reauthenticating the user. D’oh!

To the best of my knowledge, I cannot control the order in which the preProcess() interceptor calls fire. So, in lieu of a prePreProcess() interception point, what would be a good way to ensure an app has a change to recall a user before cbSecurity can perform the firewall check?

What about SessionStart()?
My initial thought was to use the sessionStart() interception point. However, I ran into instances where RememberMe’s or CBAuth’s global UDF helpers weren’t registered by the time sessionStart() fired and it triggered exceptions. I also ran into race conditions when using the provider: injection annotation, so I’m fairly sure I need to use an interception method that occurs after sessionStart() and before preProcess()

Perhaps if cbSecurity had a preFirewall() interceptor, I could update RememberMe’s documentation to use that interception point instead of preProcess()?

That change would look something like this:

// modules\cbsecurity\interceptors\Security.cfc
/**
 * Our firewall kicks in at preProcess
 *
 * @event        
 * @interceptData
 * @rc           
 * @prc          
 * @buffer       
 */
function preProcess( event, interceptData, rc, prc, buffer ){
	// Add SecureView() into the requestcontext
	arguments.event.secureView = variables.cbSecurity.secureViewProxy;
	
	// announce the firewall check
	interceptorService.announce( "cbSecurity_preFirewall" );
	
	// Execute Rule Security
	...
	
	// Execute Annotation Security
	...

I know performance is paramount with cbSecurity, so I’m reluctant to suggest adding new calls that would fire on every request.

Additionally, if there’s a way to delay firing the sessionStart() interceptor until I can use the provider: injection DSL, that could be another way to go.

If anyone has any ideas, I’d love to hear them!

I would suggest moving the interception point to onRequestCapture. Then you will be guaranteed to execute before preProcess

1 Like

Because the Application.cfc calls the onSessionStart method in the bootstrap, which announces that interception, and that can get fired before the requests, you are better off not using injection in any interceptor that has that point. You will probably need to use wirebox manually to retrieve the instance you need, within the method.

Excellent! I will give onRequestCapture() a try and report back how it goes. If all goes well, I will update the RememberMe docs with the suggestion to use that application life cycle event.