Can't enable CORS for /token #147

Closed
plupp-git opened this Issue Jan 20, 2014 · 4 comments

Projects

None yet

2 participants

@plupp-git

Hi!

I cannot enable CORS (System.Web.Http.Cors), when using authentication with Thinktecture.IdentityModel.45.

I have a problem with the endpoint for token, and I'm using the default "/token".

What happens is that when calling /token (from a javascript client) the browser issues 2 calls, the "OPTION" call and the "GET" call for the "/token" resource. I'm using a simple PolicyProviderFactory just to be able to check that requests get the correct CORS policy and it just returns

            new EnableCorsAttribute("*", "*", "*");

The first OPTION call works, and the GetCorsPolicyProvider gets hit. The other call works, but the GetCorsPolicyProvider doesn't get hit and the result is that the server returns a 200 OK with all the correct headers etc, but, the content response is empty.

I needed to add the following for the token resource in the route configuration otherwise I would get a "NOT FOUND".

            config.Routes.MapHttpRoute(
                name: "SecurityToken",
                routeTemplate: "api/token");

On all other requests both the OPTIONS and the GET invokes the CORS Policy provider and everything works. I've debugged into thinktecture.identitymodel and the corrent response, the correct token is returned.

The GET method of /token resource doesn't invoke the CORS Policy provider.. but why? Mabye it's related to issue #101?

The authentication configuration looks like

    var authentication = new AuthenticationConfiguration
        {
             ClaimsAuthenticationManager = new ClaimsTransformer(),
             RequireSsl = false, 
             EnableSessionToken = true,
             SendWwwAuthenticateResponseHeaders = true
         };

         var accessKeyHandler = new SimpleSecurityTokenHandler(
                "accessKey", 
                AccessKey.Validate);

            authentication.AddAccessKey(
                accessKeyHandler,
                AuthenticationOptions.ForHeader("access-key"));

            authentication.AddBasicAuthentication(UserCredentials.Validate, retainPassword: true);
            PassiveSessionConfiguration.ConfigureMackineKeyProtectionForSessionTokens();
@vonbv
vonbv commented Jan 22, 2014

I think the key to your solution is in Brock's reply in issue 101.

"Also, make sure you've registered the CORS handler prior to the security handler"

// do this first
var corsConfig = new WebApiCorsConfiguration();
corsConfig.RegisterGlobal(your_HttpConfiguration_here);
// then
your_HttpConfiguration_here.MessageHandlers.Add(new AuthenticationHandler(CreateYourAuthConfig()));

@plupp-git

I've tried that, and it doesn't change anything :(. I've debugged the internals of web api and I can see that the InnerHandler of the CorsHandler is the HttpRoutingDispatcher, and it has the "/api/token" route as a HttpWebRoute. But if I in the debugger step from HttpServer and through the pipeline, it is different if the request is a options request or a get request. When the options request execute, the CorsHandler is called (All the handlers are called like expected), but when the get request executes the AuthenticationHandler gets called directly and the CorsHanlder.SendAsync never gets called.

From what I understood about handlers they should get called if they are registered globally? The AuthenticationHandler have the CorsHandler as InnerHandler... I don't understand what determines which handlers that gets called for a request..

I've tried to enable Cors in the sample for thinktecture and there it works, it's something strange with how this works in my web project which also has MVC, not just web api. But for test purposes I've removed all other routes but web api default and the token route.

@plupp-git

Looks like I found the problem, it is the order of the handlers. But I've tried to do .EnableCors() before and after doing config.MessageHandlers.Add(new AuthenticationHandler(authentication)); It needs to be in correct order since the AuthenticationHandler.SendAsync calls SendSessionTokenResponse which just returns the response and doesn't call base.SendAsync().

What happens is that CorsHandler always gets added last. And I think that it is because of how the EnableCors work internally.. it doesn't call MessageHandlers.Add right away:

    httpConfiguration.set_Initializer(delegate (HttpConfiguration config) {
        if (!config.get_Properties().TryGetValue("MS_CorsEnabledKey", out corsEnabled))
        {
            config.get_MessageHandlers().Add(new CorsMessageHandler(config));

Strange.. since this works in the sample...

@plupp-git

One simple line of code fixes the problem:

config.EnsureInitialized();

EnableCors first then Ensure... then Add AuthenticationHandler

@plupp-git plupp-git closed this Jan 22, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment