Acegi Security System for Spring
Reference Documentation
0.4
Ben
Alex
Preface
This document provides a reference guide to the Acegi Security
System for Spring, which is a series of classes that deliver
authentication and authorization services within the Spring Framework.
Whilst the Acegi Security System for Spring is not officially part of
Spring, it is hoped this implementation will further discussion concerning
the implementation of security capabilities within Spring itself.
I would like to acknowledge this reference was prepared using the
DocBook configuration included with the Spring Framework. The Spring team
in turn acknowledge Chris Bauer (Hibernate) for his assistance with their
DocBook.
Security
Introduction
The Acegi Security System for Spring provides authentication and
authorization capabilities for Spring-powered projects, with full
integration with popular web containers. The security architecture was
designed from the ground up using "The Spring Way" of development, which
includes using bean contexts, interceptors and interface-driven
programming. As a consequence, the Acegi Security System for Spring is
useful out-of-the-box for those seeking to secure their Spring-based
applications, and can be easily adapted to complex customized
requirements.
Security involves two distinct operations, authentication and
authorization. The former relates to resolving whether or not a caller
is who they claim to be. Authorization on the other hand relates to
determining whether or not an authenticated caller is permitted to
perform a given operation.
Throughout the Acegi Security System for Spring, the user, system
or agent that needs to be authenticated is referred to as a "principal".
The security architecture does not have a notion of roles or groups,
which you may be familiar with from other security
implementations.
High Level Design
Key Components
The Acegi Security System for Spring essentially comprises six
key functional parts:
An Authentication object which holds the
principal, credentials and the authorities granted to the
principal.
A ContextHolder which holds the
Authentication object in a
ThreadLocal-bound object.
An AuthenticationManager to authenticate
the Authentication object presented via the
ContextHolder.
An AccessDecisionManager to authorize a
given operation.
A RunAsManager to optionally replace the
Authentication object whilst a given operation
is being executed.
A "secure object" interceptor, which coordinates the
authentication, authorization, run-as replacement and execution of
a given operation.
Secure objects refer to any type of object that can have
security applied to it. A secure object must provide some form of
callback, so that the security interceptor can transparently do its
work as required, and callback the object when it is time for it to
proceed with the requested operation. If secure objects cannot provide
a native callback approach, a wrapper needs to be written so this
becomes possible.
Each secure object has its own package under
net.sf.acegisecurity.intercept. Every other package
in the security system is secure object independent, in that it can
support any type of secure object presented.
Only developers contemplating an entirely new way of
intercepting and authorizing requests would need to use secure objects
directly. For example, it would be possible to build a new secure
object to secure calls to a messaging system that does not use
MethodInvocations. Most Spring applications will
simply use the two currently supported secure object types
(MethodInvocation and
FilterInterceptor) with complete
transparency.
Each of the six key parts is discussed in detail throughout this
document.
Supported Secure Objects
The Acegi Security System for Spring currently supports two
secure objects.
The first handles an AOP Alliance
MethodInvocation. This is the secure object type
used to protect Spring beans. Developers will generally use this
secure object type to secure their business objects. To make a
standard Spring-hosted bean available as a
MethodInvocation, the bean is simply published
through a ProxyFactoryBean or
BeanNameAutoProxyCreator. Most Spring developers
would already be familiar with these due to their use in transactions
and other areas of Spring.
The second type is a FilterInvocation. This
is an object included with the Acegi Security System for Spring. It is
created by an included filter and simply wraps the HTTP
ServletRequest, ServletResponse
and FilterChain. The
FilterInvocation enables HTTP resources to be
secured. Developers do not usually need to understand the mechanics of
how this works, because they just add the filters to their
web.xml and let the security system do its
work.
Configuration Attributes
Every secure object can represent an infinite number of
individual requests. For example, a
MethodInvocation can represent the invocation of
any method with any arguments, whilst a
FilterInvocation can represent any HTTP URL.
The Acegi Security System for Spring needs to record the
configuration that applies to each of these possible requests. The
security configuration of a request to
BankManager.getBalance(int accountNumber) needs to
be very different from the security configuration of a request to
BankManager.approveLoan(int applicationNumber).
Similarly, the security configuration of a request to
http://some.bank.com/index.htm needs to be very
different from the security configuration of
http://some.bank.com/manage/timesheet.jsp.
To store the various security configurations associated with
different requests, a configuration attribute is used. At an
implementation level a configuration attribute is represented by the
ConfigAttribute interface. One concrete
implementation of ConfigAttribute is provided,
SecurityConfig, which simply stores a configuration
attribute as a String.
The collection of ConfigAttributes associated
with a particular request is held in a
ConfigAttributeDefinition. This concrete class is
simply a holder of ConfigAttributes and does
nothing special.
When a request is received by the security interceptor, it needs
to determine which configuration attributes apply. In other words, it
needs to find the ConfigAttributeDefinition which
applies to the request. This decision is handled by the
ObjectDefinitionSource interface. The main method
provided by this interface is public
ConfigAttributeDefinition getAttributes(Object object), with
the Object being the secure object. Recall the
secure object contains details of the request, so the
ObjectDefinitionSource implementation will be able
to extract the details it requires to lookup the relevant
ConfigAttributeDefinition.
Request Contexts
Contexts
Many applications require a way of sharing objects between
classes, but without resorting to passing them in method signatures.
This is commonly achieved by using a ThreadLocal.
The Acegi Security System for Spring uses
ThreadLocal functionality and introduces the
concept of "request contexts".
By placing an object into a request context, that object becomes
available to any other object on the current thread of execution. The
request context is not passed around as a method parameter, but is
held in a ThreadLocal. The Acegi Security System
for Spring uses the request context to pass around the authentication
request and response.
A request context is a concrete implementation of the
Context interface, which exposes a single
method:
public void validate() throws ContextInvalidException;
This validate() method is called to confirm
the Context is properly setup. An implementation
will typically use this method to check that the objects it holds are
properly setup.
The ContextHolder class makes the
Context available to the current thread of
execution using a ThreadLocal. A
ContextInterceptor is also provided, which is
intended to be chained into the bean context using
ProxyFactoryBean. The
ContextInterceptor simply calls
Context.validate(), which guarantees to business
methods that a valid Context is available from the
ContextHolder.
Secure Contexts
The Acegi Security System for Spring requires the
ContextHolder to contain a request context that
implements the SecureContext interface. An
implementation is provided named SecureContextImpl.
The SecureContext simply extends the
Context discussed above and adds a holder and
validation for an Authentication object.
Custom Contexts
Developers can create their own request context classes to store
application-specific objects. Such request context classes will need
to implement the Context interface. If the Acegi
Security System for Spring is to be used, developers must ensure any
custom request contexts implement the SecureContext
interface.
Future Work
Over time it is hoped that the Spring remoting classes can be
extended to support propagation of the Context
between ContextHolders on the client and
server.
Security Interception
All Secure Objects
As described in the High Level Design section, each secure
object has its own security interceptor which is responsible for
handling each request. Handling involves a number of
operations:
Store the configuration attributes that are associated with
each secure request.
Extract the ConfigAttributeDefinition
that applies to the request from the relevant
ObjectDefinitionSource.
Obtain the Authentication object from the
SecureContext, which is held in the
ContextHolder.
Pass the Authentication object to the
AuthenticationManager, update the
ContextHolder with the response.
Pass the Authentication object, the
ConfigAttributeDefinition, and the secure
object to the AccessDecisionManager.
Pass the Authentication object, the
ConfigAttributeDefinition, and the secure
object to the RunAsManager.
If the RunAsManager returns a new
Authentication object, update the
ContextHolder with it.
Call a secure object-specific
SecurityInterceptorCallback so that the request
execution can proceed.
If the RunAsManager earlier returned a
new Authentication object, update the
ContextHolder with the
Authentication object that was previously
returned by the AuthenticationManager.
Return any result received from the
SecurityInterceptorCallback.
Whilst this may seem quite involved, don't worry. Developers
interact with the security process by simply implementing basic
interfaces (such as AccessDecisionManager), which
are fully documented below.
The AbstractSecurityInterceptor handles the
majority of the flow listed above. Each secure object has its own
security interceptor which subclasses
AbstractSecurityInterceptor. Each of these secure
object-specific security interceptors are discussed below.
MethodInvocation Security Interceptor
To secure MethodInvocations, developers
simply add a properly configured
MethodSecurityInterceptor into the application
context. Next the beans requiring security are chained into the
interceptor. This chaining is accomplished using Spring’s
ProxyFactoryBean or
BeanNameAutoProxyCreator, as commonly used by many
other parts of Spring (refer to the sample application for examples).
The MethodSecurityInterceptor is configured as
follows:
<bean id="bankManagerSecurity" class="net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor">
<property name="validateConfigAttributes"><value>true</value></property>
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
<property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property>
<property name="runAsManager"><ref bean="runAsManager"/></property>
<property name="objectDefinitionSource">
<value>
net.sf.acegisecurity.context.BankManager.delete*=ROLE_SUPERVISOR,RUN_AS_SERVER
net.sf.acegisecurity.context.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_AS_SERVER
</value>
</property>
</bean>
As shown above, the MethodSecurityInterceptor
is configured with a reference to an
AuthenticationManager,
AccessDecisionManager and
RunAsManager, which are each discussed in separate
sections below. The MethodSecurityInterceptor is
also configured with configuration attributes that apply to different
method signatures. A full discussion of configuration attributes is
provided in the High Level Design section of this document.
The MethodSecurityInterceptor can be
configured with configuration attributes in three ways. The first is
via a property editor and the application context, which is shown
above. The second is via defining the configuration attributes in your
source code using Jakarta Commons Attributes. The third is via writing
your own ObjectDefinitionSource, although this is
beyond the scope of this document. Irrespective of the approach used,
the ObjectDefinitionSource is responsible for
returning a ConfigAttributeDefinition object that
contains all of the configuration attributes associated with a single
secure method.
It should be noted that the
MethodSecurityInterceptor.setObjectDefinitionSource()
method actually expects an instance of
MethodDefinitionSource. This is a marker interface
which subclasses ObjectDefinitionSource. It simply
denotes the ObjectDefinitionSource understands
MethodInvocations. In the interests of simplicity
we'll continue to refer to the
MethodDefinitionSource as an
ObjectDefinitionSource, as the distinction is of
little relevance to most users of the
MethodSecurityInterceptor.
If using the application context property editor approach (as
shown above), commas are used to delimit the different configuration
attributes that apply to a given method pattern. Each configuration
attribute is assigned into its own SecurityConfig
object. The SecurityConfig object is discussed in
the High Level Design section.
If using the Jakarta Commons Attributes approach, your bean
context will be configured differently:
<bean id="attributes" class="org.springframework.metadata.commons.CommonsAttributes"/>
<bean id="objectDefinitionSource" class="net.sf.acegisecurity.intercept.method.MethodDefinitionAttributes">
<property name="attributes"><ref local="attributes"/></property>
</bean>
<bean id="bankManagerSecurity" class="net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor">
<property name="validateConfigAttributes"><value>false</value></property>
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
<property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property>
<property name="runAsManager"><ref bean="runAsManager"/></property>
<property name="objectDefinitionSource"><ref bean="objectDefinitionSource"/></property>
</bean>
In addition, your source code will contain Jakarta Commons
Attributes tags that refer to a concrete implementation of
ConfigAttribute. The following example uses the
SecurityConfig implementation to represent the
configuration attributes, and results in the same security
configuration as provided by the property editor approach
above:
public interface BankManager {
/**
* @@SecurityConfig("ROLE_SUPERVISOR")
* @@SecurityConfig("RUN_AS_SERVER")
*/
public void deleteSomething(int id);
/**
* @@SecurityConfig("ROLE_SUPERVISOR")
* @@SecurityConfig("RUN_AS_SERVER")
*/
public void deleteAnother(int id);
/**
* @@SecurityConfig("ROLE_TELLER")
* @@SecurityConfig("ROLE_SUPERVISOR")
* @@SecurityConfig("BANKSECURITY_CUSTOMER")
* @@SecurityConfig("RUN_AS_SERVER")
*/
public float getBalance(int id);
}
You might have noticed the
validateConfigAttributes property in the above
MethodSecurityInterceptor examples. When set to
true (the default), at startup time the
MethodSecurityInterceptor will evaluate if the
provided configuration attributes are valid. It does this by checking
each configuration attribute can be processed by either the
AccessDecisionManager or the
RunAsManager. If neither of these can process a
given configuration attribute, an exception is thrown. If using the
Jakarta Commons Attributes method of configuration, you should set
validateConfigAttributes to
false.
FilterInvocation Security Interceptor
To secure FilterInvocations, developers need
to add a SecurityEnforcementFilter to their
web.xml. A typical configuration example is
provided below: <filter>
<filter-name>Acegi HTTP Request Security Filter</filter-name>
<filter-class>net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter</filter-class>
<init-param>
<param-name>appContextLocation</param-name>
<param-value>web-filters-acegisecurity.xml</param-value>
</init-param>
<init-param>
<param-name>loginFormUrl</param-name>
<param-value>/acegilogin.jsp</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Acegi HTTP Request Security Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
As shown above, an appContextLocation
indicates the location of a Spring XML application context. In the
example above, this file should be placed at the root of the web
application's classpath (in the WEB-INF/classes
directory). The loginFormUrl is where the filter
will redirect the user's browser if they request a secure HTTP
resource but they are not authenticated. If the user is authenticated,
a "403 Forbidden" response will be returned to the browser. All paths
are relative to the web application root.
The SecurityEnforcementFilter will load the
Spring XML application context expressed in the
appContextLocation. It will expect to find in this
application context a properly configured
FilterSecurityInterceptor. The configuration of the
FilterSecurityInterceptor is very similar to the
MethodSecurityInterceptor:
<bean id="filterInvocationInterceptor" class="net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
<property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property>
<property name="runAsManager"><ref bean="runAsManager"/></property>
<property name="objectDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
\A/secure/super.*\Z=ROLE_WE_DONT_HAVE
\A/secure/.*\Z=ROLE_SUPERVISOR,ROLE_TELLER
</value>
</property>
</bean>
Like any other security interceptor, the
FilterSecurityInterceptor requires a reference to
an AuthenticationManager,
AccessDecisionManager and
RunAsManager, which are each discussed in separate
sections below. The FilterSecurityInterceptor is
also configured with configuration attributes that apply to different
HTTP URL requests. A full discussion of configuration attributes is
provided in the High Level Design section of this document.
The FilterSecurityInterceptor can be
configured with configuration attributes in two ways. The first is via
a property editor and the application context, which is shown above.
The second is via writing your own
ObjectDefinitionSource, although this is beyond the
scope of this document. Irrespective of the approach used, the
ObjectDefinitionSource is responsible for returning
a ConfigAttributeDefinition object that contains
all of the configuration attributes associated with a single secure
HTTP URL.
It should be noted that the
FilterSecurityInterceptor.setObjectDefinitionSource()
method actually expects an instance of
FilterInvocationDefinitionSource. This is a marker
interface which subclasses ObjectDefinitionSource.
It simply denotes the ObjectDefinitionSource
understands FilterInvocations. In the interests of
simplicity we'll continue to refer to the
FilterInvocationDefinitionSource as an
ObjectDefinitionSource, as the distinction is of
little relevance to most users of the
FilterSecurityInterceptor.
If using the application context property editor approach (as
shown above), commas are used to delimit the different configuration
attributes that apply to each HTTP URL. Each configuration attribute
is assigned into its own SecurityConfig object. The
SecurityConfig object is discussed in the High
Level Design section. The ObjectDefinitionSource
created by the property editor,
FilterInvocationDefinitionSource, matches
configuration attributes against FilterInvocations
based on regular expression evaluation of the request URL. It works
down the list in the order they are defined. Thus it is important that
more specific regular expressions are defined higher in the list than
less specific regular expressions. This is reflected in our example
above, where the more specific /secure/super
pattern appears higher than the less specific
/super pattern. If they were reversed, the
/super pattern would always match and the
/secure/super pattern would never be evaluated. The
special keyword
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON causes
the FilterInvocationDefinitionSource to
automatically convert a request URL to lowercase before comparison
against the regular expressions. Whilst by default the case of the
request URL is not converted, it is generally recommended to use
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON and
write each regular expression assuming lowercase.
As with other security interceptors, the
validateConfigAttributes property is observed. When
set to true (the default), at startup time the
FilterSecurityInterceptor will evaluate if the
provided configuration attributes are valid. It does this by checking
each configuration attribute can be processed by either the
AccessDecisionManager or the
RunAsManager. If neither of these can process a
given configuration attribute, an exception is thrown.
Authentication
Authentication Requests
Authentication requires a way for client code to present its
security identification to the Acegi Security System for Spring. This
is the role of the Authentication interface. The
Authentication interface holds three important
objects: the principal (the identity of the caller), the credentials
(the proof of the identity of the caller, such as a password), and the
authorities that have been granted to the principal. The principal and
its credentials are populated by the client code, whilst the granted
authorities are populated by the
AuthenticationManager. The Acegi Security System
for Spring includes several concrete Authentication
implementations:
UsernamePasswordAuthenticationToken
allows a username and password to be presented as the principal
and credentials respectively. It is also what is created by the
HTTP Session Authentication system.
TestingAuthenticationToken facilitates
unit testing by automatically being considered an authenticated
object by its associated
AuthenticationProvider.
RunAsUserToken is used by the default
run-as authentication replacement implementation. This is
discussed further in the Run-As Authentication Replacement
section.
PrincipalAcegiUserToken and
JettyAcegiUserToken implement
AuthByAdapter (a subclass of
Authentication) and are used whenever
authentication is completed by Acegi Security System for Spring
container adapters. This is discussed further in the Container
Adapters section.
The authorities granted to a principal are represented by the
GrantedAuthority interface. The
GrantedAuthority interface is discussed at length
in the Authorization section.
Authentication Manager
As discussed in the Security Interception section, the
AbstractSecurityInterceptor extracts the
Authentication object from the
SecureContext in the
ContextHolder. This is then passed to an
AuthenticationManager. The
AuthenticationManager interface is very
simple:
public Authentication authenticate(Authentication authentication) throws AuthenticationException;
Implementations of AuthenticationManager are
required to throw an AuthenticationException should
authentication fail, or return a fully populated
Authentication object. In particular, the returned
Authentication object should contain an array of
GrantedAuthority objects. The
SecurityInterceptor places the populated
Authentication object back in the
SecureContext in the
ContextHolder, overwriting the original
Authentication object.
The AuthenticationException has a number of
subclasses. The most important are
BadCredentialsException (an incorrect principal or
credentials), DisabledException and
LockedException. The latter two exceptions indicate
the principal was found, but the credentials were not checked and
authentication is denied. An
AuthenticationServiceException is also provided,
which indicates the authentication system could not process the
request (eg a database was unavailable).
Provider-Based Authentication
Whilst the basic Authentication and
AuthenticationManager interfaces enable users to
develop their own authentication systems, users should consider using
the provider-based authentication packages provided by the Acegi
Security System for Spring. The key class,
ProviderManager, is configured via the bean context
with a list of AuthenticationProviders:
<bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref bean="daoAuthenticationProvider"/>
<ref bean="someOtherAuthenticationProvider"/>
</list>
</property>
</bean>
ProviderManager calls a series of registered
AuthenticationProvider implementations, until one
is found that indicates it is able to authenticate a given
Authentication class. When the first compatible
AuthenticationProvider is located, it is passed the
authentication request. The AuthenticationProvider
will then either throw an AuthenticationException
or return a fully populated Authentication
object.
Note the ProviderManager may throw a
ProviderNotFoundException (a subclass of
AuthenticationException) if it none of the
registered AuthenticationProviders can validate the
Authentication object.
Several AuthenticationProvider
implementations are provided with the Acegi Security System for
Spring:
TestingAuthenticationProvider is able
to authenticate a TestingAuthenticationToken.
The limit of its authentication is simply to treat whatever is
contained in the TestingAuthenticationToken
as valid. This makes it ideal for use during unit testing, as
you can create an Authentication object with
precisely the GrantedAuthority objects
required for calling a given method. You definitely would not
register this AuthenticationProvider on a
production system.
DaoAuthenticationProvider is able to
authenticate a
UsernamePasswordAuthenticationToken by
accessing an authentication respository via a data access
object. This is discussed further below, as it is the main way
authentication is initially handled.
RunAsImplAuthenticationToken is able to
authenticate a RunAsUserToken. This is
discussed further in the Run-As Authentication Replacement
section. You would not register this
AuthenticationProvider if you were not using
run-as replacement.
AuthByAdapterProvider is able to
authenticate any AuthByAdapter (a subclass of
Authentication used with container adapters).
This is discussed further in the Container Adapters section. You
would not register this
AuthenticationProvider if you were not using
container adapters.
Data Access Object Authentication Provider
The Acegi Security System for Spring includes a
production-quality AuthenticationProvider
implementation called DaoAuthenticationProvider.
This authentication provider is able to authenticate a
UsernamePasswordAuthenticationToken by obtaining
authentication details from a data access object configured at bean
creation time:
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
<property name="ignorePasswordCase"><value>false</value></property>
<property name="ignoreUsernameCase"><value>true</value></property>
</bean>
By default the DaoAuthenticationProvider does
not require an exact match on usernames, but it does require an exact
match on passwords. This behavior can be configured with the optional
properties shown above.
For a class to be able to provide the
DaoAuthenticationProvider with access to an
authentication repository, it must implement the
AuthenticationDao interface:
public User loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException;
The User object holds basic information such
as the username, password, granted authorities and whether the user is
enabled or disabled.
Given AuthenticationDao is so simple to
implement, it should be easy for users to retrieve authentication
information using a persistence strategy of their choice.
A design decision was made not to support account locking in the
DaoAuthenticationProvider, as doing so would have
increased the complexity of the AuthenticationDao
interface. For instance, a method would be required to increase the
count of unsuccessful authentication attempts. Such functionality
could be easily provided in a new
AuthenticationManager or
AuthenticationProvider implementation if it were
desired.
In-Memory Authentication
Whilst it is easy to use the
DaoAuthenticationProvider and create a custom
AuthenticationDao implementation that extracts
information from a persistence engine of choice, many applications do
not require such complexity. One alternative is to configure an
authentication repository in the application context itself using the
InMemoryDaoImpl:
<bean id="inMemoryDaoImpl" class="net.sf.acegisecurity.providers.dao.memory.InMemoryDaoImpl">
<property name="userMap">
<value>
marissa=koala,ROLE_TELLER,ROLE_SUPERVISOR
dianne=emu,ROLE_TELLER
scott=wombat,ROLE_TELLER
peter=opal,disabled,ROLE_TELLER
</value>
</property>
</bean>
The userMap property contains each of the
usernames, passwords, a list of granted authorities and an optional
enabled/disabled keyword. Commas delimit each token. The username must
appear to the left of the equals sign, and the password must be the
first token to the right of the equals sign. The
enabled and disabled keywords
(case insensitive) may appear in the second or any subsequent token.
Any remaining tokens are treated as granted authorities, which are
created as GrantedAuthorityImpl objects (refer to
the Authorization section for further discussion on granted
authorities). Note that if a user has no password and/or no granted
authorities, the user will not be created in the in-memory
authentication repository.
JDBC Authentication
The Acegi Security System for Spring also includes an
authentication provider that can obtain authentication information
from a JDBC data source. The typical configuration for the
JdbcDaoImpl is shown below:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"><value>org.hsqldb.jdbcDriver</value></property>
<property name="url"><value>jdbc:hsqldb:hsql://localhost:9001</value></property>
<property name="username"><value>sa</value></property>
<property name="password"><value></value></property>
</bean>
<bean id="jdbcDaoImpl" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl">
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>
You can use different relational database management systems by
modifying the DriverManagerDataSource shown above.
Irrespective of the database used, a standard schema must be used as
indicated in dbinit.txt. Of particular note is the
database must return responses that treat the username as case
insensitive, in order to comply with the
AuthenticationDao contract.
The Acegi Security System for Spring ships with a Hypersonic SQL
instance that has the required authentication information and sample
data already populated. To use this server, simply execute the
server.bat or server.sh script
included in the distribution. This will load a new database server
instance that will service requests made to the URL indicated in the
bean context configuration shown above.
Authentication Recommendations
With the heavy use of interfaces throughout the authentication
system (Authentication,
AuthenticationManager,
AuthenticationProvider and
AuthenticationDao) it might be confusing to a new
user to know which part of the authentication system to customize. In
general, the following is recommended:
Use the
UsernamePasswordAuthenticationToken
implementation where possible.
If you simply need to implement a new authentication
repository (eg to obtain user details from your application’s
existing database), use the
DaoAuthenticationProvider along with the
AuthenticationDao. It is the fastest and safest
way to integrate an external database.
If you're using Container Adapters or a
RunAsManager that replaces the
Authentication object, ensure you have
registered the AuthByAdapterProvider and
RunAsManagerImplProvider respectively with your
ProviderManager.
Never enable the
TestingAuthenticationProvider on a production
system. Doing so will allow any client to simply present a
TestingAuthenticationToken and obtain whatever
access they request.
Adding a new AuthenticationProvider is
sufficient to support most custom authentication requirements.
Only unusual requirements would require the
ProviderManager to be replaced with a different
AuthenticationManager.
Authorization
Granted Authorities
As briefly mentioned in the Authentication section, all
Authentication implementations are required to
store an array of GrantedAuthority objects. These
represent the authorities that have been granted to the principal. The
GrantedAuthority objects are inserted into the
Authentication object by the
AuthenticationManager and are later read by
AccessDecisionManagers when making authorization
decisions.
GrantedAuthority is an interface with only
one method:
public String getAuthority();
This method allows AccessDecisionManagers to
obtain a precise String representation of the
GrantedAuthority. By returning a representation as
a String, a GrantedAuthority can
be easily "read" by most AccessDecisionManagers. If
a GrantedAuthority cannot be precisely represented
as a String, the
GrantedAuthority is considered "complex" and
getAuthority() must return
null.
An example of a "complex" GrantedAuthority
would be an implementation that stores a list of operations and
authority thresholds that apply to different customer account numbers.
Representing this complex GrantedAuthority as a
String would be quite complex, and as a result the
getAuthority() method should return
null. This will indicate to any
AccessDecisionManager that it will need to
specifically support the GrantedAuthority
implementation in order to understand its contents.
The Acegi Security System for Spring includes one concrete
GrantedAuthority implementation,
GrantedAuthorityImpl. This allows any
user-specified String to be converted into a
GrantedAuthority. All
AuthenticationProviders included with the security
architecture use GrantedAuthorityImpl to populate
the Authentication object.
Access Decision Managers
The AccessDecisionManager is called by the
AbstractSecurityInterceptor and is responsible for
making final access control decisions. The
AccessDecisionManager interface contains three
methods:
public void decide(Authentication authentication, Object object, ConfigAttributeDefinition config) throws AccessDeniedException;
public boolean supports(ConfigAttribute attribute);
public boolean supports(Class clazz);
As can be seen from the first method, the
AccessDecisionManager is passed via method
parameters all information that is likely to be of value in assessing
an authorization decision. In particular, passing the secure
Object enables those arguments contained in the
actual secure object invocation to be inspected. For example, let's
assume the secure object was a MethodInvocation. It
would be easy to query the MethodInvocation for any
Customer argument, and then implement some sort of
security logic in the AccessDecisionManager to
ensure the principal is permitted to operate on that customer.
Implementations are expected to throw an
AccessDeniedException if access is denied.
The supports(ConfigAttribute) method is
called by the AbstractSecurityInterceptor at
startup time to determine if the
AccessDecisionManager can process the passed
ConfigAttribute. The
supports(Class) method is called by a security
interceptor implementation to ensure the configured
AccessDecisionManager supports the type of secure
object that the security interceptor will present.
Voting Decision Manager
Whilst users can implement their own
AccessDecisionManager to control all aspects of
authorization, the Acegi Security System for Spring includes several
AccessDecisionManager implementations that are
based on voting. Using this approach, a series of
AccessDecisionVoter implementations are polled on
an authorization decision. The
AccessDecisionManager then decides whether or not
to throw an AccessDeniedException based on its
assessment of the votes.
The AccessDecisionVoter interface has three
methods:
public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config);
public boolean supports(ConfigAttribute attribute);
public boolean supports(Class clazz);
Concrete implementations return an int, with
possible values being reflected in the
AccessDecisionVoter static fields
ACCESS_ABSTAIN, ACCESS_DENIED
and ACCESS_GRANTED. A voting implementation will
return ACCESS_ABSTAIN if it has no opinion on an
authorization decision. If it does have an opinion, it must return
either ACCESS_DENIED or
ACCESS_GRANTED.
There are three concrete
AccessDecisionManagers provided with the Acegi
Security System for Spring that tally the votes. The
ConsensusBased implementation will grant or deny
access based on the consensus of non-abstain votes. Properties are
provided to control behavior in the event of an equality of votes or
if all votes are abstain. The AffirmativeBased
implementation will grant access if one or more
ACCESS_GRANTED votes were received (ie a deny vote
will be ignored, provided there was at least one grant vote). Like the
ConsensusBased implementation, there is a parameter
that controls the behavior if all voters abstain. The
UnanimousBased provider expects unanimous
ACCESS_GRANTED votes in order to grant access,
ignoring abstains. It will deny access if there is any
ACCESS_DENIED vote. Like the other implementations,
there is a parameter that controls the behaviour if all voters
abstain.
It is possible to implement a custom
AccessDecisionManager that tallies votes
differently. For example, votes from a particular
AccessDecisionVoter might receive additional
weighting, whilst a deny vote from a particular voter may have a veto
effect.
There is one concrete AccessDecisionVoter
implementation provided with the Acegi Security System for Spring. The
RoleVoter class will vote if any ConfigAttribute
begins with ROLE_. It will vote to grant access if
there is a GrantedAuthority which returns a
String representation (via the
getAuthority() method) exactly equal to one or more
ConfigAttributes starting with
ROLE_. If there is no exact match of any
ConfigAttribute starting with
ROLE_, the RoleVoter will vote
to deny access. If no ConfigAttribute begins with
ROLE_, the voter will abstain.
RoleVoter is case sensitive on comparisons as well
as the ROLE_ prefix.
It is possible to implement a custom
AccessDecisionVoter. Several examples are provided
in the Acegi Security System for Spring unit tests, including
ContactSecurityVoter and
DenyVoter. The
ContactSecurityVoter abstains from voting decisions
where a CONTACT_OWNED_BY_CURRENT_USER
ConfigAttribute is not found. If voting, it queries
the MethodInvocation to extract the owner of the
Contact object that is subject of the method call.
It votes to grant access if the Contact owner
matches the principal presented in the
Authentication object. It could have just as easily
compared the Contact owner with some
GrantedAuthority the
Authentication object presented. All of this is
achieved with relatively few lines of code and demonstrates the
flexibility of the authorization model.
Authorization Tag Library
The Acegi Security System for Spring comes bundled with a JSP
tag library that eases JSP writing. The tag library is known as
authz.
This library allows you to easy develop JSP pages which
reference the security environment. For example,
authz allows you to determine if a principal holds
a particular granted authority, holds a group of granted authorities,
or does not hold a given granted authority.
Usage
The following JSP fragment illustrates how to use the
authz taglib:
<authz:authorize ifAllGranted="ROLE_SUPERVISOR">
<td>
<A HREF="del.htm?id=<c:out value="${contact.id}"/>">Del</A>
</td>
</authz:authorize>
This code was copied from the Contacts sample
application.
What this code says is: if the principal has been granted
ROLE_SUPERVISOR, allow the tag's body to be output.
Installation
Installation is a simple matter. Simply copy the
acegi-security-taglib.jar file into your
application's WEB-INF/lib folder. The tag library
includes it's TLD, which makes it easier to work with JSP 1.2+
containers.
If you are using a JSP 1.1 container, you will need to declare
the JSP tag library in your application's web.xml
file, with code such as this:
<taglib>
<taglib-uri>http://acegisecurity.sf.net/authz</taglib-uri>
<taglib-location>/WEB-INF/authz.tld</taglib-location>
</taglib>
For JSP 1.1 containers you will also need to extract the
authz.tld file from the
acegi-security-taglib.jar file and put it into
your application's WEB-INF/lib folder. Use a
regular Zip tool, or Java's JAR utility.
Reference
The authz:authorize tag declares the
following attributes:
ifAllGranted: All the listed roles
must be granted for the tag to output its body.
ifAnyGranted: Any of the listed roles
must be granted for the tag to output its body.
ifNotGranted: None of the listed
roles must be granted for the tag to output its body.
You'll note that in each attribute you can list multiple
roles. Simply separate the roles using a comma. The
authorize tag ignores whitespace in
attributes.
The tag library logically ANDs all of it's parameters
together. This means that if you combine two or more attributes, all
attributes must be true for the tag to output it's body. Don't add
an ifAllGranted="ROLE_SUPERVISOR", followed by an
ifNotGranted="ROLE_SUPERVISOR", or you'll be
surprised to never see the tag's body.
By requiring all attributes to return true, it allows you to
create more complex authorization scenarios. For example, you could
declare an ifAllGranted="ROLE_SUPERVISOR" and an
ifNotGranted="ROLE_NEWBIE_SUPERVISOR" in the same
tag, in order to prevent new supervisors from seeing the tag body.
Although it would no doubt be simpler to use
ifAllGranted="ROLE_EXPERIENCED_SUPERVISOR" rather
than inserting NOT conditions into your design.
One last item: the tag verifies the authorizations in a
specific order: first ifNotGranted, then
ifAllGranted, and finally,
ifAnyGranted.
Authorization Recommendations
Given there are several ways to achieve similar authorization
outcomes in the Acegi Security System for Spring, the following
general recommendations are made:
Grant authorities using
GrantedAuthorityImpl where possible. Because it
is already supported by the Acegi Security System for Spring, you
avoid the need to create custom
AuthenticationManager or
AuthenticationProvider implementations simply
to populate the Authentication object with a
custom GrantedAuthority.
Most authorization decision rules can be easily satisfied by
writing an AccessDecisionVoter implementation
and using either ConsensusBased,
AffirmativeBased or
UnanimousBased as the
AccessDecisionManager.
Run-As Authentication Replacement
Purpose
The AbstractSecurityInterceptor is able to
temporarily replace the Authentication object in
the SecureContext and
ContextHolder during the
SecurityInterceptorCallback. This only occurs if
the original Authentication object was successfully
processed by the AuthenticationManager and
AccessDecisionManager. The
RunAsManager will indicate the replacement
Authentication object, if any, that should be used
during the SecurityInterceptorCallback.
By temporarily replacing the Authentication
object during a SecurityInterceptorCallback, the
secured invocation will be able to call other objects which require
different authentication and authorization credentials. It will also
be able to perform any internal security checks for specific
GrantedAuthority objects.
Usage
A RunAsManager interface is provided by the
Acegi Security System for Spring:
public Authentication buildRunAs(Authentication authentication, Object object, ConfigAttributeDefinition config);
public boolean supports(ConfigAttribute attribute);
public boolean supports(Class clazz);
The first method returns the Authentication
object that should replace the existing
Authentication object for the duration of the
method invocation. If the method returns null, it
indicates no replacement should be made. The second method is used by
the AbstractSecurityInterceptor as part of its
startup validation of configuration attributes. The
supports(Class) method is called by a security
interceptor implementation to ensure the configured
RunAsManager supports the type of secure object
that the security interceptor will present.
One concrete implementation of a RunAsManager
is provided with the Acegi Security System for Spring. The
RunAsManagerImpl class returns a replacement
RunAsUserToken if any
ConfigAttribute starts with
RUN_AS_. If any such
ConfigAttribute is found, the replacement
RunAsUserToken will contain the same principal,
credentials and granted authorities as the original
Authentication object, along with a new
GrantedAuthorityImpl for each
RUN_AS_ ConfigAttribute. Each
new GrantedAuthorityImpl will be prefixed with
ROLE_, followed by the RUN_AS
ConfigAttribute. For example, a
RUN_AS_SERVER will result in the replacement
RunAsUserToken containing a
ROLE_RUN_AS_SERVER granted authority.
The replacement RunAsUserToken is just like
any other Authentication object. It needs to be
authenticated by the AuthenticationManager,
probably via delegation to a suitable
AuthenticationProvider. The
RunAsImplAuthenticationProvider performs such
authentication. It simply accepts as valid any
RunAsUserToken presented.
To ensure malicious code does not create a
RunAsUserToken and present it for guaranteed
acceptance by the RunAsImplAuthenticationProvider,
the hash of a key is stored in all generated tokens. The
RunAsManagerImpl and
RunAsImplAuthenticationProvider is created in the
bean context with the same key:
<bean id="runAsManager" class="net.sf.acegisecurity.runas.RunAsManagerImpl">
<property name="key"><value>my_run_as_password</value></property>
</bean><bean id="runAsAuthenticationProvider" class="net.sf.acegisecurity.runas.RunAsImplAuthenticationProvider">
<property name="key"><value>my_run_as_password</value></property>
</bean>
By using the same key, each RunAsUserToken
can be validated it was created by an approved
RunAsManagerImpl. The
RunAsUserToken is immutable after creation for
security reasons.
User Interfacing with the ContextHolder
Purpose
Everything presented so far assumes one thing: the
ContextHolder is populated with a valid
SecureContext, which in turn contains a valid
Authentication object. Develolpers are free to do
this in whichever way they like, such as directly calling the relevant
objects at runtime. However, several classes have been provided to
make this process transparent in many situations.
The net.sf.acegisecurity.ui package is design
to make interfacing web application user interfaces with the
ContextHolder as simple as possible. There are two
major steps in doing this:
Actually authenticate the user and place the resulting
Authentication object in a "well-known
location".
Extract the Authentication object from
the "well-known location" and place in into the
ContextHolder for the duration of the secure
object invocation.
Several alternatives are available for the first step. The two
most supported approaches are HTTP Session Authentication, which uses
the HttpSession object and filters to authenticate
the user. The other is via Container Adapters, which allow supported
web containers to perform the authentication themselves. HTTP Session
Authentication is discussed below, whilst Container Adapters are
discussed in a separate section.
HTTP Session Authentication
HTTP Session Authentication involves using the
AuthenticationProcessingFilter to process a login
form. The login form simply contains j_username and
j_password input fields, and posts to a URL that is
monitored by the filter (by default
j_acegi_security_check). The filter is defined in
web.xml as follows:
<filter>
<filter-name>Acegi Authentication Processing Filter</filter-name>
<filter-class>net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter</filter-class>
<init-param>
<param-name>appContextLocation</param-name>
<param-value>web-filters-acegisecurity.xml</param-value>
</init-param>
<init-param>
<param-name>authenticationFailureUrl</param-name>
<param-value>/acegilogin.jsp?login_error=1</param-value>
</init-param>
<init-param>
<param-name>defaultTargetUrl</param-name>
<param-value>/</param-value>
</init-param>
<init-param>
<param-name>filterProcessUrl</param-name>
<param-value>/j_acegi_security_check</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Acegi Authentication Processing Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
The appContextLocation specifies the location
of a Spring XML application context. In the example above the root of
the classpath is used, so the XML file should be placed in
WEB-INF/classes. The
AuthenticationProcessingFilter will load this
application context, expecting to find a properly configured
AuthenticationManager. It will use this
AuthenticationManager to process each
authentication request. If authentication fails, the browser will be
redirected to the authenticationFailureUrl. The
AuthenticationException will be placed into the
HttpSession attribute indicated by
AuthenticationProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY,
enabling a reason to be provided to the user on the error page.
If authentication is successful, the resulting
Authentication object will be placed into the
HttpSession attribute indicated by
HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY.
This becomes the "well-known location" from which the
Authentication object is later extracted.
Once the HttpSession has been updated, the browser will need to
be redirected to the target URL. The target URL is usually indicated
by the HttpSession attribute specified by
AuthenticationProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY.
This attribute is automatically set by the
SecurityEnforcementFilter when an
AuthenticationException occurs, so that after login
is completed the user can return to what they were trying to access.
If for some reason the HttpSession does not
indicate the target URL, the browser will be redirected to the
defaultTargetUrl filter initialization
property.
Because this authentication approach is fully contained within a
single web application, HTTP Session Authentication is recommended to
be used instead of Container Adapters.
Well-Known Location Integration
Once a web application has used either HTTP Session
Authentication or a Container Adapter, an
Authentication object will exist in a well-known
location. The final step in automatically integrating the user
interface with the backend security interceptor is to extract this
Authentication object from the well-known location
and place it into a SecureContext in the
ContextHolder.
The AbstractIntegrationFilter and its
subclasses provide this well-known location integration. These classes
are standard filters, and at the start of each request they will
attempt to extract the Authentication object from a
well-known location. The Authentication object will
then be added to a SecureContext, the
SecureContext associated with the
ContextHolder for the duration of the request, and
the ContextHolder be cleared when the request is
finished. Four concrete subclasses of
AbstractIntegrationFilter are provided with the
Acegi Security System for Spring:
HttpSessionIntegrationFilter is used
with HTTP Session Authentication, or any other approach that
populates the HttpSession accordingly. It
extracts the Authentication object from the
HttpSession attribute indicated by
HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY.
HttpRequestIntegrationFilter is used
with Catalina, Jetty and Resin Container Adapters. It extracts
the authentication information from
HttpServletRequest.getUserPrincipal().
JbossIntegrationFilter is used with the
JBoss Container Adapter. It extracts the authentication from
java:comp/env/security/subject.
AutoIntegrationFilter automatically
determines which filter to use. This makes a web application WAR
file more portable, as the web.xml is not
hard-coded to a specific
AbstractIntegrationFilter.
To define the AutoIntegrationFilter
(recommended), simply add the following to your web.xml:
<filter>
<filter-name>Acegi Security System for Spring Auto Integration Filter</filter-name>
<filter-class>net.sf.acegisecurity.ui.AutoIntegrationFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Acegi Security System for Spring Auto Integration Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Once in the ContextHolder, the standard Acegi
Security System for Spring classes can be used. Because
ContextHolder is a standard object which is
populated using a filter at the container level, JSPs and Servlets do
not need to use Spring's MVC packages. This enables those applications
that use other MVC frameworks to still leverage Spring's other
capabilities, with full authentication and authorization support. The
debug.jsp page provided with the sample application
demonstrates accessing the ContextHolder
independent of Spring's MVC packages.
Container Adapters
Overview
Early versions of the Acegi Security System for Spring
exclusively used Container Adapters for interfacing authentication
with end users. Whilst this worked well, it required considerable time
to support multiple container versions and the configuration itself
was relatively time-consuming for developers. For this reason the HTTP
Session Authentication approach was developed, and is today
recommended for most applications.
Container Adapters enable the Acegi Security System for Spring
to integrate directly with the containers used to host end user
applications. This integration means that applications can continue to
leverage the authentication and authorization capabilities built into
containers (such as isUserInRole() and form-based
or basic authentication), whilst benefiting from the enhanced security
interception capabilities provided by the Acegi Security System for
Spring.
The integration between a container and the Acegi Security
System for Spring is achieved through an adapter. The adapter provides
a container-compatible user authentication provider, and needs to
return a container-compatible user object.
The adapter is instantiated by the container and is defined in a
container-specific configuration file. The adapter then loads a Spring
application context which defines the normal authentication manager
settings, such as the authentication providers that can be used to
authenticate the request. The application context is usually named
acegisecurity.xml and is placed in a
container-specific location.
The Acegi Security System for Spring currently supports Jetty,
Catalina (Tomcat), JBoss and Resin. Additional container adapters can
easily be written.
Adapter Authentication Provider
As is always the case, the container adapter generated
Authentication object still needs to be
authenticated by an AuthenticationManager when
requested to do so by the
AbstractSecurityInterceptor. The
AuthenticationManager needs to be certain the
adapter-provided Authentication object is valid and
was actually authenticated by a trusted adapter.
Adapters create Authentication objects which
are immutable and implement the AuthByAdapter
interface. These objects store the hash of a key that is defined by
the adapter. This allows the Authentication object
to be validated by the AuthByAdapterProvider. This
authentication provider is defined as follows:
<bean id="authByAdapterProvider" class="net.sf.acegisecurity.adapters.AuthByAdapterProvider">
<property name="key"><value>my_password</value></property>
</bean>
The key must match the key that is defined in the
container-specific configuration file that starts the adapter. The
AuthByAdapterProvider automatically accepts as
valid any AuthByAdapter implementation that returns
the expected hash of the key.
To reiterate, this means the adapter will perform the initial
authentication using providers such as
DaoAuthenticationProvider, returning an
AuthByAdapter instance that contains a hash code of
the key. Later, when an application calls a security interceptor
managed resource, the AuthByAdapter instance in the
SecureContext in the
ContextHolder will be tested by the application's
AuthByAdapterProvider. There is no requirement for
additional authentication providers such as
DaoAuthenticationProvider within the
application-specific application context, as the only type of
Authentication instance that will be presented by
the application is from the container adapter.
Classloader issues are frequent with containers and the use of
container adapters illustrates this further. Each container requires a
very specific configuration. The installation instructions are
provided below. Once installed, please take the time to try the sample
application to ensure your container adapter is properly
configured.
Catalina (Tomcat) Installation
The following was tested with Jakarta Tomcat 4.1.30 and 5.0.19.
We automatically test the following directions using our container
integration test system and these versions of Catalina
(Tomcat).
$CATALINA_HOME refers to the root of your
Catalina (Tomcat) installation.
Edit your $CATALINA_HOME/conf/server.xml file
so the <Engine> section contains only one
active <Realm> entry. An example realm
entry:
<Realm className="net.sf.acegisecurity.adapters.catalina.CatalinaAcegiUserRealm"
appContextLocation="conf/acegisecurity.xml"
key="my_password" />
Be sure to remove any other <Realm>
entry from your <Engine> section.
Copy acegisecurity.xml into
$CATALINA_HOME/conf.
Copy acegi-security-catalina-server.jar into
$CATALINA_HOME/server/lib.
Copy the following files into
$CATALINA_HOME/common/lib:
aopalliance.jar
spring.jar
acegi-security-catalina-common.jar
None of the above JAR files (or
acegi-security.jar) should be in your application's
WEB-INF/lib. The realm name indicated in your
web.xml does not matter with Catalina.
We have received reports of problems using this Container
Adapter with Mac OS X. A work-around is to use a script such as
follows:
#!/bin/sh
export CATALINA_HOME="/Library/Tomcat"
export JAVA_HOME="/Library/Java/Home"
cd /
$CATALINA_HOME/bin/startup.sh
Jetty Installation
The following was tested with Jetty 4.2.18. We automatically
test the following directions using our container integration test
system and this version of Jetty.
$JETTY_HOME refers to the root of your Jetty
installation.
Edit your $JETTY_HOME/etc/jetty.xml file so
the <Configure class> section has a new
addRealm call:
<Call name="addRealm">
<Arg>
<New class="net.sf.acegisecurity.adapters.jetty.JettyAcegiUserRealm">
<Arg>Spring Powered Realm</Arg>
<Arg>my_password</Arg>
<Arg>etc/acegisecurity.xml</Arg>
</New>
</Arg>
</Call>
Copy acegisecurity.xml into
$JETTY_HOME/etc.
Copy the following files into
$JETTY_HOME/ext:
aopalliance.jar
commons-logging.jar
spring.jar
acegi-security-jetty-ext.jar
None of the above JAR files (or
acegi-security.jar) should be in your application's
WEB-INF/lib. The realm name indicated in your
web.xml does matter with Jetty. The
web.xml must express the same
<realm-name> as your
jetty.xml (in the example above, "Spring Powered
Realm").
JBoss Installation
The following was tested with JBoss 3.2.3. We automatically test
the following directions using our container integration test system
and this version of JBoss.
$JBOSS_HOME refers to the root of your JBoss
installation.
Edit your
$JBOSS_HOME/server/your_config/conf/login-config.xml
file so that it contains a new entry under the
<Policy> section:
<application-policy name = "SpringPoweredRealm">
<authentication>
<login-module code = "net.sf.acegisecurity.adapters.jboss.JbossSpringLoginModule"
flag = "required">
<module-option name = "appContextLocation">acegisecurity.xml</module-option>
<module-option name = "key">my_password</module-option>
</login-module>
</authentication>
</application-policy>
Copy acegisecurity.xml into
$JBOSS_HOME/server/your_config/conf.
Copy the following files into
$JBOSS_HOME/server/your_config/lib:
aopalliance.jar
spring.jar
acegi-security-jboss-lib.jar
None of the above JAR files (or
acegi-security.jar) should be in your application's
WEB-INF/lib. The realm name indicated in your
web.xml does not matter with JBoss. However, your
web application's WEB-INF/jboss-web.xml must
express the same <security-domain> as your
login-config.xml. For example, to match the above
example, your jboss-web.xml would look like
this:
<jboss-web>
<security-domain>java:/jaas/SpringPoweredRealm</security-domain>
</jboss-web>
Resin Installation
The following was tested with Resin 3.0.6.
$RESIN_HOME refers to the root of your Resin
installation.
Resin provides several ways to support the container adapter. In
the instructions below we have elected to maximise consistency with
other container adapter configurations. This will allow Resin users to
simply deploy the sample application and confirm correct
configuration. Developers comfortable with Resin are naturally able to
use its capabilities to package the JARs with the web application
itself, and/or support single sign-on.
Copy the following files into
$RESIN_HOME/lib:
aopalliance.jar
commons-logging.jar
spring.jar
acegi-security-resin-lib.jar
Unlike the container-wide acegisecurity.xml
files used by other container adapters, each Resin web application
will contain its own
WEB-INF/resin-acegisecurity.xml file. Each web
application will also contain a resin-web.xml file
which Resin uses to start the container adapter:
<web-app>
<authenticator>
<type>net.sf.acegisecurity.adapters.resin.ResinAcegiAuthenticator</type>
<init>
<app-context-location>WEB-INF/resin-acegisecurity.xml</app-context-location>
<key>my_password</key>
</init>
</authenticator>
</web-app>
With the basic configuration provided above, none of the JAR
files listed (or acegi-security.jar) should be in
your application's WEB-INF/lib. The realm name
indicated in your web.xml does not matter with
Resin, as the relevant authentication class is indicated by the
<authenticator> setting.
Contacts Sample Application
Included with the Acegi Security System for Spring is a very
simple application that can demonstrate the basic security facilities
provided by the system (and confirm your Container Adapter is properly
configured if you're using one).
The Contacts sample application includes two deployable versions:
contacts.war is configured with the HTTP Session
Authentication approach, and does not use Container Adapters. The
contacts-container-adapter.war is configured to use a
Container Adapter. If you're just wanting to see how the sample
application works, please use contacts.war as it does
not require special configuration of your container.
If you are going to use the
contacts-container-adapter.war version, first
configure your container as described in the Container Adapters section
of this chapter. Do not modify acegisecurity.xml. It
contains a very basic in-memory authentication configuration that is
compatible with the sample application.
To deploy, simply copy the relevant
contacts.war or
contacts-container-adapter.war file from the Acegi
Security System for Spring distribution into your container’s
webapps directory.
After starting your container, check the application can load.
Visit http://localhost:8080/contacts (or whichever
URL is appropriate for your web container and the WAR you deployed). A
random contact should be displayed. Click "Refresh" several times and
you will see different contacts. The business method that provides this
random contact is not secured.
Next, click "Debug". You will be prompted to authenticate, and a
series of usernames and passwords are suggested on that page. Simply
authenticate with any of these and view the resulting page. It should
contain a success message similar to the following:
Context on ContextHolder is of type:
net.sf.acegisecurity.context.SecureContextImpl
The Context implements SecureContext.
Authentication object is of type:
net.sf.acegisecurity.adapters.PrincipalAcegiUserToken
Authentication object as a String:
net.sf.acegisecurity.adapters.PrincipalAcegiUserToken@e9a7c2:
Username: marissa; Password: [PROTECTED]; Authenticated: true; Granted
Authorities: ROLE_TELLER, ROLE_SUPERVISOR
Authentication object holds the following granted
authorities:
ROLE_TELLER (getAuthority(): ROLE_TELLER)
ROLE_SUPERVISOR (getAuthority(): ROLE_SUPERVISOR)
SUCCESS! Your [container adapter|web filter] appears to be
properly configured!
If you receive a different message, and deployed
contacts-container-adapter.war, check you have
properly configured your Container Adapter. Refer to the instructions
provided above.
Once you successfully receive the above message, return to the
sample application's home page and click "Manage". You can then try out
the application. Notice that only the contacts belonging to the
currently logged on user are displayed, and only users with
ROLE_SUPERVISOR are granted access to delete their
contacts. Behind the scenes, the
MethodSecurityInterceptor is securing the business
objects. If you're using contacts.war, the
FilterSecurityInterceptor is also securing the HTTP
requests. If using contacts.war, be sure to try
visiting http://localhost:8080/contacts/secure/super,
which will demonstrate access being denied by the
SecurityEnforcementFilter.
Become Involved
We welcome you to become involved in the Acegi Security System for
Spring project. There are many ways of contributing, including reading
the mailing list and responding to questions from other people, writing
new code, improving existing code, assisting with documentation, or
simply making suggestions.
SourceForge provides CVS services for the project, allowing
anybody to access the latest code. If you wish to contribute new code,
please observe the following requirements. These exist to maintain the
quality and consistency of the project:
Run the Ant format task (or use a suitable
IDE plug-in) to convert your code into the project's consistent
style
Ensure your code does not break any unit tests (run the Ant
tests target)
Please use the container integration test system to test your
code in the project's officially supported containers
When writing a new container adapter, expand the container
integration test system to properly test it
If you have added new code, please provide suitable unit tests
(use ant clover.html to view coverage)
Add a CVS $Id: index.xml,v 1.3 2004/04/02 21:12:25
fbos Exp $ tag to the JavaDocs for any new class you
create
Mentioned above is our container integration test system, which
aims to test the Acegi Security System for Spring container adapters
with current, production versions of each container. Some containers
might not be supported due to difficulties with starting or stopping the
container within an Ant target. You will need to download the container
release files as specified in the integration test
readme.txt file. These files are intentionally
excluded from CVS due to their large size.
Further Information
Questions and comments on the Acegi Security System for Spring are
welcome. Please direct comments to the Spring Users mailing list or
ben.alex@acegi.com.au. Our project home page (where you can obtain the
latest release of the project and access to CVS) is at
http://acegisecurity.sourceforge.net.