I use the Spring framework. If I send a request using postman, I get the authorization header, but if I use Axois I don't get it. What is the problem?
Axois send:
axios({
method: 'get',
url: 'http://localhost:8081/api/posts',
headers: { 'Authorization': 'Bearer_' + localStorage.getItem("username")} // Cookies.get('Token')
})
Cors in spring
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedHeaders("*")
.exposedHeaders("Authorization", "authorization")
.allowedOrigins("*")
.allowedMethods("*")
.allowCredentials(false).maxAge(3600);;
}
Spring security config:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().disable()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(LOGIN_ENDPOINT, REGISTRATION_ENDPOINT).permitAll()
.antMatchers(ADMIN_ENDPOINT).hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.apply(new JwtConfigurer(jwtTokenProvider));
}
Get the headers here:
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) req;
Map<String, List<String>> headersMap = Collections.list(httpRequest.getHeaderNames())
.stream()
.collect(Collectors.toMap(
Function.identity(),
h -> Collections.list(httpRequest.getHeaders(h))
));
Postman request
Headers with postman
Headers with Axios
I added Bean:
#Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new
UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config.applyPermitDefaultValues());
return source;
}
Related
Is it possible that if AndRequestMatcher which checks if url is orders/notify and request comes from proper IP return 403? Below configuration always passes which shouldnt if IP address don't match.
#Override
public void configure(HttpSecurity http) throws Exception {
AntPathRequestMatcher antRequestMatcher = new AntPathRequestMatcher("/orders/notify/**", HttpMethod.POST.name());
AndRequestMatcher andMatcher = new AndRequestMatcher(new HeaderIPAddressRequestMatcher(ips), antRequestMatcher);
http.cors()
.and()
.httpBasic().disable()
.csrf().disable()
.formLogin().disable()
.logout().disable()
.sessionManagement().disable()
.authorizeRequests()
.requestMatchers(andMatcher).permitAll()
.anyRequest().permitAll();
http.headers()
.httpStrictTransportSecurity().maxAgeInSeconds(YEAR.toSeconds()).includeSubDomains(false);
}
I achieve it by creating custom filter:
public class IPHeaderFilter implements Filter {
private final List<String> ips;
public IPHeaderFilter(List<String> ips) {
this.ips = ips;
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
var request = (HttpServletRequest) servletRequest;
var response = (HttpServletResponse) servletResponse;
AntPathRequestMatcher antRequestMatcher = new AntPathRequestMatcher("/orders/notify/**", HttpMethod.POST.name());
if (antRequestMatcher.matches(request)) {
HeaderIPAddressRequestMatcher ipHeaderMatcher = new HeaderIPAddressRequestMatcher(ips);
if (!ipHeaderMatcher.matches(request)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
} else {
chain.doFilter(request, response);
}
} else {
chain.doFilter(request, response);
}
}
}
After deploy I got problem with CORS. I can access data directly from my API but when trying fetch it from React app I got problem as in an image:
I tried to add filters to add to every header Access-Control-Allow-Origin and it now return data from API and I can see it in browsers console but react cant get it
WebSecurity.java
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and();
http.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and();
http.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/test/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
#Bean
public FilterRegistrationBean crosFilterRegistration(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean(new MyCorsFilter());
registrationBean.setName("CORS Filter");
registrationBean.addUrlPatterns("/*");
registrationBean.setOrder(1);
return registrationBean;
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Collections.singletonList("https://*************"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS"));
configuration.setAllowedHeaders(Arrays.asList("Access-Control-Allow-Headers", "Access-Control-Allow-Origin",
"Access-Control-Request-Method", "Access-Control-Request-Headers", "Origin",
"Cache-Control", "Content-Type"));
configuration.setAllowCredentials(true);
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
MyCorseFiltre.java
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class MyCorsFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
final HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "https://**************");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, HEAD, OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
response.setHeader("Access-Control-Max-Age", "3600");
if ("OPTIONS".equalsIgnoreCase(((HttpServletRequest) req).getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
#Override
public void destroy() {
}
#Override
public void init(FilterConfig config) throws ServletException {
}
}
Application.java
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("https://*************");
}
};
}
This row
response.setHeader("Access-Control-Allow-Origin", "https://**************");
adds the duplicated header. So does this row:
configuration.setAllowedOrigins(Collections.singletonList("https://*************"));
One of them is enough. Preferably the latter. The same goes for most of the CORS config you have.
I'm trying to configure spring security and controller CORS requests, but the preflight request is not working. I have a controller, test, and spring security config which are related to the problem. What I'm doing wrong?)
Java 8, Spring Boot 2.1.4
Controller
#RestController
#RequestMapping("/login")
#CrossOrigin
public class LoginController {
#RequestMapping(path = "/admin", consumes = "application/json", produces = "application/json")
public ResponseEntity<Admin> loginAdmin(#RequestBody Admin admin) {
String username = admin.getUsername();
String password = admin.getPassword();
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
ResponseEntity<Admin> responseEntity;
Admin foundAdmin = adminRepository.findByUsername(username);
if (foundAdmin != null) {
String token = jwtTokenProvider.createToken(username, adminRepository.findByUsername(username).getRoles());
AdminAuthenticatedResponse contractorAuthenticatedResponse = new AdminAuthenticatedResponse(foundAdmin, token);
responseEntity = new ResponseEntity<>(contractorAuthenticatedResponse, HttpStatus.ACCEPTED);
} else {
responseEntity = new ResponseEntity<>(admin, HttpStatus.NOT_FOUND);
}
return responseEntity;
}
}
Security config
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().disable()
.csrf().disable()
.cors().and().formLogin().and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/login/**").permitAll()
.antMatchers("/register/**").permitAll()
.antMatchers("/h2-console/**").permitAll()
.antMatchers(HttpMethod.GET, "/restapi/customers/**").permitAll()
.antMatchers(HttpMethod.DELETE, "/restapi/customers/**").hasRole("CUSTOMER")
.antMatchers(HttpMethod.PUT, "/restapi/customers/**").hasRole("CUSTOMER")
.antMatchers(HttpMethod.PATCH, "/restapi/customers/**").hasRole("CUSTOMER")
.antMatchers(HttpMethod.GET, "/restapi/contractors/**").permitAll()
.antMatchers(HttpMethod.DELETE, "/restapi/contractors/**").hasRole("CONTRACTOR")
.antMatchers(HttpMethod.PUT, "/restapi/contractors/**").hasRole("CONTRACTOR")
.antMatchers(HttpMethod.PATCH, "/restapi/contractors/**").hasRole("CONTRACTOR")
.antMatchers(HttpMethod.PATCH, "/restapi/workRequests/**").hasAnyRole("CONTRACTOR", "CONTRACTOR", "ADMIN")
.antMatchers(HttpMethod.PUT, "/restapi/workRequests/**").hasAnyRole("CONTRACTOR", "CONTRACTOR", "ADMIN")
.antMatchers(HttpMethod.POST, "/restapi/workRequests/**").hasAnyRole("CONTRACTOR", "CONTRACTOR", "ADMIN")
.antMatchers(HttpMethod.DELETE, "/restapi/workRequests/**").hasAnyRole("CONTRACTOR", "CONTRACTOR", "ADMIN")
.antMatchers(HttpMethod.GET, "/restapi/workRequests/**").hasAnyRole("CONTRACTOR", "CONTRACTOR", "ADMIN")
.anyRequest().authenticated()
.and()
.apply(new JwtConfigurer(jwtTokenProvider))
// Allow pages to be loaded in frames from the same origin; needed for H2-Console
.and()
.headers()
.frameOptions()
.sameOrigin();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userRepositoryUserDetailsService)
.passwordEncoder(encoder());
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList(ALL));
configuration.setAllowedMethods(Arrays.asList(ALL));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/**", "/resources/**", "/index.html", "/login/admin", "/template/**", "/",
"/error/**", "/h2-console", "*/h2-console/*");
}
Test
#Test
public void testLogin() {
Admin admin = new Admin("network", "network");
// adminRepository.save(admin);
String s = adminRepository.findByUsername("network").getUsername();
RequestEntity<Admin> requestEntity =
RequestEntity
.post(uri("/login/admin"))
.contentType(MediaType.APPLICATION_JSON)
.body(admin);
ResponseEntity<Admin> responseEntity = this.restTemplate.exchange(requestEntity, Admin.class);
assertNotNull(responseEntity);
System.out.println(responseEntity.getStatusCode());
}
I'm expecting successful request, but I'm getting INTERNAL SERVER ERROR.
403 Forbidden or No Permission to Access.
A 403 Forbidden error means that you do not have permission to view the requested file or resource
Please attempt the test runs with #WithMockUser
#Test
#WithMockUser
public void corsWithAnnotation() throws Exception {
ResponseEntity<Admin> entity = this.restTemplate.exchange(
...
}
Reference : Preview Spring Security Test: Web Security
I have probem with Spring Boot and Cors
After some searches I was able to find solutions (Spring Data Rest and Cors and How to configure CORS in a Spring Boot + Spring Security application?) which I tried but which does not solve my problem.
My code for the Authentication with JWT
public class AuthenticationFilter extends AbstractAuthenticationProcessingFilter
{
private final Logger log = LoggerFactory.getLogger(AuthenticationFilter.class);
private final String tokenHeader = "Authorization";
private final TokenUtils tokenUtils = new TokenUtils();
public AuthenticationFilter()
{
super("/api/v1/**");
tokenUtils.expiration = 86400;
tokenUtils.secret = "papipapo123popo";
}
#Override
public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException
{
String header = httpServletRequest.getHeader(tokenHeader);
if(header == null || !header.startsWith("Bearer "))
{
log.error("Not found JWT token in request headers","Not found header Authorization");
throw new JwtTokenMissingException("No JWT token found in request headers");
}
String token = header.substring(7);
JwtAuthentication jwtAuthentication = new JwtAuthentication(token);
boolean isValid = tokenUtils.validateToken(token);
if(!isValid)
{
log.error("JWT token is expired",token);
throw new JwtTokenExpired("JWT token is expired");
}
return this.getAuthenticationManager().authenticate(jwtAuthentication);
}
#Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException
{
super.successfulAuthentication(request, response, chain, authResult);
String token = ((JwtAuthentication)authResult).getToken();
log.info("Token is authenticated : ",token);
chain.doFilter(request, response);
}
#Override
protected AuthenticationManager getAuthenticationManager()
{
return authentication -> (JwtAuthentication) authentication;
}
}
My code for Configuration security
#Configuration
#EnableWebSecurity
#EnableAutoConfiguration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter
{
#Inject
private EntryPointUnauthorizedHandler entryPointUnauthorizedHandler;
#Inject
private JwtAuthenticationProvider jwtAuthenticationProvider;
#Bean
#Override
public AuthenticationManager authenticationManager() throws Exception
{
return new ProviderManager(Arrays.asList(jwtAuthenticationProvider));
}
#Bean
public AuthenticationFilter authenticationFilter() throws Exception
{
AuthenticationFilter authenticationFilter = new AuthenticationFilter();
authenticationFilter.setAuthenticationManager(authenticationManager());
authenticationFilter.setAuthenticationSuccessHandler(new EntryPointSuccessHandler());
return authenticationFilter;
}
#Bean
public FilterRegistrationBean corsFilter()
{
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.addAllowedOrigin("*");
source.registerCorsConfiguration("/**",config);
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new CorsFilter(source));
filterRegistrationBean.setOrder(0);
return filterRegistrationBean;
}
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(entryPointUnauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers(HttpMethod.POST,"/api/auth").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(authenticationFilter(),UsernamePasswordAuthenticationFilter.class);
http.headers().cacheControl();
}
}
I always receive an error 401 refused accesse.
I am a beginner in Spring-Boot.
You can help me.
I solved my problem by adding a Class which implements Filter.
#Component
public class CorsConfig implements Filter
{
#Override
public void init(FilterConfig filterConfig) throws ServletException
{}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException
{
HttpServletRequest request = (HttpServletRequest) servletRequest;
String method = request.getMethod();
if(method.equals("OPTIONS") || method.equals("options"))
{
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
response.setStatus(200);
filterChain.doFilter(servletRequest, servletResponse);
}
else
{
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
filterChain.doFilter(servletRequest, servletResponse);
}
}
#Override
public void destroy()
{}
}
First class:
#Configuration
public class MyConfiguration {
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
};
}
}
Second class:
#EnableWebSecurity
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**").authorizeRequests().requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.anyRequest().fullyAuthenticated().and().httpBasic().and().csrf().disable();
}
}
And be happy my friend
1: Create a class WebMvcConfig extends WebMvcConfiguration and override addCorsMappings method.
2: Don't forget to make it #Configuration annotation
#Configuration
public class WebMvcCofig implements WebMvcConfigurer{
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/*")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*")
.allowCredentials(true);
}
}
How to configure spring security on cross-platform, for example I have two application one is server side where all the java code and spring security part I am doing and other client side where all angular js and html files present.
I want to integrate my custom login page which is present at client side with Spring security how can I achieve that, following is my code for Spring security.
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/index.html", "/assests/**", "/app/**",
"/**/*.js", "/**/*.css", "/**/*.jpg", "/**/*.png",
"/**/*.jpg", "/**/*.gif", "#/index.html", "/home",).permitAll()
.anyRequest().authenticated()
.and().formLogin()
.loginPage("/login").failureUrl("/login?error")
.usernameParameter("username")
.passwordParameter("password")
.and()
.addFilterBefore(new AppCORSFilter(), ChannelProcessingFilter.class)
.addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class)
.csrf().disable();
}
}
and this is My CORS filter.
public class AppCORSFilter implements Filter {
private static final String ALLOWED_ORIGINS = "*";
private static final String ALLOWED_HTTP_HEADERS = "accept, x-requested-with, access-control-allow-origin,Content-Type,authorization";
private static final String ALLOWED_HTTP_METHODS = "POST,GET,PUT,OPTIONS,DELETE";
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
//String headerValue = request.getHeaders("Access-Control-Request-Headers");
response.setHeader("Access-Control-Allow-Origin", ALLOWED_ORIGINS);
response.setHeader("Access-Control-Allow-Methods", ALLOWED_HTTP_METHODS);
response.setHeader("Access-Control-Allow-Headers", ALLOWED_HTTP_HEADERS);
response.setHeader("Access-Control-Max-Age", "3600");
HttpServletRequest request = (HttpServletRequest) req;
if (request.getMethod().equals("OPTIONS")) {
try {
response.getWriter().print("OK");
response.getWriter().flush();
} catch (IOException e) {
e.printStackTrace();
}
} else {
chain.doFilter(req, res);
}
}
public void init(FilterConfig filterConfig) {
}
public void destroy() {
}
}
You can share security session between your services by using Redis. Read this documentation. You can also find an example of it from this link.