How to identify whether context come from authentication hook (certain hook) or other hook? - feathersjs

I'm setting up a hook for BEFORE ALL of users service. The hook is to check requester's role and decide whether to continue the request or throw forbidden.
Auth needs to be called before my hook to make sure that context user is populated beforehand. That's fine.
But then, auth will fail on getting user since my hook is called first, leading to forbidden thrown since no context user found.
What I'm trying to do is to identify the context whether its from auth or not so that i can let auth passthrough without check. But how? or is my approach wrong?
FYI: only [authenticate("jwt"), acl] in BEFORE ALL. acl is my hook. also, auth(jwt) from #feathersjs/authentication's hook
-whotfisthis, pardon the bad grammar.

Solved, i guess.
Rather than trying to identify if it's auth hook and let it passthrough without check:
All GET request with _id params other than the _id's of requester will go through acl check. Initial GET request with authenticated: true and request with self _id will passthrough

Related

Best way to response as JSON to frontend when the result of a request is null / not found

To simplify, say you have a REST API with a frontend that has login form in the frontend and you want to check whether a User exists or not. Front-end HTTP/POST some data to the back-end and back-end queries the database. The result is the user does not exist and you want to return that result to the front-end.
I know there might be tons of ways to return the result, but is there any "standard" or "more correct way" to return "User does not exist" result as JSON? Some posibilities i'm thinking:
Return a JSON as a string with the result?
Return empty object?
Return empty User object with a boolean doesNotExist=false?
Return 404 not found or some other http code response?
A mix between 4 and 1?
Solution:
Responding with a HTTP 404 Code is enough, no JSON body is needed. Keep in mind for this login use case, as pointed out by the answers, it is not recommended to repond with a 404 HTTP when the user is not found for security purposes.
Useful resource:
Understanding REST: Verbs, error codes, and authentication
The standard way to handle the situation where you don't find a resource is to return a 404 error status. If, for example, your uri is something like /user/{id} then this is an attempt to access a resource/document of type user with the given id, and in this case, if the user is not found then a 404 would be entirely appropriate. You do not need to specifically return a json response in this case.
However, you should be aware that for security purposes it is considered insecure to validate the existence of a user in this way. If an attacker knows a valid username or id they can try to brute-force their password. A lot of systems return the same error for invalid user identifiers and invalid password -- invalid credentials -- so that attackers cannot know if they have guessed the username correctly. A 401 error is often considered a useful response when attempting to authenticate a user. If the user does not exist or the given creds are invalid, then a 401 should be returned.
There is some standard way, most of the time HTTP status code is sufficient.
In case you think of a custom message with more detail then make a POJO containing error code, detail, or even an exception category and return it to UI.

No Traces in Azure API Response

The Flag Ocp-Apim-Tracehas been set to true.
The API Response displays this information under the Trace Tab:
Trace location was not specified in the response or trace log is not
available.
Yet no traces are available. How does one resolve this?
To enable trace, you need to include "Ocp-Apim-Trace" and "Ocp-Apim-Subscription-Key" in request header.
If the API does not require subscription, you can still get admin subscription key in developer portal. This enforces that only admin can get tracing log. To get admin subscription key if you are an admin, go to Developer Portal -> Profile -> find your target API and copy the key.
The Ocp-Apim-Trace feature enables you to specify whether or not APIM should generate a trace file on blob storage.
Setting the header to 'true' within Postman for example, will give you back a HTTP Header in the response called Ocp-Apim-Trace-Location.
This will contain the URL to your trace file, which you can open in any browser.
You might want to install a plugin/extension to be able to format JSON files properly in order to make it easy to read.
Just setting the flag Ocp-Apim-Trace to true will not suffice.
One needs to set the subscription key as well as per this doc.
https://learn.microsoft.com/en-us/azure/api-management/api-management-advanced-policies#Trace
So, for API's which do not have a subscription key, not sure how one can get the traces

Appgyver - Unable to load resource's data model - dreamfactory API

