angular2: asp.net core service throws 'No access control allow origin' when Windows Authentication is on - asp.net-web-api

I have any angular2 app accessing asp.net core webapi service. It is working if webapi iis configuration is (Properties\launchSettings.json):
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:12246/",
"sslPort": 0
}
},
However, it throws the error once WindowsAuthentication is true and AnonymousAuthentication is false. The error:
XMLHttpRequest cannot load
http://localhost:12246/api//values/getSettings. 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 401.
Any idea please?

You are attempting to make a cross-origin request. This is permitted under the CORS specification, but requires configuration.
There are three steps to fixing this problem.
Configure both web servers to use Windows Authentication (and disable anonymous authentication). That is, both the server hosting your Angular 2 app and the server hosting your ASP.NET Core WebAPI app must be configured.
Enable CORS your ASP.NET Core WebAPI app:
in your Startup.cs file:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
if (env.IsDevelopment())
{
app.UseCors(builder =>
builder
.WithOrigins("http://localhost:4200") //<-- OP's origin
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials()
);
}
app.UseMvc();
}
Have Angular 2 send your credentials along with its CORS request:
import {Injectable} from '#angular/core'
import {Headers, Http, Response} from '#angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/toPromise';
#Injectable()
export class SomeAngularServiceThatCallsYourAPI{
constructor(private http: Http) { }
getApiData(): Promise<MyDataResult[]> {
var apiUrl = 'http://localhost:12246/api//values/getSettings';
return this.http.get(apiUrl,{
withCredentials: true
})
.toPromise()
.then(response => this.extractData(response) as MyDataResult[])
.catch(this.handleError);
}
}
For further details, see my blog post.

Related

How should I set net core api cors?

I am coding an unofficial twitter api for myself. Then I send a get to this api using the console screen in my browser with the following method.
function httpGet(theUrl)
{
var xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", theUrl, false ); // false for synchronous request
xmlHttp.send( null );
return xmlHttp.responseText;
}
such
httpGet(https://localhost:44311/WeatherForecast/alienationxs/true);
the problem is that when i do this via www.google.com it's ok and json data reaches me. but when I do it via twitter.com I get the following error.
via google.com
my cors settings on api
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddCors(options =>
options.AddDefaultPolicy(builder =>
builder.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin())); ;
services.AddMvc();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "twitterAPI", Version = "v1" });
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "twitterAPI v1"));
}
app.UseRouting();
app.UseCors(builder => builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
all i want is to reach my api via twitter.com just like google.com.
First, let's separate the flies from the cutlets.
Cross-Origin Resource Sharing (CORS) - is a separate security layer.
Content Security Policy (CSP) - is a separate security layer, it's appied before CORS. After passing through CSP yous can face with CORS if last one is breached.
As you can see from error message "... because it violates the following Content Security Policy directive ...", you faced with CSP violation therefore your CORS settings have no mean.
What's goin on.
You enter twitter.com web page and tries to execute connect request to localhost:44311 on behalf of twitter web page. But twitter's web page protected by CSP which forbid such requests:
Pay attention on 'connect-src' directive, which governs XMLHttpRequest().
The www.google.com web page does not have CSP, therefore you request on behalf of google does success.
The Twitter API does not support CORS.

Cannot includ/send jwt token using auth0/angular-jwt

I use "https://github.com/auth0/angular2-jwt" to send JWT token to my server, I can see the token when I debug http request (angular) but at the server (java) the token is not found
this is my config jwt
JwtModule.forRoot({
config: {
headerName: 'API_TOKEN',
tokenGetter: function tokenGetter() {
return localStorage.getItem('API_TOKEN');
},
whitelistedDomains: ['localhost:8092'],
// blacklistedRoutes: ['https://localhost:8092/login'],
authScheme: ''
}
}),
I added a JwtHttpInterceptor for debug my request :
#Injectable()
export class JwtHttpInterceptor implements HttpInterceptor {
constructor() {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req);
}
}
and this is a screenshot : JWT token in header request
but server could not find this token.
When I try to add token with a chrome pluging, It work and server can find my token : token added with chrome pluging
Can you help me please?
I found the solution if it will help another person, in fact it comes from the backend, I reversed the spring security filters and my request "OPTIONS" should go through the filter CORS first
httpSecurity
.addFilter(jwtAuthenticationFilter)
.addFilterBefore(corsInputFilter, UsernamePasswordAuthenticationFilter.class) // OPTIONS REQUEST SHOULD COME HERE IN THE FIRST AND RETURN THE RESPONSE WITHOUT CONTINUE OTHERS FILTERS
.addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

Angular 2 JWT doesnot sends Authorization Bearer Token during page reload

