OAuth 1.0, javascript and server-to-server authentication - oauth

We are trying to integrate a "sign in with twitter" function in our application and for this purpose we are using javascript (hello.js).
Unfortunately, twitter is using oauth 1.0 so we can't have only a javascript solution but we need to implement a server-to-server communication to sign the request. The hello.js author provided an auth-server implementation for demo purposes based on node.js.
In our application for the backend part we are using java and I was wondering if a java solution exists for this purpose. Could I use for instance signpost or similar to do the job of auth-server ?
[UPDATE]
I tried to set the proxy used by hello.js to a mine servlet (so, instead of herokuap now I'm using a localhost servlet with oauth in the buildpath).
This servlet is doing the following:
OAuthConsumer consumer = new DefaultOAuthConsumer(
"xxxx",
"yyyyyyyyyyy");
OAuthProvider provider = new DefaultOAuthProvider(
"https://api.twitter.com/oauth/request_token",
"https://api.twitter.com/oauth/access_token",
"https://api.twitter.com/oauth/authorize");
System.out.println("Fetching request token from Twitter...");
// we do not support callbacks, thus pass OOB
String authUrl = provider.retrieveRequestToken(consumer, "http://localhost:8080/oauth1/twitter/response_server");
URL url = new URL(authUrl);
HttpURLConnection req = (HttpURLConnection) url.openConnection();
req.setRequestMethod("GET");
req.connect();
BufferedReader rd = new BufferedReader(new InputStreamReader(req.getInputStream()));
StringBuilder d = new StringBuilder();
String line = null;
while ((line = rd.readLine()) != null){
d.append(line + '\n');
}
System.out.println(d);
PrintWriter out = response.getWriter();
out.println(d);
and it prints the twitter login page in the hello.js popup. In this way I got some encoding error but it is quite working.
Anyway the callback url is mapped to another servlet where I should simply "sign" the request but I think I am missing something because sometimes I got the error
"The server understand the request but it is still refusing it"
but if I close all browser window it works.
However the response servlet is similar to this one
OAuthConsumer consumer = new AbstractOAuthConsumer(
"xxxxx",
"yyyyyyyyyyy"){
#Override
protected HttpRequest wrap(Object arg0) {
return (HttpRequest)arg0;
}
};
consumer.sign(request);
But this code does not work because I don't know how to sign a tomcat request. In oauth homepage is explained how to sign jetty and apache common http request but not the tomcat one. However, is it correct my approach ?

Please checkout the spec of node-oauth-shim which is used my //auth-server and which HelloJS delivers.

Related

Where is the OAuth2.0 Authorization Code stored?

I'm developing a C# application that needs to contact a web-based API. When contacting the API, the first thing it does is try to get an authorization code from an authorization server. Using RestSharp, my code is this:
static string GetAuthCode(string authUri, string clientId, string scope, Guid state, string callbackUri)
{
var client = new RestClient(authUri);
var request = new RestRequest("", Method.Post);
client.Options.MaxTimeout = -1;
request.AddParameter("client_id", clientId);
request.AddParameter("response_type", "code");
request.AddParameter("scope", scope);
request.AddParameter("state", state);
request.AddParameter("redirect_uri", callbackUri);
RestResponse response = client.Execute(request);
if (response.IsSuccessful)
{
string code = HttpUtility.ParseQueryString(response.ResponseUri.Query).Get("code");
return code;
}
else
throw new Exception(response.Content);
}
When I call this method, the response is successful, however I was expecting that the resulting authorization code would be appended to the ResponseUri property of the response (in its Query property). But it's not. The ResponseUri property is set to the authorization Uri (authUri). Am I looking in the wrong spot for the authorization code? Where can I find the actual authorization code?
It should be in the query parameters:
If the resource owner grants the access request, the authorization
server issues an authorization code and delivers it to the client by
adding the following parameters to the query component of the
redirection URI using the "application/x-www-form-urlencoded" format,
per Appendix B:
4.1 Authorization Code Grant - 4.1.2 Authorization Response

How to enable an dotnet 6 client app in a linux container to authenticate with user/password against a kestrel server with kerberos

I'm developing a Service in ASP.Net-Core (.net6) that connects to a BusinessCentral OData API.
The Server has SSL/Kerberos enabled and I have a user and password to authenticate with.
I use the AddHttpClient-IServiceCollectionExtension in my Program.cs like:
services.AddHttpClient([name], httpClient =>
{
httpClient.BaseAddress = new Uri(config[BaseUrl]);
}).ConfigurePrimaryHttpMessageHandler(() =>
new HttpClientHandler()
{
Credentials = new NetworkCredential(
config[Username],
config[Password],
config[Domain])
}
);
...and inject the IHttpClientFactory to my client-class:
MyODataClient(IHttpClientFactory factory)
{
_client = factory!.CreateClient([name]);
}
public HttpResponseMessage GetEntity(Entity src)
{
var path = $"{src.Type}('{src.SysId}')?";
var request = new HttpRequestMessage(HttpMethod.Get, path);
var response = _client.SendAsync(request);
return response;
}
So far so good. Everything ist fine and works (with swagger)!
BUT...
When I start this service within a linux Docker container, I get the error:
GSSAPI operation failed with error - Unspecified GSS failure. Minor code may provide more information (Cannot find KDC for realm "[domain]").
Then I tried:
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = options.DefaultPolicy;
});
Now Swagger ask me for username and password. It doesn't work but I think this is why I don't passthrough the headers from swagger to BC19... with HeaderPropagation or so (??).
Btw. I need to use a static user. No interaction...
I also read and tried keytab-stuff... But everything I read was >2 years old. Does anybody know, how to deal with it in .net6? It seems to be quite easy but I don't find the two lines of code, that I need to connect the httpClientHandler (credentials) with the AuthenticationBuilder (negotiate)
Maybe this log helps:
Authorization failed. These requirements were not met:
DenyAnonymousAuthorizationRequirement: Requires an authenticated user.
[17:20:26 INF] AuthenticationScheme: Negotiate was challenged.
[17:20:26 INF] Request finished HTTP/1.1 GET https://localhost:49179/Entity?[...]. - - - 401 0 - 28.0138ms
best regards
Oli

