permitAll() requires Authentication - spring

I'm having a go at developing a REST application with Spring and using JWT for authentication.
At the moment, what I'm trying to achieve is:
GET /api/subjects/* should be accessible to all users.
POST /api/subjects/* should only accessible to admin users.
The issue is that for both cases, the JWT filter gets invoked and I get an error response stating the JWT token is missing.
I've implemented my WebSecurityConfig as follows, including a JWT filter to replace the BasicAuthenticationFilter:
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
JWTAuthenticationEntryPoint authenticationEntryPoint;
#Autowired
JWTAuthenticationProvider jwtAuthenticationProvider;
#Override
public void configure(WebSecurity web) throws Exception {
//web.ignoring().antMatchers(HttpMethod.GET,"/api/subjects/*");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/api/subjects/*").permitAll()
.antMatchers(HttpMethod.POST, "/api/subjects/*").hasRole(Profile.Role.ADMIN.toString())
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterAt(authenticationTokenFilter(), BasicAuthenticationFilter.class)
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
}
public JWTAuthenticationFilter authenticationTokenFilter() {
return new JWTAuthenticationFilter(authenticationManager(), authenticationEntryPoint);
}
public ProviderManager authenticationManager() {
return new ProviderManager(new ArrayList<AuthenticationProvider>(Arrays.asList(jwtAuthenticationProvider)));
}
}
My implementation of JWTAuthenticationFilter is based on the implementation of BasicAuthenticationFilter:
public class JWTAuthenticationFilter extends OncePerRequestFilter {
private static final String JWT_TOKEN_START = "JWT ";
private AuthenticationManager authenticationManager;
private AuthenticationEntryPoint authenticationEntryPoint;
public JWTAuthenticationFilter(AuthenticationManager authenticationManager, AuthenticationEntryPoint authenticationEntryPoint) {
Assert.notNull(authenticationManager, "Authentication Manager must not be null");
Assert.notNull(authenticationEntryPoint, "Authentication Entry point must not be null");
this.authenticationManager = authenticationManager;
this.authenticationEntryPoint = authenticationEntryPoint;
}
#Override
protected void doFilterInternal(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
FilterChain filterChain) throws ServletException, IOException {
String header = httpServletRequest.getHeader("Authorization");
if (header == null || !header.startsWith(JWT_TOKEN_START)) {
throw new IllegalStateException("Header does not contain: \"Authorization\":\"JWT <token>\". Value: "+header);
}
try {
String jwt = header.substring(JWT_TOKEN_START.length()).trim().replace("<", "").replace(">", "");
JWTAuthenticationToken jwtAuthenticationToken = new JWTAuthenticationToken(jwt);
this.authenticationManager.authenticate(jwtAuthenticationToken);
filterChain.doFilter(httpServletRequest, httpServletResponse);
} catch (AuthenticationException auth) {
SecurityContextHolder.clearContext();
this.authenticationEntryPoint.commence(httpServletRequest, httpServletResponse, auth);
}
}
}
What is causing this issue?

Related

spring security fail authentication

I am a beginner with spring boot I want to implement authentication using spring security but when I send a request with postman to authenticate the authentication fails I did a debug and I see that the variable username and password equal a null I think that's the reason, I want to know why these 2 variables equal to null? can you help me
#Configuration
#EnableConfigurationProperties
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
#Autowired
UsersService userService;
#Autowired
PasswordEncoder passwordEncoder;
#Override
protected void configure(HttpSecurity http) throws Exception {
// TODO Auto-generated method stub
http.cors().and().csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.POST,"/add-users").permitAll()
.anyRequest()
.authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilter(new AuthenticationFilter(authenticationManagerBean(), userService));
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// TODO Auto-generated method stub
auth.userDetailsService(userService)
.passwordEncoder(passwordEncoder());
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
// TODO Auto-generated method stub
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter{
private String secretKey = "lpmppm";
private final AuthenticationManager authManager;
private final UsersService userservice;
public AuthenticationFilter(AuthenticationManager authManager, UsersService userservice) {
super();
this.authManager = authManager;
this.userservice = userservice;
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
// TODO Auto-generated method stub
String username=request.getParameter("username");
String password = request.getParameter("password");
UsernamePasswordAuthenticationToken authToken=new UsernamePasswordAuthenticationToken(username, password);
return authManager.authenticate(authToken);
}
#Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authResult) throws IOException, ServletException {
// TODO Auto-generated method stub
// super.successfulAuthentication(request, response, chain, authResult);
String token= Jwts.builder()
.setSubject(authResult.getName())
.claim("authorites", authResult.getAuthorities())
.setIssuedAt(new Date())
.setExpiration(java.sql.Date.valueOf(LocalDate.now().plusDays(3)))
.signWith(Keys.hmacShaKeyFor(secretKey.getBytes()))
.compact();
response.addHeader("Authorization","Bearer" + token);
}

Spring security: My Authorization filter authorizes my request even tho the URL is permited

In my security configuration class i have permitted the request to the welcome url and any other url which follows the "welcome/**" format.
this is my securityconfiguration class:
#EnableGlobalMethodSecurity(prePostEnabled = true)
//#Configuration
#EnableWebSecurity
public class JwtSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
private final CustomerDetailsService customerDetailsService;
#Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
#Autowired
public JwtSecurityConfiguration(CustomerDetailsService customerDetailsService) {
this.customerDetailsService = customerDetailsService;
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(customerDetailsService)
.passwordEncoder(passwordEncoderBean());
}
#Bean
public PasswordEncoder passwordEncoderBean() {
return new BCryptPasswordEncoder();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("**/resources/static/**")
.and()
.ignoring()
.antMatchers(
HttpMethod.GET,
"/",
"/*.html",
"/favicon.ico",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/index_assets/**"
);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/welcome/login").permitAll()
.antMatchers("/welcome").permitAll()
.antMatchers("/welcome/signup").permitAll()
.antMatchers("admin/rest/**").authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
//http.addFilterBefore(new JWTAuthenticationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class);
http.addFilterBefore(new JWTAuthorizationFilter(authenticationManager(),customerDetailsService),UsernamePasswordAuthenticationFilter.class);
// disable page caching
http
.headers()
.frameOptions().sameOrigin() // required to set for H2 else H2 Console will be blank.
.cacheControl();
//http.headers().cacheControl();
}
}
but I noticed that in my JWTAuthorizationFilter.class the doFilterInternal() method picks up this URL
public class JWTAuthorizationFilter extends OncePerRequestFilter {
private final CustomerDetailsService customerDetailsService;
#Autowired
DefaultCookieService defaultCookieService;
public JWTAuthorizationFilter(AuthenticationManager authenticationManager, CustomerDetailsService customerDetailsService) {
// super(authenticationManager);
this.customerDetailsService = customerDetailsService;
}
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String header = request.getHeader(HEADER);
if(Objects.isNull(header) || !header.startsWith(TOKEN_PREFIX)){
return;
}
UsernamePasswordAuthenticationToken usernamePasswordAuth = getAuthenticationToken(request);
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuth);
chain.doFilter(request,response);
}
private UsernamePasswordAuthenticationToken getAuthenticationToken(HttpServletRequest request){
String token = request.getHeader(HEADER);
if(Objects.isNull(token)) return null;
String username = Jwts.parser().setSigningKey(SECRET)
.parseClaimsJws(token.replace(TOKEN_PREFIX,""))
.getBody()
.getSubject();
UserDetails userDetails = customerDetailsService.loadUserByUsername(username);
return username != null ? new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()) : null;
}
}
What is the cause of this ?
Filter is suppose to pick up each and every request. It doesn't matter if that you have permitted or not in security configuration.
You have got two options:
If you don't want welcome/** to go through the filter you add it to web ignore
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("**/resources/static/**")
.and()
.ignoring()
.antMatchers(
HttpMethod.GET,
"/",
"/*.html",
"/favicon.ico",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/index_assets/**",
"/welcome/**"
);
}
But note, it will skip all filters and you may not want that.
In doFilterInternal method skip it when you find welcome/** pattern.

Spring security using JWT, how to exclude certain endpoints like /login from being authenticated using JwtAuthenticationFilter?

I want to exclude /login url from being authenticated by spring security.
My configuration class looks like'
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().authorizeRequests().antMatchers("/v1/pricing/login").permitAll()
.antMatchers("v1/pricing/**").authenticated().and()
.addFilterBefore(corsFilter,UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/v1/pricing/login");
}
JwtAuthenticationFilter looks like
- commented the exception part, as it starts throwing exception in login also
#Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
#Autowired
JwtTokenProvider jwtTokenProvider;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String jwt = getJwtFromRequest(request);
if (StringUtils.hasText(jwt) && jwtTokenProvider.validateToken(jwt)) {
String[] userInfo = jwtTokenProvider.getUserDetailsFromJWT(jwt);
UserDetails userDetails = new UserPrincipal(Long.parseLong(userInfo[0]), userInfo[1], userInfo[2], null,
userInfo[3]);
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(userDetails, null, null);
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
filterChain.doFilter(request, response);
}
private String getJwtFromRequest(HttpServletRequest request) {
String token = request.getHeader("Authorization");
if (StringUtils.hasText(token)) {
return token;
} /*else {
throw new AuthenticationServiceException("Authorization header cannot be blank!");
}*/
return null;
}
}
Any request with /v1/pricing/login still goes to JWtAuthentication filter and fails.
JwtTokenAuthenticationProcessingFilter filter is configured to skip following endpoints: /api/auth/login and /api/auth/token. This is achieved with SkipPathRequestMatcher implementation of RequestMatcher.
public class SkipPathRequestMatcher implements RequestMatcher {
private OrRequestMatcher matchers;
private RequestMatcher processingMatcher;
public SkipPathRequestMatcher(List<String> pathsToSkip, String processingPath) {
Assert.notNull(pathsToSkip);
List<RequestMatcher> m = pathsToSkip.stream().map(path -> new AntPathRequestMatcher(path)).collect(Collectors.toList());
matchers = new OrRequestMatcher(m);
processingMatcher = new AntPathRequestMatcher(processingPath);
}
#Override
public boolean matches(HttpServletRequest request) {
if (matchers.matches(request)) {
return false;
}
return processingMatcher.matches(request) ? true : false;
}
}
Then call :
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
public static final String JWT_TOKEN_HEADER_PARAM = "X-Authorization";
public static final String FORM_BASED_LOGIN_ENTRY_POINT = "/api/auth/login";
public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/api/**";
public static final String TOKEN_REFRESH_ENTRY_POINT = "/api/auth/token";
protected JwtTokenAuthenticationProcessingFilter buildJwtTokenAuthenticationProcessingFilter() throws Exception {
List<String> pathsToSkip = Arrays.asList(TOKEN_REFRESH_ENTRY_POINT, FORM_BASED_LOGIN_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();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(ajaxAuthenticationProvider);
auth.authenticationProvider(jwtAuthenticationProvider);
}
#Bean
protected BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable() // We don't need CSRF for JWT based authentication
.exceptionHandling()
.authenticationEntryPoint(this.authenticationEntryPoint)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(FORM_BASED_LOGIN_ENTRY_POINT).permitAll() // Login end-point
.antMatchers(TOKEN_REFRESH_ENTRY_POINT).permitAll() // Token refresh end-point
.antMatchers("/console").permitAll() // H2 Console Dash-board - only for testing
.and()
.authorizeRequests()
.antMatchers(TOKEN_BASED_AUTH_ENTRY_POINT).authenticated() // Protected API End-points
.and()
.addFilterBefore(buildAjaxLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(buildJwtTokenAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class);
}
}

Handling OPTIONS and CORS when using a sign in filter instead of controller

I've got an AbstractAuthenticationProcessingFilter that I'm using to handle POST requests at path /sign-in. CORS preflight requests are coming back 404 because there is no path that matches. This makes sense to me.
What I would like to know is if there is a way to inform Spring that there is a filter handling the POST (rather than a controller), so that Spring can dispatch the OPTIONS in the same way it would if a controller were handling the POST. Would it be bad practice to write a controller with one PostMapping? I'm not sure how that would behave since technically the filter handles the POST.
Thanks for your help!
Update
Here's my setup. I originally posted from my phone so wasn't able to add these details then. See below. To reiterate, there is no controller for /sign-in. The POST is handled by the JwtSignInFilter.
CORS Config
#EnableWebMvc
#Configuration
public class CorsConfig extends WebMvcConfigurerAdapter {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*") // TODO: Lock this down before deploying
.allowedHeaders("*")
.allowedMethods(HttpMethod.GET.name(), HttpMethod.POST.name(), HttpMethod.DELETE.name())
.allowCredentials(true);
}
}
Security Config
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public JwtSignInFilter signInFilter() throws Exception {
return new JwtSignInFilter(
new AntPathRequestMatcher("/sign-in", HttpMethod.POST.name()),
authenticationManager()
);
}
#Bean
public JwtAuthenticationFilter authFilter() {
return new JwtAuthenticationFilter();
}
#Autowired
private UserDetailsService userDetailsService;
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers(HttpMethod.POST, "/sign-in").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(
signInFilter(),
UsernamePasswordAuthenticationFilter.class
)
.addFilterBefore(
authFilter(),
UsernamePasswordAuthenticationFilter.class
);
}
}
Sign In Filter
public class JwtSignInFilter extends AbstractAuthenticationProcessingFilter {
#Autowired
private TokenAuthenticationService tokenAuthService;
public JwtSignInFilter(RequestMatcher requestMatcher, AuthenticationManager authManager) {
super(requestMatcher);
setAuthenticationManager(authManager);
}
#Override
public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException, IOException, ServletException {
SignInRequest creds = new ObjectMapper().readValue(
req.getInputStream(),
SignInRequest.class
);
return getAuthenticationManager().authenticate(
new UsernamePasswordAuthenticationToken(
creds.getEmail(),
creds.getPassword(),
emptyList()
)
);
}
#Override
protected void successfulAuthentication(
HttpServletRequest req,
HttpServletResponse res, FilterChain chain,
Authentication auth) throws IOException, ServletException {
tokenAuthService.addAuthentication(res, auth.getName());
}
}
Authentication Filter
public class JwtAuthenticationFilter extends GenericFilterBean {
#Autowired
private TokenAuthenticationService tokenAuthService;
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
Authentication authentication = tokenAuthService.getAuthentication((HttpServletRequest)request);
SecurityContextHolder
.getContext()
.setAuthentication(authentication);
filterChain.doFilter(request, response);
}
}
Alright, finally found out how to fix this. After hours of tinkering and searching, I found that I needed to use a filter-based CORS configuration and then handle CORS preflights (OPTIONS requests) in the sign-in filter by simply returning 200 OK. The CORS filter will then add appropriate headers.
Updated configuration below (note that my CorsConfig is no longer needed, since we have a CORS filter in SecurityConfig, and JwtAuthenticationFilter is the same as before).
Security Config
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*"); // TODO: lock down before deploying
config.addAllowedHeader("*");
config.addExposedHeader(HttpHeaders.AUTHORIZATION);
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
#Bean
public JwtSignInFilter signInFilter() throws Exception {
return new JwtSignInFilter(
new AntPathRequestMatcher("/sign-in"),
authenticationManager()
);
}
#Bean
public JwtAuthenticationFilter authFilter() {
return new JwtAuthenticationFilter();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf().disable()
.authorizeRequests()
.antMatchers("/sign-in").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(
signInFilter(),
UsernamePasswordAuthenticationFilter.class
)
.addFilterBefore(
authFilter(),
UsernamePasswordAuthenticationFilter.class
);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
#Autowired
private UserDetailsService userDetailsService;
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Sign In Filter
public class JwtSignInFilter extends AbstractAuthenticationProcessingFilter {
#Autowired
private TokenAuthenticationService tokenAuthService;
public JwtSignInFilter(RequestMatcher requestMatcher, AuthenticationManager authManager) {
super(requestMatcher);
setAuthenticationManager(authManager);
}
#Override
public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException, IOException, ServletException {
if (CorsUtils.isPreFlightRequest(req)) {
res.setStatus(HttpServletResponse.SC_OK);
return null;
}
if (!req.getMethod().equals(HttpMethod.POST.name())) {
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
return null;
}
SignInRequest creds = new ObjectMapper().readValue(
req.getInputStream(),
SignInRequest.class
);
return getAuthenticationManager().authenticate(
new UsernamePasswordAuthenticationToken(
creds.getEmail(),
creds.getPassword(),
emptyList()
)
);
}
#Override
protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain, Authentication auth) throws IOException, ServletException {
tokenAuthService.addAuthentication(res, auth.getName());
}
}

PermitAll not working in Spring Security

I have two rules, the first one every url from oauth/** should be without security and and other url have to security. But now all urls are secure include url from oauth/**.
This is my security config rule.
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// JWT dont need CSRF
httpSecurity.csrf().disable().exceptionHandling().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()
.antMatchers("oauth/**").permitAll().and()
.addFilterBefore(new JwtAuthenticationTokenFilter(), BasicAuthenticationFilter.class);
// disable page caching
httpSecurity.headers().cacheControl();
}
}
when I request the url http://localhost:8080/oauth/fb that is enter my JwtAuthenticationTokenFilter, and I want this url don't enter this filter.
You can override configure method with WebSecurity parameter.
#Override
public void configure(final WebSecurity web) throws Exception
{
web.ignoring().antMatchers("oauth/**");
}
This method should be used when serving static content such as css/* js/*, suggested in the documentation, however I couldn't find another way to permit URL mapping with custom filter in Spring Security.
<security:http pattern="/support/**" security="none"/>
You would probably need to write the Java equivalent of the above XML configuration. Basically, you are setting a new filter chain with no security for the above pattern.
I faced a similar problem. My security config:
// ... imports
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final UserDetailsService userDetailsService;
private final PasswordEncoder passwordEncoder;
private final JwtFilter jwtFilter;
#Autowired
public SecurityConfig(#Qualifier("userDetailsServiceImpl") UserDetailsService userDetailsService,
PasswordEncoder passwordEncoder,
JwtProvider jwtProvider) {
this.userDetailsService = userDetailsService;
this.passwordEncoder = passwordEncoder;
this.jwtFilter = new JwtFilter(jwtProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.httpBasic().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/auth/**").permitAll()
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(daoAuthenticationProvider());
}
protected DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(passwordEncoder);
return provider;
}
}
And my security filter:
// ... imports
public class JwtFilter extends GenericFilterBean {
public static final String AUTHORIZATION_HEADER = "Authorization";
public static final String TOKEN_PREFIX = "Bearer ";
public static final int TOKEN_START_POSITION = 7;
private final JwtProvider jwtProvider;
#Autowired
public JwtFilter(JwtProvider jwtProvider) {
this.jwtProvider = jwtProvider;
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
String token = getTokenFromRequest((HttpServletRequest) servletRequest);
if (token != null && jwtProvider.validateToken(token)) {
Map<String, Object> properties = jwtProvider.getUserPropertiesFromToken(token);
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
properties.get("login"),
null,
(Set<GrantedAuthority>) properties.get("authirities"));
SecurityContextHolder.getContext().setAuthentication(auth);
}
filterChain.doFilter(servletRequest, servletResponse);
}
private String getTokenFromRequest(HttpServletRequest request) {
String bearer = request.getHeader(AUTHORIZATION_HEADER);
if (bearer != null && bearer.startsWith(TOKEN_PREFIX)) {
return bearer.substring(TOKEN_START_POSITION);
}
return null;
}
}
The reason my code didn't work for me was that I skipped the line filterChain.doFilter(servletRequest, servletResponse); in my filter, i.e. I didn't pass on the request and response to the next entity in the chain.

Resources