Hi again,

I've made a new version of the SecurityModule.java that follows the usual
build + contribute pattern in tapestry-ioc.

Sorry for the changed formatting, I hit Ctrl-Shift-F by accident in Eclipse.

Regards,
Olle

2008/3/28, Olle Hallin <[EMAIL PROTECTED]>:
>
> Hi, I found the solution.
>
> It was an empty AuthenticationProcessingFilter.exceptionMappings that
> caused all
> AuthenticationExceptions to be treated equally.
>
> I added a default public static Properties
> buildAuthenticationExceptionMappings() to SecurityModule.java, which maps
> certain AuthenticationExceptions to "${acegi.accessDenied.url}" if it is
> defined, and then sets this mapping in
> buildAuthenticationProcessingFilter().
>
> The user of the tapestry5-acegi module can then override this default
> mapping
> in his own AppModule, e.g., to map CredentialsExpiredException and
> LockedException to different URLs.
>
> I've attached the modified SecurityModule.java, with my changes marked
> with "// patch"
>
> Regards,
> Olle
>
>
/*
 * Copyright 2007 Ivan Dubrov
 * Copyright 2007 Robin Helgelin
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package nu.localhost.tapestry.acegi.services;

import java.util.List;
import java.util.Map;
import java.util.Properties;

import nu.localhost.tapestry.acegi.services.internal.AcegiExceptionTranslationFilter;
import nu.localhost.tapestry.acegi.services.internal.AcegiWorker;
import nu.localhost.tapestry.acegi.services.internal.HttpServletRequestFilterWrapper;
import nu.localhost.tapestry.acegi.services.internal.LogoutServiceImpl;
import nu.localhost.tapestry.acegi.services.internal.RequestFilterWrapper;
import nu.localhost.tapestry.acegi.services.internal.SecurityChecker;
import nu.localhost.tapestry.acegi.services.internal.StaticSecurityChecker;

import org.acegisecurity.AccessDecisionManager;
import org.acegisecurity.AccountExpiredException;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.AuthenticationTrustResolver;
import org.acegisecurity.AuthenticationTrustResolverImpl;
import org.acegisecurity.CredentialsExpiredException;
import org.acegisecurity.LockedException;
import org.acegisecurity.context.HttpSessionContextIntegrationFilter;
import org.acegisecurity.context.SecurityContextImpl;
import org.acegisecurity.providers.AuthenticationProvider;
import org.acegisecurity.providers.ProviderManager;
import org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider;
import org.acegisecurity.providers.anonymous.AnonymousProcessingFilter;
import org.acegisecurity.providers.dao.DaoAuthenticationProvider;
import org.acegisecurity.providers.dao.SaltSource;
import org.acegisecurity.providers.dao.salt.SystemWideSaltSource;
import org.acegisecurity.providers.encoding.PasswordEncoder;
import org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider;
import org.acegisecurity.ui.AccessDeniedHandlerImpl;
import org.acegisecurity.ui.AuthenticationEntryPoint;
import org.acegisecurity.ui.ExceptionTranslationFilter;
import org.acegisecurity.ui.logout.LogoutHandler;
import org.acegisecurity.ui.logout.SecurityContextLogoutHandler;
import org.acegisecurity.ui.rememberme.RememberMeProcessingFilter;
import org.acegisecurity.ui.rememberme.RememberMeServices;
import org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices;
import org.acegisecurity.ui.webapp.AuthenticationProcessingFilter;
import org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.userdetails.memory.UserAttribute;
import org.acegisecurity.userdetails.memory.UserAttributeEditor;
import org.acegisecurity.vote.AccessDecisionVoter;
import org.acegisecurity.vote.AffirmativeBased;
import org.acegisecurity.vote.RoleVoter;
import org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter;
import org.apache.tapestry.ioc.Configuration;
import org.apache.tapestry.ioc.MappedConfiguration;
import org.apache.tapestry.ioc.OrderedConfiguration;
import org.apache.tapestry.ioc.ServiceBinder;
import org.apache.tapestry.ioc.annotations.Inject;
import org.apache.tapestry.ioc.annotations.InjectService;
import org.apache.tapestry.ioc.annotations.Marker;
import org.apache.tapestry.ioc.annotations.Value;
import org.apache.tapestry.services.ComponentClassTransformWorker;
import org.apache.tapestry.services.HttpServletRequestFilter;
import org.apache.tapestry.services.LibraryMapping;
import org.apache.tapestry.services.RequestFilter;
import org.apache.tapestry.services.RequestGlobals;
import org.springframework.context.ApplicationContext;

/**
 * This module is automatically included as part of the Tapestry IoC Registry,
 * 
 * @author Ivan Dubrov
 * @author Robin Helgelin
 */
