in spring boot 2.3.3, facing issue regarding CORS. no spring security has been used - spring-boot

"has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource."
getting this message when api is being hit by angular portion, but proper response is obtained when end point is being hit from POSTMAN.

You will need to enable/configure CORS (Cross-Origin Resource Sharing) in your spring boot application -
Enabling CORS for the whole application (This is a global configuration)-
#Configuration
#EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
Additionally Spring allows you to control CORS configuration at Controller as well as at the RequestMapping level -
To enable CORS for the whole controller -
#CrossOrigin(origins = "http://your-client-domain.com", maxAge = 3600)
#RestController
#RequestMapping("/booking")
public class BookingController {
#RequestMapping("/{id}")
public Booking retrieve(#PathVariable Long id) {
// ...
}
#RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
public void remove(#PathVariable Long id) {
// ...
}
}
To enable the CORS for specific path mapping (RequestMapping) -
#RestController
#RequestMapping("/booking")
public class BookingController {
#CrossOrigin(origins = "http://your-client-domain.com")
#RequestMapping("/{id}")
public Booking retrieve(#PathVariable Long id) {
// ...
}
#RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
public void remove(#PathVariable Long id) {
// ...
}
}
You can also apply CORS configuration only for required mappings (paths), you can always configure it to the granular details -
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/v1/**")
.allowedOrigins("http://your-client-domain.com")
.allowedMethods("OPTIONS", "GET", "POST", "PUT", "DELETE")
.allowedHeaders("Some-Header-x", "Authorization")
.exposedHeaders("X-API-Limit")
.allowCredentials(false).maxAge(3600);
}
}
You can read more about enabling and configuring CORS in Spring Applications here

Related

Can not get user info with Spring Security SAML WITHOUT Spring Boot

I´m working on SAML integration in an older project but I can´t get the user information.
I've guided me with the response of this question:
https://stackoverflow.com/questions/70275050/spring-security-saml-identity-metadata-without-spring-boot
The project has these versions:
spring framework 5.3.24
spring security 5.6.10
opensaml 3.4.6
This is my code:
#Configuration
public class SAMLSecurityConfig {
private static final String URL_METADATA = "https://auth-dev.mycompany.com/app/id/sso/saml/metadata";
#Bean("samlRegistration")
public RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() {
RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations.fromMetadataLocation(URL_METADATA)
.registrationId("id")
.build();
return new InMemoryRelyingPartyRegistrationRepository(relyingPartyRegistration);
}
}
#EnableWebSecurity
public class WebSecurity {
#Configuration
#Order(2)
public static class SAMLSecurityFilter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.saml2Login(Customizer.withDefaults())
.antMatcher("/login/assertion")
.authorizeRequests()
.anyRequest()
.authenticated();
}
}
}
#Controller("loginController")
public class BoCRLoginController {
#RequestMapping(value = "/login/assertion", method = {RequestMethod.POST},
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<String> assertLoginData(#AuthenticationPrincipal Saml2AuthenticatedPrincipal principal) {
System.out.println(principal); //here I get a null
return new ResponseEntity<>(HttpStatus.OK);
}
}
Once I did the login on okta the class: Saml2AuthenticatedPrincipal comes null value.
Could you help me to know why I received null value on the object Saml2AuthenticatedPrincipal where suppose have to receive the user information?

Vaadin + Spring Boot returns 403 Forbidden error on PUT, POST, DELETE requests

Implementing a simple web application using REST Api using Spring Boot + Vaadin. Also, Security is connected in the project, a simple login with a login-password is carried out. Get() requests work fine, but a 403 "Forbidden" error occurs on PUT, POST, DELETE requests.
I tried disabling csrf using the http.httpBasic().and().csrf().disable() method, it does not help, and this is not recommended in production either.
I also tried adding to antMatchers() specifically a request type like this: http.httpBasic().and().authorizeRequests().antMatchers(HttpMethod.POST,"/**").permitAll(), also not helps.
Configuration class:
#EnableWebSecurity
#Configuration
public class SecurityConfig extends VaadinWebSecurity {
private static class SimpleInMemoryUserDetailsManager extends InMemoryUserDetailsManager {
public SimpleInMemoryUserDetailsManager() {
createUser(Manager.withUsername("manager1")
.password("{noop}123")
.roles(ROLE_MANAGER)
.build());
createUser(Manager.withUsername("manager2")
.password("{noop}123")
.roles(ROLE_MANAGER)
.build());
}
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests().antMatchers("/enterprises/\*\*").hasRole(ROLE_MANAGER);
super.configure(http);
setLoginView(http, LoginView.class);
}
#Bean
public InMemoryUserDetailsManager enterprisesService() {
return new SimpleInMemoryUserDetailsManager();
}
}
Rest-controller:
#org.springframework.web.bind.annotation.RestController
#RequestMapping(path = "/")
public class RestController {
#Autowired
private VehiclesRepository vehiclesRepository;
#Autowired
private EnterprisesRepository enterprisesRepository;
#Autowired
private DriversRepository driversRepository;
#Autowired
private ManagersRepository managersRepository;
#GetMapping(
path = "/vehicles",
produces = "application/json")
public VehiclesDto getVehicles() {
VehiclesDto vehiclesDto = new VehiclesDto();
for (Vehicle vehicle : vehiclesRepository.findAll()) {
vehiclesDto.getVehicles().add(vehicle);
}
return vehiclesDto;
}
#GetMapping(
path = "/enterprises",
produces = "application/json")
public #ResponseBody EnterprisesDto getEnterprises(#RequestParam("managerId") String managerId) {
Manager manager = null;
for (Manager managerFromRepo : managersRepository.findAll()) {
if (managerFromRepo.getId().equals(Long.parseLong(managerId))) {
manager = managerFromRepo;
break;
}
}
EnterprisesDto enterprisesDto = new EnterprisesDto();
if (manager == null) return enterprisesDto;
for (Enterprise enterprise : enterprisesRepository.findAll()) {
if (manager.getEnterprises().contains(enterprise.getId()))
enterprisesDto.getEnterprises().add(enterprise);
}
return enterprisesDto;
}
#GetMapping(
path = "/drivers",
produces = "application/json")
public DriversDto getDrivers() {
DriversDto driversDto = new DriversDto();
for (Driver driver : driversRepository.findAll()) {
driversDto.getDrivers().add(driver);
}
return driversDto;
}
#PostMapping("/createVehicle")
public #ResponseBody String createVehicle(#RequestBody String info) {
return "it works!!!";
}
#DeleteMapping("/deleteVehicle")
public #ResponseBody String deleteVehicle(){
return "it works!!!";
}
}
Testing requests through Postman using Basic Authentication.
You can disable CSRF just for your API:
http.csrf().ignoringRequestMatchers(new AntPathRequestMatcher("/enterprises/**"));

PreAuthorize not getting honored over ResourceServerConfigurerAdaptor

I have a Spring Resource Server with Spring Security enabled. In Resource Server, i am extending the ResourceServerConfigurerAdaptor, some like the following.
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.anonymous().disable().requestMatcher(new OAuthRequestedMatcher()).authorizeRequests()
.antMatchers(HttpMethod.POST, "/api/admin/**").hasAnyRole("ADMIN")
.anyRequest().authenticated();
}
private static class OAuthRequestedMatcher implements RequestMatcher {
public boolean matches(HttpServletRequest request) {
String auth = request.getHeader("Authorization");
boolean haveOauth2Token = (auth != null) && auth.toLowerCase().startsWith("bearer");
boolean haveAccessToken = request.getParameter("access_token") != null;
return haveOauth2Token || haveAccessToken;
}
}
}
Here i am expecting /api/admin/** to be accessible to ADMIN Role only.
Everything works fine till now.
But now i am trying to override this behavior at the method level using #PreAuthorize method level annotation.
Following is the RestController
#RestController
#RequestMapping("/api/admin/event")
public class ShunyaEventResource {
#Autowired
private ShunyaEventService eventService;
#PreAuthorize("hasRole('ADMIN') or #oauth2.hasScope('write')")
#PostMapping
public void createEvent(#RequestBody ShunyaEvent event, Principal user) {
eventService.create(event);
}
}
So, i want to allow /api/admin/event to be accessible to #oauth2 write scope as well. But this does not work, unless either i remove /api/admin/** from antmatcher altogether or i add #oauth2.hasScope('write') in antmatcher itself.
I have already defined the below configuration
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
Here my question is why Method Level security not working for an endpoint that is already covered by ResourceServerConfigurerAdapter? What is precedence of security filter when same endpoint is covered by MethodLevel Security (using PreAuthorize) and HttpSecurity antMatcher?
Really appreciate any help on this.

After enabling Zuul proxy for the Spring boot app (We have set of miroservices), spring mvc interceptor doesnot work

Below is the Application.java. It has code to invoke the interceptor
#EnableEurekaClient
#SpringBootApplication
#EnableZuulProxy
public class Application extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public TokenValidateInterceptor tokenValidateInterceptor() {
TokenValidateInterceptor localeChangeInterceptor = new TokenValidateInterceptor();
System.out.println("In WEB MVC Intereptor, Interceptor returned");
return localeChangeInterceptor;
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
System.out.println("In WEB MVC Intereptor");
// registry.addInterceptor(tokenValidateInterceptor()).addPathPatterns("/");
registry.addInterceptor(tokenValidateInterceptor()).addPathPatterns("/api/**");
// registry.addInterceptor(new
// TokenValidateInterceptor()).addPathPatterns("/api/**");
}
}
Below is the snippet of the interceptor code:
#Component
public class TokenValidateInterceptor extends HandlerInterceptorAdapter {
private static final Logger LOG = Logger.getLogger(TokenValidateInterceptor.class);
// before the actual handler will be executed ..
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String apikey = request.getHeader("apikey");
// if (LOG.isDebugEnabled()) {
LOG.info("#### Starting TokenValidateInterceptor.preHandle ####");
LOG.info("apikey-->" + apikey);
// }
if (StringUtils.isBlank(apikey) || apikey == null || apikey.isEmpty()) {
return true;
}
}
}
But the call does not reach prehandle of the interceptor.
AFAIK, all requests that are defined in Zuul routing are handled by ZuulServlet.
Spring MVC doesn't handle these requests, so any Spring HandlerInterceptor will not be called for these requests. If you need any preprocessing for API requests, you should implement it in Zuul prefilter or servlet filter.

Spring #CrossOrigin does not work with DELETE method

Spring #CrossOrigin annotation does not work with DELETE methods.
Example code (in Groovy):
#CrossOrigin
#RestController
#RequestMapping('/rest')
class SpringController {
#RequestMapping(value = '/{fileName}', RequestMethod.DELETE)
void deleteFile(#PathVariable fileName) {
// logic
}
}
For this code I get the exception:
XMLHttpRequest cannot load http://localhost:8080/rest/filename.txt. 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 404.
Notes:
I tested it in Chrome 58 and Postman 4.10.7
According to https://spring.io/guides/gs/rest-service-cors/ by
default #CrossOrigin allows only GET, HEAD and POST cross-origin
requests. Although specifying #CrossOrigin(methods =
[RequestMethod.GET, RequestMethod.DELETE]) did not help
I omitted some code for brevity. Actual controller also has GET request by the same mapping, delete method has return type and produces JSON response, and other minor stuff that I don't think affects the issue.
#Configuration
public class AppConfig extends WebMvcConfigurerAdapter {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("your cross origin url")
.allowedOrigins("your cross origin host/url")
.allowedHeaders("Access-Control-Allow-Origin", "*")
.allowedHeaders("Access-Control-Allow-Headers", "Content-Type,x-requested-with").maxAge(20000)
.allowCredentials(false)
.allowedMethods("DELETE");
}
}
// in your controller
#RequestMapping(value = '/{fileName:.+}', RequestMethod.DELETE)
void deleteFile(#PathVariable fileName) {
// your custom logic
}
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "PUT", "POST", "PATCH", "DELETE", "OPTIONS");
}
};
}

Resources