How I can fix broken CORS In Spring Boot + Vue app? - spring

In my problem I have Spring Boot Application (which is using Spotify API) on backend and Vue application on front. I use server on localhost:8080 and front on localhost:8081. I want to connect my frontend to my backend via axios and I try everything and still get CORS error.
When I call test GET endpoint /getList() I' ve got
Access to XMLHttpRequest at 'http://localhost:8080/getList' from origin 'http://localhost:8081' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
When I try to call POST /findTracks() I've got:
Access to XMLHttpRequest at 'http://localhost:8080/findTracks' from origin 'http://localhost: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.
And I alread tried everything (as you can see in the code below).
First:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
#EnableWebMvc
public class CorsConfiguration implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry){
registry.addMapping("/**").allowedHeaders("*").allowedMethods("*");
} //even with .allowedOrgins("http://localhost:8081");
}
Then in Controller class:
#CrossOrigin(origins = "*", allowedHeaders = "*")
#RestController
public class SpotifyApiController {
#CrossOrigin(origins = "*", allowedHeaders = "*")
#RequestMapping(value = "/getList", method = RequestMethod.GET)
public List<String> getList() {
ArrayList<String> a = new ArrayList<>();
a.add("dwa");
a.add("trzy");
return a;
}
#RequestMapping(value = "/findTracks",
method = RequestMethod.POST,
consumes = "application/json",
produces = "application/json")
public List<Track> getTracksForTitles(#RequestBody TrackWrapper userTracks, TrackService tracksService, OAuth2Authentication details) {
return tracksService.generateTracksDetails(getActiveToken(details), userTracks);
}
Then in Vue:
import axios from 'axios';
const SERVER_URL = 'http://localhost:8080'
const instance = axios.create({
baseURL: SERVER_URL,
timeout: 1000
});
export default{
findTracksInSpotify:(jsonObject)=>instance.post('/findTracks',{
userTracks: jsonObject.userTracks,
headers:{
'Content-Type': 'application/json',
}
}).then(() => function(data){
return JSON.parse(data)
}),
getList:()=>instance.get('/getList',{
transformResponse:[function(data){
return JSON.parse(data)
}]
}),
}
And my Spring Security class if needed:
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.web.context.request.RequestContextListener;
#Configuration
#EnableOAuth2Sso
#EnableWebSecurity
public class OAuth2Configuration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.antMatcher("/**")
.authorizeRequests()
.antMatchers("/", "/login**")
.permitAll()
.anyRequest()
.authenticated()
.and().logout().logoutSuccessUrl("/").permitAll();
}
#Bean
public RequestContextListener requestContextListener() {
return new RequestContextListener();
}
}
I even install chrome extension but it does not work either.
Can you tell me what I am doing wrong?

I think that you do not need the class CorsConfiguration.
You do not need to annotate with CrossOrigin the SpotifyApiController either.
The configuration of CORS ideally should be placed in the security configuration. Something like that (in OAuth2Configuration):
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
#Configuration
#EnableOAuth2Sso
#EnableWebSecurity
public class OAuth2Configuration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
// The configuration that you needed
// If preflight requests are redirected by OAuth conf, you can try adding:
// .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
// CORS configuration
// This value must be parameterized according to your application needs
final String corsOrigin="http://localhost:8081";
// The idea is to insert the CORS filter before the filter injected by
// the #EnableOAuth2Sso annotation
http.addFilterBefore(new CorsFilter(corsConfigurationSource(corsOrigin)), AbstractPreAuthenticatedProcessingFilter.class);
}
private CorsConfigurationSource corsConfigurationSource(String corsOrigin) {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList(corsOrigin));
configuration.setAllowedMethods(Arrays.asList("GET","POST","HEAD","OPTIONS","PUT","PATCH","DELETE"));
configuration.setMaxAge(10L);
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList("Accept","Access-Control-Request-Method","Access-Control-Request-Headers",
"Accept-Language","Authorization","Content-Type","Request-Name","Request-Surname","Origin","X-Request-AppVersion",
"X-Request-OsVersion", "X-Request-Device", "X-Requested-With"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}

There is a sample of RestConfiguration corsfilter. You can add the following bean to your code:
#CrossOrigin
#Configuration
public class RestConfiguration {
#Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
source.registerCorsConfiguration("/**", config);
final FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
}