public class SecurityModule {
    public static void bind(final ServiceBinder binder) {
        binder.bind(LogoutService.class, LogoutServiceImpl.class).withMarker(
            AcegiServices.class);
        binder.bind(AuthenticationTrustResolver.class,
            AuthenticationTrustResolverImpl.class).withMarker(
            AcegiServices.class);
    }

    @Marker(AcegiServices.class)
    public static PasswordEncoder buildPasswordEncoder(@Inject
    @Value("${acegi.password.encoder}")
    final String passwordEncoder) {
        try {
            return (PasswordEncoder) Class.forName(passwordEncoder)
                                          .newInstance();
        } catch (ClassNotFoundException ex) {
            throw new IllegalArgumentException(ex);
        } catch (IllegalAccessException ex) {
            throw new IllegalArgumentException(ex);
        } catch (InstantiationException ex) {
            throw new IllegalArgumentException(ex);
        }
    }

    @Marker(AcegiServices.class)
    public static SaltSource buildSaltSource(@Inject
    @Value("${acegi.password.salt}")
    final String salt) {
        SystemWideSaltSource s = new SystemWideSaltSource();
        s.setSystemWideSalt(salt);
        return s;
    }

    public static void contributeFactoryDefaults(
        final MappedConfiguration<String, String> configuration) {
        configuration.add("acegi.check.url", "/j_acegi_security_check");
        configuration.add("acegi.failure.url", "/loginfailed");
        configuration.add("acegi.target.url", "/");
        configuration.add("acegi.afterlogout.url", "/");
        configuration.add("acegi.accessDenied.url", "");
        configuration.add("acegi.rememberme.key", "REMEMBERMEKEY");
        configuration.add("acegi.loginform.url", "/loginpage");
        configuration.add("acegi.anonymous.key", "acegi_anonymous");
        configuration.add("acegi.anonymous.attribute",
            "anonymous,ROLE_ANONYMOUS");
        configuration.add("acegi.password.encoder",
            "org.acegisecurity.providers.encoding.PlaintextPasswordEncoder");
        configuration.add("acegi.password.salt", "DEADBEEF");
        configuration.add("acegi.password.saltsource",
            "org.acegisecurity.providers.dao.salt.SystemWideSaltSource");
    }

    public static void contributeComponentClassTransformWorker(
        OrderedConfiguration<ComponentClassTransformWorker> configuration,
        SecurityChecker securityChecker) {
        configuration.add("Acegi", new AcegiWorker(securityChecker));
    }

    public static void contributeHttpServletRequestHandler(
        OrderedConfiguration<HttpServletRequestFilter> configuration,
        @InjectService("HttpSessionContextIntegrationFilter")
        HttpServletRequestFilter httpSessionContextIntegrationFilter,
        @InjectService("AuthenticationProcessingFilter")
        HttpServletRequestFilter authenticationProcessingFilter,
        @InjectService("RememberMeProcessingFilter")
        HttpServletRequestFilter rememberMeProcessingFilter,
        @InjectService("SecurityContextHolderAwareRequestFilter")
        HttpServletRequestFilter securityContextHolderAwareRequestFilter,
        @InjectService("AnonymousProcessingFilter")
        HttpServletRequestFilter anonymousProcessingFilter) {

        configuration.add("acegiHttpSessionContextIntegrationFilter",
            httpSessionContextIntegrationFilter, "before:acegi*");
        configuration.add("acegiAuthenticationProcessingFilter",
            authenticationProcessingFilter);
        configuration.add("acegiRememberMeProcessingFilter",
            rememberMeProcessingFilter);
        configuration.add("acegiSecurityContextHolderAwareRequestFilter",
            securityContextHolderAwareRequestFilter,
            "after:acegiRememberMeProcessingFilter");
        configuration.add("acegiAnonymousProcessingFilter",
            anonymousProcessingFilter, "after:acegiRememberMeProcessingFilter",
            "after:acegiAuthenticationProcessingFilter");
    }

    @Marker(AcegiServices.class)
    public static HttpServletRequestFilter buildHttpSessionContextIntegrationFilter()
        throws Exception {
        HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
        filter.setContext(SecurityContextImpl.class);
        filter.setAllowSessionCreation(true);
        filter.setForceEagerSessionCreation(false);
        filter.afterPropertiesSet();
        return new HttpServletRequestFilterWrapper(filter);
    }

    // Start patch
    public static Properties buildAuthenticationExceptionMappings(
        Map<Class, String> contributions) {
        Properties exceptionMappings = new Properties();
        for (Class clazz : contributions.keySet()) {
            exceptionMappings.put(clazz.getName(), contributions.get(clazz));
        }
        return exceptionMappings;
    }

