Modified OAuth tokens can still authenticate / authorize successfully - oauth

Using Owin and OAuth, I've noticed that if you modify the last character of a token you can still get authenticated / authorized successfully.
I'm using a C# WebAPI application, but I don't know if this applies to OAuth in general. This might be by design but it seems like strange behaviour to me so I'm curious to know why this happens.
To replicate this behaviour:
In Visual Studio, create a new project and select 'ASP.NET Web Application' as the template.
Choose the 'Web API' template, and choose 'Individual User Accounts' as the authentication type.
Build the project.
Using a REST client, POST to http://localhost:23220/api/account/register * with a Content-Type: application/json header and the following body:
{
"UserName": "test",
"Password": "password",
"ConfirmPassword": "password"
}
Using a REST client, POST to http://localhost:23220/token * with no headers and the following body:
grant_type=password&username=test&password=password
Using a REST client, GET http://localhost:23220/api/values * with a Authorization: Bearer xxx header, where xxx is the access token you generated in the previous request. This request should be authorized and you should get a 200 response.
Make the same GET request again, but this time modify the last character of the Authorization header value by incrementing it by 1. So for example, if the last character is a, change it to b; if it's 1, change it to 2 etc. The request will still be successful.
* Change the port accordingly.

AccessTokenFormat - The data format used to protect the information contained in the
access token. If not provided by the application the default data
protection provider depends on the host server. The SystemWeb host on
IIS will use ASP.NET machine key data protection, and HttpListener and
other self-hosted servers will use DPAPI data protection.
Since setting up the project this way will run under IIS Express, the token is protected with the MachineKey API. I was not able to find a description of the exact data format of the encrypted value, but from previous work in cryptography, I expect perhaps there is padding at the end. This padding would not be protected by the token's signature, but this doesn't matter as it is just stripped off and discarded. Note that the range of changes is limited, so I expect only the last few bits of the last byte can be modified.

Related

Do I Pass the Identity Token in a Header or Body of a Post Request?

