Restrict access to application's pages

Commonly, when building a graphical user interface, if you want to restrict the access to some page to a category of users, you create a myPage.page.xml file in which you edit the restriction.

A service has been implemented which enables you to easily manage the permissions; it make use of the Page interface you may have already implemented if you build a dynamic menu. This post is a tutorial to put in place this service. All you need is having a project which depends on gazelle-seam-tools module.

First of all, create a public enumeration which implements the net.ihe.gazelle.common.pages.Authorization interface. This enum must listed the various permissions you want to set, for instance : ADMIN, MONITOR, EDITOR, FULL_MODE and so on. The boolean method isGranted which have to be implemented may make references to basic permissions (Identity.instance().loggedIn(), Identity.instance.hasRole('my_role') ...) or to value in your application preferences or even something else which will help the application knowing if the current user is or is not allowed to access a given page.

public enum Authorizations implements Authorization {

	ALL,

	LOGGED,

	ADMIN,

	EDITOR;

	@Override
	public boolean isGranted(Object... context) {
		switch (this) {
		case ALL:
			return true;
		case LOGGED:
			return Identity.instance().isLoggedIn();
		case ADMIN:
			return Identity.instance().hasRole("admin_role");
		case EDITOR:
			return Identity.instance().hasRole("admin_role") || Identity.instance().hasRole("test_editor_role");
		}
		return false;
	}

}

 

Then, create a new public enumeration which implements the net.ihe.gazelle.common.pages.Page interface. This enum must listed all the pages which are available through your graphical user interface and for each page, the list of Authorization to be applied. Not that if you are listed several Authorizations, the final Authorization is computed using the logical AND. If you rather want to use the OR operator, you can use the AuthorizationOr class. The AutorizationNot and AuthorizationAnd classes are also available if you need to create complex authorizations based on the ones you have defined in the enum.

public enum Pages implements
		Page {

	HOME("/home.xhtml", "/img/gazelle.png", "Home", Authorizations.ALL),

	APPLICATION_CONF("/admin/configure.xhtml", "/img/configure.gif", "Application configuration", Authorizations.ADMIN),
	
	LOGIN_PAGE ("/login.seam", "", "", Authorizations.ALL),

	ERROR_PAGE ("/error.seam", "", "", Authorizations.ALL),
	
	ERROR_EXPIRED_PAGE ("/errorExpired.seam", "", "", Authorizations.ALL);
	
	private String link;

	private Authorization[] authorizations;

	private String label;

	private String icon;

	Pages(String link, String icon, String label, Authorization... authorizations) {
		this.link = link;
		this.authorizations = authorizations;
		this.label = label;
		this.icon = icon;
	}
....
}

 

Then, you need to provide a PageLister so that the GazelleSecurityCheck class will be able to retrieve the list of pages available in your application along with the specific authorizations for each of them. This class must implement the net.ihe.gazelle.common.pages.PageLister interface.

@MetaInfServices(PageLister.class)
public class RuleEditorPageLister implements PageLister {

	@Override
	public Collection getPages() {
		Collection pages = new ArrayList();
		pages.addAll(Arrays.asList(XValidationPages.values()));
		pages.addAll(Arrays.asList(Pages.values()));
		return pages;
	}

}

 

In the above examples, pages come from different modules, each of them declaring the pages it owns in a separate enum.

Finally, update the WEB-INF/pages.xml files of your main WAR project to declare the class which controls the access restriction:

 
<page view-id="*">
    <restrict>#{gazelleSecurityCheck.checkSecurity()}</restrict>	
...
</page>
	

 

When a user accesses any page of your application, the GazelleSecurityCheck will be first called to check that he/she is allowed to access the page he/she asked for, if it is not the case, it will be notified by a faces message that he/she is not allowed to access the requested page. You can give a try by accessing a page which requests to be logged without being logged.