How may I access my own protected API via IHttpClientFactory

I'm trying to access my own API via IHttpClientFactory but am getting redirected to the login page. I had this same problem via jquery but when I included credentials: 'include' it was fixed.
This is for c# / asp.net core 2.1 MVC controller. I'm using stock identity
I've tried constructing my headers to include the Authorization with Basic and base64 encoded string including my username:password. If I allow anonymous to my endpoint then my code works fine.
The form lives in a razor page and on post sends an object in the body of the request to the endpoint. If my endpoint doesn't have the [AllowAnonymous] attribute then I get redirected back to the login and/or receive a 400 bad request
string contentJson = JsonConvert.SerializeObject(content);
HttpRequestMessage httpRequest = new HttpRequestMessage(HttpMethod.Patch, baseUrl);
HttpClient client = _clientFactory.CreateClient();
httpRequest.Content = new StringContent(contentJson, Encoding.UTF8, "application/json-patch+json");
httpRequest.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json-patch+json"));
httpRequest.Headers.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($"{yourusername}:{yourpwd}")));
HttpResponseMessage response = await client.SendAsync(httpRequest);

Securing a Web API with Windows Server 2012 R2 ADFS 3.0 and Katana

I would like to make a MVC Web Application that talks to a Web API application and use ADFS 3.0 (on Windows 2012 R2) for authentication.
I managed to make the MVC Web Application to authenticate using ADFS.
and configured everything as shown in this article by Vittorio Bertocci
http://www.cloudidentity.com/blog/2013/10/25/securing-a-web-api-with-adfs-on-ws2012-r2-got-even-easier/
Now I use the latest pre release of AAL from nuget
Now after authenticating with ADFS from web MVC app, I try to call the webapi
public async Task<String> CallSecuredAPI()
{
string authority = "https://fs.domain.com/adfs";
string resourceURI = "https://{hostheader}/SecuredAPI";
string clientID = "ExternalWebSite1";
string clientReturnURI = "https://{hostheader}/ExternalSite";
AuthenticationContext ac = new AuthenticationContext(authority, false);
AuthenticationResult ar = ac.AcquireToken(resourceURI, clientID, new Uri(clientReturnURI));
string authHeader = ar.CreateAuthorizationHeader();
var client = new HttpClient();
HttpRequestMessage request =
new HttpRequestMessage(HttpMethod.Get, "https://hostheader/SecuredAPI/api/Claims");
request.Headers.TryAddWithoutValidation("Authorization", authHeader);
HttpResponseMessage response = await client.SendAsync(request);
string responseString = await response.Content.ReadAsStringAsync();
return responseString;
}
but I get this error which I think is with the client not being a UI based client or WPF , windows App. Can someone let me know whether I am doing something wrong.
![Error when trying to get Authorization code using AAL][1]
Server Error in '/ExternalSite' Application.
Showing a modal dialog box or form when the application is not running in UserInteractive mode is not a valid operation. Specify the ServiceNotification or DefaultDesktopOnly style to display a notification from a service application.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: Showing a modal dialog box or form when the application is not running in UserInteractive mode is not a valid operation. Specify the ServiceNotification or DefaultDesktopOnly style to display a notification from a service application.
Source Error:
Line 43:
Line 44: AuthenticationContext ac = new AuthenticationContext(authority, false);
Line 45: AuthenticationResult ar = ac.AcquireToken(resourceURI, clientID, new Uri(clientReturnURI));
Line 46:
Line 47: string authHeader = ar.CreateAuthorizationHeader();
Source File: c:\Users\balakrishna.takkalla\Documents\Visual Studio 2013\Projects\ExternalSite\ExternalSite\Controllers\HomeController.cs Line: 45
Stack Trace:
[InvalidOperationException: Showing a modal dialog box or form when the application is not running in UserInteractive mode is not a valid operation. Specify the ServiceNotification or DefaultDesktopOnly style to display a notification from a service application.]
System.Windows.Forms.Form.ShowDialog(IWin32Window owner) +5701502
Microsoft.IdentityModel.Clients.ActiveDirectory.Internal.WindowsFormsWebAuthenticationDialog.ShowBrowser() +18
Microsoft.IdentityModel.Clients.ActiveDirectory.Internal.WindowsFormsWebAuthenticationDialog.OnAuthenticate() +23
Microsoft.IdentityModel.Clients.ActiveDirectory.Internal.WindowsFormsWebAuthenticationDialogBase.AuthenticateAAD(Uri requestUri, Uri callbackUri) +284
Microsoft.IdentityModel.Clients.ActiveDirectory.Internal.InteractiveWebUI.OnAuthenticate() +103
Microsoft.IdentityModel.Clients.ActiveDirectory.OAuth2Request.SendAuthorizeRequest(Authenticator authenticator, String resource, Uri redirectUri, String clientId, String userId, PromptBehavior promptBehavior, String extraQueryParameters, IWebUI webUi, CallState callState) +363
Microsoft.IdentityModel.Clients.ActiveDirectory.<>c__DisplayClass9b.<AcquireAuthorization>b__9a() +111
System.Threading.Tasks.Task.Execute() +110
if I understood correctly: you want to access a Web API from the code-behind of an MVC application.
That topology is possible with Azure Active Directory today, you can see that in action in the sample https://github.com/AzureADSamples/WebApp-WebAPI-OpenIDConnect-DotNet (I am in the process of updating it to the latest ADAL refresh, you can take a peek at the RCUpdate branch to see the work in progress).
However that topology is NOT achievable today from ADFS WS2012 R2. The reason is that an MVC app (and any other web site) is a confidential client, which OAuth2 handles differently from a public client (the WPF app you used as a starting point is a public client). In the scenario you are targeting, to use ADAL for getting a token from a confidential client you would use ADAL's method AcquireTokenByAuthorizationCode (see the sample I mentioned). However ADFS WS2012 R2 is incapable of processing that method. Today the OAuth2 support in ADFS WS2012 R2 is limited to public clients only.
Sorry for bringing bad news! As a mitigation, you might consider federating your ADFS with an AAD tenant: at that point you would be able to do what you want, authenticating as an ADFS user but getting tokens from AAD (which does support the necessary OAuth2 grant).
HTH
V.

