Spring Boot CORS configuration is not accepting authorization header - spring

Angular2 app is sending a HTTP GET request with X-AUTH-TOKEN header value to the Spring Boot. Every time request.getHeader("X-AUTH-TOKEN") returns null.
Interestingly it works fine if I send the request from ARC client or any other rest client.
I have also spent a great amount of time making sure that Angular HTTP GET request is sending JWT token.
Angular code
getCandidatesByUserId(userId: number): Observable<Candidate[]> {
let headers = new Headers({ 'X-AUTH-TOKEN': 'let-jwt-test-token-in' });
console.log('Token is '+ headers.get('X-AUTH-TOKEN'));
return this.http.get(this.url+userId+'/candidates', {
headers: headers
})
.map((response: Response) => <Candidate[]> response.json())
.do(data => console.log('All: '+ JSON.stringify(data)))
.catch(this.handleError);
}
JWTFilter
#Override
public void doFilter(ServletRequest request, ServletResponse res, FilterChain filterChain)
throws IOException, ServletException {
try {
final HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "X-AUTH-TOKEN, Content-Type, Accept");
response.setHeader("Access-Control-Expose-Headers", "X-AUTH-TOKEN, Content-Type");
HttpServletRequest httpRequest = (HttpServletRequest) request;
Map<String, String> blackListedTokenMap =
(Map<String, String>) ((HttpServletRequest) request)
.getSession()
.getServletContext()
.getAttribute(WebAppListener.TOKEN_BLACK_LIST_MAP);
String authToken = authenticationService.getToken(httpRequest);
if (authToken != null && blackListedTokenMap.containsValue(authToken)) {
throw new RuntimeException("token invalidated");
}
UserAuthentication authentication = (UserAuthentication) authenticationService.getAuthentication(httpRequest);
SecurityContextHolder.getContext().setAuthentication(authentication);
filterChain.doFilter(request, response);
SecurityContextHolder.getContext().setAuthentication(null);
} catch (RuntimeException e) {
((HttpServletResponse) res).sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
SpringSecurityConfig
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.csrfTokenRepository(new HttpSessionCsrfTokenRepository())
.requireCsrfProtectionMatcher(new AntPathRequestMatcher("*/*"));
http
.exceptionHandling()
.and()
.anonymous()
.and()
.servletApi()
.and()
.headers()
.cacheControl();
http
//.addFilterBefore(corsFilter, ChannelProcessingFilter.class)
.authorizeRequests()
.antMatchers("/resources/**").permitAll()// allow for static resources
.antMatchers("/signup").permitAll()
.antMatchers("/forgot").permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/reset").permitAll()
.antMatchers("/health").permitAll()
.antMatchers("/hello").permitAll()
.antMatchers("/").permitAll()
.antMatchers("/reset_pw").permitAll()
.anyRequest().authenticated()
.and()
.addFilterAfter(new JJWTFilter(tokenAuthenticationService),
UsernamePasswordAuthenticationFilter.class);
}
Console Logs

I resolved with :
//Define class with this annotation
#Configuration
public class CorsConfig {
#Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
source.registerCorsConfiguration("/**", config);
// return new CorsFilter(source);
final FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
#Bean
public WebMvcConfigurer mvcConfigurer() {
return new WebMvcConfigurerAdapter() {
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("GET", "PUT", "POST", "GET", "OPTIONS");
}
};
}
}
You can define this class and add in your boot spring class #ComponentScan(basePackageClasses= CorsConfig.class)
Or just use the above method inside the boot class.
Then should work.

Related

Spring Authorization Server 0.3.1 CORS issue

