This is my implementation of WebSecurityConfigurerAdapter:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JWTAuthenticationEntryPoint jwtAuthenticationEntryPoint;
#Autowired
private JWTUserDetailsService jwtUserDetailsService;
#Autowired
private JWTRequestFilter jwtRequestFilter;
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public JWTAuthenticationEntryPoint jwtAuthenticationEntryPoint() {
return new JWTAuthenticationEntryPoint();
}
#Bean
public JWTUserDetailsService jwtUserDetailsService() {
return new JWTUserDetailsService();
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
Implementation omitted
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
implementation omitted
}
}
This is my implementation of User Detail Service:
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
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.Component;
import tidbit.models.Reader;
import tidbit.models.ReaderRepository;
#Component
public class JWTUserDetailsService implements UserDetailsService {
#Autowired private ReaderRepository<Reader> repository;
public JWTUserDetailsService() {
super();
}
#Override
public UserDetails loadUserByUsername(String username) {
Implementation omitted
}
}
This is my implementation of the Request Filter
import io.jsonwebtoken.ExpiredJwtException;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
#Component
public class JWTRequestFilter extends OncePerRequestFilter {
private final JWTUserDetailsService jwtUserDetailsService;
private final JWTTokenUtils jwtTokenUtils;
#Autowired
public JWTRequestFilter(
JWTUserDetailsService jwtUserDetailsService, JWTTokenUtils jwtTokenUtils) {
this.jwtUserDetailsService = jwtUserDetailsService;
this.jwtTokenUtils = jwtTokenUtils;
}
#Override
protected void doFilterInternal(
Implementation omitted
}
}
In the WebSecurityConfig class I get an error for all the fields saying that Spring cannot autowire those fields:
Could not autowire. No beans of 'JWTRequestFilter' found.
I was able to solve this problem for the first two fields by creating those two methods annotated with #Bean.
However, I don't know how solve it for RequestFilter since it contains a constructor with parameters that technically should be already autowired.
In general, I think that I shouldn't have this error in the first place. I have looked at some tutorials online and they were able to autowire those fields without any problems and without creating any #bean method.
EDIT:
Thank you for your help:
Now I get the following error
Parameter 3 of constructor in tidbit.controllers.AuthenticationController required a single bean, but 2 were found:
- JWTUserDetailsService: defined in file [/Users/matteoomenetti/Documents/TidBit/backend/build/classes/java/main/tidbit/config/JWTUserDetailsService.class]
- jwtUserDetailsService: defined by method 'jwtUserDetailsService' in class path resource [tidbit/config/WebSecurityConfig.class]
It looks like I'm creating two beans of jwtUserDetailService. One is already defined in jwtUserDetailService and the other one is defined in WebSecurityConfig with the #bean annotation. However, if I already have a bean in jwtUserDetailService why isn't WebSecurityConfig finding it?
I have noticed that if I try to autowire jwtUserDetailService in any other class (without the bean method that I created) it works perfectly, meaning that the bean is found. For some reason my WebSecurityConfig class doesn't find beans...
SOLUTION
The error that I get is an error only of IntelliJ. If I try to compile through the terminal I don't get any error.
Thank you everybody
I suggest you stop using new keyword to instantiate beans. modify the following methods:
#Bean
public JWTAuthenticationEntryPoint jwtAuthenticationEntryPoint() {
return jwtAuthenticationEntryPoint;
}
#Bean
public JWTUserDetailsService jwtUserDetailsService() {
return jwtUserDetailsService;
}
Also, modify the following class as follows:
#Component
public class JWTRequestFilter extends OncePerRequestFilter {
#Autowired
private final JWTUserDetailsService jwtUserDetailsService;
#Autowired
private final JWTTokenUtils jwtTokenUtils;
public JWTRequestFilter() {
}
#Override
protected void doFilterInternal(
Implementation omitted
}
}
You should not create new #Bean except the for the AuthenticationManager and PasswordEncoder.
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JWTAuthenticationEntryPoint jwtAuthenticationEntryPoint;
#Autowired
private JWTUserDetailsService jwtUserDetailsService;
#Autowired
private JWTRequestFilter jwtRequestFilter;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
//authorizeRequests() order is important
http
.csrf().disable()
.authorizeRequests().antMatchers("/**").authenticated()
.and()
.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint);
}
#Override
#Bean(name = BeanIds.AUTHENTICATION_MANAGER)
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public DaoAuthenticationProvider authenticationProvider(){
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(jwtUserDetailsService);
provider.setPasswordEncoder(encoder());
return provider;
}
#Bean
public PasswordEncoder encoder(){
return new BCryptPasswordEncoder(12);
}
}
Note: you can use the DaoAuthenticationProvider omit it by adding the jwtUserDetailsService in:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
}
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
How can you put the right, so that only the admin can go to the JSP pages using his username and password. Suppose a page (allStudents.jsp) is available only to the admin, for this he must enter his username and password
How can you put the right, so that only the admin can go to the JSP pages using his username and password. Suppose a page (allStudents.jsp) is available only to the admin, for this he must enter his username and password
package adil.java.schoolmaven.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.stereotype.Component;
#Order(1)
#Configuration
#EnableWebSecurity
#Component
public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Autowired
private MyBasicAuthenticationEntryPoint authenticationEntryPoint;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password(passwordEncoder().encode("1234"))
.authorities("ROLE_ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/securityNone").permitAll() //??????
.anyRequest().authenticated()
.and()
.httpBasic()
.authenticationEntryPoint(authenticationEntryPoint);
http.addFilterAfter(new CustomFilter(),
BasicAuthenticationFilter.class);
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
enter image description here
I am Changed code please view this code
#Order(1)
#Configuration
#EnableWebSecurity
#Component
public class СostumWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Autowired
private MyBasicAuthenticationEntryPoint authenticationEntryPoint;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password(passwordEncoder().encode("1234"))
.authorities("ROLE_ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/allStudents").hasRole("ADMIN");
.anyRequest().authenticated()
.and()
.httpBasic()
.authenticationEntryPoint(authenticationEntryPoint);
http.addFilterAfter(new CustomFilter(),
BasicAuthenticationFilter.class);
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Full Page Authorization Example
With expressions enabled for the http element, an URL pattern can be
secured as follows:
#Configuration
#EnableWebSecurity
public class SecSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/allStudents").hasRole("ROLE_ADMIN"); // assuming this is your endpoint/controller for allStudents.jsp page
}
}
Method Level Authorization Example – #PreAuthorize
Security Expressions can be used to secure business functionality at
the method level as well, by using annotations.
The annotations #PreAuthorize and #PostAuthorize (as well as
#PreFilter and #PostFilter) support Spring Expression Language (SpEL)
and provide expression-based access control.
First, in order to use method level security, we need to enable this
in the security configuration using #EnableGlobalMethodSecurity:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
}
Then, we can secure methods using the Spring #PreAuthorize annotation:
#Service
public class FooService {
#PreAuthorize("hasRole('ROLE_ADMIN')")
public List<Foo> findAll() { ... }
...
}
For more in depth explanation for this examples, you can refer to this link
I looking for a way how to test Spring Boot REST API with following setup:
#RestController
class SomeRestController {
#Autowired
private SomeService someService;
#GetMapping("/getSome")
#PreAuthorize("#canGetSome.isValid()")
public SomeObject getSomeObject() {
return someService.getSomeObject();
}
}
_
#Component
public class CanGetSome{
#Autowired
private final LoggedUser loggedUser;
public boolean isValid() {
return loggedUser.getPermissions().isCanGetSome();
}
}
_
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
...
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionFixation().newSession()
.and()
.authorizeRequests())
.anyRequest().authenticated();
}
//custom LoggedUser object which is initzialized on authentication sucessfull
#Bean
#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public LoggedUser loggedUser() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return (LoggedUser) authentication.getPrincipal();
}
...
}
My test case:
#SpringBootTest(
classes = SpringBootApplication,
webEnvironment = RANDOM_PORT)
#ContextConfiguration
class RestSecurityTest extends Specification {
#Autowired
private TestRestTemplate testRestTemplate
#LocalServerPort
private int port
#WithCustomMockUser
def "test testRestTemplare"(){
expect:
def respone = testRestTemplate.getForObject('http://localhost:'+ port+'/getSome', String)
}
_
public class WithCustomMockUserSecurityContextFactory implements WithSecurityContextFactory<WithCustomMockUser> {
#Override
public SecurityContext createSecurityContext(WithCustomMockUser annotation) {
//init securityContext like #WithMockUser but with LoggedUser as principal which return true on loggedUser.getPermissions().isCanGetSome();
}
}
Unfortunately I getting following response in test:
{
"timestamp": 1524759173851,
"status": 403,
"error": "Forbidden",
"message": "Access Denied",
"path": "/getSome"
}
I also debug different spring filters after request and there SecurityContext authentication is null and later is switched to AnonymousAuthenticationToken
I don't know why SecurityContext is a null after request and isn't SecurityContext which is initialized with #WithCustomMockUser annotation. Any ideas how to fix it ?
Spring MVC should be the way to go.
Test class:-
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { TestContext.class, TestWebMvcConfigurerAdapter.class, SecurityConfiguration .class })
#WebAppConfiguration
public class SomeControllerTest {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
#Autowired
private FilterChainProxy springSecurityFilterChain;
#Before
public void setUp() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext)
.addFilters(this.springSecurityFilterChain)
.build();
}
#Test
public void shouldPreAuthorise() throws Exception {
this.mockMvc.perform(get("/getSome")
.with(user("user.name"))
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}
Test web configurer:-
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {
"your.package.here"
})
public class TestWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter {
}
Some mock objects:-
#Configuration
public class TestContext {
#Bean
public SomeService someService() {
return mock(SomeService.class);
}
}
I have extendend WebSecurityConfigurerAdapter in a different package other than the package containing class for #SpringBootApplication. Then it's not working its generating default username and password.
And it's working fine when it's in the same package.
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
class extending WebSecurityConfigurerAdapter
package com.securitymodule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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;
#Configuration
#EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
// TODO Auto-generated method stub
super.configure(http);
http.antMatcher("/**").authorizeRequests().anyRequest().hasRole("USER").and().formLogin();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// TODO Auto-generated method stub
super.configure(auth);
auth.
inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
#SpringBootApplication is a short hand for #Configuration, #EnableAutoConfiguration, #ComponentScan. This makes Spring to do componentscan for the current packages and packages below this. So all classes in com.example and under com.example are scanned for bean creation while not any others above com.example like com.securitymodule
Hence either add #ComponentScan(basePackages = {"com.securitymodule"}) into your main class, or make the package of WebSecurityConfigurerAdapter as com.example.securitymodule
Below I have a customUserDetailsService property, and a tokenAuthenticationService property. I need to pass customUserDetailsService into tokenAuthenticationService but tokenAuthenticationService is a #Bean file and customUserDetailsService is a #Service which means that tokenAuthenticationService gets called first with parameter for UserDetailsService as null for the UserDetailsService parameter. I need to either delay the initiation of tokenAuthenticationService as a Bean or Turn tokenAuthenticationService into a service as well and some how pass those parameters as a constructor. How do I go about doing this ?
package app.config;
import app.repo.User.CustomUserDetailsService;
import app.security.*;
import app.security.filters.StatelessAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.sql.DataSource;
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
#Order(2)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private static PasswordEncoder encoder;
#Autowired
private TokenAuthenticationService tokenAuthenticationService;
#Autowired
private UserDetailsService customUserDetailsService;
#Autowired
private RESTAuthenticationEntryPoint authenticationEntryPoint;
#Autowired
private RESTAuthenticationFailureHandler authenticationFailureHandler;
#Autowired
private RESTAuthenticationSuccessHandler authenticationSuccessHandler;
public WebSecurityConfig() {
super(true);
}
#Autowired
public void configureAuth(AuthenticationManagerBuilder auth,DataSource dataSource) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/**").authenticated();
http.csrf().disable();
http.httpBasic();
http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
http.formLogin().defaultSuccessUrl("/").successHandler(authenticationSuccessHandler);
http.formLogin().failureHandler(authenticationFailureHandler);
http.addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService),
UsernamePasswordAuthenticationFilter.class);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService);
}
#Bean
public TokenAuthenticationService tokenAuthenticationService() {
tokenAuthenticationService = new TokenAuthenticationService("tooManySecrets", customUserDetailsService);
return tokenAuthenticationService;
}
}
You can define the userDetailsService as direct dependency of the TokenAuthenticationService like this:
#Bean
public TokenAuthenticationService tokenAuthenticationService(UserDetailsService userDetailsService) {
tokenAuthenticationService = new TokenAuthenticationService("tooManySecrets", userDetailsService);
return tokenAuthenticationService;
}
That way, Spring will make sure, that the UserDetailsService is instantiated and injected when the TokenAuthenticationService is created.
You can try annotating tokenAuthenticationService() with #Lazy. Though even if that worked its a bit unpredictable, and future modifications to this or related beans may leave you wondering on why it stopped working.
Best to declare TokenAuthenticationService as #Service & inject UserDetailsService in it.
As a side note its better to not mix #Configuration with application code to avoid these kind of issues.
Update - I don't think #Lazy is going to work here. Since you are relying on #Bean being invoked in the middle of #Autowired beans being processed.
In order for your code to work the #Autowired customUserDetailsService should be set first, then #Bean method called and then #Autowired tokenAuthenticationService should be set.
I want to retrieve the current user in my controller methods with the #AuthenticationPrincipal annotation. The docs state the following:
Annotation that binds a method parameter or method return value to the Authentication.getPrincipal().
But in fact I get the Authentication object instead of Authentication.getPrincipal().
This is my simple controller method:
#RequestMapping("/")
public #ResponseBody String index(#AuthenticationPrincipal final WindowsAuthenticationToken user) {
return String.format("Welcome to the home page, %s!", user.getName());
}
WindowsAuthenticationToken implements Authentication. In this implementation getPrincipal returns a WindowsPrincipal.
The controller method above works, but when I change the arguments type to WindowsPrincipal and try to access the website, I get the following error page:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Tue Mar 03 15:13:52 CET 2015
There was an unexpected error (type=Internal Server Error, status=500).
argument type mismatch HandlerMethod details: Controller [pkg.HomeController] Method [public java.lang.String pkg.HomeController.index(waffle.servlet.WindowsPrincipal)] Resolved arguments: [0] [type=waffle.spring.WindowsAuthenticationToken] [value=waffle.spring.WindowsAuthenticationToken#121a2581]
This is my configuration file:
package pkg;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import waffle.servlet.spi.BasicSecurityFilterProvider;
import waffle.servlet.spi.NegotiateSecurityFilterProvider;
import waffle.servlet.spi.SecurityFilterProvider;
import waffle.servlet.spi.SecurityFilterProviderCollection;
import waffle.spring.NegotiateSecurityFilter;
import waffle.spring.NegotiateSecurityFilterEntryPoint;
import waffle.windows.auth.impl.WindowsAuthProviderImpl;
#Configuration
#EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private NegotiateSecurityFilterEntryPoint negotiateSecurityFilterEntryPoint;
#Autowired
private NegotiateSecurityFilter waffleNegotiateSecurityFilter;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().authenticationEntryPoint(negotiateSecurityFilterEntryPoint).and()
.addFilterBefore(waffleNegotiateSecurityFilter, BasicAuthenticationFilter.class).authorizeRequests()
.anyRequest().fullyAuthenticated();
}
#Bean
public WindowsAuthProviderImpl waffleAuthProvider() {
return new WindowsAuthProviderImpl();
}
#Bean
public NegotiateSecurityFilterProvider negotiateSecurityFilterProvider(
final WindowsAuthProviderImpl waffleAuthProvider) {
return new NegotiateSecurityFilterProvider(waffleAuthProvider);
}
#Bean
public BasicSecurityFilterProvider basicSecurityFilterProvider(final WindowsAuthProviderImpl waffleAuthProvider) {
return new BasicSecurityFilterProvider(waffleAuthProvider);
}
#Bean
public SecurityFilterProviderCollection waffleSecurityFilterProviderCollection(
final NegotiateSecurityFilterProvider negotiateSecurityFilterProvider,
final BasicSecurityFilterProvider basicSecurityFilterProvider) {
final SecurityFilterProvider[] providers = { negotiateSecurityFilterProvider, basicSecurityFilterProvider };
return new SecurityFilterProviderCollection(providers);
}
#Bean
public NegotiateSecurityFilterEntryPoint negotiateSecurityFilterEntryPoint(
final SecurityFilterProviderCollection waffleSecurityFilterProviderCollection) {
final NegotiateSecurityFilterEntryPoint entryPoint = new NegotiateSecurityFilterEntryPoint();
entryPoint.setProvider(waffleSecurityFilterProviderCollection);
return entryPoint;
}
#Bean
public NegotiateSecurityFilter waffleNegotiateSecurityFilter(
final SecurityFilterProviderCollection waffleSecurityFilterProviderCollection) {
final NegotiateSecurityFilter filter = new NegotiateSecurityFilter();
filter.setProvider(waffleSecurityFilterProviderCollection);
return filter;
}
}
Why is the behaviour different from how it should be?
My principal object did not implement UserDetails. Because WindowsPrincipal is a class of an external library I could not make any changes to it. In the end I created a new filter that wraps the WindowsPrincipal in a class that implements UserDetails. Now I get the correct principal object using #AuthenticationPrincipal.
It is because your WindowsPrincipal implements Principal. Remove the implements clause and it will work again. I had the same problem and this resolved it.