Testing API Key Authentication in Spring Boot - java

I have a Spring Boot Application where an endpoint is secured with an API Key like this:
#Configuration
#EnableWebSecurity
#Order(1)
public class AuthConfiguration {
public static final String API_KEY_VALUE = "skrdgvsnelrkv";
public static final String API_KEY_HEADER = "API_KEY";
#Value(API_KEY_HEADER)
private String principalRequestHeader;
#Value(API_KEY_VALUE)
private String principalRequestValue;
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
AuthFilter apiKeyFilter = new AuthFilter(principalRequestHeader);
apiKeyFilter.setAuthenticationManager(new AuthenticationManager() {
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String principal = (String) authentication.getPrincipal();
if (!principalRequestValue.equals(principal)) {
throw new BadCredentialsException(
"The API key was not found or not the expected value."
);
}
authentication.setAuthenticated(true);
return authentication;
}
});
http.antMatcher(Endpoints.VALIDATE)
.csrf()
.disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilter(apiKeyFilter)
.authorizeRequests()
.anyRequest()
.authenticated();
return http.build();
}
}
I have tests for that endpoint before, but now they understandably fail with a 403 Forbidden error. Here's how one of them looks like:
#AutoConfigureTestEntityManager
#SpringBootTest
#ContextConfiguration(classes = { TestContext.class })
#TestPropertySource(properties = { "spring.main.allow-bean-definition-overriding=true" })
#AutoConfigureMockMvc
class ControllerTest {
#Autowired
private MockMvc mockMvc;
#Test
void callingValidateEndpointWithValidFileShouldReturnResponseWithStatusOk()
throws Exception {
MockMultipartFile file =
MockMultipathFileBuilder.buildFromFilePath(TestFiles.VALID_FILE);
mockMvc.perform(MockMvcRequestBuilders.multipart(Endpoints.VALIDATE).file(file))
.andExpect(status().isOk());
}
}
How do I need to adjust this test to make it pass?

All that is needed is to add the API Key as a header, like this:
.header(AuthConfiguration.API_KEY_HEADER, AuthConfiguration.API_KEY_VALUE)
That means the test should look like this:
#Test
void callingValidateEndpointWithValidFileShouldReturnResponseWithStatusOk()
throws Exception {
MockMultipartFile file =
MockMultipathFileBuilder.buildFromFilePath(TestFiles.VALID_FILE);
mockMvc.perform(
MockMvcRequestBuilders.multipart(Endpoints.VALIDATE)
.file(file)
.header(AuthConfiguration.API_KEY_HEADER, AuthConfiguration.API_KEY_VALUE)
).andExpect(status().isOk());
}

Related

Custom UserDetailsService is not called by spring-boot

