Netflix DGS GraphQL Subscription Produces empty Security Context - How can this be made available? - netflix-dgs

We are using the following stack :
Kotlin 1.6.0 running on JVM 11
com.netflix.graphql.dgs:graphql-dgs-spring-boot-starter 5.0.4
com.netflix.graphql.dgs:graphql-dgs-subscriptions-websockets 5.0.4
com.netflix.graphql.dgs:graphql-dgs-subscriptions-websockets-autoconfigure 5.0.4
org.springframework.boot:spring-boot-starter-security 2.6.7
org.springframework.boot:spring-boot-starter-oauth2-resource-server 2.6.7
We are authenticating using the Google Identity Platform from the client side and passing the resulting Bearer token to the DGS API.
The pure HTTP requests (DgsQuery, DgsMutation) are able to extract the processed/validated token without an issue - and we are able to determine the userId from this.
Expected Results
When calling a subscription graph call we are expecting to extract the same details from the processed Bearer token - so we can then utilise the User Identification within the business logic.
Actual Results
The SecurityContextHolder returns an authorization value that is null. And passing in an invalid token still correctly returns subscribed results, suggesting that the subscription endpoint is not being hooked into the JWT authentication at all.
Question
What would be the recommended approach in providing the same authentication behavior and availability of Security Context to Subscriptions as is available to both DGSQuery and DGSMutation annotated functions?
From research - I understand that this needs to be performed in the initial handshake and then saved to the session.
Worth mentioning - that when calling the server from the GraphiQL UI - therefore using the newest protocol - the authentication occurs and the Security Context is populated with the correct information. However, this then fails with "Trying to execute subscription on /graphql. Use /subscriptions instead!" - which is to be expected with the incompatible client/server versions.

Related

Creating scene definition against beta server gets 422 error

