On Demand Challenges
Centrify provides the ability to define challenge policies which can be used to perform one or more challenges at arbitrary points in your application's code. For example, your application could require challenge policies to be fulfilled every 10 minutes during a session, or after a certain timeout period. In the case of OAuth, it could be used to provide multi-factor authentication (MFA) on behalf of a designated user (e.g. so OAuth clients can provide MFA).
This is accomplished using the /security/OnDemandChallenge endpoint in conjunction with the other APIs described on this page. /security/OnDemandChallenge
provides this capability by calling a policy modifier that holds its own authentication profile.
An on-demand challenge must be invoked by a scoped administrative Centrify user account and takes in the username of the Centrify user to challenge. In other words, the on-demand challenge can't be done in the context of an end user, but rather by an administrative user invoking it for an end user (e.g. a service account or OAuth Client Credentials service/scoped token).
Note: for OAuth, an on-demand challenge only works with the Client Credentials Flow.
This page contains two main sections describing the API flows for obtaining and using on-demand challenges:
Before continuing, ensure you are familiar with:
Creating a Challenge Policy
This section shows the API workflow for obtaining a challenge policy. Once complete, the challenges of the policy can then be used for on-demand challenges.
Step 1. Get the Roles
The first step is to get all roles by invoking the /RedRock/Query endpoint as shown here:
POST /RedRock/query
{
"Script":"Select *, COALESCE(Name, ID) AS DisplayName from Role ORDER BY DisplayName COLLATE NOCASE",
"Args":{
"PageNumber":1,
"PageSize":100000,
"Limit":100000,
"SortBy":"",
"direction":"False",
"Caching":-1
}
}
The Results
array contains information about each policy:
{
"success":true,
"Result":{
"IsAggregate":false,
"Count":57,
"Columns":[
{
"Name":"Description",
"IsHidden":false,
"DDName":"Description",
"Title":"Description",
"DDTitle":"Description",
"Description":null,
"Type":12,
"Format":null,
"Width":0,
"TableKey":"NotAKey",
"ForeignKey":null,
"TableName":"Role"
},
...
],
"FullCount":57,
"Results":[
{
"Entities":[
{
"Type":"Role",
"Key":"12332112_cea1_4fb6_80d7_de847c152d82",
"IsForeignKey":false
}
],
"Row":{
"ReadOnly":false,
"Description":null,
"DisplayName":"App Gateway Devs",
"DirectoryServiceUuid":"ABC12345-6CE8-465F-AB03-65766D33B05E",
"RoleType":"PrincipalList",
"_MatchFilter":null,
"Name":"App Gateway Devs",
"ID":"18240b41_cea1_4fb6_80d7_de847c152d82"
}
},
...
],
"ReturnID":""
},
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
Step 2. Determine if Cloud Mobile GP is being used.
The next step is determine if cloud mobile GP is enabled by invoking the /policy/GetUsingCloudMobileGP:
POST /policy/GetUsingCloudMobileGP
The useCloudGP
field indicates whether cloud GP is enabled:
{
"success":true,
"Result":{
"useCloudGP":true,
"useCloudCA":false,
"refreshInterval":15,
"gpUpdateInterval":300,
"activeDirectoryCA":"CA-CA1.centrify.com\\GLOBAL-CA2",
"cloudOuManagement":true,
"hasProxy":true,
"boundMobileForest":"centrify.com",
"hideMobilePolicyForAD":true
},
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
Step 3. Get the Plinks
Get information about each policy by invoking the /policy/getniceplinks endpoint:
POST /policy/getniceplinks
{
"Args":{
"PageNumber":1,
"PageSize":100000,
"Limit":100000,
"SortBy":"",
"direction":"False",
"Caching":-1
}
}
The Results
array contains information about each policy:
{
"success":true,
"Result":{
"Columns":[
{
"Name":"Params",
"IsHidden":false,
"DDName":null,
"Title":"Params",
"DDTitle":null,
"Description":null,
"Type":16,
"Format":null,
"Width":0,
"TableKey":null,
"ForeignKey":null,
"TableName":null
},
...
],
"RevStamp":"636537274890000000",
"Count":28,
"Results":[
{
"Entities":[
{
"Type":"PolicyLink",
"Key":"/Policy/Default Policy",
"IsForeignKey":false
}
],
"Row":{
"Params":[
],
"ID":"/Policy/Default Policy",
"EnableCompliant":true,
"I18NDescriptionTag":"_I18N_DefaultGlobalPolicyDescriptionTag",
"Description":"DO NOT DISABLE Login MFA IN THIS POLICY for unknown devices.",
"LinkType":"Global",
"PolicySet":"/Policy/Default Policy"
}
},
...
],
"FullCount":28,
"ReturnID":"",
"IsAggregate":false
},
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
Step 4. Get the Policy Block
Using the policies returned in the previous response, determine the policy that you want to add a challenge policy to, and then invoke the /Policy/getpolicyblock endpoint, passing the ID via the name
field in the body:
POST /policy/getpolicyblock
{
"name":"/Policy/Default Policy"
}
The response contains information about the policy:
{
"success":true,
"Result":{
"Description":"DO NOT DISABLE Login MFA IN THIS POLICY for unknown devices.",
"PolicyModifiers":[
],
"Settings":{
"/Mobile/Software/Policies/Centrify/Common/AllowNotificationOnMutipleDevices":true,
"/Core/Authentication/IwaSatisfiesAllMechs":false,
"/Core/Authentication/SecurityQuestionAnswerMinLength":3,
"/Core/Authentication/IwaSetKnownEndpoint":true,
"/Core/MfaRestrictions/BlockMobileMechsOnMobileLogin":false,
"/Core/PasswordReset/AccountUnlockAuthProfile":"e4eeeeee-2e9e-4567-b9e2-a568360c8eb7",
"/Core/Authentication/ZsoSatisfiesAllMechs":false,
"/Core/Authentication/AdminSecurityQuestionsPerUser":0,
"/Core/Security/CDS/ExternalMFA/ShowQRCodeForSelfService":true,
"/Core/Authentication/ChallengeDefinitionId":"0d799995-ca79-43df-9355-fdf12394965b",
"/Core/Authentication/ZsoSetKnownEndpoint":true,
"PasswordResetEnabled":true,
"/Mobile/Software/Policies/Centrify/Common/Restrictions/TrackLocationHistory":true,
"/Core/PasswordReset/Max":10,
"/Core/PasswordReset/PasswordResetADEnabled":true,
"/Mobile/EnrollRules/Common/AllowJailBrokenDevices":true,
"/Core/PasswordReset/PasswordResetIdentityCookieOnly":false,
"/Core/Security/CDS/LockoutPolicy/Threshold":5,
"/Core/PasswordReset/UseADAdmin":false,
"AuthenticationEnabled":true,
"/Core/PasswordReset/MaxTime":60,
"/Core/PasswordReset/PasswordResetEnabled":true,
"/Mobile/DeviceManagement/UseCentrifyAsMdm":false,
"/Core/Security/CDS/ExternalMFA/UiPrompt":"OATH OTP Client",
"/Core/Authentication/AuthenticationRules":{
"_UniqueKey":"Condition",
"_Value":[
{
"Conditions":[
{
"Prop":"IdentityCookie",
"Op":"OpExists"
}
],
"ProfileId":"44bd658e-defc-4d69-b6de-3dc0d6812f9b"
}
],
"Enabled":true,
"_Type":"RowSet"
},
"/Core/Security/CDS/ExternalMFA/ShowQRCode":true,
"/Core/Authentication/AuthenticationRulesDefaultProfileId":"cfefffff-9bf7-4569-895d-9dfbb3a9e8d7",
"/Core/PasswordReset/PasswordResetAuthProfile":"a7dddddd-fe4e-4f37-a885-2176beb4a501",
"/Mobile/EnrollRules/Common/AllowEnrollment":true,
"/Core/Authentication/ConfigureSecurityQuestions":true,
"/Core/PasswordReset/AccountUnlockADEnabled":false,
"/Core/Authentication/UserSecurityQuestionsPerUser":1,
"/Core/Authentication/CookieAllowPersist":false,
"/Core/PasswordReset/AccountUnlockEnabled":true,
"/Core/Authentication/AuthenticationRulesHighAuthRequestedProfileId":"12222222-9aad-4e49-8e23-1e4561d9b7c3",
"/Core/PasswordReset/AccountUnlockIdentityCookieOnly":false,
"/Core/Authentication/NoMfaMechLogin":false,
"/Core/Authentication/AllowIwa":true,
"/Core/Authentication/AllowZso":true
},
"Path":"/Policy/Default Policy",
"RiskAnalysisLevels":{
"Levels":[
{
"Name":"Normal",
"TranslatedName":"None Detected"
},
{
"Name":"Low",
"TranslatedName":"Low"
},
{
"Name":"Med",
"TranslatedName":"Medium"
},
{
"Name":"High",
"TranslatedName":"High"
},
{
"Name":"Unknown",
"TranslatedName":"Undetermined"
}
]
},
"AuthProfiles":[
{
"Uuid":"12222222-9aad-4e49-8e23-1e4561d9b7c3",
"Name":"Default New Device Login Profile",
"DurationInMinutes":720,
"Challenges":[
"UP"
],
"AdditionalData":{
}
},
{
"Uuid":"a7dddddd-fe4e-4f37-a885-2176beb4a501",
"Name":"Default Password Reset Profile",
"DurationInMinutes":720,
"Challenges":[
"OTP,SMS,EMAIL,OATH"
],
"AdditionalData":{
}
},
...
],
"RevStamp":"636486318310000000",
"Version":6
},
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
Step 5. Add the Challenge Policy
Add a challenge policy by invoking the /Policy/AddAuthPolicyModifier endpoint, setting the PolicyModifier
body parameter to the name of the new challenge policy:
POST /Policy/AddAuthPolicyModifier
{
"PolicyModifier":"test1"
}
The success
field in the response indicates if the request was successful:
{
"success":true,
"Result":null,
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
Step 6. Save the Policy Block
Save the policy block by invoking the /policy/savepolicyblock3 endpoint and passing the information returned in the response to the /policy/getpolicyblock
above:
POST /policy/savepolicyblock3
{
"policy":{
"Description":"DO NOT DISABLE Login MFA IN THIS POLICY for unknown devices.",
"PolicyModifiers":[
],
"Settings":{
"/Mobile/Software/Policies/Centrify/Common/AllowNotificationOnMutipleDevices":true,
"/Core/Authentication/IwaSatisfiesAllMechs":false,
"/Core/Authentication/SecurityQuestionAnswerMinLength":3,
"/Core/Authentication/IwaSetKnownEndpoint":true,
"/Core/MfaRestrictions/BlockMobileMechsOnMobileLogin":false,
"/Core/PasswordReset/AccountUnlockAuthProfile":"e4eeeeee-2e9e-4567-b9e2-a568360c8eb7",
"/Core/Authentication/ZsoSatisfiesAllMechs":false,
"/Core/Authentication/AdminSecurityQuestionsPerUser":0,
"/Core/Security/CDS/ExternalMFA/ShowQRCodeForSelfService":true,
"/Core/Authentication/ChallengeDefinitionId":"0d799995-ca79-43df-9355-fdf12394965b",
"/Core/Authentication/ZsoSetKnownEndpoint":true,
"PasswordResetEnabled":true,
"/Mobile/Software/Policies/Centrify/Common/Restrictions/TrackLocationHistory":true,
"/Core/PasswordReset/Max":10,
"/Core/PasswordReset/PasswordResetADEnabled":true,
"/Mobile/EnrollRules/Common/AllowJailBrokenDevices":true,
"/Core/PasswordReset/PasswordResetIdentityCookieOnly":false,
"/Core/Security/CDS/LockoutPolicy/Threshold":5,
"/Core/PasswordReset/UseADAdmin":false,
"AuthenticationEnabled":true,
"/Core/PasswordReset/MaxTime":60,
"/Core/PasswordReset/PasswordResetEnabled":true,
"/Mobile/DeviceManagement/UseCentrifyAsMdm":false,
"/Core/Security/CDS/ExternalMFA/UiPrompt":"OATH OTP Client",
"/Core/Authentication/AuthenticationRules":{
"_UniqueKey":"Condition",
"_Value":[
{
"Conditions":[
{
"Prop":"IdentityCookie",
"Op":"OpExists"
}
],
"ProfileId":"44bd658e-defc-4d69-b6de-3dc0d6812f9b"
}
],
"Enabled":true,
"_Type":"RowSet"
},
"/Core/Security/CDS/ExternalMFA/ShowQRCode":true,
"/Core/Authentication/AuthenticationRulesDefaultProfileId":"cfea9de5-9bf7-4569-895d-9dfbb3a9e8d7",
"/Core/PasswordReset/PasswordResetAuthProfile":"a7dddddd-fe4e-4f37-a885-2176beb4a501",
"/Mobile/EnrollRules/Common/AllowEnrollment":true,
"/Core/Authentication/ConfigureSecurityQuestions":true,
"/Core/PasswordReset/AccountUnlockADEnabled":false,
"/Core/Authentication/UserSecurityQuestionsPerUser":1,
"/Core/Authentication/CookieAllowPersist":false,
"/Core/PasswordReset/AccountUnlockEnabled":true,
"/Core/Authentication/AuthenticationRulesHighAuthRequestedProfileId":"12222222-9aad-4e49-8e23-1e4561d9b7c3",
"/Core/PasswordReset/AccountUnlockIdentityCookieOnly":false,
"/Core/Authentication/NoMfaMechLogin":false,
"/Core/Authentication/AllowIwa":true,
"/Core/Authentication/AllowZso":true,
"/Core/test1/AuthenticationEnabled":true,
"/Core/test1/Authentication/AuthenticationRules":{
"_Type":"RowSet",
"Enabled":true,
"_UniqueKey":"Condition",
"_Value":[
{
"Conditions":[
{
"Prop":"DateRange",
"Op":"OpBetween",
"Val":"L,02/23/2018,02/28/2018"
}
],
"ProfileId":"cfea9de5-9bf7-4569-895d-9dfbb3a9e8d7"
}
]
},
"/Core/test1/Authentication/AuthenticationRulesDefaultProfileId":"cfefffff-9bf7-4569-895d-9dfbb3a9e8d7",
"/Core/test1/Authentication/NoMfaMechLogin":false
},
"Path":"/Policy/Default Policy",
"RiskAnalysisLevels":{
"Levels":[
{
"Name":"Normal",
"TranslatedName":"None Detected"
},
{
"Name":"Low",
"TranslatedName":"Low"
},
{
"Name":"Med",
"TranslatedName":"Medium"
},
{
"Name":"High",
"TranslatedName":"High"
},
{
"Name":"Unknown",
"TranslatedName":"Undetermined"
}
]
},
"AuthProfiles":[
{
"Uuid":"122f46ae-9aad-4e49-8e23-1e4561d9b7c3",
"Name":"Default New Device Login Profile",
"DurationInMinutes":720,
"Challenges":[
"UP"
],
"AdditionalData":{
}
},
...
],
"RevStamp":"636486318310000000",
"Version":6,
"Newpolicy":false
},
"plinks":[
{
"Params":[
"Device|@Active Devices"
],
"ID":"/Policy/louie1",
"EnableCompliant":true,
"Description":"",
"LinkType":"Collection",
"PolicySet":"/Policy/louie1"
},
{
"Params":[
"52577777_7f2f_4654_97f5_3123dfc5d5c7"
],
"ID":"/Policy/RichPolicy",
"EnableCompliant":true,
"Description":"",
"LinkType":"Role",
"PolicySet":"/Policy/RichPolicy"
},
{
"Params":[
"8a666666_ec81_4f52_86b7_9377d49c217b"
],
"ID":"/Policy/U2F Login Policy",
"EnableCompliant":true,
"Description":"",
"LinkType":"Role",
"PolicySet":"/Policy/U2F Login Policy"
},
...
]
}
The success
field in the response indicates if the request was successful and the RevStamp
field indicates the revision of the new policy block that was created:
{
"success":true,
"Result":{
"RevStamp":"636549980660000000"
},
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
Using the Challenges
This section shows an API flow in which regular authentication takes place followed by the on-demand challenges acquired from the steps above in Creating a Challenge Policy.
Step 1. Start the Authentication
Start the normal authentication process by invoking the /security/startauthentication endpoint:
POST /security/startauthentication
{
"User": "[email protected]",
"Version": "1.0"
}
The response contains authentication challenges:
{
"success":true,
"Result":{
"ClientHints":{
"PersistDefault":false,
"AllowPersist":false,
"AllowForgotPassword":true
},
"Version":"1.0",
"SessionId":"N_XRw-zRM0GUZOA8vdOnWnT...",
"Challenges":[
{
"Mechanisms":[
{
"AnswerType":"Text",
"Name":"UP",
"PromptMechChosen":"Enter Password",
"PromptSelectMech":"Password",
"MechanismId":"nOt4E8G9rUybPu_ph4t..."
}
]
}
],
"Summary":"NewPackage",
"TenantId":"AAA1234"
},
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
Step 2. Advance the Authentication
Invoke the /security/advanceauthentication endpoint for each challenge. In this example a password is being provided for a password challenge:
POST /security/advanceauthentication
{
"MechanismId": "nOt4E8G9rUybPu_ph4tTG-0P...",
"Answer": "abcd1234",
"SessionId": "N_XRw-zRM0GUZOA8vdOnW...",
"TenantId": "AAA1234",
"PersistentLogin": false,
"Action": "Answer"
}
The success
field in the response indicates if the request was successful:
{
"success":true,
"Result":{
"SystemID":"AAA1234",
"DisplayName":"J N",
"EmailAddress":"[email protected]",
"CustomerID":"AAA1234",
"AuthLevel":"Normal",
"PodFqdn":"corp.my-dev.centrify.com",
"Auth":"F67AFC...",
"User":"[email protected]",
"UserDirectory":"AdProxy",
"Summary":"LoginSuccess",
"UserId":"128cadec-b5f5-4995-a5...",
"SourceDsType":"AdProxy"
},
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
Step 3. Start the Application
Invoke the endpoint corresponding to your application. Construct the endpoint URL by concatenating /token/ and the name of your application, and then pass the application-specific parameters as a text string in the body:
POST /oauth2/token/_genericmfa
scope=GenericMFA&grant_type=client_credentials
The response contains application-specific information. In the example below, the access_token
field contains a new access token to use in the next request:
{
"access_token":"eyJhb...",
"token_type":"Bearer",
"expires_in":31536000,
"scope":"GenericMFA"
}
Step 4. Specify the Challenge Policy
Invoke the /security/OnDemandChallenge endpoint specifying the name of the user to authenticate on behalf of in the User
field, and the name of the challenge policy in the PolicyModifier
field:
POST /security/OnDemandChallenge
{
"User": "[email protected]",
"arguments": null,
"PolicyModifier": "test1"
}
The response contains the set of challenges associated with that challenge policy. In the example below, there are two challenges: a password challenge and an Oob verification code challenge which can be sent either by email or SMS:
{
"success":true,
"Result":{
"ClientHints":{
"PersistDefault":false,
"AllowPersist":false,
"AllowForgotPassword":true
},
"Version":"1.0",
"SessionId":"-AW5S9HtHGv...",
"Challenges":[
{
"Mechanisms":[
{
"AnswerType":"Text",
"Name":"UP",
"PromptMechChosen":"Enter Password",
"PromptSelectMech":"Password",
"MechanismId":"UFx-ivi..."
}
]
},
{
"Mechanisms":[
{
"AnswerType":"StartTextOob",
"Name":"EMAIL",
"PromptMechChosen":"Click the link in the email sent to [email protected]",
"PromptSelectMech":"Email... @centrify.com",
"PartialAddress":"centrify.com",
"MechanismId":"UuWMQ3CAoU..."
},
{
"AnswerType":"StartTextOob",
"Name":"SMS",
"PartialDeviceAddress":"4660",
"PromptMechChosen":"Sending a text to mobile phone ending... 4660. Enter the code or click the link in the message to proceed with authentication.",
"PromptSelectMech":"SMS... XXX-1234",
"MechanismId":"oTE_Oxjdqk..."
}
]
}
],
"Summary":"NewPackage",
"TenantId":"AAA1234"
},
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
Step 5. Advance the Authentication on Behalf of the User
Invoke the /security/advanceauthentication
endpoint for each of the challenges returned from the /security/OnDemandChallenge
endpoint.
The following example provides the password for the first challenge:
POST /security/advanceauthentication
{
"MechanismId": "UFx-iviXi_EoET50...",
"Answer": "123abcd",
"SessionId": "-AW5S9HtHGv5NK...",
"TenantId": "AAA1234",
"PersistentLogin": false,
"Action": "Answer"
}
The Summary
field in the response indicates that the next challenge is to be started:
{
"success":true,
"Result":{
"Summary":"StartNextChallenge"
},
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
The next example starts the Oob challenge to send a verification code to the user's device via SMS:
POST /security/advanceauthentication
{
"TenantId": "AAA1234",
"MechanismId": "oTE_OxjdqkGR...",
"PersistentLogin": false,
"Action": "StartOOB",
"SessionId": "-AW5S9HtHGv5NKIfG..."
}
The Summary
field in the response indicates that the Oob verification code has been sent and that Centrify is waiting for the user to provide that code:
{
"success":true,
"Result":{
"Summary":"OobPending"
},
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
In the final example below, the code is sent to Centrify via the Answer
field:
POST /security/advanceauthentication
{
"MechanismId": "oTE_OxjdqkGRzbQPdIPvG4A...",
"Action": "Answer",
"SessionId": "-AW5S9HtHGv5NKIfGA3...",
"Answer": "123456789",
"TenantId": "AAA1234",
"PersistentLogin": false
}
The success
field in the response indicates that the challenge was successfully fulfilled:
{
"success":true,
"Result":{
"SystemID":"AAA1234",
"DisplayName":"J N",
"EmailAddress":"[email protected]",
"CustomerID":"AAA1234",
"AuthLevel":"High",
"PodFqdn":"corp.my-dev.centrify.com",
"User":"[email protected]",
"UserDirectory":"AdProxy",
"Summary":"LoginSuccess",
"UserId":"128cadec-b5f5-49...7",
"SourceDsType":"AdProxy"
},
"Message":null,
"MessageID":null,
"Exception":null,
"ErrorID":null,
"ErrorCode":null,
"InnerExceptions":null
}
The client has now successfully logged the user in using MFA from a challenge policy.
Try the API in Postman:
.
Click here for help with using our sample Postman collection.
Updated about 5 years ago