i created an authorization server using spring-auth-server 0.3.1, and implemented the Authorization code workflow, my issue is that when my front end -springdoc- reaches the last step i get a 401 and this is what's logged into browser console :
Access to fetch at 'http://authorization-server:8080/oauth2/token' from origin 'http://client:8081' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
i'm using spring boot 2.6.12 and here is my CORS configuration for authorization server (also copy pasted it to the client in case ):
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration {
private final Set<String> allowedOrigins;
#Autowired
public WebSecurityConfiguration(
#Value("${spring.security.cors.allowed-origins:*}") List<String> allowedOrigins) {
this.allowedOrigins = new LinkedHashSet<>(allowedOrigins);
}
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.cors().configurationSource(corsConfigurationSource())
.and()
.csrf().disable() // without session cookies we do not need this anymore
.authorizeRequests().anyRequest().permitAll();
return http.build();
}
private CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
boolean useAllowedOriginPatterns = allowedOrigins.isEmpty() || allowedOrigins.contains("*");
if (useAllowedOriginPatterns) {
configuration.setAllowedOriginPatterns(Collections.singletonList(CorsConfiguration.ALL));
} else {
configuration.setAllowedOrigins(new ArrayList<>(allowedOrigins));
}
configuration.setAllowedMethods(Collections.singletonList(CorsConfiguration.ALL));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Collections.singletonList(CorsConfiguration.ALL));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
and here are my security filter chain for the Auth server :
#Order(1)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
return http.formLogin(Customizer.withDefaults()).build();
}
#Bean
#Order(2)
public SecurityFilterChain standardSecurityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults());
return http.build();
}
Any idea on what i'm missing ?
If your backend and your app are not running on the same address your browser does normally not allow you to call your backend. This is intended to be a security feature.
To allow your browser to call your api add the Access-Control-**** headers to your backend response (when answering from Spring).
please add the below line in your header
Access-Control-Allow-Origin: *
here is an tutorial also, please visit here on spring.io
i solved it by dropping the corsconfiguration from filter chain bean and creating a filter instead.
'''
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCORSFilter implements Filter {
private final Set<String> allowedOrigins;
#Autowired
public SimpleCORSFilter(#Value("${spring.security.cors.allowed-origins:*}") Set<String> allowedOrigins) {
this.allowedOrigins = allowedOrigins;
}
#Override
public void init(FilterConfig fc) throws ServletException {
}
#Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) resp;
HttpServletRequest request = (HttpServletRequest) req;
String origin = request.getHeader("referer");
if(origin != null ){
Optional<String> first = allowedOrigins.stream().filter(origin::startsWith).findFirst();
first.ifPresent(s -> response.setHeader("Access-Control-Allow-Origin", s));
}
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, resp);
}
}
#Override
public void destroy() {
}
}
'''

Cross-Origin API Spring boot Security [duplicate]

This question already has answers here:
CORS issue - No 'Access-Control-Allow-Origin' header is present on the requested resource
(8 answers)
Closed 6 months ago.
I'm trying to call a secure Resource. I use #CrossOrigin(origins = "*") in all rest controllers. But I get cross origin error
I can't call "http://localhost:8081/ifrs/api/v1/period" with "GET" method But I can call "getJwtToken" because it's not scure.
my config is:
#Configuration
public class SecuirtyConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtFilter jwtFilter;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().and()
.csrf().disable()
.authorizeRequests()
.antMatchers("/ifrs/api/v1/user/token").permitAll()
.anyRequest().authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
;
http.exceptionHandling().authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder getPasswordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
and JWT config:
#Component
public class JwtFilter extends OncePerRequestFilter {
#Autowired
private JwtUtils jwtUtils;
#Autowired
private UserDomainService userDomainService;
#Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
try {
String token = request.getHeader("Authorization");
String jwtToken = null;
if ( token != null ) {
if ( token.startsWith("Bearer ") ) {
jwtToken = token.replace("Bearer ", "");
String username = jwtUtils.getUsername(jwtToken);
username = username.trim();
// isUserAuthentication
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (username != null && authentication == null) {
User user = (User) userDomainService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
} else if ( token.startsWith("Basic ") ) {
jwtToken = token.replace("Basic ", "");
Base64 codec = new Base64();
byte[] decoded = codec.decode(jwtToken);
String[] userAndPass = new String(decoded).split(":");
String username = userAndPass[0];
String password = userAndPass[1];
request.setAttribute("username", username);
request.setAttribute("password", password);
}
}
filterChain.doFilter(request, response);
} catch (ExpiredJwtException e) {
throw e;
} catch (Exception e) {
throw e;
}
}
}
I test all ways to fix it. #CrossOrigin(origins = "*") is only working for not secure Resources. how to fixe it?
thanks
I changed my code
class SecuirtyConfig --> corsConfigurationSource :
#Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.addAllowedHeader("*"); // new Line
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
and configure(HttpSecurity http) :
.cors().and()
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.antMatchers("/ifrs/api/v1/user/token").permitAll()
thanks

Spring Boot : CORS Issue