I'm trying to use the Unity AR/VR Toolkit with a SVF file I've created by following the test-2legged script. My understanding from this answer is that the script needs to be updated to use the new server (https://developer-api-beta.autodesk.io) and a URL-safe encoded URN everywhere. I've done that, but when I try to create the scene definition (PUT /arkit/v1/${urn}/scenes/${scene}) I get a 422 with a msg of "must be a valid Bearer token for the requested resource (TK1-003)" (I've tried giving the token all scopes listed in the Forge docs).
This works fine with the server in the non-modified test-2legged script. I'm operating on a file that's already in Forge so I'm not including the bucket, and I've experimented with including and not including the object ID; the default server (https://developer-api.autodesk.io) works fine with just an urn; the beta server I can't get to work no matter what I try.
I don't see any documentation for this endpoint so I'm not sure if it's use changed between the servers. As far as I can tell, in the toolkit I can't get SVF files created against the non-beta server (I get 404's for the meshes), so I'm assuming I should be on the beta server, but I can't get it to work.
I took a look into the source code and TK1-003 means that the Bearer token was either invalid, expired, and the token was missing the data:create data:write scoped for this operation. Note that in case, you call and API with an invalid token, the server bans you for couple of minutes.
If you still having issues, please let me know and I'll remote assist you.

Rest APIS - HTTP Delete - Request body gets ignored/dropped WSO2 API Manager

Environment :-
Web Service - Rest APIs.
Media Type - JSON.
JAX RS implementation - Jersey.
HTTP Methods - POST, GET, PUT & DELETE.
WSO2 API Gateway Manager - To sit on top of it to publish these APIs.
Problem :-
The delete operation has a request body(a json message) which has input values in it. When I hit the services directly - the whole operation performs successfully.
But once I go through the API Manager (using the URL that it publishes) - the request body seems to be getting dropped/ignored & hence the operation fails.
Rest all the operations are working fine & so is the OAuth too.
Can someone please help me - as to why is the the request body (a json message) is getting discarded when I go through the WSO2 API gateway manager - and what can I do to get it working, please !!
Thanks in advance.
HTTP DELETE opration isn't supposed have body. You can check here and here
Many frameworks discourage using it or warn you that the body may be dropped. The reason is that you want to DELETE some resource identified by your URI thus no body should be required.
Update
WSO2 API Manager depends on Apache HttpComponents/HttpCore library for this functionality and this issue is fixed in their 5.0 which isn't released yet.
You can find the JIRA here reported against httpCode library.

WSO2 IS 5.1.0 as OAuth/OIDC IdP response with different claims on UserInfo endpoint

Anyone know why if I make a call to /userinfo endpoint I obtain different JSON response? Specifically:
When I make a call with curl from command line, like $curl -k -H "Authorization: Bearer 2bcea7cc9d7e4b63fd2257aa31116512" https://localhost:9443/oauth2/userinfo?schema=openid I obtain as response the JSON: {"sub":"asela","name":"asela","preferred_username":"asela","given_name":"asela","family_name":"asela"}
If I make the call with a java client (a library that implement the Authorization Code Flow), when the client make the /userinfo call I have as response a JSON like {"sub":"asela#carbon"} without all other claims.
The claims for the service defined in WSO2 IS are the default ones. Thanks for any help.
I have tried this and got the same issue that you have faced. As I have mentioned in my previous comment, the issue occurs due to the claim mapping issue. Normally we get the user's attributes from the “http://wso2.org/claims” dialect. But when we call to OpenID userInfo endpoint, it will provide the user's attributes from “http://wso2.org/oidc/claim”. But all the claims in http://wso2.org/claims are not defined in http://wso2.org/oidc/claim. (Ex:Mobile, Address, Organization). So we have to define those required claims on http://wso2.org/oidc/claim dialect, if it is not defined.
You can check this claims from Identity Server Management console. To do this, Log into ManagementConsole > Main > List (under Claims)
Then you can go though the two claim dialects and add required claims to http://wso2.org/oidc/claim dialect. To add new claim, Goto ManagementConsile > Main > Add(under Claims) > Add new claim. See the attached screen shot of defining a sample claim. Here you need to map the exact Mapped Attribute & Claim Uri with the http://wso2.org/claims.
Hope this will helpful.
WSO2 IS normally returns the claims that are configured under the “http://wso2.org/oidc/claim” claim dialect. But the claim in the response should return normally. So make sure you have defined claim values in the user's profile. You can follow [1] & [2] for more details about this. Still you couldn't get the correct response, please attached your SP configurations and claim configurations for further analyze.
[1] http://xacmlinfo.org/2015/03/09/openid-connect-support-with-resource-owner-password-grant-type/
[2] http://shanakaweerasinghe.blogspot.com/2016/01/get-user-profile-for-oauth-token-using.html

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

Use oAuth token with Azure MobileServiceClient.login()

I am using the native Facebook SDK (through an opensource tool called 'SimpleFacebook') to authenticate with Facebook. That part is working great. I find the Microsoft Azure implementation of Facebook authentication to be lacking.
Anyway, the next step is to use the token from this Facebook session and authenticate with MS/Azure. There are two methods like look like they should do the job
public void login(java.lang.String provider,
java.lang.String oAuthToken,
UserAuthenticationCallback callback)
Invokes Windows Azure Mobile Service authentication using a provider-specific oAuth token
Parameters:
provider - The provider used for the authentication process
oAuthToken - The oAuth token used for authentication
callback - Callback to invoke when the authentication process finishes
And another very similar method where the second param is a JSON object of type:
com.google.gson.JsonObject oAuthToken,
Is it just me or is the documentation lacking here? I tried just calling the Facebook session's .getAccessToken() and passing that to the functions and I get an error from Azure:
Caused by: com.microsoft.windowsazure.mobileservices.MobileServiceException: {"code":400,"error":"Error: invalid json"}
at com.microsoft.windowsazure.mobileservices.MobileServiceConnection$1.onNext(MobileServiceConnection.java:115)
How do we know what the correct JSON format is?
Am Using the right token?
More information can be found at:
at this Azure site
I think I have this figured out. Essentially all I had to do was create a JSON object (which is fairly new for me). I tried this earlier but I had imported the wrong JSON class (I had imported org.json.JsonObject or something rather than the com.google.gson.JsonObject).
once I did that I had to figure out what the correct json properties should be. Through a lot of Google searches I found out this is the correct format:
JsonObject jo = new JsonObject();
jo.addProperty("access_token", token);
Then use jo.toString() in the call like:
mClient.login(MobileServiceAuthenticationProvider.Facebook, jo.toString(), new UserAuthenticationCallback() {
.....
}
Really not that difficult, but why wouldn't Azure team put this in their docs???
Maybe this is just "obvious" information for a seasoned dev, but it took me a whole evening to figure out.