2
votes

I have an Azure Worker role running a ASP.Net Web API application. This is protected by ACS. When I browse to the web api using a browser, I get challenged by ACS to authenticate against either Google or LiveId. When I authenticate, I can see the data.

I am trying to access the same API from a Win 8 Metro Style App. I am trying to use the WebAuthenticationBroker.

WebAuthenticationResult webAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync(
                                                        WebAuthenticationOptions.None,
                                                        new Uri("https://xxxxx.accesscontrol.windows.net:443/v2/wsfederation?wa=wsignin1.0&wtrealm=http%3a%2f%2fyyyyy.cloudapp.net%2f"),
                                                        new Uri("http://yyyyy.cloudapp.net/")
                                                       );

When I start the app, it challenges me to Authenticate either through Google or LiveId as before. This passes and I get a successful result.

Then I create a call to the API using a HttpClient:

    HttpClient client = new HttpClient();
    Uri _baseUri = new Uri("http://yyyyy.cloudapp.net/api/");
    client.BaseAddress = _baseUri;

    var response = client.GetAsync("Values/").Result;
    var responseBodyAsText = response.Content.ReadAsStringAsync().Result;

    var ids = JsonConvert.DeserializeObject<IList<int>>(responseBodyAsText);

This sort of works, it appears to be navigating to the URI correctly, but the payload that come back is HTML asking me to log in rather than the JSON data I am expecting.

I have spent more time on this than is sensible and have run out of ideas! Can anyone please help?

3
I have the same issues. Depending on what login provider used, the responsedata are different. Using facebook, the result are a long string like : /v2/facebook?cx=cHI9d3NmZWRlcmF0aW9uJnJtPWh0 and using LiveID its short: net/v2/wsfederation?wa=wsignin1.0. I also would love to know how to go on from herePoul K. Sørensen
So far i have found out that, the url for facebook needs response_type=token to get the token. Assuming something like that for the other providers alsoPoul K. Sørensen
response_type=code for googlePoul K. Sørensen
My next issue is, that now i have changed the return url on ACS to the controller that redirects such it work for the metro app. But then my web interface dont work as it excepts the return url to be yyyyy.cloudapp.netPoul K. Sørensen

3 Answers

2
votes

You have to make sure when testing on localhost that ACS can access your computer.

And as @caleb wrote, you need to listen for the token and redirect it for the broker. You can see my post with a working example and how to set it up.

Does the WebAuthenticationBroker work in Windows 8 Metro App post Release Candidate

1
votes

The WebAuthenticationBroker will simply keep browsing until the url the browser is going to load is the one specified in the callbackUri parameter. It will then return the final url to you, including any query parameters. It never actually makes the request to the callbackUri.

The problem you are having is that the WS-Federation protocol which ACS implements posts the token back to return url (specified in the ACS config portal), which is probably the same url you have specified as the callbackUri parameter in your AuthenticateAsync method.

What you need to do is handle that post and redirect the request to the callbackUri, but with the query string including the token.

I'm using WebApi and WIF and I have my callbackUri specified as http://localhost:3949/api/federationcallback/end and return url specified as http://localhost:3949/api/federationcallback. This allows me to have a controller handle the post and then redirect with the token in the URL. The controller looks like this.

public class FederationcallbackController : ApiController
{
    public HttpResponseMessage Post()
    {
        var response = this.Request.CreateResponse(HttpStatusCode.Redirect);
        response.Headers.Add("Location", "/api/federationcallback/end?acsToken=" + ExtractBootstrapToken());

        return response;
    }

    protected virtual string ExtractBootstrapToken()
    {
        return HttpContext.Current.User.BootstrapToken();
    }
}

I can then get the token like this:

var authenticateResult = await WebAuthenticationBroker.AuthenticateAsync(
            WebAuthenticationOptions.None,
            new Uri("https://xyz.accesscontrol.windows.net:443/v2/wsfederation?wa=wsignin1.0&wtrealm=http%3a%2f%2flocalhost:3949%2f"),
            new Uri("http://localhost:3949/api/federationcallback/end"));

var oauthToken = authenticateResult.ResponseData.Substring(authenticateResult.ResponseData.IndexOf("acsToken=", StringComparison.Ordinal) + 9);
0
votes

Shouldn't you re-use the token in WebAuthenticationResult when calling the API?

var webAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.None, 
        new Uri("https://xxxxx.accesscontrol.windows.net:443/v2/wsfederation?wa=wsignin1.0&wtrealm=http%3a%2f%2fyyyyy.cloudapp.net%2f"), new Uri("http://yyyyy.cloudapp.net/"));

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization
        = new AuthenticationHeaderValue("OAuth", webAuthenticationResult.ResponseData);