Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

Why use Spring Security (Formerly known as Acegi)?

Spring Secuity Security is a pretty complete solution for all kinds of security needs. It is very configurable and supports many authentication sources out of the box. These include: database queries, LDAP queries and CAS. It can be a bit complex to set up, but following the how to below should get you started quickly.

...

A new Wicket project is currently in the works. You can read more about it on http://wicketstuff.org/confluence/display/STUFFWIKI/Wicket-Security. Please investigate whether it will suite suit your needs better.

For those still wanting to use Spring Security, there is an howto on getting Swarm working with Spring Security http://wicketstuff.org/confluence/display/STUFFWIKI/Swarm+and+Acegi+HowTo 

See the examples below for how to setup your project.

  1. Wicket 1.3.5, Spring 2.5.5, Spring Security 2.0.4 on JDK 5.0
  2. Wicket 1.2.6, Spring 2.0.5, Acegi 1.0.2 on JDK 1.4

Example Wicket 1.3.5

This example uses Maven 2 for dependency management.

...

Code Block
xml
xml
titleweb.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
	version="2.4">


	<filter>
		<filter-name>spring.securityFilterChain<name>springSecurityFilterChain</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
		<init-param>
			<param-name>targetBeanName</param-name>
			<param-value>springSecurityFilterChain</param-value>
		</init-param>
	</filter>

	<filter>
		<filter-name>wicket.filter</filter-name>
		<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
	</filter>

	<filter-mapping>
		<filter-name>spring.securityFilterChain<name>springSecurityFilterChain</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<filter-mapping>
		<filter-name>wicket.filter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
</web-app>

It is important to add springSecurityFilterChain mapping higher in code than the Wicket filter mappin. Wicket filter is only passing filter call down by filter chain if it is unable to handle request itself.

Spring security version 3 and wicket 1.4Adding the spring.securityFilterChain is only necessary if you also want to secure static resources.

Code Block
xml
xml
titlespring-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:security="http://www.springframework.org/schema/security"
	xsi:schemaLocation="http://wwwjava.springframeworksun.orgcom/xml/schemans/beansj2ee http://wwwjava.springframeworksun.orgcom/xml/schemans/beansj2ee/springweb-beans-app_2_4.5.xsd
       http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">

	<bean id="myApplication" class="com.foo.bar.MyApplication" />

	<security:http auto-config="false">
		<security:intercept-url pattern="/login*" filters="none" />
		<security:intercept-url pattern="/**" access="ROLE_ADMIN" />
		<security:form-login login-page="/login" />
	</security:http>

	<security:authentication-provider>
		<security:user-service>
			<security:user password="admin" name="admin" authorities="ROLE_ADMIN" />
		</security:user-service>
	</security:authentication-provider>

</beans>

The above example uses the spring security namespace. For those who were familiar with the Acegi way one might notice the huge improvement of XML setup. The above example states that all URLs, except the /login* are only accessible for users with the role ROLE_ADMIN.
Using the authentication-provider XML element we register an AuthenticationManager in the Spring context. In this case we use a simple in-memory user service using the user-service element.

Wicket setup

WebSession

"
	version="2.4">

	<display-name>example</display-name>


	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/applicationContext-security.xml</param-value>
	</context-param>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<filter>
		<filter-name>wicket.example</filter-name>
		<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
		<init-param>
			<param-name>applicationClassName</param-name>
			<param-value>org.wicket.example.WicketApplication
			</param-value>
		</init-param>
	</filter>


	<filter-mapping>
		<filter-name>wicket.example</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

</web-app>

Spring 2 context

