Integrating older ASP.NET server-side application into ADFS for authentication, which means I pretty much had to write everything from scratch. have everything working (/authorize, /token) up until the /userinfo call.
My code, in a nutshell -
HttpClient client = new HttpClient();
var req = new HttpRequestMessage {
RequestUri = new Url("https://<server_ip>/adfs/oauth2/userinfo"),
Method = HttpMethod.Get,
};
req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.AccessToken);
req.Headers.UserAgent.Clear();
req.Headers.UserAgent.Add(new ProductInfoHeaderValue("OldApp", "11.3.0"));
var result = await client.SendAsync(req);
The result is a HTTP error 405 - Method Not Allowed. Doing searches online, I see this as a common issue when the trailing "/" is left off the url, but I get the same result with a trailing slash.
After poking around, there are a lot of examples that use newer libraries and such that I can't use, sadly. None mention usage of the /userinfo, and I'm thinking that the issue isn't necessarily in how I'm calling the URL, but configuration of the 'Application Group' in ADFS.
Okay - I found the issue, and will document it here in case others come across the same thing..
While I am not sure why /userinfo is giving a 405 - the URL I was using is wrong, despite it being listed in the Endpoints folder. There shouldn't be any "oauth2" in the URL. The correct code (and URL) is:
var req = new HttpRequestMessage {
RequestUri = new Url("https://<server_ip>/adfs/userinfo"),
Method = HttpMethod.Get,
};
req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.AccessToken);
req.Headers.UserAgent.Clear();
req.Headers.UserAgent.Add(new ProductInfoHeaderValue("OldApp", "11.3.0"));
var result = await client.SendAsync(req);
Also something to keep in mind - this has been stated elsewhere, but not as clearly as here, I hope:
The /userinfo will ONLY give you the NameIdentifier ("sub") claim. (As far as I can see.) No matter what scope you pass it. You will get all your information (that should normally be in the /userinfo call) in the "id_token" parameter from you /token call, encoded as JWT.
Personally I was led to do the same thing as you, the only solution was to download the ADAL library (You will find the link below) and debug the code in order to re-produce the same HTTP stream from ADAL.
You can create a new project so that you can integrate ADAL, for debugging or else intercepting the HTTP stream
Link ADAL
Related
I ran into some issues with CORS when setting up my Blazor client-side API client to make requests. I think I found the solution to that, but the solution is also throwing errors.
The main error is:
"WASM: System.Net.Http.HttpRequestException: TypeError: Failed to execute 'fetch' on 'Window': The provided value '2' is not a valid enum value of type RequestCredentials."
the code is
string link = API_RequestLoginTokenEndPoint;
Http.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
Http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Authorization", "basic:testuser:testpassword");
var requestMessage = new HttpRequestMessage(new HttpMethod("GET"), link);
requestMessage.Properties[WebAssemblyHttpMessageHandler.FetchArgs] = new
{
credentials = FetchCredentialsOption.Include
};
var response = await Http.SendAsync(requestMessage);
var responseStatusCode = response.StatusCode;
var responseBody = await response.Content.ReadAsStringAsync();
output = responseBody + " " + responseStatusCode;
I also tried changing the request message to:
var requestMessage = new HttpRequestMessage(HttpMethod.Get, link);
In case this was the ENUM the error referred to. In the Startup ConfigureServices I tried to add:
WebAssemblyHttpMessageHandler.DefaultCredentials = FetchCredentialsOption.Include;
I am using Blazor preview 9. I also tried adding some CORS code to my PHP script on the API route that should accept all origins, but the last question I posted I was told to use this method to fix the CORS problem, which now gives me a new error.
Am I doing something wrong or am I missing something? The error in the browser usually points to the line with the async request:
var response = await Http.SendAsync(requestMessage);
This is a bug not yet fixed. Use this instead :
requestMessage.Properties[WebAssemblyHttpMessageHandler.FetchArgs] = new
{
credentials = "include"
};
I had a similar issue and could not resolve the pre-flight activity.
I WAS ABLE TO SOLVE THIS BY COMMENTING OUT HTTP REDIRECTION MIDDLEWARE.
context: Blazor client calls asp.net.core api in different url.
Not sure if this a good solution but I felt I needed to mention this after
spending 1 week on this frustrating issue! Hope it helps someone.
List item
I have created a Google App Script REST - Application (starting with "script.google.com/"), that works with HTTP-requests.
The application works fine when it is available to 'everyone, even anonymous' but when I set it available to my domain only [EDIT:] OR "only myself" from the publish/deploy as WebApp[/EDIT], I can only access the web app with browser and signing in but not with http request.
I have tried requesting an authorization token with both Google OAuth Playground and an android application based on a Xamarin Auth Tutorial.
Both methods have resulted me a working authorization token that I can copy+paste to an other platform an confirm it is working with a request to https://wwww.googlapis.com/plus/v1/people/me.
I can access the Web app with browser and signing in. Now when I call my script with http request I get the following result:
"<HTML> <HEAD> <TITLE>Unauthorized</TITLE> </HEAD> <BODY BGCOLOR="#FFFFFF" TEXT="#000000"> <H1>Unauthorized</H1> <H2>Error 401</H2> </BODY> </HTML>"
I have tried to call the Web App with another App Script:
var headers = {
"authorization": "Bearer [access_token]",
};
var params = {
method:"GET",
contentType:"application/json",
muteHttpExceptions:true,
headers:headers,
};
var url = "https://script.google.com/[rest_of_the_script_url]";
var response = UrlFetchApp.fetch(url, params);
Also I have tried calling the Web App with C# OAuth2Request (Taken from the Xamarin tutorial):
var url = "https://script.google.com/[rest_of_the_script_url]";
var request = new OAuth2Request("GET", new Uri(url), null, account );
Also I have tried C# HttpWebRequest:
string accessToken = "Bearer [access_token]";
string url = "[https://script.google.com/[rest_of_the_script_url]";
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.create(url);
request.Method = "GET";
request.ContentType = "application/json";
request.Headers.Add("Authorization", accessToken);
var response = request.getResponse();
All previous methods have the same result: "(401) Unauthorized".
For scopes I have set:
https://www.googleapis.com/auth/plus.me
https://www.googleapis.com/auth/userinfo.email
My WebApp does not require any scopes according to it's properties.
[EDIT:] Also to make sure it does not I did set a doGet() method as simple as possible:
function doGet(e)
{
return ContentService.CreateTextOutput("success");
}
This question has been asked before, but some have found the solution and some have not. Also I did not success with the answers either.
I think my first attempt covers this one.
I tried to translate the Java answer to C#
Ok, thanks for reading down here, wish some one can help me out with this as I'm running out of ideas (and time, eventually).
EDIT:
Though the issue has resolved and turned out to be a scope-issue I am answering the questions in the comments below, in case this question might be of any help to anyone in the future.
I was able to get this to work with an access token authorized with the https://www.googleapis.com/auth/drive.file scope in the Google OAuth Playground.
That doesn't seem quite right in my opinion, but it's the least permissive scope I got to work.
I have an API Gateway where I'm setting the authentication to use AWS_IAM. This requires that I sign each request with the AWS V4 signature and attach the HMAC in the header. I've found libraries to sign a request with the V4 signature in nodejs. But I cannot find a library to sign for me. Even the aws-sdk for .NET has this abstracted for their own specific use case. Is there a library out there (i've done a quick google search and found no results)? Or do I need to write out the hmac myself?
While this is an old question, since AWS has not "prioritized accordingly" with regards to the .NET AWS SDK as stated in their comment above and this is still a relevant problem today, I found a good library that will take care of the AWS V4 request signing for you.
Here is the Nuget package.
Here is the GitHub source and implementation documentation.
In addition, I've found that for my API Gateway AWS_IAM Authorization to work with temporary security credentials, you also need to include the "x-amz-security-token" header with the current session token as it's value as well in your request.
you can read on how the signature is done and you can (if you want).
I would recommend pulling in the AWS SDK for .NET and using the functionality from the SDK to actually perform the signature.
Here is the signer form the SDK:
https://github.com/aws/aws-sdk-net/blob/6c3be79bdafd5bfff1ab0bf5fec17abc66c7b516/sdk/src/Core/Amazon.Runtime/Internal/Auth/AWS4Signer.cs
You may need to adapt it (ie it knows about AWS services and endpoints by default)
An alternative to Aws4RequestSigner is AwsSignatureVersion4. I think its API is easier to work with, but I am biased since I am the author of the latter.
When using SSO authentication, you also have a session token that you need to include in the http request.
After signing the request, add the session token inside the http header x-amz-security-token.
Here is an example of implementing this inside a search request:
var baseUrl = "es_url";
var indexName = "index_name";
var requestUri = new Uri($"{baseUrl}/{indexName}/_search");
var req = new HttpRequestMessage
{
RequestUri = requestUri,
Method = System.Net.Http.HttpMethod.Post,
Content = new StringContent(query, Encoding.UTF8, "application/json")
};
var accessKeyId = "ACCESS_KEY";
var secretKey = "SECRET_KEY"
var sessionToken = "SESSION_TOKEN";
var signer = new AWS4RequestSigner(accessKeyId, secretKey);
req = await signer.Sign(req, "es", "us-west-2");
req.Headers.Add("x-amz-security-token", sessionToken);
var client = new HttpClient();
var response = await client.SendAsync(req);
I am struggling to call APIs hosted in Google Cloud https://apis-explorer.appspot.com/apis-explorer/?base=https%3A%2F%2Finnovative-glass.appspot.com%2F_ah%2Fapi#p/mirror/v1/
Up to my understanding, APIs are exposed as REST service. I need to make rest service call from .net application.
I have done OAuth Authentication. I am passing access_token as per the guidance given https://developers.google.com/accounts/docs/OAuth2WebServer
My Code:
UriBuilder uriBuilder = new UriBuilder("https://innovative-glass.appspot.com/_ah/api/mirror/v1/timeline");
string userId = Session["userId"] as string;
var state = Utils.GetStoredCredentials(userId);
NameValueCollection queryParameters = HttpUtility.ParseQueryString(uriBuilder.Query);
queryParameters.Set("access_token", state.AccessToken);
uriBuilder.Query = queryParameters.ToString();
var request = (HttpWebRequest)WebRequest.Create(uriBuilder.ToString());
request.Method = "GET";
var response = (HttpWebResponse)request.GetResponse();
I am getting UnAuthorized exception.
Is my understanding is right? Am I doing right way?
It seems that cloud endpoints don't use the Google API default of accepting access_token as query parameter. According to the Discovery document the equivalent query parameter is oauth_token so it should work with:
queryParameters.Set("oauth_token", state.AccessToken);
Alternatively (which in my opinion is the better solution) you can also set the Authorization header of the request instead of adding the token as query parameter:
request.Headers.Add("Authorization", "Bearer " + state.AccessToken);
Where are you getting the AccessToken from, and are you sure it is still a valid token? Remember that access tokens expire about an hour after being generated, although can be revoked earlier.
Clicking on the sign-in button at innovative-glass.appspot.com gives me an origin mismatch error, so it looks like you may also have a configuration issue.
Have you been able to get it to work using just the API Explorer?
After Twitter deprecated their Twitter API 1.0, I've tried several methods in order to get the 1.1 API working for my Windows 8 application. However, what you see below is basically what I've ended up with:
public List<UserTweet.User> jsonFromTwitter;
private async void fetchTweet()
{
var jsonTwitter = new Uri("http://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=stackoverflow&result_type=recent");
HttpClient client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, jsonTwitter);
var oAuthHeader = "OAuth oauth_consumer_key=\"XXXXX\", oauth_nonce=\"XXXXX\", oauth_signature=\"XXXXX\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"1318622958\", oauth_token=\"XXXXX-XXXXXX\", oauth_version=\"1.0\"";
request.Headers.Add("Authorization", oAuthHeader);
var response = await client.SendAsync(request);
var responseString = await response.Content.ReadAsStringAsync();
jsonFromTwitter = JsonConvert.DeserializeObject<List<UserTweet.User>>(await client.GetStringAsync(responseString));
//listbox.ItemsSource = jsonFromTwitter;
}
However, this won't do much good, and it switches between mainly a couple of errors. One of them can be seen below, and the other one is "Could not authenticate user" or similar, basically there's something wrong with the headers as far as I've understood.
Anyone got any ideas on how to construct a working OAuth header for this? I'm clueless at the moment.
There's a lot more you need to do for the value assigned to the Authorization header - plain text won't work. The following pages in the Twitter OAuth documentation might help you get started in the right direction.
Twitter's Docs have a section on Authentication
Authorizing a Request
Creating Signatures