owin cors or web api cors - asp.net-web-api

there are 100s of question on CORS on web-api, and on how to enable CORS, there is a different answer each one provides. I am so confused and dont know which answer is correct. And the problem is none of the answers actually explains it point wise, what each line of code does, so that I can understand and solve my problem rather than copy-pasting the code.
anyways, the question is: I am using asp.net web api 2 using owin. And i need to enable CORS. how do I do it? There is cors settings for OWIN
application.UseCors(CorsOptions.AllowAll);
and there is cors settings for asp.net web api
var cors = new EnableCorsAttribute("*", "*", "*", "*");
config.EnableCors(cors);
which one should I use given I am not using OAUTH (I am specifying this because answers on SO differ on when we use OAUTH v/s when we dont use it).
Do i need to enable CORS for both OWIN & WEB-API or only for one of them. There is issue if both are enabled, read here
It would be really helpful if someone can explain me the difference between
OWIN CORS
WEB API CORS
CORS with OAUTH using OWIN/WEBAPI
Also there are answers for self-hosted web api against owin hosted web-api, which further adds to the confution :(, sorry for the rant

You are supposed to use Web API's CORS if you need CORS applied to your API Controllers. For everything else (like a token service) you're stuck with having to use Owin.Cors.
If you end up using both, you'll need to make sure they don't overlap and apply CORS twice to the same request.
Web API 2.2 makes it easy to enable CORS by providing the EnableCorsAttribute.
Basic Usage
[EnableCors("*", "*", "*")]
public class ResourcesController : ApiController
{
...
Attribute definition
[AttributeUsageAttribute(AttributeTargets.Class|AttributeTargets.Method, AllowMultiple = false)]
public EnableCorsAttribute(
string origins,
string headers,
string methods
)
To enable CORS globally use
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var cors = new EnableCorsAttribute("www.example.com", "*", "*");
config.EnableCors(cors);
// ...
}
}
You will also need to install the CORS package from nuget
Install-Package Microsoft.AspNet.WebApi.Cors

There is a way to fix this. Since OWIN and ASP.NET.CORS libraries are working simultaneously. Owin token or authentication method needs to be configured to enable CORS separately from all other API controllers.
Fist thing first, don't use cors with Owin in Startup.cs :
public void Configuration(IAppBuilder app)
{
//app.UseCors(CorsOptions.AllowAll);
Find GrantResourceOwnerCredentials method and add Access-Control-Allow-Origin to context so when it returns a call after authentication is completed that browser finds the header and accepts it.
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "http://localhost" });
Now install Microsoft.AspNet.WebApi.Cors package from Nuget to your webapi project, and add this to Register method
public static void Register(HttpConfiguration config)
{
var cors = new EnableCorsAttribute("http://localhost, ", "accept,accesstoken,authorization,cache-control,pragma,content-type,origin", "GET,PUT,POST,DELETE,TRACE,HEAD,OPTIONS");
config.EnableCors(cors);
Worked for me.

Related

Override CORS policy in java springboot

I am trying to have my frontend server pull an http request from my backend server, but am getting the following error in my browser console:
Access to XMLHttpRequest at 'http://localhost:8080/run' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I know this is a security protocol, but is there an easy way to override this issue and allow for port 8080 (my backend) to return calls from port (3000)?
edit: I am using java springboot as my backend framework and React as my frontend framework
edit 2: I installed and used the Moesif Origin & CORS Changer extension and it works, I just would like to know if there is a more permanent workaround.
A quick approach is to add #CrossOrigin (import is org.springframework.web.bind.annotation.CrossOrigin) to your Rest Controller(s).
You can use CRA proxy setting, too.
This may help:
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:3000");
}
};
}

Prevent direct call to my spring boot rest API

I have several REST services (on spring boot) used by a javascript file (website) and these services can be called directly by anyone (and you can see the API url/parameters with the developper console on any browser).
So I would like to prevent the direct calls to the API, exept of course from the front side of my app.
I saw that I can use an API key with spring security but is it reliable? Since I think you can see the key if you intercept the message with developper console.
What you can do are the following :
Disable CORS in your springboot application by setting the following globally or per endpoint as you wish.
To set the CORS per endpoint :
#CrossOrigin(origins = "http://localhost:9000")
#GetMapping("/greeting")
public Test testing(#RequestParam(required=false, defaultValue="Test") String name) {
System.out.println("in test");
return new Testing(10, String.format(template, name));
}
You can use spring security to preauthorize your controller endpoints to make sure that only the authorized has access to the controller.
Like for example :
#RestController
#RequestMapping({"/v2/"})
public class ExampleTestController {
#PreAuthorize("hasAuthority('ROLE_ADMIN')")
#RequestMapping(value = "/test", method = RequestMethod.GET)
String test() {
return "Hello";
}
}
Using spring security is safe, as the user is always validated before access is granted . Even while using Oath2 the key generated is after validating the user login and the key can be used to validate every request to the controller by passing it in the header or using it in the rest template.
Another way of isolating your rest endpoints is by using the load balancer (or ngnix or anything) to block requests to these endpoints from outside your domain.