I am using Tymon JWT to setup the JWT Token from my Laravel application.
I have setup similar to the quick start guide and when i test using the postman, the backend successfully returns the access token.
On frontend i am using Angular2-jwt to send the request from frontend also replacing the Http module with AuthHttp from this package which is a wrapper for the Http module.
Configured the AuthModule similar to the guide:
import { NgModule } from '#angular/core';
import { Http, RequestOptions } from '#angular/http';
import { AuthHttp, AuthConfig } from 'angular2-jwt';
export function authHttpServiceFactory(http: Http, options: RequestOptions) {
return new AuthHttp(new AuthConfig({
tokenName: 'token',
noJwtError : true, //<== Using this explicitely because i am using AuthHttp on every routes.
tokenGetter: (() => sessionStorage.getItem('token')),
globalHeaders: [{'Content-Type':'application/json'}],
}), http, options);
}
#NgModule({
providers: [
{
provide: AuthHttp,
useFactory: authHttpServiceFactory,
deps: [Http, RequestOptions]
}
]
})
export class AuthModule {}
During the first load of the login page also if i have valid auth token there is no any Authorization: Bearer <token> added in the Get request. Sometimes it gets added in the Header and on some request there is no Authorization in the header.
Image1:
No Authorization added in the header even though there is valid token
Image2:
Authorization Header Added before requesting the token to the backend.
I am not sure about the addition of the header when does it adds and when does it removes from the header.
Have anyone else received this kind of issue?
If further details is required will add them.

Cors not working in web api 2.0

I'm trying very hard to understand and enable CORS in a web api project. I've hit a blocking point. I've started with an ASP.NET MVC Web Api 2 project with an ASP.NET identity. Whatever I do seems to not work.
I've deleted my global.asx file and my startup looks like this:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration configuration = new HttpConfiguration();
// I'm not sure it this is the proper way to use webapiconfig
WebApiConfig.Register(configuration);
app.UseWebApi(configuration);
app.UseCors(CorsOptions.AllowAll);
ConfigureAuth(app);
}
}
and the WebApiConfig.Register code is:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
config.AddODataQueryFilter();
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
RegisterModels(); //Automapper here
}
I have the mc aspnet cors and microsoft owin host System web installed.
The "[assembly: OwinStartup(typeof(MyProject.Startup))]" is in place, and in the web.config I have:
<appSettings>
<add key="owin:AutomaticAppStartup" value="true" />
</appSettings>
I only call app.UseCors(CorsOptions.AllowAll) to enable CORS, no other way like config.enableCors or anything else, but whenever I try getting the token or anything in the API, I get the error:
Reason: CORS header ‘Access-Control-Allow-Origin’ missing.
I have tried putting a breakpoint in the Configuration method but it is not called... ever. I'm debugging with IIS Express.
Nothing worked for me.. after many tries I finally managed to get something working.
if you have the same problem..
1) remove anything related to cors from the nugget packages installed .. everything.
2) remove anything related to cors from the web.config.
3) In Gloabal.asax
protected void Application_BeginRequest(object sender, EventArgs e)
{
var context = HttpContext.Current;
var response = context.Response;
response.AddHeader("Access-Control-Allow-Origin", "*");
response.AddHeader("X-Frame-Options", "ALLOW-FROM *");
if (context.Request.HttpMethod == "OPTIONS")
{
response.AddHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PATCH, PUT");
response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
response.AddHeader("Access-Control-Max-Age", "1000000");
response.End();
}
}
This work for both /api and /token.
This is a generic solution please be aware before deploying it to prod.
Hope will help anyone who has the same problem.

WebAPI EnableCors with SupportsCredentials = true not working

I have an MVC site deployed to mysite.mydomain.co that authenticates against ADFS and creates an auth cookie:
public partial class Startup
{
public void ConfigureUserAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(WsFederationAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType
});
app.UseWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
MetadataAddress = ConfigurationManager.AppSettings["adsfs.MetadataAddress"],
Wtrealm = ConfigurationManager.AppSettings["adsfs.Wtrealm"]
});
}
}
There is also a WebAPI site deployed on "myapi.mydomain.com" with CORS enabled:
GlobalConfiguration.Configuration.EnableCors(new EnableCorsAttribute("https://mysite.mydomain.com", "*", "*") { SupportsCredentials = true });
The the user goes to mysite.mydomain.com. The MVC site authenticates against ADFS and I see the auth cookie being set with no problem.
My application is mostly an SPA, so from javascript there's a AJAX calls to myapi.mydomain.com using jQuery, setting the withCredentials option to true:
$.ajaxSetup({
xhrFields: { withCredentials: true }
});
That options is supposed to send security credentials (cookies) to the API. At runtime I don't see the cookies being set to the API and I get a 401 (unauthorized) error as expected.
If I run the same code on localhost (except for changing the origins to localhost of course) I see the cookie flowing to the API with no problem. My best guess is it works because it's the same subdomain (localhost) whereas on my servers is "mysite" vs "myapi".
Any ideas?

Resources