#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().configurationSource(request -> {
CorsConfiguration cors = new CorsConfiguration();
cors.setAllowedOrigins(
Lists.newArrayList("*"));
cors.setAllowedMethods(Lists.newArrayList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
cors.setAllowedHeaders(Lists.newArrayList("*"));
return cors;
}).and().csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("")
.permitAll().and()
.addFilterBefore(setLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class);
}

Did you try using #CrossOrigin(origins="http://localhost:8081") on your controller class and repository class?
Also in conjuction to it : Try to add WebConfigurer Bean in you main SpringBoot Application class and annonate that too with #CrossOrigin(origins="http://localhost:8081")
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
System.out.println("here");
registry.addMapping("/**").allowedOrigins("http://localhost:8081").allowedMethods("PUT", "DELETE" )
.allowedHeaders("header1", "header2", "header3")
.exposedHeaders("header1", "header2")
.allowCredentials(false).maxAge(3600);;
}
};
}
Please visit this link too for enabling CORS in your application server side and check as per your configuration which CORS method you can use.

Related

Always getting redirected from /authorized to /login page using new spring authorization server

I am using new spring authorization server. And everything was working fine with version 0.3.1. But after migration to 1.0.0. When I am trying to login (and I am supposed to be redirected to /authorized?code=) I am always getting redirected back to login. Could somebody please explain me what is going wrong? Maybe config for security should be specified in one place only?
Thank you.
AuthorizationServerConfig
package oauth2.config;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import oauth2.converter.AuthorizationClientConverter;
import oauth2.handler.FederatedIdentityAuthenticationSuccessHandler;
import oauth2.repository.AuthorizationClientRepository;
import oauth2.repository.ClientRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.RequestMatcher;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.time.Duration;
import java.util.UUID;
#Configuration(proxyBeanMethods = false)
public class AuthorizationServerConfig {
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
private AuthorizationClientConverter authorizationClientConverter;
#Autowired
private FederatedIdentityAuthenticationSuccessHandler federatedIdentityAuthenticationSuccessHandler;
#Bean
#Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
new OAuth2AuthorizationServerConfigurer();
RequestMatcher endpointsMatcher = authorizationServerConfigurer.getEndpointsMatcher();
http
.securityMatcher(endpointsMatcher)
.csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher))
.authorizeHttpRequests(auth -> {
auth.anyRequest().authenticated();
})
.formLogin(Customizer.withDefaults())
.oauth2Login(Customizer.withDefaults())
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
.apply(authorizationServerConfigurer);
return http.build();
}
#Bean
public OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer() {
return context -> {
JwtClaimsSet.Builder claims = context.getClaims();
if (context.getTokenType().equals(OAuth2TokenType.ACCESS_TOKEN)) {
claims.claim("claim", "zabur_claim");
}
};
}
#Bean
public RegisteredClientRepository registeredClientRepository(ClientRepository clientRepository) {
RegisteredClient registeredClient = RegisteredClient.withId("messaging-client")
.clientId("messaging-client")
.clientSecret(passwordEncoder.encode("secret"))
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.redirectUri("http://127.0.0.1:8080/authorized")
.scope("message.read")
.scope("message.write")
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
.build();
AuthorizationClientRepository registeredClientRepository = new AuthorizationClientRepository(authorizationClientConverter, clientRepository);
registeredClientRepository.save(registeredClient);
return registeredClientRepository;
}
#Bean
public JWKSource<SecurityContext> jwkSource() {
RSAKey rsaKey = generateRsa();
JWKSet jwkSet = new JWKSet(rsaKey);
return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
}
#Bean
public AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder()
.issuer("http://localhost:8080")
.build();
}
#Bean
public TokenSettings tokenSettings() {
return TokenSettings.builder()
.accessTokenTimeToLive(Duration.ofMinutes(5))
.build();
}
private RSAKey generateRsa() {
KeyPair keyPair = generateRsaKey();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// #formatter:off
return new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString())
.build();
// #formatter:on
}
private KeyPair generateRsaKey() {
KeyPair keyPair;
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
keyPair = keyPairGenerator.generateKeyPair();
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
return keyPair;
}
}
SecurityConfig
package oauth2.config;
import oauth2.handler.FederatedIdentityAuthenticationSuccessHandler;
import oauth2.handler.FormLoginAuthenticationSuccessHandler;
import oauth2.service.impl.CustomUserDetailsService;
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.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
#Configuration
#EnableWebSecurity
public class SecurityConfig {
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
private FederatedIdentityAuthenticationSuccessHandler federatedIdentityAuthenticationSuccessHandler;
#Autowired
private FormLoginAuthenticationSuccessHandler formLoginAuthenticationSuccessHandler;
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.ignoringRequestMatchers("/signUp", "/logout"))
.authorizeHttpRequests(auth -> {
auth.requestMatchers("/logout", "/signUp", "/authorized").permitAll();
auth.anyRequest().authenticated();
})
.formLogin(formLogin -> formLogin.successHandler(formLoginAuthenticationSuccessHandler))
.oauth2Login(oauth2Login -> oauth2Login.successHandler(federatedIdentityAuthenticationSuccessHandler));
return http.build();
}
#Bean
public DaoAuthenticationProvider authenticationProvider(CustomUserDetailsService customUserDetailsService) {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setPasswordEncoder(passwordEncoder);
authenticationProvider.setUserDetailsService(customUserDetailsService);
return authenticationProvider;
}
}
I am trying to login with OAuth2 and expecting to be redirected to the /authorized?code= but after that I am redirected to /login.
Might you are using lot more code to serve your purpose. I integrated OAuth 2 in my Application using Spring security 6.0.0 and Spring Authorization Server 1.0.0. It made me sweating lot. But I got success. For that I shared my Authorization server configuration as it did.
#Bean
#Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
http
.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(Customizer.withDefaults()); // Enable OpenID Connect 1.0
http
.exceptionHandling((exceptions) -> exceptions
.authenticationEntryPoint(
new LoginUrlAuthenticationEntryPoint("/login"))
)
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
return http.build();
}
#Bean
#Order(Ordered.HIGHEST_PRECEDENCE + 1)
public SecurityFilterChain securityFilterChain(HttpSecurity http)
throws Exception {
http
.cors().and().csrf().disable()
.headers().frameOptions().sameOrigin()
.httpStrictTransportSecurity().disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults());
return http.build();
}
I think it may help you a little bit or you may get an idea what actually going on in your code.
SecurityFilterChain by default masks any request for authentication, it acts as a safety net, shadowing any permitAll() matcher. This is somehow not clear in the documentation, as per my understanding for the documentation, and needs to be better clarified.
Allowable paths must be declared in a SecurityFilterChain Bean, while authenticated and authorized paths must be kept in another SecurityChain Bean. To differentiate between allowed and authorized paths, use '.securityMaters()', as shown in the example below:
#Bean
#Order(0)
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.ignoringRequestMatchers("/signUp", "/logout"))
.securityMatcher("/logout", "/signUp", "/authorized")
.authorizeHttpRequests(auth -> {
auth.anyRequest().permitAll();
});
return http.build();
}
#Bean
#Order(1)
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.ignoringRequestMatchers("/signUp", "/logout"))
.authorizeHttpRequests(auth -> {
auth.anyRequest().authenticated();
})
.formLogin(formLogin -> formLogin.successHandler(formLoginAuthenticationSuccessHandler))
.oauth2Login(oauth2Login -> oauth2Login.successHandler(federatedIdentityAuthenticationSuccessHandler));
return http.build();
}
Try it and let me know how it goes with you!

