After upgrading some dependencies in our maven project to make the project run with jdk11 containers, I had to update from SpringSecurity 4.0.x to 4.2.x. So I wanted to give it a shot and convert the messy XML to a proper Java-config.
the 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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd" default-autowire="byName">
<!-- Spring Security Settings -->
<security:global-method-security pre-post-annotations="enabled"></security:global-method-security>
<security:http-firewall ref="defaultHttpFirewall"/>
<security:http pattern="/api/**" security="none" />
<security:http pattern="/prometheus/**" security="none" />
<security:http entry-point-ref="restEntryPoint" pattern="/login*">
<security:intercept-url pattern="/login*"/>
<security:custom-filter ref="managerRequestRedirectFilter" before="BASIC_AUTH_FILTER" />
<security:csrf disabled="true"/>
</security:http>
<security:http entry-point-ref="restEntryPoint" pattern="/login/sso*">
<security:intercept-url pattern="/login/sso*"/>
<security:custom-filter ref="managerRequestRedirectFilter" before="BASIC_AUTH_FILTER" />
<security:csrf disabled="true"/>
</security:http>
<security:http pattern="/authenticate" security="none" />
<security:http pattern="/resources/bootstrap/**" security="none" />
<security:http pattern="/resources/css/**" security="none" />
<security:http pattern="/resources/js/**" security="none" />
<security:http pattern="/WEB-INF/views/login.jsp*" security="none" />
<security:http pattern="/databaseStatus" security="none" />
<security:http pattern="/module/**" security="none" />
<security:http pattern="/myarea/**" security="none" />
<security:http pattern="/ajax/**" security="none" />
<security:http pattern="/logout/sso" security="none" />
<security:http pattern="/download/**" security="none" />
<bean id="managerRequestRedirectFilter" class="com.pany.managertemplate.authentication.service.ManagerRequestRedirectFilter"/>
<!-- Spring Security Kerberos Settings -->
<bean id="authenticationResultFilter" class="com.pany.managertemplate.authentication.service.ManagerAuthenticationResultFilter"/>
<!-- rest -->
<bean id="restAuthenticationProcessingFilter" class=" com.pany.managertemplate.authentication.service.RestAuthenticationProcessingFilter" />
<bean id="restEntryPoint" class="com.pany.managertemplate.authentication.service.RestAuthenticationEntryPoint" />
<security:http entry-point-ref="restEntryPoint" pattern="/rest/**">
<security:intercept-url pattern="/rest/**" access="hasRole('ROLE_USER')" />
<security:custom-filter ref="restAuthenticationProcessingFilter" position="BASIC_AUTH_FILTER" />
<security:custom-filter ref="authenticationResultFilter" after="BASIC_AUTH_FILTER" />
<security:csrf disabled="true"/>
</security:http>
<security:http entry-point-ref="restEntryPoint" pattern="/hooks/**">
<security:intercept-url pattern="/hooks/**" access="hasRole('ROLE_USER')" />
<security:custom-filter ref="restAuthenticationProcessingFilter" position="BASIC_AUTH_FILTER" />
<security:custom-filter ref="authenticationResultFilter" after="BASIC_AUTH_FILTER" />
<security:csrf disabled="true"/>
</security:http>
<security:http entry-point-ref="restEntryPoint" pattern="/get/**">
<security:intercept-url pattern="/get/**" access="hasRole('ROLE_USER')" />
<security:custom-filter ref="restAuthenticationProcessingFilter" position="BASIC_AUTH_FILTER" />
<security:custom-filter ref="authenticationResultFilter" after="BASIC_AUTH_FILTER" />
<security:csrf disabled="true"/>
</security:http>
<security:http entry-point-ref="restEntryPoint" pattern="/hook/**">
<security:intercept-url pattern="/hook/**" access="hasRole('ROLE_USER')" />
<security:custom-filter ref="restAuthenticationProcessingFilter" position="BASIC_AUTH_FILTER" />
<security:custom-filter ref="authenticationResultFilter" after="BASIC_AUTH_FILTER" />
<security:csrf disabled="true"/>
</security:http>
<security:http entry-point-ref="restEntryPoint" pattern="/hookhistories/**">
<security:intercept-url pattern="/hookhistories/**" access="hasRole('ROLE_USER')" />
<security:custom-filter ref="restAuthenticationProcessingFilter" position="BASIC_AUTH_FILTER" />
<security:custom-filter ref="authenticationResultFilter" after="BASIC_AUTH_FILTER" />
<security:csrf disabled="true"/>
</security:http>
<security:http entry-point-ref="restEntryPoint" pattern="/hookcalls/**">
<security:intercept-url pattern="/hookcalls/**" access="hasRole('ROLE_USER')" />
<security:custom-filter ref="restAuthenticationProcessingFilter" position="BASIC_AUTH_FILTER" />
<security:custom-filter ref="authenticationResultFilter" after="BASIC_AUTH_FILTER" />
<security:csrf disabled="true"/>
</security:http>
<security:http entry-point-ref="restEntryPoint" pattern="/hookversions/**">
<security:intercept-url pattern="/hookversions/**" access="hasRole('ROLE_USER')" />
<security:custom-filter ref="restAuthenticationProcessingFilter" position="BASIC_AUTH_FILTER" />
<security:custom-filter ref="authenticationResultFilter" after="BASIC_AUTH_FILTER" />
<security:csrf disabled="true"/>
</security:http>
<!-- -->
<bean id="webexpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler" />
<bean id="accessDeniedHandler" class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
<property name="errorPage" value="/login"/>
</bean>
<security:http entry-point-ref="spnegoEntryPoint">
<security:intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
<security:custom-filter ref="managerRequestRedirectFilter" before="BASIC_AUTH_FILTER" />
<security:custom-filter ref="spnegoAuthenticationProcessingFilter" position="BASIC_AUTH_FILTER" />
<security:custom-filter ref="authenticationResultFilter" after="BASIC_AUTH_FILTER" />
<security:session-management session-fixation-protection="newSession">
<security:concurrency-control max-sessions="1" expired-url="/login"/>
</security:session-management>
<security:csrf disabled="true"/>
</security:http>
<bean id="spnegoEntryPoint" class="com.pany.managertemplate.authentication.service.ManagerAuthenticationEntryPoint" />
<bean id="simpleUrlAuthenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="useForward" value="true"/>
<property name="defaultFailureUrl" value="/login"/>
</bean>
<bean id="authenticationSuccessHandler" class="com.pany.managertemplate.authentication.service.ManagerAuthenticationSuccessHandler" />
<bean id="spnegoAuthenticationProcessingFilter" class="com.pany.managertemplate.authentication.service.ManagerSpnegoAuthenticationProcessingFilter">
<property name="authenticationManager" ref="authenticationManager" />
<property name="failureHandler" ref="simpleUrlAuthenticationFailureHandler"/>
<property name="successHandler" ref="authenticationSuccessHandler"/>
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="kerberosServiceAuthenticationProvider" />
<security:authentication-provider ref="kerberosAuthenticationProvider"/>
</security:authentication-manager>
<bean id="kerberosAuthenticationProvider"
class="org.springframework.security.kerberos.authentication.KerberosAuthenticationProvider">
<property name="kerberosClient">
<bean class="org.springframework.security.kerberos.authentication.sun.SunJaasKerberosClient">
<property name="debug" value="false"/>
</bean>
</property>
<property name="userDetailsService" ref="kerberosUserDetailsService"/>
</bean>
<bean id="kerberosServiceAuthenticationProvider" class="org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider">
<property name="ticketValidator">
<bean class="org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator">
<property name="servicePrincipal"
value="HTTP/an.URL"/>
<property name="keyTabLocation"
value="file:/etc/krb5.keytab"/>
<property name="debug" value="false" />
</bean>
</property>
<property name="userDetailsService" ref="kerberosUserDetailsService" />
</bean>
<bean class="org.springframework.security.kerberos.authentication.sun.GlobalSunJaasKerberosConfig">
<property name="debug" value="false" />
<property name="krbConfLocation" value="/etc/krb5.conf"/>
</bean>
<bean id="kerberosUserDetailsService" class="com.pany.managertemplate.authentication.service.KerberosUserDetailsService"/>
</beans>
and the try of a config I used:
package com.pany.managertemplate.configuration.service;
import java.net.MalformedURLException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.kerberos.authentication.KerberosAuthenticationProvider;
import org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider;
import org.springframework.security.kerberos.authentication.sun.GlobalSunJaasKerberosConfig;
import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosClient;
import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator;
import org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.firewall.DefaultHttpFirewall;
import org.springframework.security.web.firewall.HttpFirewall;
import com.pany.managertemplate.authentication.service.KerberosUserDetailsService;
import com.pany.managertemplate.authentication.service.ManagerAuthenticationEntryPoint;
import com.pany.managertemplate.authentication.service.ManagerAuthenticationResultFilter;
import com.pany.managertemplate.authentication.service.ManagerAuthenticationSuccessHandler;
import com.pany.managertemplate.authentication.service.ManagerRequestRedirectFilter;
import com.pany.managertemplate.authentication.service.ManagerSpnegoAuthenticationProcessingFilter;
import com.pany.managertemplate.authentication.service.RestAuthenticationEntryPoint;
import com.pany.managertemplate.authentication.service.RestAuthenticationProcessingFilter;
#Configuration
#Order(1)
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter
{
#Configuration
#Order(3)
public static class GlobalSecurity extends WebSecurityConfigurerAdapter
{
#Autowired
#Qualifier("authenticationResultFilter")
private ManagerAuthenticationResultFilter authenticationResultFilter;
#Autowired
private KerberosAuthenticationProvider kerberosAuthenticationProvider;
#Autowired
private KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider;
#Autowired
private ManagerRequestRedirectFilter managerRequestRedirectFilter;
#Autowired
#Qualifier("restEntryPoint")
private RestAuthenticationEntryPoint restEntryPoint;
#Autowired
private SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter;
#Autowired
#Qualifier("spnegoEntryPoint")
private ManagerAuthenticationEntryPoint spnegoEntryPoint;
#Bean(BeanIds.AUTHENTICATION_MANAGER)
#Override
public AuthenticationManager authenticationManagerBean() throws Exception
{
return super.authenticationManagerBean();
}
#Override
protected void configure(final AuthenticationManagerBuilder authManagerBuilder) throws Exception
{
authManagerBuilder.authenticationProvider(this.kerberosServiceAuthenticationProvider);
authManagerBuilder.authenticationProvider(this.kerberosAuthenticationProvider);
}
#Override
protected void configure(final HttpSecurity http) throws Exception
{
http.csrf().disable();
http.authorizeRequests().antMatchers(HttpMethod.GET, "/health").permitAll();
http.authorizeRequests().antMatchers("/authenticate").permitAll();
http.authorizeRequests().antMatchers("/resources/bootstrap/**").permitAll();
http.authorizeRequests().antMatchers("/resources/css/**").permitAll();
http.authorizeRequests().antMatchers("/resources/js/**").permitAll();
http.authorizeRequests().antMatchers("/WEB-INF/views/login.jsp*").permitAll();
http.authorizeRequests().antMatchers("/databaseStatus").permitAll();
http.authorizeRequests().antMatchers("/module/**").permitAll();
http.authorizeRequests().antMatchers("/myarea/**").permitAll();
http.authorizeRequests().antMatchers("/ajax/**").permitAll();
http.authorizeRequests().antMatchers("/logout/sso").permitAll();
http.authorizeRequests().antMatchers("/download/**").permitAll();
http.authorizeRequests().antMatchers("/api/**").permitAll();
http.authorizeRequests().antMatchers("/prometheus/**").permitAll();
http.authorizeRequests().antMatchers("/**").hasRole("USER");
http.exceptionHandling().authenticationEntryPoint(this.spnegoEntryPoint);
http.addFilterBefore(this.managerRequestRedirectFilter, BasicAuthenticationFilter.class);
http.addFilterAt(this.spnegoAuthenticationProcessingFilter, BasicAuthenticationFilter.class);
http.addFilterAfter(this.managerRequestRedirectFilter, BasicAuthenticationFilter.class);
}
}
#Configuration
#Order(1)
public static class LoginSecurity extends WebSecurityConfigurerAdapter
{
#Autowired
private KerberosAuthenticationProvider kerberosAuthenticationProvider;
#Autowired
private KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider;
#Autowired
private ManagerRequestRedirectFilter managerRequestRedirectFilter;
#Autowired
#Qualifier("restEntryPoint")
private RestAuthenticationEntryPoint restEntryPoint;
#Override
protected void configure(final AuthenticationManagerBuilder authManagerBuilder) throws Exception
{
authManagerBuilder.authenticationProvider(this.kerberosServiceAuthenticationProvider);
authManagerBuilder.authenticationProvider(this.kerberosAuthenticationProvider);
}
#Override
protected void configure(final HttpSecurity http) throws Exception
{
http.csrf().disable();
http.antMatcher("/login*").antMatcher("/login/sso*");
http.authorizeRequests().anyRequest().permitAll();
http.exceptionHandling().authenticationEntryPoint(this.restEntryPoint);
http.addFilterBefore(this.managerRequestRedirectFilter, BasicAuthenticationFilter.class);
http.sessionManagement().sessionFixation().newSession().maximumSessions(1).expiredUrl("/login");
http.authorizeRequests().anyRequest().authenticated();
http.formLogin().loginPage("/login");
}
}
#Configuration
#Order(2)
public static class RestSecurity extends WebSecurityConfigurerAdapter
{
#Autowired
#Qualifier("authenticationResultFilter")
private ManagerAuthenticationResultFilter authenticationResultFilter;
#Autowired
private KerberosAuthenticationProvider kerberosAuthenticationProvider;
#Autowired
private KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider;
#Autowired
private RestAuthenticationProcessingFilter restAuthenticationProcessingFilter;
#Autowired
#Qualifier("restEntryPoint")
private RestAuthenticationEntryPoint restEntryPoint;
#Override
protected void configure(final AuthenticationManagerBuilder authManagerBuilder) throws Exception
{
authManagerBuilder.authenticationProvider(this.kerberosServiceAuthenticationProvider);
authManagerBuilder.authenticationProvider(this.kerberosAuthenticationProvider);
}
#Override
protected void configure(final HttpSecurity http) throws Exception
{
http.csrf().disable();
http.antMatcher("/rest/**").antMatcher("/hooks/**").antMatcher("/get/**").antMatcher("/hook/**").antMatcher("/hookhistories/**")
.antMatcher("/hookcalls/**").antMatcher("/hookversions/**");
http.authorizeRequests().anyRequest().permitAll();
http.exceptionHandling().authenticationEntryPoint(this.restEntryPoint);
http.addFilterAt(this.restAuthenticationProcessingFilter, BasicAuthenticationFilter.class);
http.addFilterAfter(this.authenticationResultFilter, BasicAuthenticationFilter.class);
}
}
#Autowired
#Qualifier("authenticationResultFilter")
private ManagerAuthenticationResultFilter authenticationResultFilter;
#Autowired
#Qualifier("restEntryPoint")
private RestAuthenticationEntryPoint restEntryPoint;
#Autowired
#Qualifier("spnegoEntryPoint")
private ManagerAuthenticationEntryPoint spnegoEntryPoint;
#Bean
public AccessDeniedHandlerImpl accessDeniedHandler()
{
AccessDeniedHandlerImpl accessDeniedHandlerImpl = new AccessDeniedHandlerImpl();
accessDeniedHandlerImpl.setErrorPage("/login");
return accessDeniedHandlerImpl;
}
#Override
public void configure(final WebSecurity web) throws Exception
{
// though StrictHttpFirewall is advised
super.configure(web);
web.httpFirewall(this.defaultHttpFirewall());
}
#Bean
public HttpFirewall defaultHttpFirewall()
{
DefaultHttpFirewall firewall = new DefaultHttpFirewall();
firewall.setAllowUrlEncodedSlash(true);
return firewall;
}
#Bean
public GlobalSunJaasKerberosConfig globalSunJaasKerberosConfig()
{
GlobalSunJaasKerberosConfig globalSunJaasKerberosConfig = new GlobalSunJaasKerberosConfig();
globalSunJaasKerberosConfig.setDebug(false);
globalSunJaasKerberosConfig.setKrbConfLocation("/etc/krb5.conf");
return globalSunJaasKerberosConfig;
}
#Bean("kerberosAuthenticationProvider")
public KerberosAuthenticationProvider kerberosAuthenticationProvider(#Qualifier("kerberosClient") final SunJaasKerberosClient kerberosClient,
final KerberosUserDetailsService kerberosUserDetailsService)
{
KerberosAuthenticationProvider kerberosAuthenticationProvider = new KerberosAuthenticationProvider();
kerberosAuthenticationProvider.setKerberosClient(kerberosClient);
kerberosAuthenticationProvider.setUserDetailsService(kerberosUserDetailsService);
return kerberosAuthenticationProvider;
}
#Bean("kerberosServiceAuthenticationProvider")
public KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider(final KerberosUserDetailsService kerberosUserDetailsService,
#Qualifier("ticketValidator") final SunJaasKerberosTicketValidator ticketValidator)
{
KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider = new KerberosServiceAuthenticationProvider();
kerberosServiceAuthenticationProvider.setUserDetailsService(kerberosUserDetailsService);
kerberosServiceAuthenticationProvider.setTicketValidator(ticketValidator);
return kerberosServiceAuthenticationProvider;
}
#Bean
public KerberosUserDetailsService kerberosUserDetailsService()
{
return new KerberosUserDetailsService();
}
#Bean("spnegoEntryPoint")
public ManagerAuthenticationEntryPoint managerAuthenticationEntryPoint()
{
return new ManagerAuthenticationEntryPoint();
}
#Bean("authenticationResultFilter")
public ManagerAuthenticationResultFilter managerAuthenticationResultFilter()
{
return new ManagerAuthenticationResultFilter();
}
#Bean("authenticationSuccessHandler")
public ManagerAuthenticationSuccessHandler managerAuthenticationSuccessHandler()
{
return new ManagerAuthenticationSuccessHandler();
}
#Bean
public ManagerRequestRedirectFilter managerRequestRedirectFilter()
{
return new ManagerRequestRedirectFilter();
}
#Bean("spnegoAuthenticationProcessingFilter")
public ManagerSpnegoAuthenticationProcessingFilter managerSpnegoAuthenticationProcessingFilter(final AuthenticationManager authenticationManager,
final SimpleUrlAuthenticationFailureHandler simpleUrlAuthenticationFailureHandler,
#Qualifier("authenticationSuccessHandler") final AuthenticationSuccessHandler authenticationSuccessHandler)
{
ManagerSpnegoAuthenticationProcessingFilter managerSpnegoAuthenticationProcessingFilter = new ManagerSpnegoAuthenticationProcessingFilter();
managerSpnegoAuthenticationProcessingFilter.setAuthenticationManager(authenticationManager);
managerSpnegoAuthenticationProcessingFilter.setFailureHandler(simpleUrlAuthenticationFailureHandler);
managerSpnegoAuthenticationProcessingFilter.setSuccessHandler(authenticationSuccessHandler);
return managerSpnegoAuthenticationProcessingFilter;
}
#Bean("restEntryPoint")
public RestAuthenticationEntryPoint restAuthenticationEntryPoint()
{
return new RestAuthenticationEntryPoint();
}
#Bean
public RestAuthenticationProcessingFilter restAuthenticationProcessingFilter()
{
return new RestAuthenticationProcessingFilter();
}
#Bean("simpleUrlAuthenticationFailureHandler")
public SimpleUrlAuthenticationFailureHandler simpleUrlAuthenticationFailureHandler()
{
SimpleUrlAuthenticationFailureHandler simpleUrlAuthenticationFailureHandler = new SimpleUrlAuthenticationFailureHandler();
simpleUrlAuthenticationFailureHandler.setUseForward(true);
simpleUrlAuthenticationFailureHandler.setDefaultFailureUrl("/login");
return simpleUrlAuthenticationFailureHandler;
}
#Bean
public SunJaasKerberosClient sunJaasKerberosClient()
{
SunJaasKerberosClient sunJaasKerberosClient = new SunJaasKerberosClient();
sunJaasKerberosClient.setDebug(false);
return sunJaasKerberosClient;
}
#Bean("ticketValidator")
public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() throws MalformedURLException
{
SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator = new SunJaasKerberosTicketValidator();
sunJaasKerberosTicketValidator.setServicePrincipal("HTTP/an.URL");
Resource keyTabFile = new UrlResource("file:/etc/krb5.keytab");
sunJaasKerberosTicketValidator.setKeyTabLocation(keyTabFile);
sunJaasKerberosTicketValidator.setDebug(false);
return sunJaasKerberosTicketValidator;
}
}
Login via /login works fine, permissions working inside the applications webinterface.
The problem I encountered is the part for the server-to-server communication via REST.
Sending the proper credentials like used to now just returns the login page instead of the requested resource - this is the point where I am stuck.
I feel like, the config is too complex and confusing at some points because of several entrypoints. but that was what I read in the offical documentation. Or is there an easier way and I am just thinking too complex? In short Java-Config behaves not like the Java-Config, and I can't see why so far.
Related
I'm using Spring Boot MVC last version (5.3) e Spring security (5.5) with LDAP users
I'm trying to change from this xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-5.4.xsd">
<security:http auto-config="true" disable-url-rewriting="true"
use-expressions="true">
<security:form-login login-page="/signin"
authentication-failure-url="/signinAjax?error=1" authentication-details-source-ref="customWebAuthenticationDetailsSource" authentication-success-forward-url="/logged"/>
<security:intercept-url pattern="/" access="permitAll" />
<security:intercept-url pattern="/isAutenticated" access="permitAll" />
<security:intercept-url pattern="/resources/images/favicon.png"
access="permitAll" />
<security:intercept-url pattern="/resources/webfonts/**"
access="permitAll" />
<security:intercept-url pattern="/resources/**"
access="permitAll" />
<security:intercept-url pattern="/signin"
access="permitAll" />
<security:intercept-url pattern="/signinAjax"
access="permitAll" />
<security:intercept-url pattern="/userList"
access="isAuthenticated()" />
<security:intercept-url pattern="/imgages/**"
access="permitAll" />
<security:intercept-url pattern="/**"
access="isAuthenticated()" />
</security:http>
<security:global-method-security
secured-annotations="enabled" />
<security:authentication-manager
erase-credentials="true">
<security:authentication-provider
ref="ldapActiveDirectoryAuthProvider" />
</security:authentication-manager>
<bean id="ldapActiveDirectoryAuthProvider"
class="org.springframework.security.ldap.authentication.ad.CustomActiveDirectoryLdapAuthenticationProvider">
<constructor-arg value="XXXX" />
<constructor-arg value="ldap://XXX:389" />
<property name="convertSubErrorCodesToExceptions" value="true" />
<property name="searchFilter"
value="(&(objectClass=user)(sAMAccountName={0}))" />
<property name="useAuthenticationRequestCredentials" value="true" />
<property name="userDetailsContextMapper" ref="tdrUserDetailsContextMapper" />
</bean>
<bean id="tdrUserDetailsContextMapper"
class="it.xxx.account.CustomUserDetailsContextMapper" />
<bean id="customWebAuthenticationDetailsSource"
class="it.xxx.config.security.CustomWebAuthenticationDetailsSource"/>
</beans>
That function correctly to this Java Based Configuration
#Configuration
#EnableWebSecurity
//#EnableGlobalMethodSecurity(securedEnabled=true)
//#ImportResource(value = "classpath:spring-security-context.xml")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public CustomWebAuthenticationDetailsSource customWebAuthenticationDetailsSource() {
return new CustomWebAuthenticationDetailsSource();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/").permitAll()
.antMatchers("/isAutenticated").permitAll()
.antMatchers("/resources/**").permitAll()
.antMatchers("/signin").permitAll()
.antMatchers("/signinAjax").permitAll()
.antMatchers("/userList").permitAll()
.antMatchers("/images/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/signin")
.authenticationDetailsSource(customWebAuthenticationDetailsSource())
.successForwardUrl("/logged")
.failureForwardUrl("/signinAjax?error=1");
}
#Bean
public CustomActiveDirectoryLdapAuthenticationProvider ldapActiveDirectoryAuthProvider() {
CustomActiveDirectoryLdapAuthenticationProvider provider = new CustomActiveDirectoryLdapAuthenticationProvider("xxx.local","ldap://xxx:389");
provider.setConvertSubErrorCodesToExceptions(true);
provider.setSearchFilter("(&(objectClass=user)(sAMAccountName={0}))");
provider.setUseAuthenticationRequestCredentials(true);
provider.setUserDetailsContextMapper(tdrUserDetailsContextMapper());
return provider;
}
#Bean
public LoggerListener loggerListener() {
return new LoggerListener();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.eraseCredentials(true);
auth.authenticationProvider(ldapActiveDirectoryAuthProvider());
}
#Bean
public CustomUserDetailsContextMapper tdrUserDetailsContextMapper() {
return new CustomUserDetailsContextMapper();
}
}
on compile and runnung of tomcat no error but is impossible to make the loggin and having this error
org.springframework.security.access.event.LoggerListener.onAuthorizationFailureEvent Security authorization failed due to: org.springframework.security.access.AccessDeniedException: Access is denied; authenticated principal: AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=19C02E6245BF011635B6ADC374ED4EA4], Granted Authorities=[ROLE_ANONYMOUS]]; secure object: filter invocation [POST /login]; configuration attributes: [authenticated]
I don't know what is missing.
http.csrf().disable()
.authorizeRequests()
.antMatchers("/index","/images/**","/showSignUpForm","/login","/userSignUp",
"/page/**","/sort/**","/sortWithPage/**","/search/**").permitAll()
.anyRequest().authenticated()
.and().formLogin()
.loginPage("/login").defaultSuccessUrl("/index").permitAll()
.and()
.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login?logout").permitAll();
Try in this way
I found the problems:
Error from xml to java (&)
provider.setSearchFilter("(&(objectClass=user)(sAMAccountName={0}))");
Changed loginPage
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/").permitAll()
.antMatchers("/isAutenticated").permitAll()
.antMatchers("/resources/**").permitAll()
.antMatchers("/signin").permitAll()
.antMatchers("/signinAjax").permitAll()
.antMatchers("/userList").permitAll()
.antMatchers("/images/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.authenticationDetailsSource(customWebAuthenticationDetailsSource())
.successForwardUrl("/logged")
.failureForwardUrl("/signinAjax?error=1");
}
I don't know how function with xml....
I take this error when set authenticationFailureHandler: setAuthenticationFailureHandler(authenticationFailureHandler);
java.lang.IllegalArgumentException: failureHandler cannot be null at
org.springframework.util.Assert.notNull(Assert.java:193) at
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.setAuthenticationFailureHandler(AbstractAuthenticationProcessingFilter.java:448)
fragment web.xml
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
security.xml
<b:beans xmlns="http://www.springframework.org/schema/security"
xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<global-method-security secured-annotations="enabled" pre-post-annotations="enabled" jsr250-annotations="enabled"/>
<http use-expressions="true" entry-point-ref="loginUrlAuthenticationEntryPoint" authentication-manager-ref="authenticationManager" >
<csrf disabled="true"/>
<custom-filter before="FORM_LOGIN_FILTER" ref="authenticationFilter" />
<intercept-url pattern="/public_home/**" access="permitAll"/>
<intercept-url pattern="/js/**" access="permitAll"/>
<intercept-url pattern="/css/**" access="permitAll"/>
<intercept-url pattern="/image/**" access="permitAll"/>
<intercept-url pattern="/resources/**" access="permitAll"/>
<intercept-url pattern="/" access="permitAll"/>
<intercept-url pattern="/**" access="isAuthenticated()"/>
</http>
<authentication-manager/>
<b:bean id="loginUrlAuthenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<b:constructor-arg name="loginFormUrl" value="/public_home"/>
</b:bean>
<b:bean id="authenticationManager" class="n4.security.CustomAuthenticationManager">
</b:bean>
<b:bean id="authenticationFilter" class="n4.security.CustomAuthenticationFilter">
<b:property name="filterProcessesUrl" value="/j_spring_security_check" />
<b:property name="authenticationManager" ref="authenticationManager" />
<b:property name="authenticationSuccessHandler" ref="authenticationSuccessHandler"/>
<b:property name="authenticationFailureHandler" ref="authenticationFailureHandler"/>
</b:bean>
<b:bean name="authenticationSuccessHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<b:property name="defaultTargetUrl" value="/home"></b:property>
<b:property name="alwaysUseDefaultTargetUrl" value="true"></b:property>
<b:property name="useReferer" value="true"></b:property>
</b:bean>
<b:bean name="authenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<b:property name="defaultFailureUrl" value="/public_home/loginfailed"></b:property>
</b:bean>
</b:beans>
CustomAuthenticationFilter
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private SimpleUrlAuthenticationFailureHandler authenticationFailureHandler;
#Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
setAuthenticationManager(authenticationManager);
setAuthenticationFailureHandler(authenticationFailureHandler);
return super.attemptAuthentication(request, response);
}
}
CustomAuthenticationManager
public class CustomAuthenticationManager implements AuthenticationManager{
#Autowired
private UtenteDao utenteDao;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = (String)authentication.getPrincipal();
String password = (String)authentication.getCredentials();
Utente utente = utenteDao.login(username, password);
AuthUserDetail principal = new AuthUserDetail(utente);
return principal.refreshGrantAuthority();
}
}
#Component("MyAuthFilter")
public class MyAuthFilter extends UsernamePasswordAuthenticationFilter {
#Override
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
super.setAuthenticationManager(authenticationManager);
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
...
}}
my spring-security:
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.2.xsd">
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/courses*" access="hasRole('ROLE_USER')" />
<custom-filter before="FORM_LOGIN_FILTER" ref="MyAuthFilter" />
<form-login
login-page="/login"
default-target-url="/courses"
authentication-failure-url="/login?error"
username-parameter="loginField"
password-parameter="passwordField" />
<csrf disabled="true" />
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="ars" password="1234" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
i'm trying to add my custom filter in spring security, but on startup i get an error that authenticationManager must be specified. Can someone have a look?
Try adding an #Autowired to setter of AuthenticationManager
#Autowired
#Qualifier("authenticationManager")
#Override
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
super.setAuthenticationManager(authenticationManager);
}
UPDATE
Add alias="authenticationManager" for your Authentication Manager
<authentication-manager alias="authenticationManager">
<authentication-provider>
<user-service>
<user name="ars" password="1234" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
i'm learning spring framework, and i created a login app according to
http://o7planning.org/web/fe/default/en/document/29799/simple-login-web-application-using-spring-mvc-spring-security-and-spring-jdbc
but when i try to login using the username & password at database, it redirects me to error, here is the xml
spring-security.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">
<http use-expressions="true">
<intercept-url pattern="/" access="isAnonymous()" />
<intercept-url pattern="/welcome" access="isAnonymous()" />
<intercept-url pattern="/login" access="isAnonymous()" />
<intercept-url pattern="/logout" access="isAnonymous()" />
<intercept-url pattern="/userInfo"
access="hasAnyRole('ROLE_USER', 'ROLE_ADMIN')" />
<intercept-url pattern="/admin" access="hasRole('ROLE_ADMIN')" />
<intercept-url pattern="/other/**" access="isAuthenticated()" />
<access-denied-handler error-page="/403" />
<form-login login-page='/login' login-processing-url="/j_spring_security_check"
default-target-url="/userInfo" always-use-default-target="false"
authentication-failure-url="/login?error=true" username-parameter="username"
password-parameter="password" />
<logout logout-url="/logout" logout-success-url="/logoutSuccessful"
delete-cookies="JSESSIONID" invalidate-session="true" />
</http>
<authentication-manager>
<!-- authentication from database -->
<authentication-provider>
<jdbc-user-service data-source-ref="myDataSource"
users-by-username-query="select username,password, enabled from users where username=?"
authorities-by-username-query="select username, role from users where username=?" />
</authentication-provider>
</authentication-manager>
</beans:beans>
data-source-cfg.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">
<bean id="myDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/testdb_o7" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
</beans>
i use mysql, how can i check the app is connected to DB and retrieved the right username & password sucessfully
<beans:bean id="customUserDetailsService" class="com.myclass.dao.SimpleUserDetailsService">
</beans:bean>
<authentication-manager>
<authentication-provider user-service-ref="customUserDetailsService">
<password-encoder hash="md5"> </password-encoder>
<!-- [plaintext, sha, sha-256, md5, md4, {sha}, {ssha}] -->
</authentication-provider>
</authentication-manager>
<beans:bean id="authenticationFailureHandler" class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler">
<beans:property name="exceptionMappings">
<beans:props>
<beans:prop key="org.springframework.security.core.userdetails.UsernameNotFoundException">/login.action?error=1</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
In SimpleUserDetailService for example you will test and check user from DB
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import UserBean;
#Repository
#Service
#Transactional(readOnly=true)
public class SimpleUserDetailsService implements UserDetailsService {
#Autowired
private UserDao userDAO;
private UserBean domainUser;
public UserDetails loadUserByUsername(String login)
throws UsernameNotFoundException {
domainUser = userDAO.getUser(login);
boolean enabled = true;
boolean disabled = false;
boolean accountNonExpired = true;
boolean accountExpired = false;
boolean credentialsNonExpired = true;
boolean credentialsExpired = false;
boolean accountNonLocked = true;
boolean accountLocked = false;
if (null != domainUser){
return new User(
domainUser.getUsername(), //getLogin(),
domainUser.getPassword(),
enabled,
accountNonExpired,
credentialsNonExpired,
accountNonLocked,
getAuthorities(domainUser.getIduser() ) );
} else {
return new User(
"**20**",
"**//**",
disabled,
accountExpired,
credentialsExpired,
accountLocked,
getAuthorities(-20 ) ) ;
}
}
public Collection<? extends GrantedAuthority> getAuthorities(Integer userid) {
List<GrantedAuthority> authList = getGrantedAuthorities(getRoles(userid));
return authList;
}
public List<String> getRoles(Integer userid) {
List<String> roles = new ArrayList<String>();
roles = userDAO.getUserRoles(userid);
return roles;
}
public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (String role : roles) {
authorities.add(new SimpleGrantedAuthority(role));
}
return authorities;
}
}
in userDAO.getUser(login) you select user from table_user where user_name=:login or email = :login
I am working on a Spring-MVC application which uses Spring-Security for authentication and related security purpose. Currently I am having problem querying the sessionRegistry to get a list of currently online users as the getAllPrincipals() method always contains NULL. I tried solutions mentioned in the documentation and many suggestions mentioned on other SO threads. I would really appreciate some help as I am trying various combinations which will work to get list of all Online users.
Here is my security-application-context.xml:
<import resource="servlet-context.xml" />
<!-- Global Security settings -->
<security:global-method-security pre-post-annotations="enabled" />
<security:http pattern="/resources/**" security="none"/>
<security:http create-session="ifRequired" use-expressions="true" auto-config="false" disable-url-rewriting="true">
<security:form-login login-page="/login" login-processing-url="/j_spring_security_check" default-target-url="/canvas/list" always-use-default-target="false" authentication-failure-url="/denied.jsp" />
<security:remember-me key="_spring_security_remember_me" user-service-ref="userDetailsService" token-validity-seconds="1209600" data-source-ref="dataSource"/>
<security:logout delete-cookies="JSESSIONID" invalidate-session="true" logout-url="/j_spring_security_logout"/>
<security:port-mappings>
<security:port-mapping http="80" https="443"/>
</security:port-mappings>
<security:logout logout-url="/logout" logout-success-url="/" success-handler-ref="myLogoutHandler"/>
</security:http>
<bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" />
<beans:bean id="sas" class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy">
<beans:constructor-arg name="sessionRegistry" ref="sessionRegistry" />
<beans:property name="maximumSessions" value="-1" />
</beans:bean>
<beans:bean id="rememberMeAuthenticationProvider" class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
<beans:property name="key" value="_spring_security_remember_me" />
<property name="alwaysRemember" value="true"/>
<beans:property name="tokenRepository" ref="jdbcTokenRepository"/>
<beans:property name="userDetailsService" ref="LoginServiceImpl"/>
</beans:bean>
<beans:bean id="myAuthFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="sessionAuthenticationStrategy" ref="sas"/>
<property name="rememberMeServices" ref="rememberMeAuthenticationProvider"/>
<property name="allowSessionCreation" value="true"/>
<property name="authenticationManager" ref="authenticationManager"/>
</beans:bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="LoginServiceImpl">
<security:password-encoder ref="encoder"/>
</security:authentication-provider>
</security:authentication-manager>
<beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="11" />
</beans:bean>
<beans:bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="LoginServiceImpl"/>
<beans:property name="passwordEncoder" ref="encoder"/>
</beans:bean>
here is where I am trying to get back the list of OnlineUsers :
#Service
#Transactional
public class OnlineUsersServiceImpl implements OnlineUsersService {
#Autowired
#Qualifier("sessionRegistry")
private SessionRegistry sessionRegistry;
#Override
public boolean checkIfUserhasSession(int id) {
Person person = this.personService.getPersonById(id);
String email = person.getUsername();
List<Object> principals = sessionRegistry.getAllPrincipals();
for (Object principal : principals) {
// It never reaches here
System.out.println("We reached here");
if (principal instanceof User) {
String username = ((User) principal).getUsername();
System.out.println("Username is "+username);
if(email.equals(username)){
return true;
}
}
}
return false;
}
Any help would be nice. As I am on this hopeless thing since 3-4 days.
Before injecting session registry you need to define session management part in your security-application-context.xml
In concurrency-control section you should set alias for session registry object
<security:http access-denied-page="/error403.jsp" use-expressions="true" auto-config="false">
<security:session-management session-fixation-protection="migrateSession" session-authentication-error-url="/login.jsp?authFailed=true">
<security:concurrency-control max-sessions="1" error-if-maximum-exceeded="true" expired-url="/login.html" session-registry-alias="sessionRegistry"/>
</security:session-management>
...
</security:http>
For java based configuration alternative to xml configuration
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity http) throws Exception {
// ...
http.sessionManagement().maximumSessions(1).sessionRegistry(sessionRegistry());
}
#Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
#Bean
public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() {
return new ServletListenerRegistrationBean<HttpSessionEventPublisher>(new HttpSessionEventPublisher());
}
}
You need additional configuration in web.xml - listener for login/logout events
<listener>
<listener-class>
org.springframework.security.web.session.HttpSessionEventPublisher
</listener-class>
</listener>