Command Security - Authorization
This section discusses the mechanisms for configuring and managing the security of Commands (actually any object that implements the appropriate interface as defined below). Generally, this would be considered "authorization" in security lingo.
Authors
Larry Streepy
Still Being Written
Obviously, this is incomplete - I will be updating it over the next few days to flesh it out.
Overview
In many applications, there is a need to control aspects of the application based on the credentials of the current user. That is, authorizing a user to perform (or not) certain operations once they have been authenticated. One common case is controlling commands that are available to the user based on their authenticated roles. This section builds on the information detailed in the section on general authentication. Pay special attention to the section describing the SecurityAwareConfigurer, which is mandatory to get authorization based command security to work.
Note that command authorization is different than enablement. A command could be authorized, but not enabled due to other application state. However, a command that is not authorized can not be enabled. Think of authorization as a one way latch, when authorized, then the enabled state can change as desired. When not authorized, then the enabled state is latched to false. For convenience, the command implementations remember the last enabled state set and it is restored when/if the command becomes authorized. This behavior is embeded in the AbstractCommand and AbstractCommandExecutor implementations.
Core Components
Controllable interfaces
There are two primary interfaces that define how objects can be controlled:
Authorizable - is implemented by objects that can authorized or not based on some controlling objects decision. This is the core interface that all objects that need to have authorization decisions enforced on them will implement.
SecurityControllable - is implemented by objects that can be controlled by a specified SecurityController. This interface is used as part of the "wiring" process to automatically register an Authorizable object with the identified security controller.
Controlling classes
SecurityController
SecurityController and its implementation in AbstractSecurityController and UserRoleSecurityController - A security controller is any object that controls Authorizable objects. The security controller is responsible for reacting to changes in the application state (typically the user's authentication) and then making a decision to authorize or not authorize the objects regsitered with the controller.
UserRoleSecurityController is an instance that responds to changes in the users credentials (it is AuthenticationAware) and determines the authorization based on comparing the user's current roles to a list of configured roles. If the user has any of the configured roles, then the registered controllable objects are authorized. The list of roles is configured by setting the authorizingRoles property with a comma-separated list of role names. For example, two security controllers are defined as:
<bean id="adminController" class="org.springframework.richclient.security.support.UserRoleSecurityController">
<property name="authorizingRoles" value="ROLE_ADMIN" />
</bean>
<bean id="writeController" class="org.springframework.richclient.security.support.UserRoleSecurityController">
<property name="authorizingRoles" value="ROLE_WRITE,ROLE_ADMIN" />
</bean>
The adminController will authorize its controlled objects when the user has ROLE_ADMIN in their authentication token. The writeController authorizes its objects when the user has either ROLE_WRITE or ROLE_ADMIN.
By default, the UserRoleSecurityController uses an AffirmativeBased access decision manager that delegates to a simple RoleVoter. You can override this by setting the accessDecisionManager property. Here's the equivalent XML configuration (note that you wouldn't do this, it's just by way of explanation):
<bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter" />
<bean id="accessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions">
<value>false</value>
</property>
<property name="decisionVoters">
<list>
<ref bean="roleVoter" />
</list>
</property>
</bean>
<bean id="adminController" class="org.springframework.richclient.security.support.UserRoleSecurityController">
<property name="authorizingRoles" value="ROLE_ADMIN" />
<property name="accessDecisionManager" ref="accessDecisionManager"/>
</bean>
SecurityControllerManager
SecurityControllerManager - This class is responsible for managing a security controller Id registry. It provides a simple mechanism for obtaining a security controller using it's bean id, or a registered alias.
Static versus dynamic wiring
These pieces are used in two major modes:
static configuration - this model applies to objects configured in the appplication and command contexts. Using the controller definitions above, a command could be defined to be controlled by the adminController like this:
<bean id="newPhysicianCommand" class="org.springframework.richclient.command.TargetableActionCommand">
<property name="securityControllerId" value="adminController"/>
</bean>
Note the specification of the securityControllerId. This is how the static configuration is made between the controllable and the controller. The magic linkage is created by the DefaultCommandConfigurer (and the DefaultApplicationObjectConfigurer).
dynamic configuration - In the case where commands are created dynamically, which is the case for a lot of commands used in forms, there needs to be a way to declare the security controller responsible for handling them. This is done (via the SecurityControllable interface) by specifying the securityControllerId on the command. The various form classes have been updated to provide default security controller ids for the commands they create. The general pattern of the if is <form id>.<command face id>.
So, now the command has a security controller id. How does that get us to a controller? That's where the SecurityControllerManager comes in. It allows you to specify a map of aliases for security controllers. This is where you'd register the command security controller id and the proper security controller to handle it.
Here's an example configuration:
<bean id="securityControllerManager" class="org.springframework.richclient.security.support.DefaultSecurityControllerManager">
<property name="fallbackSecurityController" ref="writeController" />
<property name="securityControllerMap">
<map>
<entry key="contact.newContactCommand" value-ref="adminController"/>
<entry key="contact.deleteContactCommand" value-ref="adminController"/>
</map>
</property>
</bean>