How to enable CORS in Spring

I tried doing this but it isn't working. I also tried adding #CrossOrigin on top of my controller class but that didn't work either.
#Configuration
public class CorsConfig {
#Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*"); //'*' allows all endpoints, Provide your URL/endpoint, if any.
config.addAllowedHeader("*");
config.addAllowedMethod("POST"); //add the methods you want to allow like 'GET', 'PUT',etc. using similar statements.
config.addAllowedMethod("GET");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
There are several ways to achieve that. You can do that on method level or global. For Example (source: https://www.baeldung.com/spring-cors):
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
#EnableWebMvc
public class CorsConfiguration implements WebMvcConfigurer
{
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("GET", "POST");
}
}
also take a look on the old thread: How to configure CORS in a Spring Boot + Spring Security application?
#Configuration
public class CorsConfig {
#Bean
public WebMvcConfigurer corsConfig() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS")
.allowedOrigins("*")
.allowedHeaders("*")
.allowCredentials(false);
}
};
}
}
Try this once, it should work.

How to fix Cors error Access-Control-Allow-Origin missing

I have a spring boot rest application and I am not using Spring security. My rest service looks like this
#RestController
#CrossOrigin
public class AuthenticationService {
...
#GetMapping(path = "/getUser")
public JSONObject getUser() {
...
}
}
I call the API from a REST application using axios get. Everything works fine locally.
But when the application is deployed on cloud as a docker image, I get the 403 error
(Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
Even when I add a CorsConfiguration file I get the same error.
#Configuration
public class CorsConfiguration {
#Bean
public WebMvcConfigurer corsConfigurer()
{
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*")
.allowedHeaders("Accept", "Origin", "X-Requested-With,Content-Type", "Authorization", "X-XSRF-Header")
.allowCredentials(true);
}
};
}
}
I have spent a lot of time to find a solution for this but somehow it isn't working.
Declaring a bean works fine for me:
#Configuration
public class WebConfigurer implements ServletContextInitializer, WebMvcConfigurer {
private final Environment env;
private final MyProperties properties;
public WebConfigurer(Environment env, MyProperties properties) {
this.env = env;
this.properties = properties;
}
#Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = properties.getCors();
if (config.getAllowedOrigins() != null && !config.getAllowedOrigins().isEmpty()) {
log.debug("Registering CORS filter");
source.registerCorsConfiguration("/api/**", config);
source.registerCorsConfiguration("/management/**", config);
source.registerCorsConfiguration("/v3/api-docs", config);
}
return new CorsFilter(source);
}
}
Yaml properties:
# CORS is only enabled by default with the "dev" profile
cors:
allowed-origins: '*'
allowed-methods: '*'
allowed-headers: '*'
exposed-headers: 'Authorization,Link,X-Total-Count'
allow-credentials: true
max-age: 1800
fixed by adding spring security

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource issue