    public static void contributeAuthenticationExceptionMappings(
        MappedConfiguration<Class, String> configuration, @Inject
        @Value("${acegi.accessDenied.url}")
        final String accessDeniedUrl) {
        if (accessDeniedUrl != null && accessDeniedUrl.trim().length() > 0) {
            configuration.add(AccountExpiredException.class, accessDeniedUrl);
            configuration.add(CredentialsExpiredException.class,
                accessDeniedUrl);
            configuration.add(LockedException.class, accessDeniedUrl);
        }
    }

    // End patch

    @Marker(AcegiServices.class)
    public static HttpServletRequestFilter buildAuthenticationProcessingFilter(
        @AcegiServices
        final AuthenticationManager manager, @AcegiServices
        final RememberMeServices rememberMeServices, @Inject
        @Value("${acegi.check.url}")
        final String authUrl, @Inject
        @Value("${acegi.target.url}")
        final String targetUrl, @Inject
        @Value("${acegi.failure.url}")
        final String failureUrl,
        @InjectService("AuthenticationExceptionMappings")
        final Properties exceptionMappings) // patch
        throws Exception {
        AuthenticationProcessingFilter filter = new AuthenticationProcessingFilter();
        filter.setAuthenticationManager(manager);
        filter.setAuthenticationFailureUrl(failureUrl);
        filter.setDefaultTargetUrl(targetUrl);
        filter.setFilterProcessesUrl(authUrl);
        filter.setRememberMeServices(rememberMeServices);
        filter.setExceptionMappings(exceptionMappings); // patch
        filter.afterPropertiesSet();
        return new HttpServletRequestFilterWrapper(filter);
    }

    @Marker(AcegiServices.class)
    public static HttpServletRequestFilter buildRememberMeProcessingFilter(
        @AcegiServices
        final RememberMeServices rememberMe, @AcegiServices
        final AuthenticationManager authManager) throws Exception {
        RememberMeProcessingFilter filter = new RememberMeProcessingFilter();
        filter.setRememberMeServices(rememberMe);
        filter.setAuthenticationManager(authManager);
        filter.afterPropertiesSet();
        return new HttpServletRequestFilterWrapper(filter);
    }

    @Marker(AcegiServices.class)
    public static HttpServletRequestFilter buildSecurityContextHolderAwareRequestFilter() {
        return new HttpServletRequestFilterWrapper(new SecurityContextHolderAwareRequestFilter());
    }

    @Marker(AcegiServices.class)
    public static HttpServletRequestFilter buildAnonymousProcessingFilter(
        @Inject
        @Value("${acegi.anonymous.attribute}")
        final String anonymousAttr, @Inject
        @Value("${acegi.anonymous.key}")
        final String anonymousKey) throws Exception {
        AnonymousProcessingFilter filter = new AnonymousProcessingFilter();
        filter.setKey(anonymousKey);
        UserAttributeEditor attrEditor = new UserAttributeEditor();
        attrEditor.setAsText(anonymousAttr);
        UserAttribute attr = (UserAttribute) attrEditor.getValue();
        filter.setUserAttribute(attr);
        filter.afterPropertiesSet();
        return new HttpServletRequestFilterWrapper(filter);
    }

    @Marker(AcegiServices.class)
    public static RememberMeServices build(
        final UserDetailsService userDetailsService, @Inject
        @Value("${acegi.rememberme.key}")
        final String rememberMeKey) {
        TokenBasedRememberMeServices rememberMe = new TokenBasedRememberMeServices();
        rememberMe.setUserDetailsService(userDetailsService);
        rememberMe.setKey(rememberMeKey);
        return rememberMe;
    }

    @Marker(AcegiServices.class)
    public static LogoutHandler buildRememberMeLogoutHandler(
        final UserDetailsService userDetailsService, @Inject
        @Value("${acegi.rememberme.key}")
        final String rememberMeKey) throws Exception {
        TokenBasedRememberMeServices rememberMe = new TokenBasedRememberMeServices();
        rememberMe.setUserDetailsService(userDetailsService);
        rememberMe.setKey(rememberMeKey);
        rememberMe.afterPropertiesSet();
        return rememberMe;
    }

    public static void contributeLogoutService(
        final OrderedConfiguration<LogoutHandler> cfg,
        @InjectService("RememberMeLogoutHandler")
        final LogoutHandler rememberMeLogoutHandler) {
        cfg.add("securityContextLogoutHandler",
            new SecurityContextLogoutHandler());
        cfg.add("rememberMeLogoutHandler", rememberMeLogoutHandler);
    }

    @Marker(AcegiServices.class)
    public static AuthenticationManager buildProviderManager(
        final List<AuthenticationProvider> providers,
        ApplicationContext applicationContext) // patch
        throws Exception {
        ProviderManager manager = new ProviderManager();
        manager.setProviders(providers);
        manager.setApplicationEventPublisher(applicationContext); // patch
        manager.afterPropertiesSet();
        return manager;
    }

