Log user information on failed attempt - spring-boot

I want to be able to access my user details when login fail so that I can count the number of times of failed attempt a user has. How can i access the userdetails and save it to my database on failure? I read somewhere that AuthenticationFailureHandler might a be a solution to this but from what I see, it works only with formLogin?
I have a signin endpoint
#CrossOrigin
#RequestMapping(value = "/signin", method = RequestMethod.POST)
#ApiOperation(value = "Sign in endpoint", notes = "You have to provide a valid login request")
public ResponseEntity<?> authenticateUser(#ApiParam(value = "The login request", required = true)
#Valid #RequestBody LoginRequest loginRequest) {
Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
// Set authentication so that when /authenticate, we can retrieve the authenticated user
. . .
This is my authentrypointjwt when authenticate fails.
#Component
public class AuthEntryPointJwt implements AuthenticationEntryPoint {
private static final Logger logger = LoggerFactory.getLogger(AuthEntryPointJwt.class);
#Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
logger.info("> AuthEntryPointJwt");
logger.error("Unauthorized error: {}", authException.getMessage());
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Error: Unauthorized");
}
}
This is my websecurity
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(WebSecurityConfig.class);
#Autowired
UserDetailsServiceImpl userDetailsService;
#Autowired
private AuthEntryPointJwt unauthorizedHandler;
#Bean
public AuthTokenFilter authenticationJwtTokenFilter() {
LOGGER.info("> AuthenticationManagerBuilder authenticationJwtTokenFilter");
return new AuthTokenFilter();
}
#Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
LOGGER.info("> AuthenticationManagerBuilder authenticationManagerBuilder");
authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
LOGGER.info("> AuthenticationManagerBuilder authenticationManagerBean");
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/test/**").authenticated()
.antMatchers("/signup").hasAuthority("SUPER_ADMIN");
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
#Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("HEAD",
"GET", "POST", "PUT", "DELETE", "PATCH"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList("*"));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}

Yes. AuthenticationFailureHandler will only be called if you customise the filter for authentication by extending AbstractAuthenticationProcessingFilter like what formLogin does.
But it seems that you are now implementing a customised authentication way using spring-mvc-rest , and you can do the following which equivalents to what AbstractAuthenticationProcessingFilter does to invoke AuthenticationFailureHandler :
#RestController
public void AuthenticateController {
#Autowired AuthenticationFailureHandler failureHandler;
#RequestMapping(value = "/signin", method = RequestMethod.POST)
public ResponseEntity<?> authenticateUser(LoginRequest loginRequest, HttpServletRequest request, HttpServletResponse response) {
try {
Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
}catch (AuthenticationException failed) {
failureHandler.onAuthenticationFailure(request, response, failed);
}
}
}
P.S. As you are customising authentication using spring-mvc-rest rather than following the spring security infrastructure to implement it based on the Servlet Filter , I assume that you also need to configure spring security to totally ignore AuthenticateController and no other spring security feature will be applied to it . I normally will follow the spring security infrastructure which customize the authentication process based on Servlet Filter as it is more compatible with the spring security ecosystem.

Related

How to get JWT authentication to work on spring boot 3

I've been trying to setup spring security on spring boot 3.0.2 to use JWT, but so far, it hasn't worked.
Whenever I start my spring boot API app, none of my endpoints are exposed except /actuator. And I keep getting a default password given to me.
Here's my security config class:
#Configuration
#EnableMethodSecurity
#RequiredArgsConstructor
public class ApiSecurityConfig {
private final AuthenticationTokenFilter authenticationTokenFilter;
private final UserDetailsServiceImpl userDetailsService;
private final CustomAuthenticationEntryPoint entryPoint;
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
#Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling(e -> e.authenticationEntryPoint(entryPoint))
.authorizeHttpRequests(authorizeRequests -> authorizeRequests
.requestMatchers("/merchant/auth/**").permitAll()
.requestMatchers("/swagger-ui.html").permitAll()
.anyRequest().authenticated())
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
http.authenticationProvider(authenticationProvider());
http.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
EDIT: Here's my authentication token filter:
#Slf4j
#Configuration
public class AuthenticationTokenFilter extends OncePerRequestFilter {
#Autowired
private JwtUtils jwtUtils;
#Autowired
private UserDetailsServiceImpl userDetailsService;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String jwt = "";
String headerAuthorization = request.getHeader("Authorization");
if (StringUtils.hasText(headerAuthorization) && headerAuthorization.startsWith("Bearer ")) {
jwt = headerAuthorization.substring(7, headerAuthorization.length());
}
try {
if (!jwt.isEmpty() && jwtUtils.validateJwt(jwt)) {
String username = jwtUtils.getUsernameFromJwt(jwt);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
} else {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json");
response.getWriter().write("{\"status\": \"false\", \"message\": \"Access denied\", \"data\": \"Invalid token\"}");
response.getWriter().flush();
return;
}
} catch (InvalidKeySpecException e) {
log.error("Invalid key spec exception thrown:", e);
} catch (NoSuchAlgorithmException e) {
log.error("No such algorithm exception thrown:", e);
}
}
}
Thanks to to Tangrunze I was able to see that I missed out the filterChain.doFilter(request, response);
But also, I discovered that I had a componentScan annotation in my main class because I was trying to pick up some components in a different maven project.
Apparently, spring security auto configuration kicks in if you scan other base packages before the resident package where your config is in.

Method security ignored when using Jersey with Spring Security

I'm having trouble getting Spring-Security to work with Jersey within my Spring Boot project. It seems to be something to do with the way the two are integrated but I can't figure out why...
In Jersey endpoints the Spring Security enforced authentication requirement (configured in the WebSecurityConfigurerAdapter) works fine however some method security annotations are ignored. JSR-250 annotations (such as #DenyAll, #RolesAllowed, etc) seem to work if one registers the RolesAllowedDynamicFeature feature. However, #PreAuthorize, #PostAuthorize, #PreFilter, #PostFilter don't work.
Also, when logging in via the /login endpoint the XSRF-TOKEN cookie is not sent. Normally Spring security handles this and if I rewrite the endpoint with Spring MVC, I get both the XSRF-TOKEN and my own ACCESS-TOKEN (generated and sent by the endpoint itself).
(I found a workaround to this - see end of post)
Here's some code (I left out the obvious stuff like JwtUtils, general bean config, etc). Full source (not that there's much - this is a pared-down version of the real project) can be found at https://github.com/ChambreNoire/jersey-issue.
Thanks!
(I'm using Spring Boot 2.3.10.REALEASE and upgrading isn't currently an option)
application.yaml
spring:
jersey:
application-path: /resources
servlet:
load-on-startup: 1
type: filter
JerseyConfig
#Configuration
public class JerseyConfig {
#Bean
public ResourceConfig resourceConfig(ObjectMapper objectMapper) {
return new ResourceConfig()
.property(ServletProperties.FILTER_FORWARD_ON_404, true)
.register((ContextResolver<ObjectMapper>) aClass -> objectMapper)
.register(JacksonFeature.class)
.register(HttpMethodOverrideFilter.class)
.register(AuthResource.class)
.register(UserResource.class);
}
}
SecurityConfigurationAdapter
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class SecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
private static final String[] PUBLIC_PATTERNS;
private final JwtTokenAuthFilter jwtTokenAuthFilter;
private final JwtTokenAuthEntryPoint unauthorizedHandler;
#Autowired
public SecurityConfigurationAdapter(final JwtTokenAuthFilter jwtTokenAuthFilter, final JwtTokenAuthEntryPoint unauthorizedHandler) {
this.jwtTokenAuthFilter = jwtTokenAuthFilter;
this.unauthorizedHandler = unauthorizedHandler;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors()
.configurationSource(corsConfig()).and()
.csrf()
.ignoringAntMatchers("/login", "/login2")
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler).and()
.authorizeRequests()
.antMatchers("/login", "/login2").permitAll()
.anyRequest().authenticated().and()
.addFilterBefore(jwtTokenAuthFilter, UsernamePasswordAuthenticationFilter.class)
.headers()
.xssProtection().and()
.contentSecurityPolicy("script-src 'self';require-trusted-types-for 'script';object-src 'none';");
}
private CorsConfigurationSource corsConfig() {
return request -> {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(singletonList("http://localhost:9000"));
config.setAllowedMethods(singletonList("*"));
config.setAllowCredentials(true);
config.setAllowedHeaders(singletonList("*"));
config.setExposedHeaders(singletonList("Authorization"));
config.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return config;
};
}
}
JwtTokenAuthFilter
#Priority(Priorities.AUTHENTICATION)
public class JwtTokenAuthFilter extends OncePerRequestFilter {
private final UserDetailsService userDetailsService;
private final JwtTokenUtils jwtTokenUtils;
public JwtTokenAuthFilter(final UserDetailsService userDetailsService, final JwtTokenUtils jwtTokenUtils) {
this.userDetailsService = userDetailsService;
this.jwtTokenUtils = jwtTokenUtils;
}
#Override
protected void doFilterInternal(final HttpServletRequest req, final HttpServletResponse resp, final FilterChain chain)
throws ServletException, IOException {
if (req.getCookies() == null) {
chain.doFilter(req, resp);
return;
}
String token = Arrays.stream(req.getCookies())
.filter(c -> "ACCESS-TOKEN".equals(c.getName()))
.findFirst()
.map(Cookie::getValue)
.orElse(null);
if (isEmpty(token) || !jwtTokenUtils.validateJwtToken(token)) {
chain.doFilter(req, resp);
return;
}
String username = jwtTokenUtils.getUserNameFromJwtToken(token);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(req));
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(req, resp);
}
}
AuthResource
#Singleton
#Path("")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class AuthResource {
private final AuthenticationManager authenticationManager;
private final JwtTokenUtils jwtTokenUtils;
#Inject
public AuthResource(AuthenticationManager authenticationManager, JwtTokenUtils jwtTokenUtils) {
this.authenticationManager = authenticationManager;
this.jwtTokenUtils = jwtTokenUtils;
}
#POST
#Path("/login")
public Response login(#RequestBody LoginRequest request) {
try {
org.springframework.security.core.Authentication authentication = authenticationManager
.authenticate(
new UsernamePasswordAuthenticationToken(
request.getEmail(), request.getPassword()
)
);
UserDetailsImpl user = (UserDetailsImpl) authentication.getPrincipal();
return Response.ok()
.cookie(new NewCookie(
"ACCESS-TOKEN",
jwtTokenUtils.generateJwtToken(user),
"/", null, null,
NewCookie.DEFAULT_MAX_AGE,
true, true
))
.build();
} catch (BadCredentialsException ex) {
return Response.status(Response.Status.UNAUTHORIZED).build();
}
}
}
If anyone could enlighten me on why this is the case that would be most appreciated, or indeed any general comments/improvements you may have !
Cheers
UPDATE
It looks like adding the JWT cookie to the javax.ws.rs.core.Response is causing the issue although I'm not certain how. If I add it directly to the HttpServletResponse, the XSRF-TOKEN cookie is present in the response.
Here's the updated Jersey authentication endpoint :
#POST
#Path("/login")
public Response authenticateUser(#Context HttpServletResponse response, #RequestBody LoginRequest request) {
try {
Authentication authentication = authenticationManager
.authenticate(
new UsernamePasswordAuthenticationToken(
request.getEmail(), request.getPassword()
)
);
UserDetailsImpl user = (UserDetailsImpl) authentication.getPrincipal();
Cookie cookie = new Cookie("ACCESS-TOKEN", jwtTokenUtils.generateJwtToken(user));
cookie.setPath("/");
cookie.setSecure(true);
cookie.setHttpOnly(true);
cookie.setMaxAge(-1);
response.addCookie(cookie);
return Response.ok().build();
} catch (BadCredentialsException ex) {
return Response.status(Response.Status.UNAUTHORIZED).build();
}
}

Configuring both http basic and Form based authentication in latest Spring security 6.0

I'm trying to configure REST and Form based authentication in new Spring boot and spring secuirty latest. I went through following post Combining basic authentication and form login for the same REST Api and new spring configuration using SecurityFilterChain and created the following. As I learnt that WebSecurityConfigurerAdapter method in the above post is deprecated.
#Configuration
#Order(2)
#EnableWebSecurity
public class RESTBasedConfigurationAdapter {
#Autowired
private AuthenticationProvider authenticationProvider;
#Bean
public BCryptPasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
#Bean
public SecurityFilterChain configure(HttpSecurity http) throws Exception {
http.antMatcher("/api/**")
.authorizeRequests().anyRequest().hasAnyRole(...)
.and().httpBasic()
.authenticationEntryPoint(authenticationEntryPoint());
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
return http.build();
}
}
and
#Configuration
#Order(Ordered.HIGHEST_PRECEDENCE)
#EnableWebSecurity
public class FormBasedConfigurationAdapter {
#Autowired
private AuthenticationProvider authenticationProvider;
#Autowired
private AuthenticationSuccessHandler authenticationSuccessHandler;
#Bean
public SecurityFilterChain configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers(...)
.permitAll().anyRequest().authenticated()
.and().formLogin().loginPage("/login").successHandler(authenticationSuccessHandler)
.permitAll().and().logout().permitAll();
return http.build();
}
}
But the configure method FormBasedConfigurationAdapter's is never called. Please explain how to configure so that both http Basic and Form based Authentication can be done.
As far I under I want two flows.
One flow REST which uses the following AuthenticationProvider for logging STATELESS
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
#Lazy
private BCryptPasswordEncoder passwordEncoder;
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String userName = authentication.getName();
String password = authentication.getCredentials().toString();
UserDetails userDetails = userDetailsService.loadUserByUsername(userName);
if (passwordEncoder.matches(password, userDetails.getPassword())) {
return new UsernamePasswordAuthenticationToken(userName, password, userDetails.getAuthorities());
} else {
throw new BadCredentialsException(" Bad Credentials ");
}
}
#Override
public boolean supports(Class<?> authenticationType) {
return authenticationType.equals(UsernamePasswordAuthenticationToken.class);
}
}
and for other FormBased authentication, I would like to go through controller as below.
#PostMapping("/login")
public String login(#ModelAttribute("loginForm") LoginForm loginForm,
BindingResult bindingResult,
Model model) {
loginValidator.validate(loginForm, bindingResult);
securityService.login(loginForm.getUserName(), loginForm.getPasswd());
if (bindingResult.hasErrors()) {
return "login";
}
return "...";
}
to facilitate Validation for Authenticate using Service as below.
#Override
public void login(String username, String password) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
if (passwordEncoder.matches(password, userDetails.getPassword())) {
if (usernamePasswordAuthenticationToken.isAuthenticated()) {
SecurityContextHolder.getContext()
.setAuthentication(usernamePasswordAuthenticationToken);
logger.debug(String.format("Auto login %s successfully!", username));
}
} else {
throw new BadCredentialsException(" Bad Credentials ");
}
}
Please explain how to achieve this. I also tried doing both HttpSecurity mapping in the same class but it is not working due to various reasons.

JWT login wont work on deployed spring boot application

I'm following this JWT tutorial to secure my application.
I've ended up with the following WebSecurity configuration:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private MyUserDetailsService userDetailsService;
private MyPasswordEncoder passwordEncoder;
public SecurityConfiguration(MyUserDetailsService userService) {
this.userDetailsService = userService;
this.passwordEncoder = new MyPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().authorizeRequests()
//SIGN_UP_URL = "/login";
.antMatchers(HttpMethod.GET, SIGN_UP_URL).permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()))
// this disables session creation on Spring Security
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.logout().permitAll();
http.logout(logout -> logout
.logoutUrl("/logout")
.addLogoutHandler(new SecurityContextLogoutHandler())
.permitAll()
.clearAuthentication(true));
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration().applyPermitDefaultValues();
source.registerCorsConfiguration("/**", corsConfiguration);
return source;
}
and the following JWTAuthenticationFilter:
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
//SIGN_UP_URL= "/login"
setFilterProcessesUrl(MySettings.SIGN_UP_URL);
}
#Override
public Authentication attemptAuthentication(HttpServletRequest req,
HttpServletResponse res) throws AuthenticationException {
try {
User creds = new ObjectMapper()
.readValue(req.getInputStream(), User.class);
return authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
creds.getUsername(),
creds.getPassword(),
new ArrayList<>())
);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
#Override
protected void successfulAuthentication(HttpServletRequest req,
HttpServletResponse res,
FilterChain chain,
Authentication auth) throws IOException {
String token;
token = JWT.create()
.withSubject(((User) auth.getPrincipal()).getUsername())
.withExpiresAt(new Date(System.currentTimeMillis() + MySettings.EXPIRATION_TIME))
.sign(Algorithm.HMAC512(MySettings.SECRET.getBytes()));
String body = ((User) auth.getPrincipal()).getUsername() + " " + token;
res.getWriter().write(body);
res.getWriter().flush();
}
Problem
At the moment, the app accepts GET requests on the /login URL when starting the app on my computer/localhost. I use postman and Im able to login and receive the token.
When I deploy the application to the server, the /login automatically replies with 403 forbidden.
The databases are equal.
What am I doing wrong?
References
Set custom login url in Spring Security UsernamePasswordAuthenticationFilter JWT authentication
https://www.freecodecamp.org/news/how-to-setup-jwt-authorization-and-authentication-in-spring/
try to add
#CrossOrigin(origins = "*", allowedHeaders = "*")
above your login Api in your controller

Spring security manually authentication not working

i'm changing an existing app with spring boot, this app not use spring security for authentication, the authentication is a method in a controller, so i want use spring security and i'm trying to use manually authentication in spring security but not working, below you can see the code:
Controller:
#Autowired
#Qualifier(BeanIds.AUTHENTICATION_MANAGER)
private AuthenticationManager authenticationManager;
#PostMapping(value = "/authenticate")
public ResponseEntity<UsuarioRequest> login(#RequestBody UsuarioRequest request, HttpServletRequest servletRequest)
throws AppException {
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(request.getUsulog(), request.getUsupass());
Authentication authentication = authenticationManager
.authenticate(authToken);
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(authentication);
UsuarioRequest usuario = usuarioFacadeAPI.findByUsername(request.getUsulog());
return new ResponseEntity<UsuarioRequest>(usuario, HttpStatus.OK);
}
Security Config:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private SiscoAuthenticationProvider siscoAuthenticationProvider;
#Autowired
public SecurityConfig(SiscoAuthenticationProvider siscoAuthenticationProvider) {
super();
this.siscoAuthenticationProvider = siscoAuthenticationProvider;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(siscoAuthenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin().disable();
http.csrf().disable();
http.authenticationProvider(siscoAuthenticationProvider).authorizeRequests()
.antMatchers("/login/api/**", "/zona/api/**", "/rol/api/**").permitAll()
.anyRequest().authenticated();
}
#Bean(name = BeanIds.AUTHENTICATION_MANAGER)
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
}
CustomAuthenticationProvider:
#Component
public class SiscoAuthenticationProvider implements AuthenticationProvider{
private static final String ROLE = "ROLE_";
#Autowired
private UsuarioServiceAPI usuarioServiceAPI;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UsernamePasswordAuthenticationToken token = null;
try {
UsuarioRequest request = usuarioServiceAPI.authenticate(authentication.getPrincipal().toString(), authentication.getCredentials().toString());
List<RolRequest> rols = request.getRoles();
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (RolRequest rol : rols) {
authorities.add(new SimpleGrantedAuthority(ROLE+rol.getRolnom()));
}
token = new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), authorities);
} catch (AppException e) {
String message = BundleLoader.getMessage(e.getDetails().getBundle(), e.getDetails().getKey(),
LocaleContextHolder.getLocale());
throw new UsernameNotFoundException(message, e);
}
return token;
}
#Override
public boolean supports(Class<?> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
}
For the permitAll config no problem occurred, but any other request returns 403 error code even after authentication is success, i suspect that in the controller the SecurityContextHolder not update the authentication, by this the user is always anonymous.
i found a solution for the problem, i changed the Spring Security Config class, specifically the method configure(HttpSecurity http) code below:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin().disable();
http.csrf().disable();
http.authenticationProvider(siscoAuthenticationProvider).authorizeRequests()
.antMatchers("/login/api/**", "/zona/api/**", "/rol/api/**").not().authenticated()
.anyRequest().not().anonymous();
}
the prev config was have problems, with permitAll method and with authenticated method for anyRequest, changing this config for not().authenticated() and not().anonymous() in that order, i get the expected result.

Resources