I got stuck in implementing websocket in my application. I am using Spring Boot + angular 8
This is my websocket configuration
Security configuration
#Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("****");
http.cors().and().csrf().disable()
.authorizeRequests()
.antMatchers("/oauth/token/**").permitAll()
.antMatchers("/websocket/**").permitAll()
.antMatchers("/ws/**").authenticated()
.anyRequest().permitAll().and()
.addFilter(new JwtAuthenticationFilter(authenticationManager(),getApplicationContext()))
.addFilter(new JwtAuthorizationFilter(authenticationManager(),getApplicationContext()))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.headers().frameOptions().sameOrigin();
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*","http://localhost:4200"));
configuration.setAllowCredentials(false);
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "OPTION", "DELETE"));
configuration.setAllowedHeaders(Arrays.asList("Content-Type", "Access-Control-Allow-Headers","Origin", "x-requested-with", "Authorization"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
Websocket Configuration
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/websocket").setAllowedOrigins("*").withSockJS();
}
}
Below is my controller
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
#Controller
public class ClientForwardController {
//Below controller is used to forward all my un mapped request to index.html
// Because of this websocket /info request forwarding to index.html
#GetMapping(value = "/**/{path:[^\\.]*}")
public String forward() {
return "forward:/";
}
#MessageMapping("/test")
#SendTo("/topic/testing")
public String test() throws Exception {
Thread.sleep(3000); // simulated delay 3s
return "success";
}
}
Below is my Angular code to connect to websocket.
import * as Stomp from 'stompjs';
import * as SockJS from 'sockjs-client';
export class WebSocketAPI {
webSocketEndPoint: string = 'http://localhost:8080/websocket';
topic: string = "/topic/testing";
stompClient: any;
displayProductComponent: TodaysMarketListComponent;
constructor(displayProductComponent: TodaysMarketListComponent){
this.displayProductComponent = displayProductComponent;
}
_connect() {
console.log("Initialize WebSocket Connection");
let ws = new SockJS(this.webSocketEndPoint);
this.stompClient = Stomp.over(ws);
const _this = this;
_this.stompClient.connect({}, function (frame: any) {
_this.stompClient.subscribe(_this.topic, function (sdkEvent) {
_this.onMessageReceived(sdkEvent);
});
}, this.errorCallBack);
};
}
But i am not able to connect to server.
Kindly suggest to fix this issue.
Error
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at ‘http://localhost:8080/websocket/info?t=1585208056284’. (Reason: Credential is not supported if the CORS header ‘Access-Control-Allow-Origin’ is ‘*’).
Whoops! Lost connection to http://localhost:8080/websocket
Thanks,
Venkataramana

Spring Security CORS doesn't work for Http PUT method

