I am looking for documentation on the correct approach/pattern for JWT OAuth validation when using the Registered OAuth Clients in AEM. I have searched the internet and I have not found any good examples of how to validate the JWT OAuth Registered Client token.
I understand the flow from a 3rd Party OAuth Authentication server (ie: FaceBook, Google), but I am looking for the pattern when using the OOTB Registered OAuth Clients in AEM (/libs/granite/oauth/content/clients.html).
Can anyone please provide me with some direction or an approved validation pattern.
Solved! Go to Solution.
@jarvislukow - I never tried this but should be possible with some effort - Extend the OAuth2ServerAuthenticationHandler
The OAuth2ServerAuthenticationHandler is responsibe for validating the token and sending the AuthenticationInfo object on sucessfull validation/login(null response incase of validation/login failure) - The class is available in "Adobe Granite OAuth Server(com.adobe.granite.oauth.server)" bundle
You can create a custom AuthenticationHandler(extend - adjust the ranking) and respond with Auth Fail status code from extractCredentials method for token validation errors - currently extractCredentials respond with null for invalid tokens
e.g
if (validAccessToken) {
.......
}else
{
request.setAttribute("j_reason", "invalid_token");
return AuthenticationInfo.FAIL_AUTH;
}
Regards
Albin I
Please check if this URL helps - https://medium.com/tech-learnings/how-to-manage-the-protected-aem-resources-through-oauth-2-0-851ce4...
Regards
Albin I
Thanks. I have read this. But, I'll have a read though it again... this time in more detail.
Thanks again
@Albin_Issac Turns out I was overthinking the solution, but to be fair there is so little documentation on this pattern. Using the ScopeWithPrivileges does work as expected... with one issue. AEM returns a 404 when the token is not valid. Can this be modified to return a 404 is the resource is not found, and a 401 if the token is not valid?
@jarvislukow - I never tried this but should be possible with some effort - Extend the OAuth2ServerAuthenticationHandler
The OAuth2ServerAuthenticationHandler is responsibe for validating the token and sending the AuthenticationInfo object on sucessfull validation/login(null response incase of validation/login failure) - The class is available in "Adobe Granite OAuth Server(com.adobe.granite.oauth.server)" bundle
You can create a custom AuthenticationHandler(extend - adjust the ranking) and respond with Auth Fail status code from extractCredentials method for token validation errors - currently extractCredentials respond with null for invalid tokens
e.g
if (validAccessToken) {
.......
}else
{
request.setAttribute("j_reason", "invalid_token");
return AuthenticationInfo.FAIL_AUTH;
}
Regards
Albin I
Thank you @Albin_Issac
@Albin_Issac I have this working for the most part now - In my flow I am using the server-server integration, and I am curious about the user and user permissions.
In my working code, and in your example, when I decode the access_token returned from the Adobe Granite server the subject is always set to admin.
"sub":"admin"
This is regardless of the subject passed with the token request. It looks like the user name (subject) admin is parsed out of the accessToken.
final String userId = OAuth2Helper.getSubject(accessToken);
And this is used as the base for the user session. If this is the case, how can we restrict custom scopes?
Am I missing something? I assumed that the session created in AEM would be essentially an anonymous access plus what was defined in the scope.
How are you generating the JWT token? Have you specified the username in the sub while generating token?
Also, please parse the generated token through jwt.io and see if the user name is available(Refer to the blog for more details - https://medium.com/tech-learnings/how-to-manage-the-protected-aem-resources-through-oauth-2-0-851ce4...)
Regards
Albin I
Regardless of including the "sub" attribute in the JWT Bearer token, the generated access token always changes the sub to admin.
Since I am following the server-server pattern, I am using the urn:ietf:params:oauth:grant-type:jwt-bearer grant type.
In the example you referenced, if you decode the generated access token for the server-server flow I also see the sub was converted to admin:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJnNmIzajl2aTk4bDM5ZmFvNzFpdmc0aDlraC1xM2dydGdoaCIsImlzcyI6IkFkb2JlIEdyYW5pdGUiLCJzdWIiOiJhZG1pbiIsImV4cCI6MTU5NzI3NzYwNSwiaWF0IjoxNTk3Mjc0MDA1LCJzY29wZSI6ImRhbV9yZWFkIiwiY3R5IjoiYXQifQ.g-AXNazPxnAP1VbB8Ym1NB_UFW2MuCmYvsPWuZY-jfQ
{"alg":"HS256","typ":"JWT"}{"aud":"g6b3j9vi98l39fao71ivg4h9kh-q3grtghh","iss":"Adobe Granite","sub":"admin","exp":1597277605,"iat":1597274005,"scope":"dam_read","cty":"at"}
Maybe this doesn't matter... but I am confused what user a session is actually for if successful.
No this is the token referred in my blog for server to server OAuth(JWT)
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQ1MDIvb2F1dGgvdG9rZW4iLCJpc3MiOiJnNmIzajl2aTk4bDM5ZmFvNzFpdmc0aDlraC1xM2dydGdoaCIsInN1YiI6ImFsYmlub2F1dGgiLCJleHAiOjE1OTcyNzM4OTA5NDA2LCJpYXQiOjE1OTcyNzM4MDk0MDYsInNjb3BlIjoiZGFtX3JlYWQiLCJjdHkiOiJjb2RlIn0.EmXLGX9RK-i4OPh-kA8YSTxi8PSJxVtk7uWsYLcMqXY4Z-ZI6pJK_1uLZdJbFxurs3tLqkg300w6w3M99PTrHZg54J2s9SafZyB7psAh6K8ycEvJDHsUDD1ovZvMfQ__tqhMC8yzGFlODLWaAx095fVHO-ce4pewxdzwv3TQK593xwjtwL_hPRqLkjy6Kvt6Cu0TEJd6YFoMNiftca9KxIMEG9fMOpNkHe4rIo_oSqdmiDzbqBZ-0P_3j4gDO_AYnULF9h42NHOrgAxOucfwZbfxgHc8UODUiLw3f1Mw9WGK9POzdFPeruHcknjRf4J60BwestDbFjfHb_8owXAJwA
The sub value is specified as albinoauth when i try to parse the token throughhttps://jwt.io/
Regards
Albin I
Yes, the bearer token (or assertion) does contain the sub, like your example. But in the generated access token, in your example and in my code, the sub is converted to admin.
So, for the actual content request when the access token is validated how does the scoped permissions get bound to the request. I see the scopes being added via:
OAuth2Helper.addACLEntries(oauthServiceSession, oauthUser.getPrincipal(), user, OAuth2Helper.getScopeSetFromNames(oAuth2ResourceServer, scopes), true);
but if I remove the included scope to not include a secure path, the request still returns a 200.
I assumed that the defined resource paths in the scopeWithPrivileges class would control the actual resource security... but it seems that is not the case. It seems to be adding the paths to an existing user?
@Albin_Issac I see, the authentication handler is actually adding the newly created oauth users as members of the everyone group. I thought it was going to use anonymous for some reason... but everyone is better than using the admin group which I thought it was
The last question I have is regarding scopes - Is it possible register multiple paths in one scope? Or use a wildcard/regex pattern? For example I would like to register the following paths to one scope:
/content/dam/projectName/secure/en_ca
/content/dam/projectName/secure/fr_ca
Is there an approach to bind multiple paths to one scope?
/content/dam/projectName/secure/*
Thanks for your help on this.
Looks to be this is the default behaviour, getResourcePath(User user) returns signle path as string
Please post the extended AuthHandler here if possible, may helps others with same requirement.
Regards
Albin I
Views
Replies
Total Likes
@Albin_Issac Good to see you back in the AEM community.
Views
Likes
Replies
Views
Likes
Replies