/*
* Copyright 2002-2013 the original author or authors.
*
* 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 org.springframework.security.config.annotation.web.configurers;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.authority.mapping.SimpleMappableAttributesRetriever;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesUserDetailsService;
import org.springframework.security.web.authentication.preauth.j2ee.J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter;
/**
* Adds support for J2EE pre authentication.
*
* <h2>Security Filters</h2>
*
* The following Filters are populated
*
* <ul>
* <li>
* {@link J2eePreAuthenticatedProcessingFilter}</li>
* </ul>
*
* <h2>Shared Objects Created</h2>
*
* <ul>
* <li>
* {@link AuthenticationEntryPoint}
* is populated with an {@link Http403ForbiddenEntryPoint}</li>
* <li>A {@link PreAuthenticatedAuthenticationProvider} is populated into
* {@link HttpSecurity#authenticationProvider(org.springframework.security.authentication.AuthenticationProvider)}
* </li>
* </ul>
*
* <h2>Shared Objects Used</h2>
*
* The following shared objects are used:
*
* <ul>
* <li>{@link HttpSecurity#getAuthenticationManager()}</li>
* </ul>
*
* @author Rob Winch
* @since 3.2
*/
public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<H> {
private J2eePreAuthenticatedProcessingFilter j2eePreAuthenticatedProcessingFilter;
private AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> authenticationUserDetailsService;
private Set<String> mappableRoles = new HashSet<String>();
/**
* Creates a new instance
* @see HttpSecurity#jee()
*/
public JeeConfigurer() {
}
/**
* Specifies roles to use map from the {@link HttpServletRequest} to the
* {@link UserDetails}. If {@link HttpServletRequest#isUserInRole(String)}
* returns true, the role is added to the {@link UserDetails}. This method
* is the equivalent of invoking {@link #mappableAuthorities(Set)}. Multiple
* invocations of {@link #mappableAuthorities(String...)} will override previous
* invocations.
*
* <p>
* There are no default roles that are mapped.
* </p>
*
* @param mappableRoles
* the roles to attempt to map to the {@link UserDetails} (i.e.
* "ROLE_USER", "ROLE_ADMIN", etc).
* @return the {@link JeeConfigurer} for further customizations
* @see SimpleMappableAttributesRetriever
* @see #mappableRoles(String...)
*/
public JeeConfigurer<H> mappableAuthorities(String... mappableRoles) {
this.mappableRoles.clear();
for(String role : mappableRoles) {
this.mappableRoles.add(role);
}
return this;
}
/**
* Specifies roles to use map from the {@link HttpServletRequest} to the
* {@link UserDetails} and automatically prefixes it with "ROLE_". If
* {@link HttpServletRequest#isUserInRole(String)} returns true, the role is
* added to the {@link UserDetails}. This method is the equivalent of
* invoking {@link #mappableAuthorities(Set)}. Multiple invocations of
* {@link #mappableRoles(String...)} will override previous invocations.
*
* <p>
* There are no default roles that are mapped.
* </p>
*
* @param mappableRoles
* the roles to attempt to map to the {@link UserDetails} (i.e.
* "USER", "ADMIN", etc).
* @return the {@link JeeConfigurer} for further customizations
* @see SimpleMappableAttributesRetriever
* @see #mappableAuthorities(String...)
*/
public JeeConfigurer<H> mappableRoles(String... mappableRoles) {
this.mappableRoles.clear();
for(String role : mappableRoles) {
this.mappableRoles.add("ROLE_" + role);
}
return this;
}
/**
* Specifies roles to use map from the {@link HttpServletRequest} to the
* {@link UserDetails}. If {@link HttpServletRequest#isUserInRole(String)}
* returns true, the role is added to the {@link UserDetails}. This is the
* equivalent of {@link #mappableRoles(String...)}. Multiple invocations of
* {@link #mappableAuthorities(Set)} will override previous invocations.
*
* <p>
* There are no default roles that are mapped.
* </p>
*
* @param mappableRoles
* the roles to attempt to map to the {@link UserDetails}.
* @return the {@link JeeConfigurer} for further customizations
* @see SimpleMappableAttributesRetriever
*/
public JeeConfigurer<H> mappableAuthorities(Set<String> mappableRoles) {
this.mappableRoles = mappableRoles;
return this;
}
/**
* Specifies the {@link AuthenticationUserDetailsService} that is used with
* the {@link PreAuthenticatedAuthenticationProvider}. The default is a
* {@link PreAuthenticatedGrantedAuthoritiesUserDetailsService}.
*
* @param authenticatedUserDetailsService the {@link AuthenticationUserDetailsService} to use.
* @return the {@link JeeConfigurer} for further configuration
*/
public JeeConfigurer<H> authenticatedUserDetailsService(
AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> authenticatedUserDetailsService) {
this.authenticationUserDetailsService = authenticatedUserDetailsService;
return this;
}
/**
* Allows specifying the {@link J2eePreAuthenticatedProcessingFilter} to
* use. If {@link J2eePreAuthenticatedProcessingFilter} is provided, all of its attributes must also be
* configured manually (i.e. all attributes populated in the {@link JeeConfigurer} are not used).
*
* @param j2eePreAuthenticatedProcessingFilter the {@link J2eePreAuthenticatedProcessingFilter} to use.
* @return the {@link JeeConfigurer} for further configuration
*/
public JeeConfigurer<H> j2eePreAuthenticatedProcessingFilter(
J2eePreAuthenticatedProcessingFilter j2eePreAuthenticatedProcessingFilter) {
this.j2eePreAuthenticatedProcessingFilter = j2eePreAuthenticatedProcessingFilter;
return this;
}
/**
* Populates a {@link PreAuthenticatedAuthenticationProvider} into
* {@link HttpSecurity#authenticationProvider(org.springframework.security.authentication.AuthenticationProvider)}
* and a {@link Http403ForbiddenEntryPoint} into
* {@link HttpSecurity#authenticationEntryPoint(org.springframework.security.web.AuthenticationEntryPoint)}
*
* @see org.springframework.security.config.annotation.SecurityConfigurerAdapter#init(org.springframework.security.config.annotation.SecurityBuilder)
*/
@Override
public void init(H http) throws Exception {
PreAuthenticatedAuthenticationProvider authenticationProvider = new PreAuthenticatedAuthenticationProvider();
authenticationProvider.setPreAuthenticatedUserDetailsService(getUserDetailsService());
authenticationProvider = postProcess(authenticationProvider);
http
.authenticationProvider(authenticationProvider)
.setSharedObject(AuthenticationEntryPoint.class,new Http403ForbiddenEntryPoint());
}
@Override
public void configure(H http) throws Exception {
J2eePreAuthenticatedProcessingFilter filter = getFilter(http
.getAuthenticationManager());
http.addFilter(filter);
}
/**
* Gets the {@link J2eePreAuthenticatedProcessingFilter} or creates a default instance using the properties provided.
* @param authenticationManager the {@link AuthenticationManager} to use.
* @return the {@link J2eePreAuthenticatedProcessingFilter} to use.
*/
private J2eePreAuthenticatedProcessingFilter getFilter(
AuthenticationManager authenticationManager) {
if (j2eePreAuthenticatedProcessingFilter == null) {
j2eePreAuthenticatedProcessingFilter = new J2eePreAuthenticatedProcessingFilter();
j2eePreAuthenticatedProcessingFilter
.setAuthenticationManager(authenticationManager);
j2eePreAuthenticatedProcessingFilter
.setAuthenticationDetailsSource(createWebAuthenticationDetailsSource());
j2eePreAuthenticatedProcessingFilter = postProcess(j2eePreAuthenticatedProcessingFilter);
}
return j2eePreAuthenticatedProcessingFilter;
}
/**
* Gets the {@link AuthenticationUserDetailsService} that was specified or
* defaults to {@link PreAuthenticatedGrantedAuthoritiesUserDetailsService}.
*
* @return the {@link AuthenticationUserDetailsService} to use
*/
private AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> getUserDetailsService() {
return authenticationUserDetailsService == null ? new PreAuthenticatedGrantedAuthoritiesUserDetailsService()
: authenticationUserDetailsService;
}
/**
* Creates the
* {@link J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource} to set on
* the {@link J2eePreAuthenticatedProcessingFilter}. It is populated with a
* {@link SimpleMappableAttributesRetriever}.
*
* @return the
* {@link J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource}
* to use.
*/
private J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource createWebAuthenticationDetailsSource() {
J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource detailsSource = new J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource();
SimpleMappableAttributesRetriever rolesRetriever = new SimpleMappableAttributesRetriever();
rolesRetriever.setMappableAttributes(mappableRoles);
detailsSource.setMappableRolesRetriever(rolesRetriever);
detailsSource = postProcess(detailsSource);
return detailsSource;
}
}