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
2008/3/17, Robin Helgelin <[EMAIL PROTECTED]>:
>
> On Mon, Mar 17, 2008 at 8:40 AM, Olle Hallin <[EMAIL PROTECTED]>
> wrote:
> > It properly catches the CredentialsExpiredException that was thrown by
> the
> > UsernamePasswordAuthenticationToken and tries to publish the event, but
> the
> > ProviderManager.applicationEventPublisher is null.
> >
> > I don't know the inner mechanics of Acegi nor tapestry-ioc well enough
> to
> > inject that dependency myself, so help would be appreciated.
>
>
> Looking at the code it seems there must be an
> ApplicationEventPublished defined. I''m too green in spring for this,
> but I'll look into it.
>
>
> --
>
> regards,
> Robin
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]
>
>
--
Olle Hallin M.Sc.
+46 70 6653071
[EMAIL PROTECTED]
www.hit.se
/*
* 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.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
@Marker(AcegiServices.class)
public static Properties buildAuthenticationExceptionMappings(
@Inject @Value("${acegi.accessDenied.url}") final String accessDeniedUrl) {
Properties exceptionMappings = new Properties();
if (accessDeniedUrl != null && accessDeniedUrl.trim().length() > 0) {
exceptionMappings.put(AccountExpiredException.class.getName(),
accessDeniedUrl);
exceptionMappings.put(CredentialsExpiredException.class.getName(),
accessDeniedUrl);
exceptionMappings.put(LockedException.class.getName(),
accessDeniedUrl);
}
return exceptionMappings;
}
// 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,
@AcegiServices 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]