I am trying to validate a captcha image before validating the user.
In order to validate the captcha I have created the following class that will process POST requests from /mvc/login
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
public class CaptchaAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private final Logger logger = LoggerFactory.getLogger(getClass());
private String processUrlString;
protected CaptchaAuthenticationFilter(String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
this.processUrlString=defaultFilterProcessesUrl;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req =(HttpServletRequest) request;
HttpServletResponse res =(HttpServletResponse) response;
logger.info("doFilter.method " + req.getMethod() + " .doFilter.getRequestURI " + req.getRequestURI());
if(processUrlString.equals(req.getRequestURI()) && "POST".equalsIgnoreCase(req.getMethod())) {
String expected = req.getSession().getAttribute("captcha").toString();
req.getSession().removeAttribute("captcha");
if (expected!=null && !expected.equals(req.getParameter("answer"))) {
unsuccessfulAuthentication(req, res, new InsufficientAuthenticationException("Wrong code"));
return;
}
}
chain.doFilter(request, response);
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
return null;
}
}
In order to associate the filter to the requests I have created the following configuration class, where I specified the filter to use with: addFilterBefore
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
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.User;
import org.springframework.security.core.userdetails.User.UserBuilder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(new CaptchaAuthenticationFilter("/mvc/login"), UsernamePasswordAuthenticationFilter.class);
http.authorizeRequests()
.antMatchers("/assets/**").permitAll()
.antMatchers(HttpMethod.POST, "/mvc/login").permitAll() // Is this necessary?
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/mvc/index")
.usernameParameter("j_user")
.passwordParameter("j_password")
.permitAll()
.and()
.logout()
.permitAll();
}
#Bean
public UserDetailsService users() {
UserBuilder users = User.withDefaultPasswordEncoder();
UserDetails user = users
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
Am I following the right path in order to validate the request? Or should I follow a different strategy?
One issue that I have detected is that with every logging attempt it is displaying the following request doFilter.method POST .doFilter.getRequestURI /mvc/error instead of doFilter.method POST .doFilter.getRequestURI /mvc/login
This is my login form too:
<form action="/mvc/login" method="post">
<input type="text" id="j_user" name="j_user">
<input type="text" id="j_password" name="j_password">
<input type="text" id="answer" name="answer">
<input type="submit">
</form>
This seems like right way to validate captcha. Most likly CSRF filter in intercepting the request and because of missing CSRF, it is redrecting you to error page (URL) that you see in the logs.
Related
I am creating backend app and testing as well. my register url is resposing 403 forbidden but csrf is disabled. I can't fix this problem. Please help me P
Here is my configuration
package uz.renessans.configuration;
import lombok.RequiredArgsConstructor;
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.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import uz.renessans.entity.user.UserRepository;
import uz.renessans.security.JwtFilter;
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
#RequiredArgsConstructor
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final JwtFilter jwtFilter;
private final UserRepository userRepository;
#Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
UserDetailsService userDetailsService = username ->
userRepository.findByUsername(username).orElseThrow(() -> new UsernameNotFoundException(username));
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
String[] OPEN_URLS = {
"/api/v1/register/**",
"/swagger-ui/**",
"/api/v1/login"
};
http
.csrf()
.disable()
.httpBasic()
.disable()
.authorizeRequests()
.antMatchers(
"/api/v1/register/**",
"/swagger-ui/**",
"/api/v1/login"
)
.permitAll()
.anyRequest()
.authenticated();
// .permitAll();
http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
}
}
Here is my jwt filter class:
package uz.renessans.security;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import uz.renessans.entity.user.User;
import uz.renessans.entity.user.UserRepository;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Optional;
#Component
#RequiredArgsConstructor
public class JwtFilter extends OncePerRequestFilter {
private final JwtProvider jwtProvider;
private final UserRepository userRepository;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authorization = request.getHeader("Authorization");
if (authorization != null && authorization.startsWith("Bearer") && authorization.length() > 7) {
authorization = authorization.substring(7);
String username = jwtProvider.getPhoneNumber(authorization);
if (username != null) {
Optional<User> optionalUser = userRepository.findByUsername(username);
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = null;
if (optionalUser.isPresent()) {
usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(optionalUser.get(), null, optionalUser.get().getAuthorities());
}
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
filterChain.doFilter(request, response);
}
}
Here is my register api
public HttpEntity<?> register(RegisterDto dto, Role role) {
if (userRepository.existsByUsername(dto.getUsername()))
return new ResponseEntity<>(new ApiResponse("Username already exists", false), HttpStatus.CONFLICT);
if (!dto.getPassword().equals(dto.getRePassword()))
return new ResponseEntity<>(new ApiResponse("Password must match", false), HttpStatus.CONFLICT);
User user = new User();
user.setRole(role);
user.setUsername(dto.getUsername());
user.setPassword(passwordEncoder.encode(dto.getPassword()));
user.setFullName(dto.getFullName());
User savedUser = userRepository.save(user);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
savedUser.getUsername(), savedUser.getPassword());
authenticationManager.authenticate(authenticationToken);
String token = jwtProvider.generateToken(savedUser.getUsername(), savedUser.getRole());
Response response = Response.builder().token(token).role(role.toString()).build();
return new ResponseEntity<>(new ApiResponse("Registered Successfully", true, response), HttpStatus.OK);
}
I have been working on Spring Security
I use a role based authentication. If the user is admin he will be directed to admindashboard and user will be redirected to his respective dashboard where they share a common login portal.
If a person enters a url of the admin/user dashboard before login it asks the person to login but doesn't redirect to entered url. Instead throws an error "cannot call sendRedirect".
My code for security configuration file
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
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.Authentication;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.web.util.UrlPathHelper;
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired private LoginSuccessHandler loginSuccessHandler;
#Bean
AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider provider=new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(new BCryptPasswordEncoder());
return provider;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/").permitAll()
.antMatchers("/userhome").hasAuthority("USER").
antMatchers("/adminhome").hasAuthority("ADMIN")
.antMatchers("/register").permitAll()
.and().formLogin().loginPage("/login")
.successHandler(loginSuccessHandler)
.permitAll().and().logout().logoutSuccessHandler(new LogoutSuccessHandler() {
#Override
public void onLogoutSuccess(HttpServletRequest request,HttpServletResponse response,Authentication authentication) throws IOException,ServletException{
System.out.println("The User "+authentication.getName() + " has logged out");
UrlPathHelper helper=new UrlPathHelper();
String context=helper.getContextPath(request);
response.sendRedirect(context+"/home");
}
}).permitAll();
http.csrf().disable();
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
My Login Successful handler
package strictly.cinema.config;
import java.io.IOException;
import java.util.Collection;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import strictly.cinema.service.CustomUserDetails;
#Component
public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler{
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws ServletException, IOException {
CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal();
Collection<? extends GrantedAuthority> authorities =userDetails.getAuthorities();
authorities.forEach(auth->System.out.println(auth.getAuthority()));
String redirectURL=request.getContextPath();
if(userDetails.hasRole("USER"))
redirectURL+="/userhome";
else if(userDetails.hasRole("ADMIN"))
redirectURL+="/adminhome";
response.sendRedirect(redirectURL);
super.onAuthenticationSuccess(request, response, authentication);
}
}
Overriden the logout handler in the security handler itself.
Need help to store the entered URL once the user is authenticated and eligible to access the URL he should be redirected to the URL after the login
Instead of using successHandler, you could redirect him to a success endpoint as follow :
.defaultSuccessUrl("/loginSuccess")
And the new endpoint will redirect him to "/userhome" or "/adminhome" based on his role.
(Below was not tested)
Success endpoint :
#GetMapping("/loginSuccess")
public void getLoginInfo(
#AuthenticationPrincipal UserDetails authentication,
HttpServletResponse response) throws IOException {
if (authentication.getAuthorities()
.contains(new SimpleGrantedAuthority("ADMIN"))) {
response.sendRedirect("/adminhome");
} else {
response.sendRedirect("/userhome");
}
}
I want to authenticate a server. I want to make sure the user is giving a header key, I am not checking for login or anything.
I want the header key to check with my hardcoded one,
If its equal pass it,
Else no
I wrote two filters.
SecurityConfig.java
package com.company.framework.filter;
import javax.servlet.http.HttpServletResponse;
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.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
#Configuration
#EnableWebSecurity
public class SecurityConfig{
#Autowired private AuthFilter filtet;
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
System.out.println("reaching here3 ");
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/v1/open/**").permitAll()
.and()
.exceptionHandling()
.authenticationEntryPoint(
(request, response, authException) ->
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Error here")
)
.and()
.sessionManagement()
.and()
.httpBasic().disable();
http
.addFilter(filtet);
return http.build();
}
}
Authfilter.java
package com.company.framework.filter;
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.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
#Component
public class AuthFilter extends OncePerRequestFilter{
#Override
protected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain filterChain) throws ServletException, IOException {
String authHeader = request.getHeader("Authorization");
System.out.println("here ");
System.out.println(authHeader+"1");
if (authHeader != null && authHeader.length() == 0 && authHeader.startsWith("Bearer ")) {
String jwt = authHeader.substring(7);
System.out.println(authHeader+"2");
if (jwt == null) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid JWT Token in Bearer Header");
} else {
String rev = "bfrek";
if (jwt.equals(rev)) {
response.setStatus(200);
} else {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid JWT Token");
}
}
}
filterChain.doFilter(request, response);
}
}
But, after all days of try and error, I am still getting 401 unauthorised.
I have seen articles telling how to connect it with users database but I just want to check for header token and pass it through. (Using filter)
Edit 1:
Now after reading many articles and documentation, I understand that there are 15 filters, But how do I make sure that the system just checks for my header key and ignore everything else.
Seems you missed overriding the configure method of WebSecurityConfigurerAdapter class. This is the main logic to override the default spring security logic. This is the main problem i guess. try to extend that class(WebSecurityConfigurerAdapter) and override that method(configure) in SecurityConfig.java.
SecurityConfig.java
package com.company.framework.filter;
import javax.servlet.http.HttpServletResponse;
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.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurer{
#Autowired private AuthFilter filtet;
public SecurityFilterChain configure(HttpSecurity http) throws Exception {
System.out.println("reaching here3 ");
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/v1/open/**").permitAll()
.and()
.exceptionHandling()
.authenticationEntryPoint(
(request, response, authException) ->
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Error here")
)
.and()
.sessionManagement()
.and()
.httpBasic().disable();
http.addFilter(filtet);
return http.build();
}
}
Greetings dear members of the forum.
Please tell me why the POST Method does not work? I can not catch the parameters received via POST. It does not give any errors, only returns null. I have been struggling with this problem for several days now.
SecurityConfig.class
package com.myfilter.security;
import com.myfilter.filter.CustomFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
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.web.authentication.AnonymousAuthenticationFilter;
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// I connect my CustomFilter where I will catch POST parameters
#Autowired
CustomFilter customFilter;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.
// I add a filter where I will catch POST parameters
addFilterBefore(customFilter, AnonymousAuthenticationFilter.class)
.authorizeRequests()
.mvcMatchers("/login", "/").permitAll()
// I indicate that the POST method will be used
.mvcMatchers(HttpMethod.POST,"/login").permitAll()
.and()
.csrf().disable()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/");
}
}
CustomFilter.class (This is a filter where I will catch POST parameters)
package com.myfilter.filter;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
#Component
public class CustomFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
// I get the parameter
String email = httpServletRequest.getParameter("email");
// Display to the console
System.out.println(email);
chain.doFilter(request, response);
}
}
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Sign in</title>
</head>
<body>
<form name="user" method="post" action="/login">
<input type="text" name="email">
<input type="password" name="password">
<button type="submit">Sign in</button>
</form>
</body>
</html>
HomeController
package com.myfilter.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
#Controller
public class HomeController {
#GetMapping(value = "/")
public String home () {
return "/home";
}
#GetMapping(value = "/login")
public String login () {
return "/login";
}
#PostMapping(value = "/login")
public String loginPost () {
return "redirect:/";
}
}
View this project at github https://github.com/romanych2021/MyFilter
I am getting error in configure method of SecurityConfig class whose code is here:
package com.sumit.Security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
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.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import com.sumit.Repo.UserRepository;
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsService userDetailsService;
#Autowired
private UserRepository userRepository;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
// remove csrf and state in session because in jwt we do not need them
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager(),userRepository))
.authorizeRequests()
// configure access rules
.antMatchers("/register").permitAll()
.antMatchers("/admin").hasRole("ADMIN")
.antMatchers("/user").hasAnyRole("ADMIN","USER")
.antMatchers("/management").hasAnyRole("MANAGER","ADMIN")
.antMatchers("/page1").hasAnyAuthority("ROLE_ADMIN","ACCESS_PAGE1")
.antMatchers("/page2").hasAnyAuthority("ROLE_ADMIN","ACCESS_PAGE2")
.anyRequest().authenticated();
// .and()
// .formLogin()
// .loginPage("/login")
// .usernameParameter("username")
// .passwordParameter("password").successForwardUrl("/welcome")
// .permitAll();
}
#Bean
DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
daoAuthenticationProvider.setUserDetailsService(this.userDetailsService);
return daoAuthenticationProvider;
}
#Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
in above code, error lies here auth.authenticationProvider(authenticationProvider());
code is getting compiled fine but due to this i am getting 403 forbidden. Flow is getting broken here
JwtAutheticationFilter class is here
package com.sumit.Security;
import static com.auth0.jwt.algorithms.Algorithm.HMAC512;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.auth0.jwt.JWT;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sumit.Repo.UserRepository;
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
LoginModel credentials = null;
try {
credentials = new ObjectMapper().readValue(request.getInputStream(), LoginModel.class);
} catch (Exception e) {
e.printStackTrace();
}
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
credentials.getUsername(), credentials.getPassword(), new ArrayList<>());
Authentication auth = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
return auth;
}
#Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authResult) throws IOException, ServletException {
UserPrincipal principal = (UserPrincipal) authResult.getPrincipal();
String token = JWT.create()
.withSubject(principal.getUsername())
.withExpiresAt(new Date(System.currentTimeMillis() + JWTProperties.EXPIRATION_TIME))
.sign(HMAC512(JWTProperties.SECRET.getBytes()));
response.addHeader(JWTProperties.HEADER_STRING, JWTProperties.TOKEN_PREFIX + token);
}
}
JwtAuthorizationFilter class is here
package com.sumit.Security;
import static com.auth0.jwt.algorithms.Algorithm.HMAC512;
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.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import com.auth0.jwt.JWT;
import com.sumit.Repo.UserRepository;
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {
#Autowired
private UserRepository userRepository;
public JwtAuthorizationFilter(AuthenticationManager authenticationManager,UserRepository userRepository
) {
super(authenticationManager);
}
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
// Read the Authorization header, where the JWT token should be
String header = request.getHeader(JWTProperties.HEADER_STRING);
// If header does not contain BEARER or is null delegate to Spring impl and exit
if (header == null || !header.startsWith(JWTProperties.TOKEN_PREFIX)) {
chain.doFilter(request, response);
return;
}
// If header is present, try grab user principal from database and perform authorization
Authentication authentication = getUsernamePasswordAuthentication(request);
SecurityContextHolder.getContext().setAuthentication(authentication);
// Continue filter execution
chain.doFilter(request, response);
}
private Authentication getUsernamePasswordAuthentication(HttpServletRequest request) {
String token = request.getHeader(JWTProperties.HEADER_STRING)
.replace(JWTProperties.TOKEN_PREFIX,"");
if (token != null) {
// parse the token
String userName = JWT.require(HMAC512(JWTProperties.SECRET.getBytes()))
.build()
.verify(token)
.getSubject();
if (userName != null) {
User user = userRepository.findByUsername(userName);
UserPrincipal principal = new UserPrincipal(user);
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(userName, null, principal.getAuthorities());
return auth;
}
return null;
}
return null;
}
}
User registration process is working fine but authentication is not working because of above mentioned code.
I am using postman to verify it.
Don't know what trouble i am facing and totally frustrated.