I'm trying to use UserDetailsService in spring-security to implement my authentication logic. However, UserDetailsService is not called during an HTTP request. Here is the code:
#Service
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
private UserService userService;
#Override
public UserDetails loadUserByUsername(String userId) throws UsernameNotFoundException {
Optional<User> user = userService.getById(Long.parseLong(userId));
if (user.isEmpty()) {
throw new UsernameNotFoundException("User " + userId + " not found");
}
return new org.springframework.security.core.userdetails.User(
user.get().getName(),
user.get().getHashedPassword(),
List.of());
}
}
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private CustomUserDetailsService customUserDetailsService;
#Autowired
private PasswordEncoder passwordEncoder;
#Override
protected void configure(HttpSecurity http) throws Exception { // (2)
http.authorizeRequests()
.antMatchers("/user/add", "/user/loginByEmail").permitAll() // (3)
.anyRequest().authenticated()
.and()
.logout()
.permitAll()
.and()
.httpBasic();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService)
.passwordEncoder(passwordEncoder);
}
}
I use a test to test the authentication logic, here is the core of the test code:
MvcResult addMvcResult = mockMvc.perform(post("/habit/friend/addById")
.with(SecurityMockMvcRequestPostProcessors.httpBasic("Joey", "password"))
.contentType("application/json")
.content(StringUtils.toJSONString(addFriendRequestByIdDTO)))
.andExpect(status().isOk())
.andReturn();
The log shows that the authentication header is inserted by spring-test:
MockHttpServletRequest:
HTTP Method = POST
Request URI = /habit/friend/addById
Parameters = {}
Headers = [Content-Type:"application/json;charset=UTF-8", Content-Length:"47", Authorization:"Basic Sm9leTpwYXNzd29yZA=="]
Body = {
"currentUserId" : 1,
"friendUserId" : 2
}
Session Attrs = {org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN=org.springframework.security.web.csrf.DefaultCsrfToken#3a48c398}
However, the authentication failed, I got a 403, and CustomUserDetailsService is never called. Why?
Your problem seems to be with CSRF rather than with UserDetailsService's implementation not being registered, Starting from Spring 4.x, CSRF protection is enabled by default and unless you turn it off like
http
.csrf()
.disable()
you are going to get 403 errors.

How to test a Rest Service with Spring Security on Spring Boot?

I am working on a project that involves creating a rest service on Spring Boot that will eventually work with an Angular Web App and Discord Bot.
I am currently working on the backend and trying to unit test the endpoints. As evenually non-logged in users can make only make GET request. However, for some reason when ever I unit test an endpoint, it comes back as error 403. Even when I tell Spring Security to allow any request.
Security Config
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
//http.authorizeRequests().antMatchers("/api/*").permitAll();
http.authorizeRequests().anyRequest().permitAll();
// .authorizeRequests()
// .antMatchers("/api/**/rule","/api/**/rules" )
// .permitAll()
// .anyRequest()
// .permitAll()
// .and()
// .formLogin()
// .loginPage("/login")
// .permitAll()
// .and()
// .logout()
// .permitAll();
}
#Autowired
public void configureAuth(AuthenticationManagerBuilder auth) throws Exception{
auth
.inMemoryAuthentication()
.withUser("admin").password("password").roles("ADMIN", "USER", "EDITOR").and()
.withUser("user").password("password").roles("USER", "EDITOR");
}
}
JUnit test
#RunWith(SpringRunner.class)
#SpringBootTest()
#AutoConfigureMockMvc
public class TestSFRuleController {
ObjectMapper mapper = new ObjectMapper();
#Autowired
MockMvc mvc;
#Autowired
SFRuleRepo repo;
#Before
public void setUp(){
repo.deleteAll();
}
#Test
#WithMockUser(username = "admin")
public void testInsertNewRule() throws Exception {
SFRule rule = new SFRule("test insert rule", "test desc");
String json = mapper.writeValueAsString(rule);
mvc.perform(
post(StarfinderController.PREFIX_URL + StarfinderController.RULE_URL)
.content(json))
.andExpect(status()
.isOk())
.andExpect(jsonPath("$.id").isNotEmpty())
.andExpect(jsonPath("$.name").value("test insert rule"));
}
}
Controller
#RestController
#RequestMapping("/api/sf")
public class StarfinderController {
#Autowired
SFRuleRepo ruleRepo;
public static final String PREFIX_URL = "/api/sf";
public static final String RULE_URL = "/rule";
public static final String RULES_URL = "/rules";
public static final String RULE_REPO = "RULE";
public static final String PAGE = "page";
public static final String COUNT = "count";
#GetMapping(RULE_URL)
public Rule getRule(#RequestParam(value = "name", required = true) String name) {
return ruleRepo.findByName(name);
}
#GetMapping(RULES_URL)
public List<Rule> getRules(#RequestParam(value = "tag", required = false, defaultValue = "") String tagName,
#RequestParam(value = "page", required = false) int page,
#RequestParam(value = "count", required = false) int count) {
if (!tagName.isEmpty()) {
// noop
} else {
//TODO: add support for page and count
List<Rule> list = new LinkedList<Rule>();
list.addAll(ruleRepo.findAll());
return list;
}
return null;
}
#PostMapping(RULE_URL)
public Rule addRule(SFRule rule) {
return ruleRepo.save(rule);
}
#PutMapping(RULE_URL)
public Rule updateRule(SFRule rule) {
Optional<SFRule> savedRule = ruleRepo.findById(rule.getId());
if (savedRule.isPresent()) {
SFRule sv = savedRule.get();
sv.setName(rule.getName());
sv.setDesc(rule.getDesc());
return ruleRepo.save(sv);
} else {
return null;
}
}
#DeleteMapping(RULE_URL)
public void deleteRule(SFRule rule) {
ruleRepo.delete(rule);
}
}
This should work, just put the URL in .antMatcher().permitAll()
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/targetURL/**").permitAll()
}

Spring test: How to test method secured with #PreAuthorize("#SecurityPermission.hasPermission('somepermission')")

In our Spring Boot project we secured each method with #PreAuthorize annotation. It checks if user has permission for the requested resource.
Here is one of our controllers:
#PreAuthorize("#SecurityPermission.hasPermission('role')")
#RequestMapping(value = "/role")
public class RoleController {
#Autowired
private RoleService roleService;
#PreAuthorize("#SecurityPermission.hasPermission('role.list')")
#RequestMapping(value = "/allroles", method = RequestMethod.GET, consumes = "application/json", produces = "application/json")
public JsonData<Role> getListOfRoles() {
JsonData<Role> roleJsonData = new JsonData<>();
roleJsonData.setData(roleService.list());
return roleJsonData;
}
}
The question is: How to test properly permissions for above mentioned method?
I have tried the following two options:
#RunWith(SpringRunner.class)
#WebMvcTest(RoleController.class)
public class RoleControllerTest {
#Autowired
private MockMvc mvc;
#MockBean
private RoleService roleService;
#Test
public void optionOne() throws Exception {
ArrayList<Role> roles = new ArrayList<>();
roles.add(new Role().setId(1L).setName("administrator"));
roles.add(new Role().setId(2L).setName("user"));
given(roleService.list()).willReturn(roles);
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/json");
this.mvc.perform(get("/role/allroles").with(user("testadmin"))
.headers(headers))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.data[0].name", is( roles.get(0).getName())))
.andExpect(jsonPath("$.data[1].name", is( roles.get(1).getName())));
}
#Test
#WithMockUser(authorities = {"role.list"})
public void optionTwo() throws Exception {
ArrayList<Role> roles = new ArrayList<>();
roles.add(new Role().setId(1L).setName("administrator"));
roles.add(new Role().setId(2L).setName("user"));
given(roleService.list()).willReturn(roles);
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/json");
this.mvc.perform(get("/role/allroles")
.headers(headers))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.data[0].name", is( roles.get(0).getName())))
.andExpect(jsonPath("$.data[1].name", is( roles.get(1).getName())));
}
}
optionOne passes even though mock user doesn't have required permission("role.list") while optionTwo failes with the status 403.
java.lang.AssertionError: Status
Expected :200
Actual :403
UPDATE: I am adding WebSecurityConfig class
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
public static final String JWT_TOKEN_HEADER_PARAM = "X-Authorization";
public static final String FORM_BASED_LOGIN_ENTRY_POINT = "/auth/login";
public static final String SEARCH_BASED_ENTRY_POINT = "/search/**";
public static final String TOKEN_REFRESH_ENTRY_POINT = "/auth/token";
public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/**";
#Autowired
private RestAuthenticationEntryPoint authenticationEntryPoint;
#Autowired
private AuthenticationSuccessHandler successHandler;
#Autowired
private AuthenticationFailureHandler failureHandler;
#Autowired
private AjaxAuthenticationProvider ajaxAuthenticationProvider;
#Autowired
private JwtAuthenticationProvider jwtAuthenticationProvider;
#Autowired
private TokenExtractor tokenExtractor;
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private ObjectMapper objectMapper;
#Bean
protected AjaxLoginProcessingFilter buildAjaxLoginProcessingFilter() throws Exception {
AjaxLoginProcessingFilter filter = new AjaxLoginProcessingFilter(FORM_BASED_LOGIN_ENTRY_POINT, successHandler, failureHandler, objectMapper);
filter.setAuthenticationManager(this.authenticationManager);
return filter;
}
#Bean
protected JwtTokenAuthenticationProcessingFilter buildJwtTokenAuthenticationProcessingFilter() throws Exception {
List<String> pathsToSkip = Arrays.asList(TOKEN_REFRESH_ENTRY_POINT, FORM_BASED_LOGIN_ENTRY_POINT, SEARCH_BASED_ENTRY_POINT);
SkipPathRequestMatcher matcher = new SkipPathRequestMatcher(pathsToSkip, TOKEN_BASED_AUTH_ENTRY_POINT);
JwtTokenAuthenticationProcessingFilter filter
= new JwtTokenAuthenticationProcessingFilter(failureHandler, tokenExtractor, matcher);
filter.setAuthenticationManager(this.authenticationManager);
return filter;
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(ajaxAuthenticationProvider);
auth.authenticationProvider(jwtAuthenticationProvider);
}
#Bean
protected Md5PasswordEncoder passwordEncoder() {
return new Md5PasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("utf-8");
filter.setForceEncoding(true);
http.addFilterBefore(filter, CsrfFilter.class);
http.addFilterBefore(new WebSecurityCorsFilter(), ChannelProcessingFilter.class);
http
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(this.authenticationEntryPoint)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(FORM_BASED_LOGIN_ENTRY_POINT).permitAll()
.antMatchers(TOKEN_REFRESH_ENTRY_POINT).permitAll()
.antMatchers(SEARCH_BASED_ENTRY_POINT).permitAll()
.and()
.authorizeRequests()
.antMatchers(TOKEN_BASED_AUTH_ENTRY_POINT).authenticated()
.and()
.addFilterBefore(buildAjaxLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(buildJwtTokenAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
I had the same problem a few months ago but in a slightly different way. I think your context is not setup correctly, since you have to apply SpringSecurity explicitiy to it for testing purposes:
private MockMvc mockMvc;
#Autowired
private WebApplicationContext context;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
You can also refer to: How to unit test a secured controller which uses thymeleaf (without getting TemplateProcessingException)?
It is slightly different to your problem, but since SecurityHandling is kind of an individual setup, it ist hard to help without knowing your project better.
If you are trying to test the behaviour for a non-authorized User, you can also do something like this:
#Test
public void getLoginSuccessWithAnonymousUserReturnsAccessDeniedException() throws Exception {
MvcResult mvcResult = mockMvc.perform(get("/your-url").with(anonymous()))
.andExpect(status().is3xxRedirection()) //change to your code
.andReturn();
Class result = mvcResult.getResolvedException().getClass();
MatcherAssert.assertThat((result.equals(org.springframework.security.access.AccessDeniedException.class)), is(true));
}

Spring security 401 Unauthorized on unsecured endpoint

I'm trying to configure Spring Security on a Spring Boot application as follows:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private RestAuthenticationEntryPoint unauthorizedHandler;
#Bean
public JwtAuthenticationFilter authenticationTokenFilterBean() throws Exception {
JwtAuthenticationFilter authenticationTokenFilter = new JwtAuthenticationFilter();
authenticationTokenFilter.setAuthenticationManager(authenticationManagerBean());
return authenticationTokenFilter;
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
//#formatter:off
httpSecurity
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(this.unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/login", "/singup", "/subscribers").permitAll()
.anyRequest().authenticated();
// Custom JWT based security filter
httpSecurity
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
//#formatter:on
}
}
My unauthorizedHandler is:
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
private static final Logger LOGGER = LoggerFactory.getLogger(RestAuthenticationEntryPoint.class);
#Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
Finally, the REST controller for /subscribers is:
#RestController
public class SubscriberRestController {
#Autowired
ISubscribersService subscribersService;
#RequestMapping(value = RequestMappingConstants.SUBSCRIBERS, method = RequestMethod.GET)
#ResponseBody
public Number subscriberCount() {
return subscribersService.subscribersCount();
}
#RequestMapping(value = RequestMappingConstants.SUBSCRIBERS, method = RequestMethod.POST)
public String subscriberPost(#RequestBody SubscriberDocument subscriberDocument) {
return subscribersService.subscribersInsert(subscriberDocument);
}
#RequestMapping(value = "/test", method = RequestMethod.GET)
public String test() {
return "This is a test";
}
}
I use postman to test endpoints and when I do a POST to "localhost:8080/subscribers", I get:
I want to have opened endpoints (/subscribers) without any security control or credentials check, endpoints for singup and login and secured endpoints for authenticated users.
Thanks! :)
Spring Boot was not applying the configuration because couldn't find it. On Application.java config package was not included with #ComponentScan anotation.
After some researching, here is solution:
#SpringBootApplication(exclude = {SecurityAutoConfiguration.class })
#ComponentScan(basePackages = { PackageConstants.PACKAGE_CONTROLLERS_REST, PackageConstants.PACKAGE_SERVICES,
PackageConstants.PACKAGE_SERVICES_IMPL, PackageConstants.PACKAGE_MONGO_REPOSITORIES,
PackageConstants.PACKAGE_MONGO_REPOSITORIES_IMPL, PackageConstants.PACKAGE_UTILS })
public class Application {
// Clase principal que se ejecuta en el bootrun
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Main line is #SpringBootApplication(exclude = {SecurityAutoConfiguration.class }) it tells not use Spring Boot Security AutoConfiguration configuration. It is not full answer, because now you have to tell Spring user your Spring Security configuration class. Also i advice you to create Initializer class with init Root Config Classes, ApplicationConfiguration using and refuse to use SpringBoot applications. Something like this:
ApplicationConfig:
#Configuration
#EnableWebMvc
#ComponentScan("com.trueport.*")
#PropertySource("classpath:app.properties")
public class ApplicationConfig extends WebMvcConfigurerAdapter {
....
}
ApplicationSecurityConfig:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter {
....
}
Initializer:
public class Initializer implements WebApplicationInitializer {
private static final String DISPATCHER_SERVLET_NAME = "dispatcher";
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
....
DispatcherServlet dispatcherServlet = new DispatcherServlet(ctx);
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
ctx.register(ApplicationConfig.class);
ServletRegistration.Dynamic servlet = servletContext.addServlet(DISPATCHER_SERVLET_NAME,
dispatcherServlet);
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
servlet.setAsyncSupported(true);
}
}
You need to add the following to your configure method /error is the default fall back when error occurs to the application due to any exception and it is secured by default.
protected void configure(HttpSecurity httpSecurity) throws Exception {
//disable CRSF
httpSecurity
//no authentication needed for these context paths
.authorizeRequests()
.antMatchers("/error").permitAll()
.antMatchers("/error/**").permitAll()
.antMatchers("/your Urls that dosen't need security/**").permitAll()
Also the below code snippet
#Override
public void configure(WebSecurity webSecurity) throws Exception
{
webSecurity
.ignoring()
// All of Spring Security will ignore the requests
.antMatchers("/error/**")
}
Now you will not get 401 and get 500 exception with details when an exception occurred for permitAll Urls
If your application is simply saving APIs, and you have included dependency for spring security - for any other reason (Mine was to enables headers X-Frame and Content-Security-Policy), then by default Spring includes servlet filter for csrf protection. If you do not disable this, all requests fail with HTTP 401 error.
To disable it, You create a Configuration class extending WebSecurityConfigurerAdapter and annotated with EnableWebSecurity
#EnableWebSecurity
#Configuration
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable();
}
}
This article is worthy the read - very detailed.

Spring throwing 403 Forbidden on web service to upload image

I have a controller to upload a user's avatar that has been working for quite a while. Until recently, after I made a change to my spring security configuration. The change was to have unauthorized calls to API's return 403 forbidden and unauthorized calls to anything else redirect to login. Since making this change the app throws a 403 every time a call is made to upload an avatar. Every other API works as intended.
Here are the snippets I believe are relevant to the issue at hand:
Controller:
#Controller
#RequestMapping("/api/users")
public class UsersController {
#RequestMapping(value = "/upload_avatar", params = { "filename" }, method = RequestMethod.POST)
public #ResponseBody ResponseStatusDTO handleFileUpload(
#RequestParam("file") MultipartFile file,
#RequestParam(value = "filename") String filename) {
if (!file.isEmpty()) {
try {
String newFilename = userUtil.uploadAvatar(file, filename);
return new ResponseStatusDTO(1, newFilename);
} catch (Exception e) {
return new ResponseStatusDTO(1, "Failed to upload " + filename
+ "!");
}
} else {
return new ResponseStatusDTO(1, "Failed to upload " + filename
+ " because the file was empty.");
}
}
}
Ajax Call Performing Request:
uploadAvatar : function(){
var file = this.getSelectedFile();
var data = new FormData();
data.append('file', file);
var name = file.name;
$.ajax({
url: './api/users/upload_avatar?filename='+ name,
data: data,
cache: false,
contentType: false,
processData: false,
type: 'POST',
success: _.bind(function(data){
this.avatar = data.message;
}, this),
error: _.bind(function(data){
//TODO
}, this)
});
}
Latest Spring Security Configuration:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration {
#Autowired
private CommonAuthenticationProvider authProvider;
#Autowired
AuthFailureHandler authFailureHandler;
#Autowired
AuthSuccessHandler authSuccessHandler;
#Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth)
throws Exception {
auth.authenticationProvider(authProvider);
}
#Configuration
#Order(1)
public static class ApiLoginWebSecurityConfigurationAdapter extends
WebSecurityConfigurerAdapter {
#Autowired
private Http403ForbiddenEntryPoint forbiddenEntryPoint;
#Bean
public Http403ForbiddenEntryPoint forbiddenEntryPoint() {
return new Http403ForbiddenEntryPoint();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.antMatcher("/api/**")
.authorizeRequests()
.anyRequest().fullyAuthenticated()
.and()
.httpBasic()
.authenticationEntryPoint(forbiddenEntryPoint);
// #formatter:on
}
}
#Configuration
public static class FormLoginWebSecurityConfigurationAdapter extends
WebSecurityConfigurerAdapter {
#Autowired
AuthFailureHandler authFailureHandler;
#Autowired
AuthSuccessHandler authSuccessHandler;
#Autowired
private LoginUrlAuthenticationEntryPoint loginEntryPoint;
#Bean
public LoginUrlAuthenticationEntryPoint loginEntryPoint() {
return new LoginUrlAuthenticationEntryPoint("/login");
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/css/**", "/js/**", "/webjars/**",
"/login/**", "/session/**", "/public/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.authorizeRequests()
.anyRequest().fullyAuthenticated()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/j_spring_security_check")
.usernameParameter("username")
.passwordParameter("password")
.failureHandler(authFailureHandler)
.successHandler(authSuccessHandler)
.permitAll()
.and()
.logout()
.logoutUrl("/j_spring_security_logout")
.logoutSuccessUrl("/login")
.invalidateHttpSession(true)
// .deleteCookies(cookieNamesToClear)
.and()
.httpBasic().authenticationEntryPoint(loginEntryPoint)
.and()
.csrf().disable();
// #formatter:on
}
}
}
Finally found the issue after several hours. In the new api security configuration I didn't disable csrf and wasn't sending a token. Once I disabled csrf it worked as expected.
#Configuration
#Order(1)
public static class ApiLoginWebSecurityConfigurationAdapter extends
WebSecurityConfigurerAdapter {
#Autowired
private Http403ForbiddenEntryPoint forbiddenEntryPoint;
#Bean
public Http403ForbiddenEntryPoint forbiddenEntryPoint() {
return new Http403ForbiddenEntryPoint();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.antMatcher("/api/**")
.authorizeRequests()
.anyRequest().fullyAuthenticated()
.and()
.httpBasic()
.authenticationEntryPoint(forbiddenEntryPoint)
.and()
.csrf().disable();
// #formatter:on
}
}

Categories