GetClientAccessToken having clientIdentifier overwritten to null by NetworkCredential

I've been trying to get the GetClientAccessToken flow to work with the latest release 4.1.0 (via nuget), where I'm in control of all three parties: client, authorization server and resource server.
The situation I have started to prototype is that of a Windows client app (my client - eventually it will be WinRT but its just a seperate MVC 4 app right now to keep it simple), and a set of resources in a WebAPI project. I'm exposing a partial authorization server as a controller in the same WebAPI project right now.
Every time (and it seems regardless of the client type e.g. UserAgentClient or WebServerClient) I try GetClientAccessToken, by the time the request makes it to the auth server there is no clientIdentifier as part of the request, and so the request fails with:
2012-10-15 13:40:16,333 [41 ] INFO {Channel} Prepared outgoing AccessTokenFailedResponse (2.0) message for <response>:
error: invalid_client
error_description: The client secret was incorrect.
I've debugged through the source into DNOA and essentially the credentials I'm establishing on the client are getting wiped out by NetworkCredential.ApplyClientCredential inside ClientBase.RequestAccessToken. If I modify clientIdentifier to something reasonable, I can track through the rest of my code and see the correct lookups/checks being made, so I'm fairly confident the auth server code is ok.
My test client currently looks like this:
public class AuthTestController : Controller
{
public static AuthorizationServerDescription AuthenticationServerDescription
{
get
{
return new AuthorizationServerDescription()
{
TokenEndpoint = new Uri("http://api.leave-now.com/OAuth/Token"),
AuthorizationEndpoint = new Uri("http://api.leave-now.com/OAuth/Authorise")
};
}
}
public async Task<ActionResult> Index()
{
var wsclient = new WebServerClient(AuthenticationServerDescription, "KieranBenton.LeaveNow.Metro", "testsecret");
var appclient = new DotNetOpenAuth.OAuth2.UserAgentClient(AuthenticationServerDescription, "KieranBenton.LeaveNow.Metro", "testsecret");
var cat = appclient.GetClientAccessToken(new[] { "https://api.leave-now.com/journeys/" });
// Acting as the Leave Now client we have access to the users credentials anyway
// TODO: CANNOT do this without SSL (turn off the bits in web.config on BOTH sides)
/*var state = client.ExchangeUserCredentialForToken("kieranbenton", "password", new[] { "https://api.leave-now.com/journeys/" });
// Attempt to talk to the APIs WITH the access token
var resourceclient = new OAuthHttpClient(state.AccessToken);
var response = await resourceclient.GetAsync("https://api.leave-now.com/journeys/");
string sresponse = await response.Content.ReadAsStringAsync();*/
// A wrong one
/*var wresourceclient = new OAuthHttpClient("blah blah");
var wresponse = await wresourceclient.GetAsync("https://api.leave-now.com/journeys/");
string wsresponse = await wresponse.Content.ReadAsStringAsync();
// And none
var nresourceclient = new HttpClient();
var nresponse = await nresourceclient.GetAsync("https://api.leave-now.com/journeys/");
string nsresponse = await nresponse.Content.ReadAsStringAsync();*/
return Content("");
}
}
I can't figure out how to prevent this or if its by design what I'm doing incorrectly.
Any help appreciated.
The NetworkCredentialApplicator clears the client_id and secret from the outgoing message as you see, but it applies it as an HTTP Authorization header. However, HttpWebRequest clears that header on the way out, and only restores its value if the server responds with an HTTP error and a WWW-Authenticate header. It's quite bizarre behavior on .NET's part, if you ask me, to suppress the credential on the first outbound request.
So if the response from the auth server is correct (at least, what the .NET client is expecting) then the request will go out twice, and work the second time. Otherwise, you might try using the PostParameterApplicator instead.

Resources