Lambda reconcile does not remove role from registration
-
Lambda reconcile with Azure AD OIDC
I have set up an azure application like described here. To match the group-ids on azure to our application-specific roles, I set up a reconcile lamba (as the jwt-populate lambda is not available while on oidc), which is as follows:
function reconcile(user, registration, jwt) { //groupId matching var admin = 'd166c6a0-...'; var superuser = '738d97af-...'; var viewer = '8932d06f-...'; //azure groups are like this // "groups": [["d166c6a0-..."]]; var groupsAzure = JSON.parse(jwt.groups); registration.roles = []; user.email = jwt.upn; if(Array.isArray(groupsAzure)){ groupsAzure.forEach(function(groups){ if(groups === admin){ registration.roles.push('admin', 'superuser', 'viewer'); } if(groups === superuser){ console.info('superuser!!!!'); registration.roles.push('superuser', 'viewer'); } if(groups === viewer){ console.info('viewer!!!!'); registration.roles.push('viewer'); } }); } }
This works perfectly fine (only for testing!) If I login with a "viewer" user, the registration gets the right rule. If I "upgrade" the "viewer" with "admin" permissions, this is also updated in the registration.
But if I "downgrade" a user while removing him from the admin group, the lambda does not update the registration roles.
Do I miss something? Currently using 1.15.2. Thanks a lot! -
Hi @tl-fa,
Were you able to figure this out? If not, I can review the tutorial that you are working through to see if I have any thoughts.
Thanks,
Josh -
Hi Josh,
I was not yet able to get this done. The problem still is, that the assignment of registration rules inside the reconcile lambda. Your help is greatly appreciated.Thanks a lot,
Thomas -
Hi @tl-fa,
After discussing this issue, there are three troubleshooting strategies for you to consider:
- Add debugging statements
-- Add console log statements just preceding and immediately following any timeregistration.roles
array changes.
-- Any other location you can think of to confirm assumptions vs actual behavior - Decouple the Azure OIDC protocol
-- Reproducing the same lambda/js code but using a different OIDC partner/choice would confirm it is not Azure AD creating the issue.
-- Obviously, this is extra lifting codewise, but could prove illuminating and would be confirming. - Change the order of your roles
-- Confirm that if you were to reverse the roles on different groups, you have the opposite behavior
-- For instance, if you were to pushadmin
,superuser
, andviewer
on togroups.user
(and so forth) would things act incorrectly on the 'upgrade' but work correctly on the downgrade (as seen in the current example provided).
-- All this would be in an attempt to confirm the actual behavior of the Array. Is it resetting correctly upon initialization? Is it getting roles added as we would expect in the array and removed as expected?
We could certainly troubleshoot more in-depth if you had a support contract so please do let us know if this is something you would need (i.e. - if you are running in production at scale). I hope this gives you something more to go on.
Thanks,
Josh - Add debugging statements
-
@joshua Thank you very much for your effort. I will try to put some more light on this!
Thanks again,
Thomas -
@tl-fa said in Lambda reconcile does not remove role from registration:
registration.roles
In your example, are you trying to modify roles for a FusionAuth admin user (roles that apply when logging into the FusionAuth admin UI) or is this for your application?
For reference, if you are trying to modify roles for the FusionAuth admin UI (FusionAuth registration), the roles are documented here. https://fusionauth.io/docs/v1/tech/core-concepts/roles/#fusionauth-application-roles
-
Hi @robotdan
Actually these are roles belonging to my application. I have some more debug informations:
Downgrade Flow:
User on FusionAuth with roles [admin,superuser,viewer]:
User on Azure:
Lambda invocation result.
--- jwt --- { "sub": "5SS_....", "amr": "[\"pwd\"]", "ipaddr": "......", "name": "reader", "oid": "2c5cccd...., "rh": "0.ATsA112D...", "tid": "b9835dd7....." "unique_name": "reader@...onmicrosoft.com", "upn": "reader@......onmicrosoft.com", "uti": "LR1UTJ...", "ver": "1.0", "groups": [ "[\"8932d06f-eeb0-444f-a8d8-0c7c9972e311\"]" ] } --- registration --- { "applicationId": "9d63587b-e17c-4af0-989f-9b965ba94a60", "tokens": { "7c8a26f1....": "0.ATsA11..." }, "verified": false } --- user --- { "active": false, "fullName": "reader", "passwordChangeRequired": false, "twoFactorEnabled": false, "verified": false } --- azure groups --- 8932d06f-eeb0-444f-a8d8-0c7c9972e311 mapped group is -> viewer --- registration after assignement --- { "applicationId": "9d63587b-e17c-4af0-989f-9b965ba94a60", "tokens": { "7c8a2..": "0.ATsA.." }, "verified": false, "roles": [ "viewer" ] } --- user after assignement --- { "active": false, "fullName": "reader", "passwordChangeRequired": false, "twoFactorEnabled": false, "verified": false, "email": "reader@....onmicrosoft.com" }
The lambda as follows
// Using the JWT returned from UserInfo, reconcile the User and User Registration. function reconcile(user, registration, jwt) { console.info('--- jwt ---'); console.info(JSON.stringify(jwt, null, 2)); console.info('--- registration ---'); console.info(JSON.stringify(registration, null, 2)); console.info('--- user ---'); console.info(JSON.stringify(user, null, 2)); //groupId matching var admin = 'd166c6a0-bdd0-4649-b596-0b5ce2c58b49'; var superuser = '738d97af-f058-4eb3-b3d5-ddbf84df20f9'; var viewer = '8932d06f-eeb0-444f-a8d8-0c7c9972e311'; var groupsAzure = JSON.parse(jwt.groups); console.info('--- azure groups ---'); console.info(groupsAzure); registration.roles = []; user.email = jwt.upn; if(Array.isArray(groupsAzure)){ groupsAzure.every(function(groups){ if(groups === admin){ console.info('mapped group is -> admin'); registration.roles.push('admin', 'superuser', 'viewer'); return false; } if(groups === superuser){ console.info('mapped group is -> superuser'); registration.roles.push('superuser', 'viewer'); return false; } if(groups === viewer){ console.info('mapped group is -> viewer'); registration.roles.push('viewer'); return false; } }); } console.info('--- registration after assignement ---'); console.info(JSON.stringify(registration, null, 2)); console.info('--- user after assignement ---'); console.info(JSON.stringify(user, null, 2)); }
the payload of the jwt issued by FushionAuth to the application:
{ "aud": "9d63587b-e17c-4af0-989f-9b965ba94a60", "exp": 1620055251, "iat": 1620051651, "iss": "https://fusionauth....", "sub": "0b867bd9-ffbd-4dd8-a275-f663143c7a70", "authenticationType": "OPENID_CONNECT", "email": "reader@...onmicrosoft.com", "email_verified": true, "at_hash": "0MKgnKThS_tyAK460tE_Ng", "c_hash": "uSQ7YGhENpZyfTg-iiipWg", "applicationId": "9d63587b-...", "roles": [ "admin", "superuser", "viewer" ] }
The issued jwt from fusionauth still contains the all three roles as before the "downgrade". So it seems that the lambda assignment
registration.roles.push('viewer');
does not work as expected..
-
To confirm, you are doing something like this:
registration.roles = []; registration.roles.push('viewer');
And then the resulting registration contains the previous roles +
viewer
? And you are expecting a single role ofviewer
? -
No, only the previous roles (as they already include the viewer role). Yes, I am expecting a single role of
viewer
.If I change the previous roles of the user to
superuser
anddeveloper
(on FA) the resulting set of roles after the lambda issuperuser
,developer
andviewer
. So there is an additional role ofviewer
, but the previous two roles remain. -
Hmm... this is likely a JSON merge issue. See linked issues below.
We Marshall objects back and forth from the JS engine via JSON and I the root issue here is likely that JSON merge does not handle arrays.
We could fix this by turning off merge for this field, or we will be updating > Java 14 shortly which means we have to ditch Nashorn, so it is possible this new JS engine will allow us to directly manipulate the registration object and ditch the JSON conversation.
Related issues:
https://github.com/FusionAuth/fusionauth-issues/issues/441
https://github.com/FusionAuth/fusionauth-issues/issues/571
https://github.com/FusionAuth/fusionauth-issues/issues/667 -
Happy to hear that! Any solution is welcome for me, when implemented, I will retest the case. Can you already shout out a date?
Cheers,
Thomas -
Hi @tl-fa,
You can view our Roadmap Guidance regarding how features are implemented into FusionAuth. A good snapshot of current development can be found here as well.
We will certainly update any related issue cards as development moves forward!
Thanks!
Josh