    @Marker(AcegiServices.class)
    public final AuthenticationProvider buildAnonymousAuthenticationProvider(
        @Inject
        @Value("${acegi.anonymous.key}")
        final String anonymousKey) throws Exception {
        AnonymousAuthenticationProvider provider = new AnonymousAuthenticationProvider();
        provider.setKey(anonymousKey);
        provider.afterPropertiesSet();
        return provider;
    }

    @Marker(AcegiServices.class)
    public final AuthenticationProvider buildRememberMeAuthenticationProvider(
        @Inject
        @Value("${acegi.rememberme.key}")
        final String rememberMeKey) throws Exception {
        RememberMeAuthenticationProvider provider = new RememberMeAuthenticationProvider();
        provider.setKey(rememberMeKey);
        provider.afterPropertiesSet();
        return provider;
    }

    @Marker(AcegiServices.class)
    public final AuthenticationProvider buildDaoAuthenticationProvider(
        final UserDetailsService userDetailsService, @AcegiServices
        final PasswordEncoder passwordEncoder, @AcegiServices
        final SaltSource saltSource) throws Exception {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(userDetailsService);
        provider.setPasswordEncoder(passwordEncoder);
        System.out.println(saltSource);
        provider.setSaltSource(saltSource);
        provider.afterPropertiesSet();
        return provider;
    }

    public final void contributeProviderManager(
        final OrderedConfiguration<AuthenticationProvider> configuration,
        @InjectService("AnonymousAuthenticationProvider")
        final AuthenticationProvider anonymousAuthenticationProvider,
        @InjectService("RememberMeAuthenticationProvider")
        final AuthenticationProvider rememberMeAuthenticationProvider) {
        configuration.add("anonymousAuthenticationProvider",
            anonymousAuthenticationProvider);
        configuration.add("rememberMeAuthenticationProvider",
            rememberMeAuthenticationProvider);
    }

    @Marker(AcegiServices.class)
    public final AccessDecisionManager buildAccessDecisionManager(
        final List<AccessDecisionVoter> voters) throws Exception {
        AffirmativeBased manager = new AffirmativeBased();
        manager.setDecisionVoters(voters);
        manager.afterPropertiesSet();
        return manager;
    }

    public final void contributeAccessDecisionManager(
        final OrderedConfiguration<AccessDecisionVoter> configuration) {
        configuration.add("RoleVoter", new RoleVoter());
    }

    @Marker(AcegiServices.class)
    public static SecurityChecker buildSecurityChecker(@AcegiServices
    final AccessDecisionManager accessDecisionManager, @AcegiServices
    final AuthenticationManager authenticationManager) throws Exception {
        StaticSecurityChecker checker = new StaticSecurityChecker();
        checker.setAccessDecisionManager(accessDecisionManager);
        checker.setAuthenticationManager(authenticationManager);
        checker.afterPropertiesSet();
        return checker;
    }

    @Marker(AcegiServices.class)
    public static AuthenticationEntryPoint buildAuthenticationEntryPoint(
        @Inject
        @Value("${acegi.loginform.url}")
        final String loginFormUrl) throws Exception {
        AuthenticationProcessingFilterEntryPoint entryPoint = new AuthenticationProcessingFilterEntryPoint();
        entryPoint.setLoginFormUrl(loginFormUrl);
        entryPoint.afterPropertiesSet();
        return entryPoint;
    }

    @Marker(AcegiServices.class)
    public static RequestFilter buildAcegiExceptionFilter(
        final RequestGlobals globals, final AuthenticationEntryPoint aep,
        @Inject
        @Value("${acegi.accessDenied.url}")
        final String accessDeniedUrl) throws Exception {
        ExceptionTranslationFilter filter = new AcegiExceptionTranslationFilter();
        filter.setAuthenticationEntryPoint(aep);
        if (!accessDeniedUrl.equals("")) {
            AccessDeniedHandlerImpl accessDeniedHandler = new AccessDeniedHandlerImpl();
            accessDeniedHandler.setErrorPage(accessDeniedUrl);
            filter.setAccessDeniedHandler(accessDeniedHandler);
        }
        filter.afterPropertiesSet();
        return new RequestFilterWrapper(globals, filter);
    }

    public static void contributeRequestHandler(
        final OrderedConfiguration<RequestFilter> configuration,
        @InjectService("AcegiExceptionFilter")
        final RequestFilter acegiExceptionFilter) {
        configuration.add("AcegiExceptionFilter", acegiExceptionFilter,
            "after:ErrorFilter");
    }

    // Contribute three aspects of module: presentation, entities and
    // configuration
    public static void contributeComponentClassResolver(
        final Configuration<LibraryMapping> configuration) {
        configuration.add(new LibraryMapping("security",
                                             "nu.localhost.tapestry.acegi"));
    }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to