Code Block
xml
xml
titlespring-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:security="http://www.springframework.org/schema/security"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">

	<bean id="myApplication" class="com.foo.bar.MyApplication" />

        <bean id="filterChainProxy" class="org.springframework.security.util.FilterChainProxy">
            <property name="filterInvocationDefinitionSource">
                <value>
                    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
                    PATTERN_TYPE_APACHE_ANT
                    /**=httpSessionContextIntegrationFilter
                </value>
            </property>
        </bean>

        <bean id="httpSessionContextIntegrationFilter"
              class="org.springframework.security.context.HttpSessionContextIntegrationFilter">
            <property name="allowSessionCreation" value="false"/>
        </bean>

	<security:authentication-provider alias="authenticationManager">
		<security:user-service>
			<security:user password="admin" name="admin" authorities="ROLE_ADMIN" />
		</security:user-service>
	</security:authentication-provider>

</beans>

Spring 3 context

Code Block
xml
xml
1applicationContext-security.xml

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:security="http://www.springframework.org/schema/security"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">


	<security:http create-session="never" auto-config="true" >
		<security:remember-me/>
		<security:intercept-url pattern="/**"/>
	</security:http>


	<security:authentication-manager alias="authenticationManager">
		<security:authentication-provider>

			<!--  TODO change this to reference our real user service -->
			<security:user-service>
				<security:user name="admin" password="admin"
					authorities="ROLE_ADMIN, ROLE_USER" />
				<security:user name="user" password="user"
					authorities="ROLE_USER" />

			</security:user-service>
		</security:authentication-provider>

	</security:authentication-manager>

	<security:global-method-security secured-annotations="enabled" />
</beans>

The only filter we need defined from Acegi is the HttpSessionContextIntegrationFilter. This filter will ensure that the SecurityContext is transported to and from the HttpSession onto the Thread context. All authorization is delegated to the wicket-auth-roles module which uses Annotations (@AuthorizeInstantiation).
Using the authentication-provider XML element we register an AuthenticationManager in the Spring context. In this case we use a simple in-memory user service using the user-service element.

Wicket setup

WebSession

Code Block
tileMyAuthenticatedWebSession

public class MyAuthenticatedWebSession extends AuthenticatedWebSession {

    private static final Logger logger = Logger.getLogger(MyAuthenticatedWebSession.class);

    @SpringBean(name="authenticationManager")
    private AuthenticationManager authenticationManager;

    public MyAuthenticatedWebSession(Request request) {
        super(request);
        injectDependencies();
        ensureDependenciesNotNull();
    }

    private void ensureDependenciesNotNull() {
        if (authenticationManager == null) {
            throw new IllegalStateException("AdminSession requires an authenticationManager.");
        }
    }

    private void injectDependencies() {
        InjectorHolder.getInjector().inject(this);
    }

    @Override
    public boolean authenticate(String username, String password) {
        boolean authenticated = false;
        try {
            Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
            SecurityContextHolder.getContext().setAuthentication(authentication);
            authenticated = authentication.isAuthenticated();
        } catch (AuthenticationException e) {
            logger.warn(format("User '%s' failed to login. Reason: %s", username, e.getMessage()));
            authenticated = false;
        }
        return authenticated;
    }

    @Override
    public Roles getRoles(
Code Block
tileMyAuthenticatedWebSession

public class MyAuthenticatedWebSession extends AuthenticatedWebSession {
    
    private static final Logger logger = Logger.getLogger(MyAuthenticatedWebSession.class);

    @SpringBean
    private AuthenticationManager authenticationManager;

    public MyAuthenticatedWebSession(Request request) {
        super(requestRoles roles = new Roles();
        injectDependenciesgetRolesIfSignedIn(roles);
        return ensureDependenciesNotNull()roles;
    }

    private void ensureDependenciesNotNullgetRolesIfSignedIn(Roles roles) {
        if (authenticationManager == null(isSignedIn()) {
            Authentication throwauthentication new= IllegalStateException("AdminSession requires an authenticationManager."SecurityContextHolder.getContext().getAuthentication();
        }
    }

    private void injectDependencies() {
        InjectorHolder.getInjector().inject(thisaddRolesFromAuthentication(roles, authentication);
        }

    @Override}

    publicprivate booleanvoid authenticateaddRolesFromAuthentication(StringRoles usernameroles, StringAuthentication passwordauthentication) {
        booleanfor authenticated(GrantedAuthority =authority false;
        try : authentication.getAuthorities()) {
            Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, passwordroles.add(authority.getAuthority());
        }
    SecurityContextHolder.getContext().setAuthentication(authentication);}

}

Spring 2 Application

Code Block
titleMyWebApplication.java

public class MyWebApplication extends AuthenticatedWebApplication implements ApplicationContextAware {
    private ApplicationContext context;

    boolean  authenticatedisInitialized = authentication.isAuthenticated()false;

    @Override
    }protected catchvoid init(AuthenticationException e) {
        if (!isInitialized) {
    logger.warn(format("User '%s' failed to login. Reason: %s", username, esuper.getMessageinit()));
            authenticated = falsesetListeners();
        }
    isInitialized = true;
   return authenticated;
    }

    @Override}

    publicprivate Rolesvoid getRolessetListeners() {
        Roles roles = new Roles();addComponentInstantiationListener(new SpringComponentInjector(this, context));
    }

    @Override
    public    getRolesIfSignedIn(roles);Class<?> getHomePage() {
        return rolesHomePage.class;
    }

    privatepublic void getRolesIfSignedInsetApplicationContext(RolesApplicationContext rolescontext) {
throws        if (isSignedIn()) BeansException {
        this.context = context;
  Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); }

    @Override
    protected Class<? extends WebPage> addRolesFromAuthenticationgetSignInPageClass(roles, authentication);) {
        }
    }

    private void addRolesFromAuthentication(Roles roles, Authentication authentication) {return LoginPage.class;
    }

    @Override
    forprotected (GrantedAuthorityClass<? authorityextends :AuthenticatedWebSession> authentication.getAuthoritiesgetWebSessionClass()) {
        return    roles.add(authority.getAuthority())MyAuthenticatedWebSession.class;
        }
    }

}

Spring 3 Application

Code Block
titleMyWebApplicationMyWebApplicationSpring3.java
public class MyWebApplicationMyWebApplicationSpring3 extends AuthenticatedWebApplication implements ApplicationContextAware {
    private ApplicationContext context;

    boolean isInitialized = false;

    @Override
    protected void init() {
        if (!isInitialized) {
            super.init();
            setListeners();
            isInitialized = true;
        }
    }

    private void setListeners() {
        addComponentInstantiationListener(new SpringComponentInjector(this, context));
    }

    @Override
    public Class<?> getHomePage() {
        return HomePage.class;
    }

    public void setApplicationContext(ApplicationContext context) throws BeansException {
        this.context = context;
    }

    @Override
    protected Class<? extends WebPage> getSignInPageClass() {
        return LoginPage.class;
    }

    @Override
    protected Class<? extends AuthenticatedWebSession> getWebSessionClass() {
        return MyAuthenticatedWebSession.class;
    }
}

...