I have this json feed.
I am unable to load this into Appgyver
I have set the following required settings:
- parameter app_name with the correct value
- added the reuired header X-DREAMFACTORY-APPLICATION-NAME
I always get the Oops, Unable to load resource's data model. error
Anyone who has a clue?
I am not very familiar with AppGyver, but I know it's been used with DreamFactory successfully by others. You have not provided enough information, but I will attempt to give you troubleshooting steps from the DreamFactory side.
First, are you definitely authenticating and passing a valid X-DreamFactory-Session-Token header? I can tell that you don't have guest access enabled (to make calls without authentication) because when I navigate to your link I receive a 401 with "There is no valid session for the current request."
Second, what is the call you're making from AppGyver? Is it a GET to simply list resources of a DB called vlaamse_vinyl, or what?
Finally, if you are passing X-DreamFactory-Application-Name in addition to the URI parameter ?app_name=vlaamse_vinyl this is redundant. Perhaps that is preventing your call from succeeding.

What's wrong with this authorization exchange?

I've set up a MediaWiki server on an Azure website with the PluggableAuth and OpenID Connect extensions. The latter uses the PHP OpenID Connect Basic Client library. I am an administrator in the Azure AD domain example.com, wherein I've created an application with App ID URI, sign-on URL and reply URL all set to https://wiki.azurewebsites.net/. When I navigate to the wiki, I observe the following behavior (cookie values omitted for now):
Client Request
GET https://wiki.azurewebsites.net/ HTTP/1.1
RP Request
GET https://login.windows.net/example.com/.well-known/openid-configuration
IP Response
(some response)
RP Response
HTTP/1.1 302 Moved Temporarily
Location: https://login.windows.net/{tenant_id}/oauth2/authorize?response_type=code&redirect_uri=https%3A%2F%2Fwiki.azurewebsites.net%2F&client_id={client_id}&nonce={nonce}&state={state}
Client Request
(follows redirect)
IP Response
HTTP/1.1 302 Found
Location: https://wiki.azurewebsites.net/?code={code}&state={state}&session_state={session_state}
Client Request
(follows redirect)
RP Request (also repeats #2 & #3)
POST https://login.windows.net/{tenant_id}/oauth2/token
grant_type=authorization_code&code={code}&redirect_uri=https%3A%2F%2Fwiki.azurewebsites.net%2F&client_id={client_id}&client_secret={client_secret}
IP Response
(As interpreted by MediaWiki; I don't have the full response logged at this time)
AADSTS50001: Resource identifier is not provided.
Note that if I change the OpenID PHP client to provide the 'resource' parameter in step 8, I get the following error response from AAD instead:
RP Request
POST https://login.windows.net/{tenant_id}/oauth2/token
grant_type=authorization_code&code={code}&redirect_uri=https%3A%2F%2Fwiki.azurewebsites.net%2F&resource=https%3A%2F%2Fwiki.azurewebsites.net%2F&client_id={client_id}&client_secret={client_secret}
IP Response
AADSTS90027: The client '{client_id}' and resource 'https://wiki.azurewebsites.net/' identify the same application.
(This has come up before.)
Update
I've made some progress based on #jricher's suggestions, but after working through several more errors I've hit one that I can't figure out. Once this is all done I'll submit pull requests to the affected libraries.
Here's what I've done:
I've added a second application to the example.com Azure AD domain, with the App ID URI set to mediawiki://wiki.azurewebsites.net/, as a dummy "resource". I also granted the https://wiki.azurewebsites.net/ application delegated access to this new application.
Passing in the dummy application's URI as the resource parameter in step #8, I'm now getting back the access, refresh, and ID tokens in #9!
The OpenID Connect library requires that the ID token be signed, but while Azure AD signs the access token it doesn't sign the ID token. It comes with the following properties: {"typ":"JWT","alg":"none"}. So I had to modify the library to allow the caller to specify that unsigned ID tokens are considered "verified". Grrr.
Okay, next it turns out that the claims can't be verified because the OpenID Provider URL I specified and the issuer URL returned in the token are different. (Seriously?!) So, the provider has to be specified as https://sts.windows.net/{tenant_id}/, and then that works.
Next, I found that I hadn't run the MediaWiki DB upgrade script for the OpenID Connect extension yet. Thankfully that was a quick fix.
After that, I am now left with (what I hope is) the final problem of trying to get the user info from AAD's OpenID Connect UserInfo endpoint. I'll give that its own section.
Can't get the user info [Updated]
This is where I am stuck now. After step #9, following one or two intermediate requests to get metadata and keys for verifying the token, the following occurs:
RP Request:
(Updated to use GET with Authorization: Bearer header, per MSDN and the spec.)
GET https://login.windows.net/{tenant_id}/openid/userinfo
Authorization: Bearer {access_token}
IP Response:
400 Bad Request
AADSTS50063: Credential parsing failed. AADSTS90010: JWT tokens cannot be used with the UserInfo endpoint.
(If I change #10 to be either a POST request, with access_token in the body, or a GET request with access_token in the query string, AAD returns the error: AADSTS70000: Authentication failed. UserInfo token is not valid. The same occurs if I use the value of the id_token in place of the access_token value that I received.)
Help?
Update
I'm still hoping someone can shed light on the final issue (the UserInfo endpoint not accepting the bearer token), but I may split that out into a separate question. In the meantime, I'm adding some workarounds to the libraries (PRs coming soon) so that the claims which are already being returned in the bearer token can be used instead of making the call to the UserInfo endpoint. Many thanks to everyone who's helped out with this.
There's also a nagging part of me that wonders if the whole thing would not have been simpler with the OpenID Connect Basic Profile. I assume there's a reason why that was not implemented by the MediaWiki extension.
Update 2
I just came across a new post from Vittorio Bertocci that includes this helpful hint:
...in this request the application is asking for a token for itself! In Azure AD this is possible only if the requested token is an id_token...
This suggests that just changing the token request type in step 8 from authorization_code to id_token could remove the need for the non-standard resource parameter and also make the ugly second AAD application unnecessary. Still a hack, but it feels like much less of one.
Justin is right. For authorization code grant flow, your must specify the resource parameter in either the authorization request or the token request.
Use &resource=https%3A%2F%2Fgraph.windows.net%2F to get an access token for the Azure AD Graph API.
Use &resource=https%3A%2F%2Fmanagement.core.windows.net%2F to get a token for the Azure Service Management APIs.
...
Hope this helps
Microsoft's implementation of OpenID Connect (and OAuth2) has a known bug where it requires the resource parameter to be sent by the client. This is an MS-specific parameter and requiring it unfortunately breaks compatibility with pretty much every major OAuth2 and OpenID Connect library out there. I know that MS is aware of the issue (I've been attempting to do interoperability testing with their team for quite a while now), but I don't know of any plans to fix the problem.
So in the mean time, your only real path is to hack your client software so that it sends a resource parameter that the AS will accept. It looks like you managed to make it send the parameter, but didn't send a value that it liked.
I had issues getting this running on Azure, even though I got something working locally. Since I was trying to setup a private wiki anyway, I ended up enabling Azure AD protection for the whole site by turning on:
All Settings -> Features -> Authentication / Authorization
From within the website in https://portal.azure.com
This made it so you had to authenticate to Azure-AD before you saw any page of the site. Once you were authenticated a bunch of HTTP Headers are set for the application with your username, including REMOTE_USER. As a result I used the following plugin to automatically log the already authenticated user into Azure:
https://www.mediawiki.org/wiki/Extension:Auth_remoteuser

Role-based access control with REST (HTTP)?

I'm creating a system with a JavaScript client that will communicate with the server over REST (HTTP)[JSON].
I am using role-based access control to manage the calls.
Example: [explicit URL will stay the same]
Anonymous -> request \
Server -> route to login form: \login\
User (now with cookie!) -> request \
if (user->role == "manager") return "\manager-homepage\";
else return "\homepage\";
Since REST is stateless how would I go about managing this use-case?
Do I send the cookie with each request, and the returned HTTP status codes will tell the JS where to route?
[Which would be rather inefficient + open to MITM attacks]
Can you not use a standard authentication scheme, such as http digest?
Example: [from Wikipedia page]
The client asks for a page that requires authentication but does not provide a username and password. Typically this is because the user simply entered the address or followed a link to the page.
The server responds with the 401 "client-error" response code, providing the authentication realm and a randomly-generated, single-use value called a nonce.
At this point, the browser will present the authentication realm (typically a description of the computer or system being accessed) to the user and prompt for a username and password. The user may decide to cancel at this point.
Once a username and password have been supplied, the client re-sends the same request but adds an authentication header that includes the response code.
In this example, the server accepts the authentication and the page is returned. If the username is invalid and/or the password is incorrect, the server might return the "401" response code and the client would prompt the user again.
Note: A client may already have the required username and password without needing to prompt the user, e.g. if they have previously been stored by a web browser.
See also this answer to a very similar question: REST and authentication variants
Depending on your desired security level, you could serve the whole thing over ssl. That will prevent mitm attacks.