I am getting 'Invalid CORS request' when I try to PutMapping of my API in Postman. But it is working fine for 'POST' and 'GET' mapping.
Why is it not working for the 'PUT' operation?
My Spring Boot version: 2.0
This is my config:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/h2-console/**/**").permitAll()
.antMatchers(HttpMethod.GET,"/user/get-request").permitAll()
.antMatchers(HttpMethod.POST,"/user/post-request").permitAll()
.antMatchers(HttpMethod.PUT,"/user/put-request").permitAll()
.and()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager(), jwtUserDetailService));
}
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*").allowedHeaders("*").exposedHeaders("Authorization");
}
};
}
This is my controller :
#RestController
#RequestMapping("/user")
public class UserController {
#PutMapping("/put-request")
public void doResetPassword(#RequestBody String password) {
System.out.println("PUT MAPPING");
}
#PostMapping("/post-request")
public void doResetPassword(#RequestBody String password) {
System.out.println("POST MAPPING");
}
#GetMapping("/get-request")
public void doResetPassword() {
System.out.println("GET MAPPING");
}
}
It's much simpler than the accepted solution.
#Configuration
public class CrossOriginConfig {
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("/**")
.allowedMethods("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS");
}
};
}
}
#Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(ImmutableList.of("*"));
configuration.setAllowedMethods(ImmutableList.of("HEAD",
"GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(ImmutableList.of("*"));
configuration.setExposedHeaders(ImmutableList.of("X-Auth-Token","Authorization","Access-Control-Allow-Origin","Access-Control-Allow-Credentials"));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
I managed to allow cors request by adding this bean. You can configure setAllowedHeaders() and setExposedHeaders() by your need.
Also, I added this line to my controller;
#RequestMapping(value = "/auth")
#RestController
#CrossOrigin(origins = "*") //this line
public class AuthenticationController {..}
If your controller needs to handle on-the-fly OPTION request you can add this method to your controller. You can configure the value by your endpoint.
#RequestMapping(value = "/**/**",method = RequestMethod.OPTIONS)
public ResponseEntity handle() {
return new ResponseEntity(HttpStatus.OK);
}
If you are using a IIS server It was a problem with the WebDAVModule which seems to block PUT and DELETE methods by default!
<system.webServer>
<modules runAllManagedModulesForAllRequests="false">
<remove name="WebDAVModule" />
</modules>
</system.webServer>
I really hope no one else pain with that! =]
Fonte: https://mozartec.com/asp-net-core-error-405-methods-not-allowed-for-put-and-delete-requests-when-hosted-on-iis/
In Spring with Kotlin I did the following:
#Bean
fun corsConfigurationSource(): CorsConfigurationSource? {
val source = UrlBasedCorsConfigurationSource()
val corsConfig = CorsConfiguration()
.applyPermitDefaultValues()
.setAllowedOriginPatterns(listOf("*"))
corsConfig.addAllowedMethod(HttpMethod.PUT)
source.registerCorsConfiguration("/**", corsConfig)
return source
}
I just want to add 3 things.
The accepted answer and the one below it are wrong ways of doing CORS.
If you are trying to configure CORS, that means you are trying to make your API accessible only by a number of clients you know. The lines
configuration.setAllowedOrigins(ImmutableList.of("*")); // from the first answer
.addMapping("/**") // from the second answer
make the API accessible by any client. If that is what you want, you can just do the following with out a need to configure another bean
http.cors().disable()
The issue in the question may happen when you allow origins with http and do your request using https. So be aware that those 2 are different.
Below is a working configuration
// In the import section
import static org.springframework.security.config.Customizer.withDefaults;
// In the HttpSecurity configuration
http.cors(withDefaults())
#Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200", "https://localhost:4200"));
configuration.setAllowedMethods(Arrays.asList("HEAD",
"GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList("Content-Type", "X-Auth-Token","Authorization","Access-Control-Allow-Origin","Access-Control-Allow-Credentials"));
configuration.setExposedHeaders(Arrays.asList("Content-Type", "X-Auth-Token","Authorization","Access-Control-Allow-Origin","Access-Control-Allow-Credentials"));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
I'm using Spring Security and Spring Boot 2.1.2. In my specific case, the PUT call worked after I explicitly declared the "PUT" method in the setAllowedMethods() from CorsConfigurationSource bean. The headers can be chosen depending on the application behavior.
#Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final String headers = "Authorization, Access-Control-Allow-Headers, "+
"Origin, Accept, X-Requested-With, Content-Type, " +
"Access-Control-Request-Method, Custom-Filter-Header";
CorsConfiguration config = new CorsConfiguration();
config.setAllowedMethods(Arrays.asList("GET","POST","PUT","DELETE")); // Required for PUT method
config.addExposedHeader(headers);
config.setAllowCredentials(true);
config.applyPermitDefaultValues();
source.registerCorsConfiguration("/**", config);
return source;
}

Resources