Announcing the Saviynt Knowledge Exchange unifying the Saviynt forums, documentation, training,
and more in a single search tool across platforms. Read the announcement here.

Azure AD guest Account creation Json

sampath18
Regular Contributor II
Regular Contributor II

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

29 REPLIES 29

armaanzahir
Valued Contributor
Valued Contributor

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

Regards,
Md Armaan Zahir

sampath18
Regular Contributor II
Regular Contributor II

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')\"}'}}"

what is error now ?


Regards,
Rushikesh Vartak
If you find the response useful, kindly consider selecting Accept As Solution and clicking on the kudos button.

sampath18
Regular Contributor II
Regular Contributor II

Hi @rushikeshvartak The error remains same. Below is the error.

{\"auditDetails\":{\"call1\":[{\"message\":\"Unrecognized token '$': was expecting ('true', 'false' or 'null')

Thanks,
Sampath

sampath18
Regular Contributor II
Regular Contributor II

Hi All,

Can anyone provide sample working jsons where if else conditions are used in REST connector.

Thanks

Sampath

sampath18
Regular Contributor II
Regular Contributor II

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
]
}
}
]
}

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 ''}}

 

sampath18
Regular Contributor II
Regular Contributor II

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.

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

 

sampath18
Regular Contributor II
Regular Contributor II

can you try this and see if it is working

${if(endpoints?.displayName?.equals('Entra Tenant 1')){return ''}}

gauravchandok
New Contributor III
New Contributor III

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')

gauravchandok
New Contributor III
New Contributor III

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

sampath18
Regular Contributor II
Regular Contributor II

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

Thanks we were able to solve this issue.

 

 

 

 

sampath18
Regular Contributor II
Regular Contributor II

That is great.. what was the issue, can you highlight?

sampath18
Regular Contributor II
Regular Contributor II

Just another thing i dont find reason to have call 2 here. that seems to be  additional call to fetch user details without purpose.

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?

 

 

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. 

Hi, I am not sure if that is possible or not.. I am relatively new to saviynt..

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.

sampath18
Regular Contributor II
Regular Contributor II

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

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?

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.

sampath18
Regular Contributor II
Regular Contributor II

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?

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..

gauravchandok
New Contributor III
New Contributor III

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
        ]
      }
    }
  ]
}

,

sampath18
Regular Contributor II
Regular Contributor II

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?

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

sampath18
Regular Contributor II
Regular Contributor II

Thanks @gauravchandok