Authorization policy is breaking preflight check in APIMAN - preflight

I have 2 policies on my API (+1 for cors), first is keycloakOauthPolicy and the second is AuthorizationPolicy.
When I make some preflight request (then with verb OPTIONS and without any token in the header), I get that error from AuthorizationPolicy :
No roles have been extracted during authentication. Make sure the >authorization policy comes after a compatible authentication policy in >your configuration
What am I doing wrong?

My bad, I had a plan with another policy (keycloak authentication) which was also taking in charge or at least breaking the flow, then CORS policy (which is filtering preflight request) wasn't working properly.

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.

Should dynamic query parameters be present in the Redirection URI for an OAuth2 (Autorization Code Grant Type)

Sources such as this Okta sponsored site (see "Per-Request Customization" section) mention that the redirect_uri parameter of a autorization request SHOULD NEVER have a dynamic query part (ex: for session matching uses).
Quote:
The server should reject any authorization requests with redirect URLs
that are not an exact match of a registered URL.
Our OAuth AZ provider is BIG-IP F5. We are setting it up, and they seem to comply with the above view.
Our client is a web application built elsewhere, and they seem to not follow the above rule.
Here is a complete representation of the Authorization Endpoint (redacted):
https://ourownF5host.ca/f5-oauth2/v1/authorize?client_id=theIDofOurClient&redirect_uri=https%3A%2F%2FourClientAppHostname%2FClientRessource%2FRessource%3FSessionId%3D76eab448-52d1-4adb-8eba-e9ec1b9432a3&state=2HY-MLB0ST34wQUPCyHM-A&scope=RessourceData&response_type=code
They use a redirect_uri with a format similar to (I don't urlencode here, for simplicity's sake) : redirect_uri=https://ourClientAppHostname/ClientRessource/Ressource?SessionId=SOMELONGSESSIONID, with the SOMELONGSESSIONID value being DIFFERENT for each call.
We dug DEEP into RFC6749 (OAuth2), and found this in section 3.1.2.2:
The authorization server SHOULD require the client to provide the
complete redirection URI (the client MAY use the "state" request
parameter to achieve per-request customization). If requiring the
registration of the complete redirection URI is not possible, the
authorization server SHOULD require the registration of the URI
scheme, authority, and path (allowing the client to dynamically vary
only the query component of the redirection URI when requesting
authorization).
What I understand, and would like to validate here, is that the first source, Okta and F5 accept ONLY the first part of the rule above, and require the redirection uri to be COMPLETELY registered without any dynamic part.
Am I right to affirm that they (Okta and F5) DO NOT comply with the second part of the excerpt, citing that they should "allow(ing) the client to dynamically vary
only the query component of the redirection URI when requesting
authorization" ?
OR, is there any kind of official correction/evolution of the RFC6749, that warrants both companies design position ?
TL;DR:
No, the redirect uri must be static for security reasons. If the client needs to keep a state between the authorization request and its asynchronous response, use the OAuth 2.0 state parameter.
Long version :
RFC6749 (the initial OAuth 2.0 specification) has been published in 2012 and OAuth security landscape has evolved a lot since then.
RFC6819, an OAuth 2.0 security review from 2013 already mentioned that refusing dynamically crafted redirect uris was a good way to protect against XSS and client impersonation attacks.
OpenID Connect, from 2014, a commonly used extension of OAuth 2.0 with authentication capabilities, already takes that recommendation into account and mandates exact string matching for all redirect uris.
The current draft recommendation for OAuth 2.0 Best Security Practice confirms that by enforcing redirect_uris preregistration and mandating the use simple string comparison by the AS when validating the redirect_uri passed in the request. So a dynamic redirect_uri must not be used.
Your client definitely makes a wrong move by using the redirect_uri as a "state keeper" between the Authorization request and response, by using a dynamically crafted SessionID attribute inside the redirect_uri. OAuth2.0 has a dedicated authorization request parameter for that purpose, which is "state". The client should use it. The AS will append that state in the parameters of the redirect_uri when it issues the response, so the client will be able to find back this state inside the response.
The proper authorization request would be:
https://youras/authorize?client_id=your_client_id&response_type=code&state=SOMELONGSTATE&redirect_uri=https%3A%2F%2Fsomehost%2Fauthcallback
The response will look like:
https://somehost/authcallback?state=SOMELONGSTATE&code=anazcode
This way the redirect_uri is static, so a simple string comparison is enough to validate that uri on AS side. Any algorithm more complex than simple string comparison would be subject to security flaws.
It appears there's two things mixed up here: the URL you refer to:
https://somehost/authcallback?state=SOMELONGSTATE&scope=someobjecttype&response_type=code
suggests that you mixed up the Redirect URI (aka. callback URL, as suggested by the pathname in the URL) of the Client with the Authorization Endpoint of the Authorization Server.
Only the Authorization Endpoint would take parameters as suggested and may contain e.g. a dynamic state value. The Redirect URI of the Client would not contain e.g. response type.
A redirect_uri parameter can be added to the the authorization request, which would then have to be matched in the way that you described. After confirming the match, the Authorization Server will redirect back to the Redirect URI, adding the code and state parameters.
Update (after the question changed):
OAuth 2.0 RFC6749 allows a dynamic (SessionId) parameter though it is not considered best practice. If however your client is an OpenID Connect Client, this is not allowed since the OpenID Connect spec (a "profile" of OAuth 2.0) locks down the Redirect URI matching to "exact", in which case you'd have to configure all possible SessionIds.

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).