The access token and refresh token being in the header makes sense to me (from this answer), but I'm wondering the same thing for ID or Identity Tokens. Should those be:
Passed into the body of a post request?
Passed into some header (Authorization header is used by the access token)
Something else (I'm misunderstanding the purpose of the identity token)
A little more context, through SSO, I would like to take the claims of a user (present only in the Identity Token) and sign them up in my system. I can confirm I can do this easily by throwing the identity token into the body of the initial POST request (and validate the signature on the server), but wanted to check if I'm breaking some standard.
Thanks!
In principle you can pass the ID token assuming that:
the software that consumes and validates the ID token (Relying Party, RP) is part of the same application and security domain as the target system
the link between the RP and the target system is secure i.e. authentication of both parties and confidentiality of the communication is established
the target system indeed requires all of the information in the ID token, otherwise it would be better to apply minimal disclosure and pass only a subset of the information
Passing the ID token (or the subset of claims) in headers may work if the amount of data is relatively small, otherwise you may run into HTTP header length limitations. Using POST though has the downside of having to modify the application request in flight which may be harder and have side effects.
For completeness, the refresh token is never passed in a header and only sent to the Authorization Server / Provider by the RP in a POST request.

Cannot repeat steps on how to get OAuth2.0 Access Token on Postman

On Postman, I can get new access token for OAuth2.0 by providing callback URL, auth URL and client ID.
I want to break this task down on JMeter because I cannot find this function there. From my understanding, it is divided into authenticate -> authorise -> call back.
Authenticate
URL = https://xxxxx/login
Result = Authorising URL
Authorise
URL = https://xxxxx/oauth/authorize?client_id=mmm&redirect_uri=https://yyyyy/auth/callback&response_type=code
Result = code (e.g. zzz)
Call back
URL = https://yyyyy/auth/callback?code=zzz
Result = token
As I used HTTP(S) Test Script Recorder on JMeter, I got the three actions mentioned above. When I reran them, it told me this error on Authenticate part: <oauth><error_description>Full authentication is required to access this resource</error_description><error>unauthorized</error></oauth>.
To make sure that it was not about the program I use, I did it on Postman and found this error as well.
I wonder how I can break OAuth2.0 Get New Access Token feature into basic API settings in order to get access token on Postman or JMeter.
Dont' compare these tools:
Postman is an Electron application, it's basically a heavily customised Chromium web browser + NodeJS
According to JMeter main page
JMeter is not a browser, it works at protocol level. As far as web-services and remote services are concerned, JMeter looks like a browser (or rather, multiple browsers); however JMeter does not perform all the actions supported by browsers. In particular, JMeter does not execute the Javascript found in HTML pages. Nor does it render the HTML pages as a browser does (it's possible to view the response as HTML etc., but the timings are not included in any samples, and only one sample in one thread is ever displayed at a time).
If you can obtain the token using Postman you can just add HTTP Header Manager to your JMeter Test plan and configure it to send Authorization header with the value of Bearer YOUR_TOKEN_FROM_POSTMAN and JMeter should let you in.
After testing, I found that Postman's OAuth 2.0 Get New Access Token popped up a login page of targeted URL where I needed to fill in the username and the password so that the token could be obtained.
As I tried breaking down APIs required for this login, it required GET of that https://yyyyy and POST of that https://xxxxx/login. Click Send for POST, with username and password contained in form-data, then click Send for GET. The GET response would contain such the token.
However, just putting the aforementioned GET and POST APIs into one thread group did not work on JMeter. As I used HTTP(S) Test Script Recorder to no avail, I went with BlazeMeter and realised that it was using Transaction Controller containing 1) GET of https://yyyyy 2) POST of https://xxxxx/login. With these two arranged top-down, the job would be successful. The token was contained in the response of 2).
For now, this has been my discovery which answers my question.
Try BlazeMeter.

OpenID Connect, oAuth2 - Where to start?

I am not sure which approach I should be taking in our implementation and need some guidance.
I have a REST API (api.mysite.com) built in the Yii2 Framework (PHP) that accesses data from mysite.com (database). On mysite.com our users will be able to create Connected Apps that will provision a client id + secret - granting access to their account (full scope?).
Based on my research, the next step seems to be setting up something to actually provide the bearer tokens to be passed to the api - I have been leaning towards oAuth2, but then I read that oAuth2 does not provide authentication. Based on this I think I need OpenID Connect in order to also provide user tokens because my API needs to restrict data based on the user context.
In this approach, it is my understanding that I need to have an Authentication Server - so a few questions:
Is there software I can install to act as an OpenID Connect/oAuth2 authentication server?
Are there specific Amazon Web Services that will act as an OpenID Connect/oAuth2 Authentication Server?
I am assuming the flow will be: App makes a request to the auth server with client id + secret and receives an access token. Access token can be used to make API calls. Where are these tokens stored (I am assuming a database specific to the service/software I am using?)
When making API calls would I pass a bearer token AND a user token?
Any insight is greatly appreciated.
your understanding is not very far from reality.
Imagine you have two servers one for Authentication, this one is responsible for generating the tokens based on a Authorization Basic and base64 encoded CLientID / ClientSecret combo. This is application authentication basically. If you want to add user data as well, simply pass username / password in the post body, authenticate on the server side and then add some more data to the tokens, like the usernames, claims, roles, etc
You can control what you put in these tokens, if you use something like JWT ( Json Web Tokens ) then they are simply json bits of data.
then you have a Resource server, you hit it with a Authorization Bearer and the token you obtained from the Authorization one.
Initially the tokens are not stored anywhere, they are issued for a period of time you control. You can however do something else and store them in a db if you really want to. The expiration is much safer though, even if someone gets their hands on them they won't be available for long! In my case I used 30 minutes for token validity.
Now, you haven't specified what languages/frameworks you are looking into. If you use something like dot net then look into IdentityServer, version 4 is for Dot net core, 3 for anything below.
I also have a pretty long article on this subject if you are interested:
https://eidand.com/2015/03/28/authorization-system-with-owin-web-api-json-web-tokens/
Hopefully all this clarifies some of the questions you have.
-- Added to answer a question in comments.
The tokens contain all the information they need to be authenticated by the resource server correctly, you don't need to store them in a database for that. As I already said, you can store them but in my mind this makes them less secure. Don't forget you control what goes into a token so you can add usernames if that's what you need.
Imagine this scenario, you want to authenticate the application and the user in the same call to the Authorization Server. Do the OAuth2 in the standard way, which means authenticate the application first based on the client id / client secret. If that passes then next do the user authentication. Add the username or userid to the token you generate and any other bits of information you need. What this means that the resource server can safely assume that the username passed to it in the token has already been validated by the authentication server otherwise no token would have been generated in the the first place.
I prefer to keep these two separate myself, meaning let the AS ( Authorization Server) to deal with the application level security. Then on the RS (Resource Server) side you have an endpoint point like ValidateUser for example, which takes care of the user validation, after which you can do whatever you need. Pick whichever feels more appropriate for your project I'd say.
One final point, ALWAYS make sure all your api calls ( both AS and RS are just apis really ) are made over HTTPS and never ever have any important information transmitted via a GET call which means the URL can be intercepted. Both Headers and POST body are encrypted and secure over HTTPS.
This should address both your questions, I believe.

401 when accessing Dynamics CRM 2016 Web APIs

I am struggling to access the Dynamics 2016 CRM OData Web APIs from a console application.
We have Dynamics CRM 2016 installed, configured with Claims-based authentication, and using AD FS v3.0.
My understanding is that a console app (or web app) should be able to access the Web APIs using Windows integrated authentication (i.e. NTML or Kerberos) without any special treatment ... or maybe the OAuth flow should work when enabled.
For a regular user accessing Dynamics "pages", the authentication works fine (redirection to AD FS log in page), but accessing the OData APIs does not seem to work (for instance : https://crm.domain.org/api/discovery/v8.0/ ) :
in a browser I get a Windows login prompt and typing valid credentials always results in a HTTP 401 unauthorized error
in a brower, if I navigate to a Web API url after having logged on on the pages , then I can access the Web APIs (i.e. some cookies must be set and I am already implicitly authorized)
from code, using an HttpClient with specific valid credentials (or current credentials) , I also get a 401
Things I have tried :
if I disable Claims-based authentication completely , HttpClient works fine and I can access the OData APIs
if I leave Claims-based authentication enabled, and activate OAuth via PowerShell Add-PSSnapin Microsoft.Crm.PowerShell ; $ClaimsSettings = Get-CrmSetting -SettingType OAuthClaimsSettings; $ClaimsSettings.Enabled = $true ; Set-CrmSetting -Setting $ClaimsSettings ;.
Windows integrated authentication still does not work, but using Bearer authentication is now possible. I can use this snippet to retrieve the OAuth Endpoint for token generation, and use AuthenticationContext.AcquireTokenAsync to issue a token, and then pass it in the Authorization HTTP Header ... but then, no matter what, I get this error :
Bearer error=invalid_token, error_description
=Error during token validation!, authorization_uri=https://our.adfs.domain.org/adfs/oauth2/authorize, resource_id=https://crm.domain.org/
Am I missing something ? is that possibly a configuration issue ?
From this answer from the dynamics community forum, it looks like the api is pretty strict about the parameters and headers it requires. When doing the request, make sure you have the Cache-Control: no-cache and Content-Type: application/x-www-form-urlencoded headers set.
In the subsequent request to access the api with the retrieved token you should set the Authorization header in the form of Bearer: TOKEN (worth noting since a lot of people actually thought they could directly put the token), the OData-Version: 4.0, Cache-Control: no-cache and Accept: application/json ones too.
Looking at the different OAuth endpoints and the previously linked answer, I'm not sure the authorization uri is the right one (eg https://login.windows.net), so do you make sure that's correct. It's also stated that you should use the OAuth endpoint url and use the WWW-Authenticate header that returns the valid one, even if this route will respond with a 401. I'm sure you already saw this example, but it provides a pretty complete overview of an auth flow and how the token is retrieved using AcquireTokenAsync where you pass your resource and clientID. I might also be looking at an updated page and it's not relevant in your case.
You also want to check if the resource id you specified is the correct one, some people reported to have to specify one in the form of https://crm3.domain.org/ or https://crm4.domain.org/ instead of the bare one, so that could be one thing.
It could also be a configuration issue, given what #l said about the fact an IP would work instead of the domain name. It could very well be a certificate problem, where it's not validated correctly or untrusted, thus creating the error you see even if it's not the appropriate message. Also make sure your 443 port is allowed through your firewall(s).
One interesting post where the author explains that the Form Authentication setting of the AD FS Management Console was required for him to proceed (it's CRM 2013, but might still be related).

trying to get a oauth token using fiddler

I've been following Scott Allen's ASP.NET MVC 5 Fundamentals on pluralsight, and can successfully request a token, using a simple HTML page, but now need to try and do this using fiddler. the reason I need to test it using fiddler, is that this is in essence the way my apu will be called. An ios device app is being written, and i have to do the api piece.
So, i enter the followdin in fiddler:
HEADER:
POST http://localhost:53140/token HTTP/1.1
Content-Type: application/json
Host: localhost:53140
Content-Length: 50
BODY:
grant_type=password:
{"userName":"something",
"password":"password"}
and I get a 400 - bad request.
i've changed the content type to : application/x-www-form-urlencoded but still a 400.
what am i doing wrong?
EDIT
Even tried "username=username&password=password" still no joy
EDIT
Whoops, had the grant_type in the wrong place. this needed to be in the body:
grant_type:password&username:username&password:password
Now i get username or password are not valid:
{"error":"invalid_grant","error_description":"The user name or
password is incorrect."}
i'll leave the post active, as this may be a red herring.
In fiddler, make sure after grant_type=password&username=username&password=password there is no space or line break.
I was troubleshooting the same error message
{"error":"invalid_grant","error_description":"The user name or password is incorrect."}
while trying this tutorial myself. It seems that the UserName being persisted onto the local database is actually the email address rather than the UserName provided in the JSON payload while invoking the /api/Account/Register Web API. You can verify this by running a T-SQL query against the [AspNetUsers] table. (If you are using LocalDb database, you can open the database located in the project’s App_Data using Show All Files.)
Please note that once the actual user name is confirmed as the email address, the email address (and possibly your password) has to be URL encoded when posting the /api/Token request.
For example:
grant_type=password&username=Alice%40yourdomain.com&password=_Password123
Hope this helps.
In fiddler you can write
Host: localhost:17271
Content-Length: 81
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
In RequestBody you can write
grant_type=password&username=Alice&password=password123&response_type=token
Hope to someone help it because my problem is solve by this type of requestbody
This is how I do it using Fiddler4 (this guide assumes you are starting from scratch):
Create a new MVC Web API 2 project in Visual Studio 2015
Ensure you set the Authentication to individual user accounts (assuming this is what you want)
Once the project has loaded build the project and start the Web Application to ensure it runs
You should get the default "ASP.NET Getting started..." page with the navigation links at the top "Home" and "API".
At this point I tend to change the "DefaultConnection" in my Web.config file to point to an actual SQL Server where I will host the ASP.NET Identity tables but you don't need to just use the localDb by default.
Fire up Fiddler4 and then click on the Composer tab on the right
Change the request type to 'POST' and then change the URL to that of your local website which you ran earlier (the VS Web API 2 project) e.g:
http://localhost:49598/api/Account/Register
Change the header text to the following:
User-Agent: Fiddler
Content-Type: application/json;charset=UTF-8
In the request body you need to compose your JSON data that will be the account you are registering for example:
{
"Email": "youremail#account.com",
"Password": "YourPassw0rd!",
"ConfirmPassword": "YourPassw0rd!"
}
With your website running hit the Execute button at the top right
If successful you should see a 200 response on the left hand side of Fiddler4 which confirms the Account Controller API action Register was called a new user was successfully registered.
Now you can test your user account by requesting an Authorization token. Clear the contents of the Request body in Fiddler4 and then change the type to POST if required.
Change the header text to the following again:
User-Agent: Fiddler
Content-Type: application/json;charset=UTF-8
In the request body paste the following (changing the values for your account obviously)
grant_type=password&username=your#account.com&password=Passw0rd!
Hit Execute again and you should see a 200 response on the left hand side of Fiddler4:
http://localhost:49598/Token
Double-click the response to open up the Inspector tab on the right hand side of Fiddler4 which should display the authorization information in JSON format (you can also see it as raw by click on the 'Raw' tab).
Look for the 'access_token=' line which will have the access token you need to make "bearer" type requests.
In layman terms this is what happens now:
a. You authenticate and get an auth token.
b. Any/All requests made to the API endpoints are done using the bearer token type and this is set in the header of your request.
c. You pass in the auth token you received and this is validated and your request is processed.
d. You should ensure your Web API 2 endpoints have the [Authorize] decoration on the methods and/or class to ensure those areas are secure.
e. If your auth token has expired (set in the App_Start\Startup.Auth.cs class 'AccessTokenExpireTimeSpan'...) then you will need to handle this for example my app calls a dumb method that requires authorization, if that fails the client side AngularJS code redirects the user to the login screen where a valid user can request another auth token by logging in.
*note: I keep the expiry times to 30 minutes for my auth tokens
Okay now to use that token in Fiddler4...
Start Fiddler4 and in the Composer tab on the right change the type to GET (Clear the contents of Request Body if you need to)
Change the header text to the following:
User-Agent: Fiddler
Host: localhost:49598
Authorization: Bearer your_very_long_auth_token_here
Change the url to the good old api/values endpoint:
http://localhost:49598/api/values
Hit the Execute button and if everything was successful you should see the 200 response on the left:
200 HTTP localhost:49598 /api/values
Double click this response and the inspector tab should open showing the JSON response
This concludes how to use Fiddler4 to test Oauth2 with Web API 2. Hope someone finds this useful if you spot any mistakes let me know in your comments and I will update this answer.
One issue I see is that it looks like you putting the username and password in the Request Body as a Json string. it should just be text with no quotes:
grant_type=password&username=UserName&password=PassWord
Then making sure you have the Content Type: application/x-www-form-urlencoded
I'm not familiar with Scott's course, but normally for OAuth2, you do a GET request to the authorization server with the credentials, which then gives you an AuthorizationCode which you then POST along with some other stuff to the token server to get your token.
I'm not aware of a shortcut where you can get a token by just passing the credentials to the token server.

Resources