I'm doing OAuth2 authentication in my Windows Phone 8.1 app and I'm using the WebAuthenticationBroker with the AuthenticateAndContinue() method for WP.
I'm authenticating to my server where I send two parameters and it returns my access token, without any other step in and between. Given this situation I don't have a callbakUri, so I use the WebAuthenticationBroker.GetCurrentApplicationCallbackUri()
My code looks like this:
Uri endpointURL = new Uri(_requestUrl + "&client_id=" + clientId + "&client_secret=" + clientSecret);
Uri callbackUri = WebAuthenticationBroker.GetCurrentApplicationCallbackUri();
WebAuthenticationBroker.AuthenticateAndContinue(endpointURL, callbackUri, null, WebAuthenticationOptions.None);
I have the ContinuationManager.cs class in my project, as well as all the changed needed in the App.xaml.cs, as described here: http://msdn.microsoft.com/en-us/library/dn631755.aspx
My problem is that after I execute the code above, the Continue() method in the ContinuationManager class is never executed, so my app blocks there.
Am I missing something here?
WebAuthenticationBroker.AuthenticateAndContinue knows the authentication is done when the user is redirected to a specific page.
There's two way to deal with it:
Most services accept a parameter to set the URI the user is redirected to (the parameter is often called callback. In that case, you can generate an URI with WebAuthenticationBroker.GetCurrentApplicationCallbackUri and pass it to the WebAuthenticationBroker.AuthenticateAndContinue method (as you're doing in your code sample)
If the service doesn't accept a callback parameter, then you need to do things the other way: first check what URI the service redirects too (by calling it manually once), then pass this URI to the WebAuthenticationBroker.AuthenticateAndContinue method. For instance, let's say the OAuth service redirects to http://www.stackoverflow.com, then you need to call:
WebAuthenticationBroker.AuthenticateAndContinue(endpointURL, new Uri("http://www.stackoverflow.com"), null, WebAuthenticationOptions.None);
It looks like you are using the Client Credentials Grant. This is a non-interactive flow, and you do not need a WebAuthenticationBroker to use it. Just use an HttpClient to get the token, if you are using this flow.
That being said, this flow is probably not what you need. First of all, I am assuming that you do want to authenticate the actual user, a.k.a. the resource owner. Secondly, the flow you are using requires the client secret to be present in your phone application. That is a big no-no! This flow is intended for server-side processes!
I think you need to look at the Authorization Code Grant instead.
Related
I have a ASP.NET MVC (NOT ASP.NET Core) single page application with angular js on the front end.
My client (browser) talks to server through ASP.NET Web APIs. Now, the web application is on https but anonymous. There is no login/ user authentication.
The web app is in the form of a wizard where user can go back and forth and add or update input fields on the web page. The form input values are then updated on the server through Web API.
I'm looking for a way to secure my Web API calls alone, especially the POST/ PUT requests. In summary, I want to prevent any user calling my Web API directly from POSTMAN or Fiddler. The Web API, though anonymous can be only called from the browser session where the request originated.
What are options do I have to achieve this?
Can I use Anti-Forgery token here (without authentication)?
One way, I can think of achieving this is to add a custom header to each request and store some kind of session key in the header. Then, validate the custom header on every request I received from client. Are any other ways of achieving this out-of-box or some proven library without going for custom solution?
If I have to go for the above custom solution, what are the pitfalls or potential issues I need to be aware of?
First of all when you remove login and there's no authentication mechanism in your application, there's really no way to secure anything, because anyone can access your APIs. I think what you want is to make sure that your APIs are called only from your own website. Unfortunately you can't completely achieve that, since your web APIs are http/https, and anyone, from anywhere (like postman, fiddler, ...) can create a http request and call your API.
All you can do is to make it harder for your API to response to requests, like using Anti-Forgery as you mentioned.
And also I suggest you add a cookie for your application and check that cookie in every request, in this case it's more complicated ( not impossible ) to call your API using Fiddler or Postman.
And last I suggest that you use CORS, so browsers would only allow your domain to call your APIs. So nobody can call your APIs in a browser from different domain.
Based on answer from #Arvin and comment from #Evk, here's how I plan to proceed:
Once, the user starts the anonymous session generate a GUID using regular Guid.NewGuid() method and save it in DB to identify the request (I'm doing this now). However, as mentioned here,
GUID can be unique but they are not cryptographically secured.
Hence, instead of using plain-text GUID, encrypt it with current timestamp as token and append it with request query string.
For every subsequent API request, read the token from query string, decrypt it and validate it as follows:
Check the timestamp. If the time difference is more than pre-defined time (i.e. token expired), reject the request
Validate the unique id (GUID) against DB
Since, I'm not using plain text GUID anymore, the URI would not easy to guess.
Additionally, with the timestamp, URI is invalidated after sometime. While theoretically it is still possible to call the API through Fiddler but this should make it very difficult for the attacker, if not impossible.
As a further security measure, I can also add Anti-Forgery token to the request
As per my understanding this helps solving my underlying problem and with this approach, I may not even need add a cookie to secure my anonymous session.
Love to hear from you all if this approach looks good and how can it be improved.
I also once had the weird need for having session functionality on WebAPI and created an OWIN Session middleware that does exactly what you're aiming for.
The library is called OwinSessionMiddleware and is available on github and NuGet.
Usage
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseSessionMiddleware();
// other middleware registrations...
app.UseWebApi();
}
}
You can also pass some options to further tweak cookie-name, add a database backed session store (instead of in-memory), add your own session id generator (instead of default id generator which is based on GUID + secure random part generated by RNGCryptoServiceProvider).
The unique session id itself is stored as a secure cookie and the session is restored automatically by the middleware on each request.
There are extension methods you can call inside your API controller to get and set session data:
public SomeApiController : ApiController
{
public IHttpActionResult MyAction()
{
var requestCount = Request.GetSessionProperty<int>("RequestCount");
Request.SetSessionProperty("RequestCount", ++requestCount);
}
}
Create Anonymous JWT token with some claims related to your scenario, Sign it with some key, Use that as in cookie (Http Only) or As bearer token. To make it little more harder further combine it with some cookies.
1)verify token signature and
2) Verify token expiry time
3) Verify Claim(skey) against cookies(skey)- no database storage required everything is in ur JWT token.
I'm working on an AWS project. We want to be able to issue STS temporary security credentials, with limited permissions, in order to access AWS services. We're working in .Net Core with C#.
We're using STS AssumeRoleAsync(), which is the .Net SDK's method for using the AWS AssumeRole action, to generate these credentials. The response from the call to AssumeRoleAsync() is an AssumeRoleResponse object, which is comprised in part of an AssumeRoleUser object and a Credentials object. One of the properties of AssumedRoleUser is AssumedRoleId, which is in the form of role-id:role-session-name.
We have a Lambda function which handles calling AssumeRoleAsync and returning the generated credentials in the form of a JSON object. That Lambda function is called via an API Gateway method.
All of this is working fine. The above was just to set the scene.
The next thing we want to be able to do is to use the STS temporary credentials to make other calls into AWS services. When that happens, we want be able to use GetCallerIdentity() to retrieve the AssumedRoleId for the person to whom the credentials were issued. In particular, the role-session-name is of interest to us.
So to try to accomplish this, I created another Lambda function behind another API Gateway method. I set this API Gateway method to use AWS_IAM authorization in its Method Request configuration. In its Integration Request, I configured it to Invoke with caller credentials. The Lambda function simply accepts the incoming request and calls GetCallerIdentity() and returns the result. I used the credentials returned from the previous AssumeRoleAsync() call in the request's authorization header.
Based on the information found in the docs for GetCallerIdentity and in the Principal Table to which that page refers, I expect to receive the following items in response from the GetCallerIdentity() call:
Account
Arn
UserId (this is the important bit for this discussion)
The UserId should be in the form of role-id:caller-specified-role-name, exactly the same form in which the AssumedRoleId from the call to AssumeRoleAsync was returned. That would allow me to get the caller-specified-role-name and do what we need to do with it.
But that isn't what is returned in the UserId property of the response from GetCallerIdentity().
Instead, all that the UserId property contains is the role-id — it completely omits the essential caller-specified-role-name.
Has anyone else seen this behavior? Am I overlooking something simple? Could this be a bug in the response from GetCallerIdentity?
I'm using the following Amazon SDK components and versions to make these various calls:
Amazon.Lambda.Core/1.0.0
Amazon.Lambda.Serialization.Json/1.1.0
AWSSDK.Core/3.3.14
AWSSDK.Lambda/3.3.6.2
AWSSDK.SecurityToken/3.3.1.9
Thanks for any help you can suggest!
Derek
I am trying to get access to OneDrive for Business using OAuth2.0 authentication protocol. I have followed this example:
http://msdn.microsoft.com/EN-US/library/dn605894(v=office.15).aspx
an this is my code so far:
// Create an authentication context
AuthenticationContext ac = new AuthenticationContext(string.Format("https://login.windows.net/{0}",
ClaimsPrincipal.Current.FindFirst(TenantIdClaimType).Value));
String id = ClaimsPrincipal.Current.FindFirst(TenantIdClaimType).Value;
// Create a client credential based on the application id and secret.
ClientCredential clcred = new ClientCredential(AppPrincipalId, AppKey);
// Using the authorization code acquire an access token.
var arAD = ac.AcquireTokenByAuthorizationCode(code, new Uri(appRedirect), clcred);
I am getting a Authorization code is malformed error. I don't understand why I am getting this message.
Any help would be appreciated!
Had the same issue when I was trying to get authorization code manually and then use it from console application. Not sure why it doesn't work for me.
But when I use it from Web App, the same app which performed authorization and received code in return (because I specified it as returnURL) - everything works.
I suggest you to have a look on this example
https://github.com/AzureADSamples/WebApp-WebAPI-OAuth2-UserIdentity-DotNet
And also this article to understand what's happening under the good:
http://blogs.msdn.com/b/exchangedev/archive/2014/03/25/using-oauth2-to-access-calendar-contact-and-mail-api-in-exchange-online-in-office-365.aspx
P.S.
It's not a OneDrive, but I had exactly the same problem, so if you can make it working with Exchange or GraphApi, then it should work for OneDrive as well.
Authorization code is malformed error is occured if you send the auth code in incorrect format. May be the authorization code which you are sending is encoded value of authcode and session state. you need to seperate both values and send the auth code only. or decode the '&' symbol(seperator) between auth code and session state and send them as two parameters.
The method AcquireTokenByAuthorizationCode(...) from ADAL4j takes only authcode.
I'm just finishing authorization and resource server for OAuth2, using DotNetOpenAuth 4.3.4. For testing, I created test client by implementing OAuth2Client.
Because I'm using DNOA for all the communication and request parsing, I'm not sure if I fully understand what is going on under the hood. But this knowledge is very important when I make documentation.
So, could you please explain to me, how client authentification works in DNOA? I use authorization code as grant_type and when I use my test client to exchange code for access_token, the DNOA somehow validate the client_secret and client_id. I downloaded source code for DNOA, but it not helped.
When I set breakpoint to Oauth2 controller(token method) and parse the request as HttpRequestMessage, i see the request contains "grant_type", "code" and "redirect_uri". But where are client_id and client_secret?
Also, can you tell me where I can find any usable documentation for DNOA? I need to create documentation, which will be valid and usable for all platforms, not just C#, which can use DNOA.
Related question:
I somewhere read, that we should not create authorization codes for unauthentificated clients, but this is exactly what DNOA does (since I receive authorization code even if secret is wrong). Is it ok?
Edit:
This is the request I'm trying to read. It is token request made by DNOA client. I can not see the client_id and client_secret under other parameters like "code", "redirect_uri" and "grant_type". I tought they have to be together. Maybe I'm missing something important from http requests and responses.
When I let DNOA to HandleTokenRequest(request) to continue, it is successfully authenticate the client application (fails when bad secret is set in DNOA client app config).
Edit 2
private readonly WebServerClient Client;
protected override string QueryAccessToken(Uri returnUrl, string authorizationCode)
{
var authorization = Client.ProcessUserAuthorization();
if (authorization != null)
return authorization.AccessToken;
else
return null;
}
This is my implementation of QueryAccessToken. It is from some sample. I think I created this at the beginning and did not change it, because it worked.
Going rought DNOA source I found out it is method from OAuth 1. THis can be the problem. But the question is, why it works ok with right client cerdentials and not working with bad ones.
Final edit
Looks like DNOA client uses http Basic authorization (client_id and secret are in header). But I need the DNOA server to be able to grab these parameters from POST.
If anyone know how to set DNOA to support client_id and client_secret in POST parameters, it would be awesome!
Thank you
The authorization code grant requires two steps.
The first step is the browser redirecting to the identity provider and displaying the logon ui. The authorization code is returned to the browser by the identity provider and then, from the browser to the client application. This step doesn't involve client secret! This is because the end user can debug this part of the flow and she should not learn the value of the client secret.
Then, when the client application has the onetime authorization code, it concacts the token endpoint directly (server-to-server) to exchange the authorization code for authorization token. This is where client id and client secret are used to verify that only legitimate client applications exchange codes for tokens.
The idea behind this flow is to protect the end user from exposing her password to the client application and also protect the client application from exposing its client secret to the end user.
Also note that the authorization code grant flow is the most complicated one as it involves both username/password (provided by the end user) and clientid/client secret (provided by the client application). There are other flows which allow to get the authorization token in slightly different way, namely:
resource owner grant which involves sending username/password directly by end user to the token endpoint of the identity provider. This flow is suited for desktop/mobile/native apps where the logon ui can be customized (but it also can raise suspicions and users could proably refuse to use it)
client credentials flow which involves sending clientid/client secret by the client application to the idntity provider. There is no end user but only the client application authenticating in the identity provider.
More on flows here:
http://aaronparecki.com/articles/2012/07/29/1/oauth2-simplified
As for DNOA, I found it clean and understandable but the docs are lacking. Fortunately, examples are great and although barely documented, you can find almost everything there. Nonetheless, I was able to set up oauth2 identity provider and resource server in three days and support all four oauth2 flows. I am not going to dig deeply into details as this is not what your question is about, however, if you have DNOA specific questions, just ask.
Edit:: regarding your QueryAccessToken implementation, it seems that you are using the WebServerClient internally. In my code I just initialize its properties:
WebServerClient client = ...
client.ClientIdentifier = "client_id";
client.ClientCredentialApplicator =
ClientCredentialApplicator.PostParameter( "client_secret" );
With these two configured, both client_id and client_secret are sent to the token service with the client_secret passed in POST params.
What i am Trying to do:
Write a Generic Library in C# to handle OAuth Flow to every service ( Just like Twitter,LinkedIn and Foursquare). The hardest part is that, i want to simulate all the user input in code so that no user action is needed to click on buttons like "Ok,I will Allow It",or even writing its username/password.
Doubts That i have so far:
1 - Whats the usage of the authenticity_token in twitters API ?
2 - What are the factors that all services use, so that i can implement a generic usage of OAuth Flow. For example i´ve found the first Step is really easy to make a Generic method to execute. All i have to do is change the URL for the webRequest,and BAM, i have the Request tokens.
3 - How do i Get the Verifier for each service? In LinkedIn Service for instance, i was able to parse a page to fetch this value, but i can't find this verifier for twitter API for example. Even when authorizing in browser my aplication, i see no Verifier in any HTML during the flow, or any JavaScript generating it.
Observations:
1 - I know that there are Lots of OAuth Libraries out there, like this or that ones, but there is no Library that allows me to make what i want to, that is to Authenticate and authorize a user, without prompting for any user input.
2 - I can't,by any means,ask for user input. All the values like username and password for the authentication, will be hardcoded and every user will use the same account for this requests.
3 - I also know, that there are other posts here that i've written, with almost the same doubts, and the reason i am resposting is to try to make it clearer and fresher.
4 - Sorry about any english mistake or missunderstanding of concepts in advance.
Basic Code Sample:
This is, for instance, the method i am using (that is avaible widely abroad the web) for getting request tokens for any service. All i have to do is change the REQUEST_TOKEN value to the specific url to be used for a service,so i can get the Tokens for LinkedIn,Twitter or Foursquare for instance. But i can't manage to apply the same process in the other steps.
public string AuthorizationLinkGet()
{
string ret = null;
string response = oAuthWebRequest(Method.GET, REQUEST_TOKEN, String.Empty);
if (response.Length > 0)
{
//response contains token and token secret. We only need the token.
NameValueCollection qs = HttpUtility.ParseQueryString(response);
if (qs["oauth_callback_confirmed"] != null)
{
if (qs["oauth_callback_confirmed"] != "true")
{
throw new Exception("OAuth callback not confirmed.");
}
}
if (qs["oauth_token"] != null)
{
ret = AUTHORIZE + "?oauth_token=" + qs["oauth_token"];
}
}
return ret;
}
Don't.
OAuth was designed to require a user to press that button once. If you automate it you will have your application key revoked and your program will no longer work.
What you need to do is save locally the authorization token and reuse that. The user clicks"I Allow" once then you re-use the authorization token for future connections. You need to check to make sure it is not expired, and if it is you just re-authorize and they click "I Allow" again.
No website doing OAuth correctly will allow you to bypass the website authorization, some will allow you to pass the username and password via a query and get a token, but if they have a web authorization, you MUST have the user manually do it.
If you are the OAuth provider and consumer you need to do something Dropbox did for their v0 of the API (I can't find any links to their old API, if anyone can find it edit this post) that passed the username and password to a special address that returned a autorization token without using a webpage. Or you need to use a different authentication scheme than OAuth.