I am using Spring Boot version 2.0.2Release.
Below is my security configuration
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(
prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true)
#ComponentScan("com.mk")
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AuthenticationProvider myAuthenticationProvider;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.cors().configurationSource(corsConfigurationSource())
.and()
.csrf().disable()
.anonymous().and()
.authorizeRequests()
.antMatchers(HttpMethod.GET,"/index.html").permitAll()
.antMatchers(HttpMethod.POST,"/login").permitAll()
.antMatchers(HttpMethod.GET,"*").authenticated()
.and().httpBasic();
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
I am unable to invoke any API (including login which is permitAll) because of CORS issue.
On Browser I am getting (It works with Postman, since CORS check is not made there)
Failed to load http://localhost:8080/myurl: Response to preflight
request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:4200' is therefore not allowed
access. The response had HTTP status code 403.
Although Spring security provides a way to configure CORS in http configurer, there's a much cleaner approach to add CORS filter to the application-
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class MyCORSFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");
chain.doFilter(req, res);
}
#Override
public void init(FilterConfig filterConfig) {
}
#Override
public void destroy() {
}
}
Ordering the filter with highest precedence makes sure that MyCORSFilter implementation of javax.servlet.Filter is the first one in the chain. Hope this helps
Checkout this guide from Spring:
https://spring.io/guides/gs/rest-service-cors/
There are few ways to add CORS support in Spring Boot.
Using global configuration:
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/greeting-javaconfig").allowedOrigins("http://localhost:9000");
}
};
}
And using #CrossOrigin annotation:
#CrossOrigin(origins = "http://localhost:9000")
#GetMapping("/greeting")
public Greeting greeting(#RequestParam(required=false, defaultValue="World") String name) {
System.out.println("==== in greeting ====");
return new Greeting(counter.incrementAndGet(), String.format(template, name));
}
There is no need of adding any additional Filters or WebMvcConfigurer. The main problem is 'Access-Control-Allow-Origin' does not present in the header because corsConfigurationSource does not add the necessary configuration to get the relevant CORS response headers. Hence, the below missing configurations have to be added when we configure CorsConfigurationSource
configuration.addAllowedOrigin("*");
configuration.addAllowedHeader("*");
configuration.addAllowedMethod("*");
We have to configure cors CorsConfigurationSource as below
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.cors().configurationSource(corsConfigurationSource())
.and()
.....
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
configuration.setAllowCredentials(true);
//the below three lines will add the relevant CORS response headers
configuration.addAllowedOrigin("*");
configuration.addAllowedHeader("*");
configuration.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
If anyone facing CORS issue with Spring Boot 2.4.0 plus versions when having the following combination then refer to answer
CorsConfigurationSource#setAllowedOrigins value as *
and
CorsConfigurationSource#setAllowCredentials value as true
Ok, so I realized that it was deprecated. If you look on baeldung it has how to do it the new way since they updated webmvcconfigurer:
#Configuration
#EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("*").allowedOrigins(frontDomain);
}
}

Angular 6 Http Interceptors, request headers not modified

I created an interceptor to add an authorization header to each request sent by the client, here is the code :
import { HttpInterceptor, HttpRequest, HttpHandler, HttpHeaderResponse, HttpSentEvent, HttpProgressEvent, HttpResponse, HttpUserEvent, HttpEvent, HttpHeaders } from "#angular/common/http";
import { Observable } from "rxjs";
import { Injectable } from "#angular/core";
#Injectable()
export class AuthenticationInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
console.log(localStorage.getItem('jwtToken'));
if(localStorage.getItem('jwtToken')){
const request = req.clone({
setHeaders: {
Authorization: `bearer ${localStorage.getItem('jwtToken')}`
}
});
console.log(request.headers.get("Authorization"));
return next.handle(request);
}
return next.handle(req);
}
}
When a request is sent the function intercept is called and the authorization header is correclty set with the token value in the variable "request" as you can see there :
token console screenshot
But the authorization header doesn't appear in the request sent by my browser : network request headers and the backend cannot resolve the token.
Do you know why ?
Here is my spring config:
WebSecurityConfig.java
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
public final static String AUTHORIZATION_HEADER = "Authorization";
#Autowired
UserService userService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(getProvider());
}
#Bean
public JwtTokenFilter jwtAuthenticationFilter() {
return new JwtTokenFilter();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/auth/**")
.permitAll()
.anyRequest()
.authenticated();
}
#Bean
public AuthenticationProvider getProvider() {
AppAuthProvider provider = new AppAuthProvider();
provider.setUserDetailsService(userService);
return provider;
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
CorsConfig.java
#Configuration
public class CorsConfiguration {
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:4200")
.allowedMethods("*")
.allowedHeaders("*");
}
};
}
}
Your problem resides into backend services. For security reasons by default only some headers are accepted, the others are ignored.
To fix your problem you need to setup custom accepted headers. Authorization header, even if is like a standard for JWT, is considered a custom header.
I can give you an example of my Spring Security configuration:
#Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("GET");
config.addAllowedMethod("POST");
config.addAllowedMethod("PUT");
config.addAllowedMethod("DELETE");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
Note the line
config.addAllowedHeader("*");
That means that my REST services accept all possible headers sent by the client.
Obviously it's not a good configuration, you should limit allowed headers and other things to match your needs, as restricted as is possible.
Obviously if you don't use Spring Security you need to find the way to do the same thing with yout language/framework.
This is my SecurityConfig.java It's a bit different from yours.
Try this and let me know
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
#Autowired
private JwtTokenUtil jwtTokenUtil;
#Autowired
private WLUserDetailsService userDetailsService;
#Value("${jwt.header}")
private String tokenHeader;
#Value("${jwt.route.authentication.path}")
private String authenticationPath;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoderBean());
}
#Bean
public PasswordEncoder passwordEncoderBean() {
return new BCryptPasswordEncoder();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
// we don't need CSRF because our token is invulnerable
.csrf().disable()
// TODO adjust CORS management
.cors().and()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
// don't create session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/auth/**").permitAll()
.anyRequest().authenticated();
// Custom JWT based security filter
JwtAuthorizationTokenFilter authenticationTokenFilter = new JwtAuthorizationTokenFilter(userDetailsService(), jwtTokenUtil, tokenHeader);
httpSecurity
.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
// // disable page caching
// httpSecurity
// .headers()
// .frameOptions().sameOrigin() // required to set for H2 else H2 Console will be blank.
// .cacheControl();
}
#Override
public void configure(WebSecurity web) {
// AuthenticationTokenFilter will ignore the below paths
web
.ignoring()
.antMatchers(
HttpMethod.POST,
authenticationPath
)
// allow anonymous resource requests
.and()
.ignoring()
.antMatchers(
HttpMethod.GET,
"/",
"/*.html",
"/favicon.ico",
"/**/*.html",
"/**/*.css",
"/**/*.js"
);
}
#Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
// config.addExposedHeader("Authorization, x-xsrf-token, Access-Control-Allow-Headers, Origin, Accept, X-Requested-With, " +
// "Content-Type, Access-Control-Request-Method, Custom-Filter-Header");
config.addAllowedHeader("*");
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("GET");
config.addAllowedMethod("POST");
config.addAllowedMethod("PUT");
config.addAllowedMethod("DELETE");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}