Deny access to a rails route if request does not originate from app

I have a route in my application that returns results from an LDAP query. I'm using a privileged account for this as it needs to return information that a regular account can't access.
Is there a way to deny users access to this route if they're not using it via one of the application's views? What I'm trying to prevent is a someone reverse engineering it and building their own app to gain access to the PII.
There is no reliable way to say this request originated from this view vs. this request originated from (e.g.) the command line.
An HTTP URL request doesn't have a verifiable source of origination. There is a "referrer" HTTP header which is intended for saying where the previous request originated, but it is not for security and completely spoofable, and not even always included in the request.
Somehow you'll need to authenticate the request. Don't invent your own way. Use devise or some other tested tool to build an authentication strategy, and figure out how to modify your application to work with existing conventions of HTTP request authentication (secure token, cookie based auth, etc.)

Wildcard support for doorkeeper redirect URIs

I have a Ruby on Rails application using Oauth 2.0 implemented using the doorkeeper gem (1.3.0).
I am trying to set up a wildcard redirect uri (e.g., http://*.mydomain.com/redirected). However, this doesn't seem to be possible. In the doorkeeper-mounted route /oauth/applications, if I type in a wildcard url it says Must be a valid uri.
Is there a configuration or way to patch doorkeeper in order to get this functionality? I need the * wildcard to pass validation during the registration of a new application and also need it to work at the client authorization endpoint.
I came across this too, thought about it for a while then checked the specification. This would be a direct violation of the specification of Oauth.
3.1.2. Redirection Endpoint
After completing its interaction with the resource owner, the
authorization server directs the resource owner's user-agent back to
the client. The authorization server redirects the user-agent to the
client's redirection endpoint previously established with the
authorization server during the client registration process or when
making the authorization request.
The redirection endpoint URI MUST be an absolute URI as defined by
[RFC3986] Section 4.3. The endpoint URI MAY include an
"application/x-www-form-urlencoded" formatted (per Appendix B) query
component ([RFC3986] Section 3.4), which MUST be retained when adding
additional query parameters. The endpoint URI MUST NOT include a
fragment component.
Source
It looks like support for wildcard Redirect URIs was removed in Doorkeeper 2.1.1.
You can see some reasoning in this commit:
https://github.com/doorkeeper-gem/doorkeeper/commit/fd57c475f4fb954faa62d7973d6c8382b5b6401f
And some further discussion here:
https://github.com/doorkeeper-gem/doorkeeper/pull/437

Resources