Overview

The security.groovy file defines the logic used to authenticate the users of your application and to give them appropriate authorizations. The file is located in the Groovy classpath root in your application (app_name/groovy):


Fig. 1: this example refers to the default app, with Portofino as the root web application in a Tomcat instance.

security.groovy defines a single Groovy class that must implement a certain API. By providing your own implementation of its methods, you will be able to handle authentication and authorization in a very flexible way: be it with database queries over a custom schema, LDAP/Active Directory, Single Sign-On, or any other method.

The default application comes with a minimal security.groovy that only knows about a hardcoded admin/admin user. However, if you create a new application using the wizard and specify the database tables containing users and roles (more info), a sample security.groovy file is created, replacing the default one. You can use it as a starting point, but you should customize it before deploying your application in production. In particular, be aware that the generated security.groovy will still allow users to log in as admin/admin!

The security.groovy API

security.groovy must define a single public class implementing the interface com.manydesigns.portofino.shiro.ApplicationRealmDelegate. In most cases, though, you should extend the class com.manydesigns.portofino.shiro.AbstractApplicationRealmDelegate that implements the boilerplate needed to handle different authentication methods (such as username+password or OpenID), built-in groups, etc.

AbstractApplicationRealmDelegate forces you to implement certain methods, while for others it provides empty defaults that you can override.

Let's look at the API breaking it down by functionality.

Fig. 2: a few lines of code taken from a sample security.groovy

Authentication

The methods involved in authentication are:

  • AuthenticationInfo getAuthenticationInfo(ApplicationRealm realm, String userName, String password) - this performs authentication with a username and a password, the default scenario in a Portofino application. This is the only method that you must implement. After running your logic (e.g. to issue a database query), the outcome of the method can be one of the following:
    • an AuthenticationInfo object is returned (generally, an instance of SimpleAuthenticationInfo; refer to the Apache Shiro documentation). This is  holds the user's identity or identities. Portofino requires that the first identity be the username. Any other identities are completely user-defined and optional; a good idea can be to provide the database ID of the user as a secondary identity. The security.groovy generated by the wizard does exactly that.
    • an AuthenticationException is thrown. This means that the login procedure failed. You can throw a more specific subclass of AuthenticationException to signal particular conditions (e.g. wrong password, username not known, etc.), although the standard Portofino login page will never show that information to the user, for security reasons.
  • AuthenticationInfo getAuthenticationInfo(ApplicationRealm realm, VerificationResult principal) - returns an authenticated user from a successful OpenID login. You're not required to implement this method; however, you may want to override it in order to associate additional information to the user (e.g. a database ID).
  • AuthenticationInfo doGetAuthenticationInfo(ApplicationRealm realm, AuthenticationToken token) - performs authentication with a token that is neither username+password nor OpenID. This will only be called if you customize Portofino to pass such a token (e.g. if you integrate a Single Sign-On system). The default implementation throws an exception.

Authorization

Authorization means associating permissions to users. In Portofino this happens through groups. There are a few built-in groups that are already handled by AbstractApplicationRealmDelegate, so you only have to override the following methods if you need to handle application-specific groups.

  • Collection<String> loadAuthorizationInfo(ApplicationRealm realm, PrincipalCollection principalCollection) - returns the list of groups associated to the user identified by the provided principal collection. The collection can contain not only the username (the first element), but other values as well, such as a database ID, depending on the implementation of the authentication methods. This method is called when checking the permissions of an authenticated user.
  • Collection<String> loadAuthorizationInfo(ApplicationRealm realm, String principal) - same as the above, but providing only the username. This method is called when testing a user's permissions in the permissions setup form (see Figure 3).
  • Collection<String> loadAuthorizationInfo(ApplicationRealm realm, Identifier principal) - loads the groups associated to an OpenID identifier.
  • Collection<String> loadAuthorizationInfo(ApplicationRealm realm, Object principal) - returns the groups associated to a principal of an unknown type. This is a customization hook in case you want to implement your own authentication/authorization strategy; normally, this methods is never called and is defined to throw an exception.

Fig. 3: the lists of users and groups are shown in the permissions page.

Miscellanea

Other methods that you can optionally implement are:

  • Set<String> getGroups(ApplicationRealm realm) - returns the set of known groups, shown when configuring the permissions of a page. The default implementation returns the built-in groups.
  • Set<String> getUsers(ApplicationRealm realm) - returns the list of known users, shown when configuring the permissions of a page.