I am getting null header value in spring security REST implementation

I am using jersey , spring boot and spring security to create rest web service.
Which will be consumed by angular 2 client.
Client is sending authorization header in request , But on server i am not receiving any header value. I am using jersey for web service resource also using spring security authentication and authorization.
Kindly help.
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
#Autowired
private CustomUserDetailsService userDetailService;
public SecurityConfiguration(CustomUserDetailsService userDetailService) {
this.userDetailService = userDetailService;
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/assets/**")
.and().ignoring().antMatchers("/app/**")
.and().ignoring().antMatchers("/opas/Payment/**") ;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.cors();
http.authorizeRequests()
.antMatchers(HttpMethod.POST, SIGN_UP_URL).permitAll()
.antMatchers(HttpMethod.POST, "/login").permitAll()
.and().authorizeRequests().antMatchers("/opas/common/**").permitAll()
.and().authorizeRequests().antMatchers("/opas/register/**").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(new CORSFilter(), ChannelProcessingFilter.class)
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailService);
}
#Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(ImmutableList.of("*"));
configuration.setAllowedMethods(ImmutableList.of("HEAD","GET", "POST", "PUT", "DELETE", "PATCH","OPTIONS"));
// setAllowCredentials(true) is important, otherwise:
// The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
configuration.setAllowCredentials(true);
// setAllowedHeaders is important! Without it, OPTIONS preflight request
// will fail with 403 Invalid CORS request
configuration.setAllowedHeaders(ImmutableList.of("Authorization", "Cache-Control", "Content-Type","X-Requested-With"));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
I am getting null header value in following code
public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
public JWTAuthorizationFilter(AuthenticationManager authManager) {
super(authManager);
}
#Override
protected void doFilterInternal(HttpServletRequest req,
HttpServletResponse res,
FilterChain chain) throws IOException, ServletException {
String header = req.getHeader(HEADER_STRING);
if (header == null || !header.startsWith(TOKEN_PREFIX)) {
chain.doFilter(req, res);
return;
}
try {
UsernamePasswordAuthenticationToken authentication = getAuthentication(req);
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(req, res);
}
catch (ExpiredJwtException eje) {
// TODO: handle exception
ResponseMessage responseMessage = new ResponseMessage();
responseMessage.setStatusCode(DomainConstants.FORBIDDEN_ERROR);
responseMessage.setMessage(DomainConstants.SESSION_EXPIRED);
Gson gson = new Gson();
res.getWriter().write(gson.toJson(responseMessage));
}
}
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request)throws ExpiredJwtException {
String token = request.getHeader(HEADER_STRING);
if (token != null) {
// parse the token.
String user = Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token.replace(TOKEN_PREFIX, ""))
.getBody()
.getSubject();
if (user != null) {
return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
}
return null;
}
return null;
}}
in latest versions of spring, if your header value equal to null, you get NullPointerException in spring security. maybe for your case you need to remove it with HttpServletResponseWrapper like this post

Resources