and more in a single search tool across platforms. Read the announcement here. |
09/15/2023 03:25 AM
Hi All,
Need your support in fixing the json error for the Azure AD guest and normal account management using REST connector. I have written following JSON based on one of the forum link https://forums.saviynt.com/t5/identity-governance/guest-accounts-in-azure-ad/m-p/33493
However i am getting following error when using for my requirement.
{\"auditDetails\":{\"call1\":[{\"message\":\"Unrecognized token '$': was expecting ('true', 'false' or 'null')
Attached is the json for your reference. I am missing something which unable to be traced.
Thank you
Sampath
Solved! Go to Solution.
09/15/2023 04:18 AM
Hi @sampath18
There seems to be some issues in the httpparams, string and variables need the concat operator:
"httpParams": "${if(user.customproperty32.equals('Guest')){return '{\"invitedUserEmailAddress\":\"' + user.email + '\",\"invitedUserDisplayName\":\"' + user.lastname+','+user.firstname + '\", \"inviteRedirectUrl\":\"https:\/\/myapplications.windowsazure.cn\",\"invitedusageLocation\":\"CN\" \"invitedUserType\": \"Guest\", \"sendInvitationMessage\":\"true\"}';} else {return '{\"accountEnabled\": \"true\", \"displayName\": \"' + user.firstname + '\",\"employeeId\":\"'+ user.username + '\",\"employeeHireDate\":\"' + user.startdate + '\",\"city\":\"'+ user.city + '\",\"country\":\"' + user.country + '\",\"state\":\"'+ user.state + '\",\"streetAddress\":\"'+ user.street+ '\",\"jobtitle\":\"' + user.title + '\",\"postalCode\":\"' + user.regioncode + '\",\"officeLocation\":\"' + user.locationdesc + '\" \"mailNickname\": \"' + user.email.toString().toLowerCase().replace('@bain.com','')+ '\", \"passwordProfile\" : {\"password\": \"Saviynt@12345\",\"forceChangePasswordNextSignIn\": true}, \"UsageLocation\": \"CN\",\"userPrincipalName\": \"' + user.email.toString().toLowerCase().replace('bain.com','bain.cn') + '\"}';}}"
Perform the same check over the whole parameter and check if that solves the issue
09/15/2023 05:19 AM
Hi @armaanzahir Thanks for your response.
I am not clear what is the use of these concat operators apart from the displayname which you highlighted. Remaining parameters i have removed the concat operator and tried with below.
But below one also giving same error as above. Hence i am thinking somewhere else it is breaking in the http param which is untraceable from error.
"httpParams": "${if(user?.customproperty32.equals('Guest')){return '{\"invitedUserEmailAddress\":\"user?.email\",\"invitedUserDisplayName\":\"user?.lastname+','+user?.firstname\", \"inviteRedirectUrl\":\"https:\/\/myapplications.windowsazure.cn\",\"invitedusageLocation\":\"CN\" \"invitedUserType\": \"Guest\", \"sendInvitationMessage\":\"true\"}'} else {return '{\"accountEnabled\": \"true\", \"displayName\": \"user?.lastname+','+user?.firstname\",\"employeeId\":\"user?.username\",\"employeeHireDate\":\"user?.startdate\",\"city\":\"user?.city\",\"country\":\"user?.country\",\"state\":\"user?.state\",\"streetAddress\":\"user?.street\",\"jobtitle\":\"user?.title\",\"postalCode\":\"user?.regioncode\",\"officeLocation\":\"user?.locationdesc\" \"mailNickname\": \"user?.email.toString().toLowerCase().replace('@abc.com','')\", \"passwordProfile\" : {\"password\": \"Saviynt@12345\",\"forceChangePasswordNextSignIn\": true}, \"UsageLocation\": \"CN\",\"userPrincipalName\": \"user?.email.toString().toLowerCase().replace('abc.com','abc.cn')\"}'}}"
09/17/2023 09:12 PM
what is error now ?
09/18/2023 11:45 PM
Hi @rushikeshvartak The error remains same. Below is the error.
{\"auditDetails\":{\"call1\":[{\"message\":\"Unrecognized token '$': was expecting ('true', 'false' or 'null')
Thanks,
Sampath
09/21/2023 03:08 AM
Hi All,
Can anyone provide sample working jsons where if else conditions are used in REST connector.
Thanks
Sampath
09/22/2023 01:57 AM
Hi All,
I was able to fix the issue , below json is working as expected for my requirement, please note the azure AD url here is used for china 21vianet. For global tenant urls will change.
{
"accountIdPath": "${(user.customproperty32=='Guest')?'call1.message.invitedUser.id': 'call1.message.id'}",
"dateFormat": "yyyy-MM-dd'T'HH:mm:ssXXX",
"responseColsToPropsMap": {
"customproperty31": "${(user?.customproperty32=='Guest')?'call1.message.inviteRedeemUrl~#~char': ''}",
"customproperty32": "${(user?.customproperty32=='Guest')?'call1.message.invitedUserType~#~char': ''}",
"displayName": "${(user?.customproperty32=='Guest')?'call1.message.invitedUserDisplayName~#~char': 'call1.message.displayName~#~char'}",
"name": "${(user?.customproperty32=='Guest')?'call1.message.invitedUserEmailAddress~#~char': 'call1.message.UserEmailAddress~#~char'}"
},
"call": [{
"name": "call1",
"connection": "userAuth",
"url": "${(user?.customproperty32=='Guest')?'https://microsoftgraph.chinacloudapi.cn/v1.0/invitations':'https://microsoftgraph.chinacloudapi.cn/v...'}",
"httpMethod": "POST",
"httpParams":"${if(user?.customproperty32?.equals('Guest')){return '{\"invitedUserEmailAddress\":\"'+user?.email+'\",\"invitedUserDisplayName\":\"'+user?.lastname+','+user?.firstname+'\", \"inviteRedirectUrl\":\"https:\/\/myapplications.windowsazure.cn\/?tenantid=47d9c042-e076-46f3-86c6-dfe85d7d78f5\",\"invitedusageLocation\":\"CN\",\"invitedUserType\": \"Guest\", \"sendInvitationMessage\":true}';}else{return '{\"accountEnabled\": \"true\", \"displayName\":\"'+user?.lastname+','+user?.firstname+'\",\"employeeId\":\"'+user?.username+'\",\"employeeHireDate\":\"'+user?.startdate+'\",\"city\":\"'+user?.city+'\",\"country\":\"'+user?.country+'\",\"state\":\"'+user?.state+'\",\"streetAddress\":\"'+user?.street+'\",\"jobtitle\":\"'+user?.title+'\",\"postalCode\":\"'+user?.regioncode+'\",\"officeLocation\":\"'+user?.locationdesc+'\",\"mailNickname\": \"'+user?.email?.toString().toLowerCase().replace('@abc.com','')+'\",\"passwordProfile\" : {\"password\": \"Saviynt@12345\",\"forceChangePasswordNextSignIn\": true}, \"UsageLocation\": \"CN\",\"userPrincipalName\": \"'+user?.email?.toString().toLowerCase().replace('abc.com','abc.cn')+'\"}';}}",
"httpHeaders": {
"Authorization": "${access_token}"
},
"httpContentType": "application/json",
"successResponses": {
"statusCode": [
200,
201,
204,
205
]
}
}
]
}
11/15/2023 03:45 AM - edited 11/15/2023 03:46 AM
Hi Sampath,
Is it possible to put condition for endpointname instead of user's customproperty ${if(user?.customproperty32?.equals('Guest'))
Something like below
${if(task?.endpoint?.displayName?.equals('Entra Tenant 1')){return ''}}
11/15/2023 04:19 AM
Endpoint attributes would be same for all users right? in that case the condition always become true. So I would suggest to try if that is the requirement.
11/15/2023 04:31 AM - edited 11/15/2023 04:33 AM
We have two endpoint (having two account name rule) in same Security system.. parent endpoint will be used to create guest account and child endpoint will be used to create admin accounts - (non guest user).. and we have to create both account for same user..
We tried lot of things, If we change that condition to some other thing (endpoint, task) except user.. we are getting {"call1":[{"message":"Unrecognized token '$': was expecting ('true', 'false' or 'null')\n
11/15/2023 04:35 AM
can you try this and see if it is working
${if(endpoints?.displayName?.equals('Entra Tenant 1')){return ''}}
11/15/2023 05:05 AM
Account got created for first endpoint where if condition matched and it failed for else if with below error.
Unrecognized token '$': was expecting ('true', 'false' or 'null')
11/15/2023 05:06 AM
Below is our JSON
{
"accountIdPath": "${(user.customproperty40=='Guest')?'call1.message.invitedUser.id': 'call1.message.id'}",
"dateFormat": "yyyy-MM-dd'T'HH:mm:ssXXX",
"responseColsToPropsMap": {
"customproperty31": "${(user.customproperty40=='Guest')?'call1.message.inviteRedeemUrl~#~char': ''}",
"customproperty1": "${(user.customproperty40=='Guest')?'call1.message.invitedUserType~#~char': ''}",
"displayName": "${(user.customproperty40=='Guest')?'call1.message.invitedUserDisplayName~#~char': 'call1.message.displayName~#~char'}",
"name": "${(user.customproperty1=='Guest')?'call2.message.userPrincipalName~#~char': 'call1.message.userPrincipalName~#~char'}"
},
"call": [
{
"name": "call1",
"connection": "userAuth",
"url": "${(endpoints.endpointname=='Entra Global Tenant')?'https://graph.microsoft.com/v1.0/invitations':'https://graph.microsoft.com/v1.0/users'}",
"httpMethod": "${(user.customproperty40=='Guest')?'POST':'POST'}",
"httpParams": "${if(endpoints?.displayName?.equals('Entra Global Tenant')){return '{\"invitedUserEmailAddress\":\"' + user.email + '\",\"invitedUserDisplayName\":\"' + user.firstname+' '+user.lastname + '\", \"inviteRedirectUrl\":\"https://portal.azure.com\", \"invitedUserType\": \"Guest\", \"sendInvitationMessage\":\"true\"}';} else {return '{\"accountEnabled\": \"true\", \"displayName\": \"' + user.displayName + '\", \"mailNickname\": \"' + user.firstname + user.lastname +'\", \"passwordProfile\": { \"password\": \"Passw0rd123\"}, \"UsageLocation\": \"US\",\"userPrincipalName\": \"' + arsTasks.accountName + '\",\"employeeId\": \"' + user.employeeID + '\"}';}}",
"httpHeaders": {
"Authorization": "${access_token}",
"Content-Type": "application/json"
},
"httpContentType": "application/json",
"successResponses": {
"statusCode": [
200,
201,
204,
205
]
},
"unsuccessResponses": {
"error.code": [
"Request_BadRequest",
"Authentication_MissingOrMalformed",
"Request_ResourceNotFound",
"Authorization_RequestDenied",
"Authentication_Unauthorized",
"BadRequest"
]
}
},
{
"name": "call2",
"connection": "userAuth",
"url": "${(user.customproperty40=='Guest')?'https://graph.microsoft.com/v1.0/users/${response.call1.message.invitedUser.id}': 'https://graph.microsoft.com/v1.0/users'}",
"httpMethod": "GET",
"httpParams": "",
"httpHeaders": {
"Authorization": "${access_token}"
},
"httpContentType": "application/json",
"successResponses": {
"statusCode": [
200,
201,
204,
205
]
},
"unsuccessResponses": {
"error.code": [
"Request_BadRequest",
"Authentication_MissingOrMalformed",
"Request_ResourceNotFound",
"Authorization_RequestDenied",
"Authentication_Unauthorized",
"BadRequest"
]
}
}
]
}
Thanks
11/15/2023 05:12 AM
It could be some value missing in else condition or JSON parsing error. please closely check the else part of the JSON for each attribute you are setting
11/15/2023 06:10 AM - edited 11/15/2023 07:29 AM
Thanks we were able to solve this issue.
11/15/2023 06:22 AM
That is great.. what was the issue, can you highlight?
11/15/2023 06:26 AM
Just another thing i dont find reason to have call 2 here. that seems to be additional call to fetch user details without purpose.
11/15/2023 06:55 AM - edited 11/15/2023 06:56 AM
hi Sampath,
Call2 is to collect the generated upn in case of guest user.. but we are still facing some issue..
task is getting completed successfully for endpoints.endpointname=='Entra Global Tenant' i.e. in case of guest account but it remains pending in case of normal account.. although call2 is success in both the case..
Can you look at the call2 and let me know why it could be creating issue by keeping task in pending state?
11/24/2023 02:47 AM - edited 11/24/2023 03:33 AM
Hi @gauravchandok,
Is there some way to set response attributes on the user in Saviynt, not the account? We have a case where we invite guest user to AAD and need to set id from Azure on user in Saviynt.
11/27/2023 10:54 PM
Hi, I am not sure if that is possible or not.. I am relatively new to saviynt..
11/28/2023 03:22 AM - edited 11/28/2023 03:27 AM
Hi @gauravchandok,
Same here, I'm also a Saviynt newbie 🙂 I figured it out actually, not sure if it's the best way but maybe it will give someone an idea how to do it in the future. I've created a REST connection, with IMPORTUSERJSON I'm getting users which are missing the Azure ID (customproperty13 on user object) via Sav4Sav getUser endpoint. In the same connection with MODIFYUSERJSON I'm getting Azure ID from the account and setting in on the customproperty13 on user object with an update statement. This is triggered via an User Import via a Connection job.
11/28/2023 04:39 AM
Hi @nmuzinic Your response looks to be good solution, So are you using Preprocess queries in the modify user json filed and it is invoked during importuser json of SAV4SAV connection?
Do you mind sharing sample queries you have written this requirement?
Thanks
11/30/2023 11:47 PM
so you are running user import in saviynt from saviynt.. nice solution.. you are importing filtered users where your cp13 is blank and then filling cp13 via preprocessor query,.. now it will skip the users processed in previous import when you run this import again... right?
12/04/2023 07:27 AM
Hi @sampath18 and @gauravchandok,
Sorry I've been busy and didn't have a chance to reply earlier, I'll try to answer your questions 🙂
So are you using Preprocess queries in the modify user json filed and it is invoked during importuser json of SAV4SAV connection?Do you mind sharing sample queries you have written this requirement?
@sampath18 - yes, I'm using pre-processor supported via the MODIFYUSERDATAJSON described here and in importUserJson I'm getting the users that need updating (we can identify them as they have customproperty59='Invite' and customproperty13 is null - where Azure ID should be) . Here is the code sample:
{
"connection": "acctAuth",
"url": "https://SAVURL/ECM/api/v5/getUser",
"httpMethod": "POST",
"httpHeaders": {
"Authorization": "${access_token}",
"contentType": "application/json"
},
"httpParams": "{\"userQuery\":\"statuskey = 1 and customproperty13 is null and customproperty59='Invite'\",\"max\":\"1000\"}",
"httpContentType": "application/json",
"colsToPropsMap": {
"username": "username~#~char"
},
"userResponsePath": "userdetails",
"pagination": {
"offset": {
"offsetParam": "offset",
"batchParam": "max",
"batchSize": 1000,
"totalCountPath": "completeResponseMap.total"
}
}
}
And in MODIFYUSERJSON I have the following query where customproprety2 (azure ID that we get from the response when we're inviting users to the AAD tenant) from account is copied to users customproperty13:
{"ADDITIONALTABLES": {"USERS": "select username, userkey from users where customproperty11 is null and customproperty59='Invite'","ACCOUNTS": "select accountkey, accountid, customproperty2,endpointkey from accounts where endpointkey=8 and customproperty2 is not null","USER_ACCOUNTS": "select ua.userkey, ua.accountkey from USER_ACCOUNTS ua inner join ACCOUNTS a on ua.accountkey = a.ACCOUNTKEY where a.endpointkey=8"},"COMPUTEDCOLUMNS": ["customproperty13"],"PREPROCESSQUERIES": ["UPDATE NEWUSERDATA nu left join CURRENTUSERS cu on nu.username = cu.username inner join currentuser_accounts ua on cu.userkey=ua.userkey inner join currentaccounts a on ua.accountkey=a.accountkey set nu.customproperty13=a.customproperty2"]}
@gauravchandok now it will skip the users processed in previous import when you run this import again... right? - well yes because users that were processed don't fit in the conditions of the user query, they already have a value in customproperty13.
11/15/2023 07:05 AM
looks to be endpoint management under same SS is not happening. can you confirm the new account tasks are getting created as per Guest and regular account endpoints?
11/15/2023 07:11 AM
tasks are getting created and both call1 and call2 are success with 201, 200 code respectively.
but one endpoint task is getting completed and another's not getting completed..
11/15/2023 07:31 AM
Thanks Sampath
able to complete the requirement, below is final json
{
"accountIdPath": "${(endpoints.endpointname=='Entra Global Tenant')?'call1.message.invitedUser.id': 'call1.message.id'}",
"dateFormat": "yyyy-MM-dd'T'HH:mm:ssXXX",
"responseColsToPropsMap": {
"customproperty31": "${(endpoints.endpointname=='Entra Global Tenant')?'call1.message.inviteRedeemUrl~#~char': ''}",
"customproperty1": "${(endpoints.endpointname=='Entra Global Tenant')?'call1.message.invitedUserType~#~char': ''}",
"displayName": "${(endpoints.endpointname=='Entra Global Tenant')?'call1.message.invitedUserDisplayName~#~char': 'call1.message.displayName~#~char'}",
"name": "call2.message.userPrincipalName~#~char"
},
"call": [
{
"name": "call1",
"connection": "userAuth",
"url": "${(endpoints.endpointname=='Entra Global Tenant')?'https://graph.microsoft.com/v1.0/invitations':'https://graph.microsoft.com/v1.0/users'}",
"httpMethod": "${(user.customproperty40=='Guest')?'POST':'POST'}",
"httpParams": "${if(endpoints?.displayName?.equals('Entra Global Tenant')){return '{\"invitedUserEmailAddress\":\"' + user.email + '\",\"invitedUserDisplayName\":\"' + user.firstname+' '+user.lastname + '\", \"inviteRedirectUrl\":\"https://portal.azure.com\", \"invitedUserType\": \"Guest\", \"sendInvitationMessage\":\"true\"}';} else {return '{\"accountEnabled\": \"true\", \"displayName\": \"' + user.firstname + '\", \"mailNickname\": \"' + user.firstname + '\", \"passwordProfile\": { \"password\": \"Passw0rd\"}, \"UsageLocation\": \"US\",\"userPrincipalName\": \"' + arsTasks.accountName + '\"}';}}",
"httpHeaders": {
"Authorization": "${access_token}",
"Content-Type": "application/json"
},
"httpContentType": "application/json",
"successResponses": {
"statusCode": [
200,
201,
204,
205
]
}
},
{
"name": "call2",
"connection": "userAuth",
"url": "${(endpoints.endpointname=='Entra Global Tenant')?'https://graph.microsoft.com/v1.0/users/${response.call1.message.invitedUser.id}': 'https://graph.microsoft.com/v1.0/users/${response.call1.message.id}'}",
"httpMethod": "GET",
"httpParams": "",
"httpHeaders": {
"Authorization": "${access_token}"
},
"httpContentType": "application/json",
"successResponses": {
"statusCode": [
200,
201,
204,
205
]
}
}
]
}
,
11/15/2023 09:33 AM
Can you tell me how you are going to handle the Import Accounts operation for both endpoints which are using same security system in this case?
11/15/2023 10:16 PM
So in this SS - one EP (parent) is for guest account and other EP (child) is for non-guest admin accounts, we are using EP filter at connection and using group membership for bifurcating account between two EP.. but parent EP will contain accounts of both parent and child
11/17/2023 02:26 AM
Thanks @gauravchandok