CORS with Spring Boot - restrict GET requests to certain domains

I am using Spring Boot and would like to restrict HTTP GET requests only from certain domains. For example, I would like to accept requests only from a list of predefined domains (e.g. https://www.frontend.com, https://www.test-frontend.com). How could I implement such a functionality?
I expected to face CORS issues, but theses do not apply for GET requests. Any ideas?
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("https://www.frontend.com", "https://www.test-frontend.com")
.allowedMethods("GET");
}
Reference: https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/cors.html
First .allowedMethods use for allow methods so if you don't want to allow "GET" then put all others methods but do not put GET method, like below:
.allowedMethods("PUT", "DELETE", "PATCH")
and second you can not CORS by non-webapp clients like curl or Postman, any non web app client.

CORS on Webjars in Spring Boot?

I'm using Spring Boot 1.4.0.M2 and Spring 4.3.0.RC1, trying to enable CORS support in a simple app. I have this added:
#Bean
public WebMvcConfigurer webMvcConfigurerAdapter() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
};
}
I also have webjars pulled in through Gradle, such as:
compile('org.webjars:jquery:2.2.3')
The CORS support works fine with my REST API (via #RestController), but somehow it doesn't seem to work when accessing my webjars. For example (UPDATE: less confusing example), requesting:
http://example.org/webjars/bootstrap-datepicker/1.6.0/package.json
gets a response with the correct content but lacking the expected CORS headers, which of course defeats any actual CORS request. I can't figure out why that would be an exception to the /** mapping. How do I fix it?
JavaScript doesn't need cors configuration . In other words, you can access JavaScript resources from a site which doesn't enable cors.
From wiki site, we can obvious know that a website can freely embed images, stylesheets, scripts, iframes, videos and some plugin content (such as Adobe Flash) from any other domain. So even if you are enabling CORS on your website, but your resource is javascript, so the request does not add CORS header.
Your code snippet copied from documentation is just a sample of showing how to enable CROS in a quick way. This code snippet is not complete. Using this will mess up what WebMvcAutoConfigurationAdapter provided for you.

Spring Boot: Secured RESTful API using Spring Social and Spring Security

I am trying to define and secure a RESTful API using Spring Boot. Ideally, I would like to use Spring Social and allow clients (web and mobile) to login via Facebook.
What is working
So far, I managed to have a working API using #RestController and secure it with a basic Spring Security configuration as follows:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/api/**").authenticated()
.antMatchers(HttpMethod.PUT, "/api/**").authenticated()
.antMatchers(HttpMethod.DELETE, "/api/**").authenticated()
.anyRequest().permitAll()
.and().httpBasic()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
The antMatchers could probably be improved, but I made it like this for my own clarity for now and it works fine. Doing GET requests is allowed and all others required to send the standard user:password given by Spring Security at runtime. An example using httpie:
http POST user:a70fd629-1e29-475d-aa47-6861feb6900f#localhost:8080/api/ideas/ title="My first idea"
Which right credentials, it sends a 200 OK back, otherwise a 401 Unauthorized.
Spring Social
Now, I am stuck and can't get my head around using Spring-Social-Facebook to get working with my current setup and keep fully RESTful controllers. Using standard forms and redirects seems trivial, but I couldn't find any solution for a REST-based approach that easily supports web and mobile clients for example.
As I understand, the client will have to handle the flow, since the back-end won't send any redirects to the /connect/facebook URL.
I followed the tutorial Accessing Facebook Data and it works on its own. However, I would like to avoid having to have those facebookConnect.html and facebookConnected.html templates like in the tutorial. So I don't know how to have change that.
Another Spring Boot tutorial for OAuth is also nice and working, but I would like to stick with Spring Social if possible due to the simplicity.
This post, helped for the Method not allowed issue of the /connect/facebook redirect when using those views mentioned above.
Post about Social Config. Probably, I am missing something there.
Any advice, solution or link to a better tutorial would be really helpful.
Thanks!
UPDATE 1
Now, I have a working website with traditional User SignUp and Login over forms. I have a "Login with Facebook" button that sends me over the "OAuth dance". So next issue is that I have to create somehow the User manually after the Facebook login has been successful, because for the moment both "logins" are not related, so even though the user is logged in with Facebook, he doesn't yet have an associated User object with the right authorisations.
SocialAuthenticationFilter by default, redirects to '/signup' in the case you described, user is signed in from a social app, however, no local account exists. You can provide a handler to create a local account. This is also covered in the spring-socal samples.
#RequestMapping(value = { "/signup" }, method = RequestMethod.GET)
public String newRegistrationSocial(WebRequest request, Model model) throws Exception {
String view = "redirect:/home";
try {
Connection<?> connection = providerSignInUtils.getConnectionFromSession(request);
if (connection != null) {
UserProfile up = connection.fetchUserProfile();
registerUser(up.getFirstName(), up.getLastName(), up.getEmail(), "DummyPassword");
providerSignInUtils.doPostSignUp(up.getEmail(), request);
//SignInUtils.signin(up.getEmail());
...
...
}
}
return view;
}

Resources