Blog

Gavin Pickin

December 23, 2017

Spread the word


Share your thoughts

At Ortus Solutions, we love the holidays, and we wanted to gift you a gift of developer productivity, we will share a few tips and tricks that will keep giving all year around. In this series we'll be giving you 12 ContentBox tips. Keep your eye out for other 12 tips of Christmas series on our blog, including a new one this year, 12 modules of Christmas on ForgeBox.

Day 10 - Security and Permissions in ContentBox Modules - One of the reasons I love working with ContentBox is all of the built in User management, permissions, roles, and creating ColdBox modules to extend ContentBox is easy. Today we'll look at how to use Security and Permissions in your ContentBox modules.

If your Module is using the ContentBox Module lifecycle, ContentBox preps your request, and handles tasks like themes, settings, checking for a logged in user etc. The current logged in user, is always available to you in the prc. This is handled by an interceptor, to ensure it is done on every request. Whether you are using a front end or admin module, you can access that user with `prc.oCurrentAuthor`

A great addition to your ContentBox Module ( also works with straight ColdBox apps ) is a module designed by Eric Peterson, called CB Guard. https://github.com/coldbox-modules/cbguard

This gives us a simple but powerful convention based security approach. There is a lot of great information on using this module in the readme on github, but we'll give you a run down here, and some secrets to using it with ContentBox.

To ensure a user is logged in to access a handler, you can add the metadata `secured` to your handler. This locks down the entire handler

component secured {

    function index( event, rc, prc ) {
        // ...
    }

    function show( event, rc, prc ) {
        // ...
    }

}

To ensure a user is logged in to access an action, you can add the metadata `secured` to your action.

component {

    function create( event, rc, prc ) secured {
        // ...
    }

}

To ensure a user is logged in and has the correct permission to access a handler, you can add the metadata `secured=”list,of,permissions”` to your handler. The user must have one of the listed permissions.

component secured="admin" {
	
    function index( event, rc, prc ) {
        // ...
    }

    function show( event, rc, prc ) {
        // ...
    }

}

To ensure a user is logged in and has the correct permission to access an action, you can add the metadata `secured=”list,of,permissions”` to your action. The user must have one of the listed permissions.

component {
	
    function show( event, rc, prc ) secured="admin,reviews_posts" {
        // ...
    }

}

These two approaches can be combined and both handler and actions can be secured together:
While the user needs to be logged in to interact at all with this handler, they also need the create_posts permission to interact with the new action.

component secured {

    function index( event, rc, prc ) {
        // ...
    }

    function new( event, rc, prc ) secured="create_posts" {
        // ...
    }

}

Configuration

CBGuard can be used with any ColdBox app, all you have to do is configure it. You can set settings for redirects:

  • authenticationOverrideEvent 
  • authorizationOverrideEvent 
  • authenticationAjaxOverrideEvent 
  • authorizationAjaxOverrideEvent 

As well as the redirects, you have to define how CBGuard checks your user is authenticated, and if the authenticated user is authorized ( has permission ), by defining the CFC that conforms to AuthenticationServiceInterface and HasPermissionInterface.

To configure the AuthenticationService, set the value of authenticationService in your moduleSettings to a WireBox mapping:

moduleSettings = {
    cbguard = {
        authenticationService = "SecurityService@myapp"
    }
};

The default authenticationService for cbguard is AuthenticationService@cbauth. cbauth follows the AuthenticationServiceInterface out of the box.

Advanced Setup - Overriding the Interface to work with ContentBox

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:

moduleSettings = {
    cbguard = {
        methodNames = {
            isLoggedIn    = "getIsLoggedIn",
            getUser       = "retrieveUser",
            hasPermission = "checkPermission"
        }
    }
};

Using CBGuard in a ContentBox App

Here is an example config for a real ContentBox app using CBGaurd, just add this into you /config/ColdBox.cfc

moduleSettings = {
	cbguard = {
		authenticationService = "UserService@rccore",
		methodNames = {
			isLoggedIn    = "isLoggedIn",
			getUser       = "getAuthorSession",
			hasPermission = "checkPermission"
		},
		authenticationOverrideEvent			= "security:login.new",
		authorizationOverrideEvent			= "ui:auth.onAuthorizationFailure",
		authenticationAjaxOverrideEvent		= "security:login.new",
		authorizationAjaxOverrideEvent		= "ui:auth.onAuthorizationFailure"
	}
};

What are we doing in this config?

  • We are using a custom authenticationService CFC, we'll share below
  • We are changing method names, so they match ContentBox's normal methods for checking Permission, and checking if a user is logged in for example.
  • We set authentication ( not logged in error ) redirects to the security module, with the action login.new.
  • We set authorization ( logged in but not the right permission ) redirects to the UI module, with the action auth.onAuthorizationFailure.

UserService.cfc required for CBGuard with ContentBox

Other than this configuration, the only code changes we need to implement, are in the UserService, lets look at that UserService.cfc.
We are looking at merging these requirements of CBGuard to make this even easier, but for now, you need to create a CFC like so.

/**
* User Service
* This User Service extends the ContentBox Author Service, allowing us to override and extend ContentBox's author service for the needs of this application
*/
component singleton extends="contentbox.models.security.AuthorService" {
	

	/**
	* Constructor
	*/
	public UserService function init(){
		super.init();
		return this;
	}

	/**
	* Proxy the getAuthorSession to the ContentBox security service getAuthorSession()
	*
	* @return author entity of the logged in user, or an empty author entity
	*/
	function getAuthorSession(){
		return securityService.getAuthorSession();
	}

	/**
	* Determinies if there is currently a user logged in
	*
	* @return boolean value - if there is a user logged in, or not.
	*/
	function isLoggedIn(){
		var author = getAuthorSession();
		return ( author.isLoaded() && author.isLoggedIn() );
	}
}

With some simple meta data, a little config, and this simple CFC, you can now use authentication and authorization all over your ContentBox modules.
Try it out, and let us know what you think.

Happy Holidays

Recent Entries

Hackers demand a ransom to restore data from my ColdFusion web applications!

Hackers demand a ransom to restore data from my ColdFusion web applications!

Hackers demand a ransom to restore data from my ColdFusion web applications!

Unfortunately, we often hear this message from clients who thought it would never happen to them... until it did. Some believed they could delay the expense of Implementing ColdFusion security best practices for one year, while others were tempted to put it off for just a few months. However, in today's rapidly evolving digital landscape, the security of web applications, including ColdFusio...

Cristobal Escobar
Cristobal Escobar
April 16, 2024
Ortus March Newsletter

Ortus March Newsletter

Welcome to Ortus Solutions’ monthly roundup, where we're thrilled to showcase cutting-edge advancements, product updates, and exciting events! Join us as we delve into the latest innovations shaping the future of technology.

Maria Jose Herrera
Maria Jose Herrera
April 01, 2024
Into the Box 2024 Last Early Bird Days!

Into the Box 2024 Last Early Bird Days!

Time is ticking, with less than 60 days remaining until the excitement of Into the Box 2024 unfolds! Don't let this golden opportunity slip away; our exclusive Early Bird Pricing is here for a limited time only, available until March 31st. Why wait? Secure your seat now and take advantage of this steal!

Maria Jose Herrera
Maria Jose Herrera
March 20, 2024