Authenticating with an External SAML Identity Provider and MFA
This use case discusses the steps to use Oracle Identity Cloud Service to authenticate using an external SAML Identity Provider (IdP) and Multi-Factor Authentication (MFA).
Note:
Use this Authenticate API only if you're building your own end-to-end login experience by developing a custom sign-in application to be used by Oracle Identity Cloud Servcice.Note:
This Authenticate API can't be used to integrate your applications with Oracle Identity Cloud Service for single sign-on purposes.Note:
See the Oracle Identity Cloud Service Authentication API Postman collection for extensive authentication use case examples. Download the collection and the global variables file from the idcs-authn-api-rest-clients folder within GitHub and then import them into your preferred REST Client.Step 1: Begin the Authentication Flow
A user opens a browser window to access a protected page.
/authorize
endpoint. This begins the authentication process. Instead of presenting the default sign-in page, Oracle Identity Cloud Service responds by creating and submitting an HTML form that contains the
loginCtx
and
signature
parameters to the browser.
Note:
You must expose an endpoint to receive the form post and read the two parameter values.Example HTML Form POST
The following is an example HTML Form POST that Oracle Identity Cloud Service returns to invoke the custom sign-in page:
<form name="autosubmit" id="autosubmit" action="<custom_ui_signin_URL>" method="POST" onload="submitform();">
<input name="loginCtx" value="<obfuscated_loginctx_value>" />
<input name="signature" value="signature_data" />
</form>
loginCtx
parameter is based64 encrypted, the custom sign-in app must decrypt the
loginCtx
by doing the following:
- Decode using a base64 decorder to get the encrypted binary data
- Use the tenant name and generate a key for decryption
- Decrypt the data using the key and binary data
Example Decryption Logic for Encrypted loginCtx in Java
The following is example decryption logic:
public static String decrypt(String tenantName, String attrName, String attrDecryptValue)
{
String attrDecrypt = attrDecryptValue;
final String SHA_256_ALG = "SHA-256";
final String ENCRYPTION_ALG = "AES/CBC/PKCS5Padding";
final String SECRET_KEY_ALG = "AES";
String data = null;
MessageDigest md = null;
byte[] keyBytes = new byte[16];
try {
md = MessageDigest.getInstance(SHA_256_ALG);
byte[] digest = md.digest(tenantName.toLowerCase().getBytes("UTF-8"));
System.arraycopy(digest, 0, keyBytes, 0, 16);
} catch (Exception ex)
{
ex.printStackTrace();
}
// encrypt the data
Cipher decipher = null;
try {
decipher = Cipher.getInstance(ENCRYPTION_ALG);
SecretKey secretKey = new SecretKeySpec(keyBytes, SECRET_KEY_ALG);
decipher.init(Cipher.DECRYPT_MODE,
secretKey, new IvParameterSpec(new byte[16]));
byte[] decryptedData = decipher.doFinal(Base64.getDecoder().decode(attrDecrypt.getBytes("UTF-8")));
data = new String(decryptedData);
System.out.println("" + data); }
catch (Exception ex)
{
ex.printStackTrace();
}
return data;
}
Response Example
The response should be similar to the following example:
{
"requestState": "TasNtIxDqWOfDKeTM",
"nextOp": [
"credSubmit",
"chooseIDP"
],
"nextAuthFactors": [
"IDP",
"USERNAME_PASSWORD"
],
"status": "success",
"ecId": "GmY95180000000000",
"USERNAME_PASSWORD": {
"credentials": [
"username",
"password"
]
},
"IDP": {
"configuredIDPs": [
{
"iconUrl": "null",
"idpName": "adc00peq",
"idpType": "Saml"
},
{
"idpId": "4bb89888feea4b00a0fab3a1a5627539",
"idpName": "Google",
"idpType": "Social"
}
],
"credentials": [
"idpId",
"idpType"
]
}
}
loginCtx
parameter contains some important attributes:
- requestState: The state of the authentication process. It needs to be used in future POSTs and GETs to Oracle Identity Cloud Service's Authentication API endpoints.
- nextOp: The next operation the custom sign-in application must perform.
- nextAuthFactors: The possible authentication factors the sign-in page must present.
The values of these attributes define which authentication factor, identity providers, and social providers are presented on the sign-in page. The sign-in page appears containing the decrypted values of the loginCtx
parameter along with the access token. The sign-in page includes JavaScript that is used to perform AJAX calls to Oracle Identity Cloud Service.
Step 2: Select an External Identity Provider
/sso/v1/sdk/idp
endpoint. For this step, the following attributes must be included:
requestState:
received in the Step 1 responseidpName:
name of the IdP received in the Step 1 responseidpType:
type of IdP received in the Step 1 response (in this example, it is SAML)idpId:
id of the IdP received in the Step 1 responseappName:
name of the app that the client wants access toclientID:
client ID of the application the browser is attempting to accessauthorization:
parameter required for secure Idp
Example HTML Form POST Code to Select an External IdP
var addParamValues = function(myform, value, paramName) {
if (value !== null && value !== 'undefined') {
param = document.createElement("input");
param.value = value;
param.name = paramName;
myform.appendChild(param);
}
};
var chooseRemoteIDP = function(name, idpId, type) {
var myform = document.createElement("form");
myform.action = GlobalConfig.idcsBaseURL + "/sso/v1/sdk/secure/idp";
myform.method = "post";
<%
Credentials creds = CredentialsList.getCredentials().get(attr);
String clientId = creds.getId();
%>
var clientId = '<%=clientId%>';
addParamValues(myform, name, "idpName");
addParamValues(myform, type, "idpType");
addParamValues(myform, idpId, "idpId");
addParamValues(myform, clientId, "clientId");
addParamValues(myform, authorization, "accesstoken")
addParamValues(myform, GlobalConfig.requestState, "requestState");
document.body.appendChild(myform);
myform.submit();
};
var activateIdp = function(name, idpId) {
chooseRemoteIDP(name, idpId, "SAML");
};
var activateSocialIdp = function(name, idpId) {
chooseRemoteIDP(name, idpId, "SOCIAL");
};
Request Example
The following is an example of the contents of the FORM POST to the /sso/v1/sdk/secure/idp
endpoint:
requestState=value&idpName=value&idpType=SAML&idpId=value&appName=name&clientID=value&authorization=accesstoken
Response Example
The following example shows the contents of the response in standard HTTP format:
HTTP/1.1 302 See Other
Date: Tue, 30 Oct 2018 04:40:05 GMT
Content-Length: 0
Connection: keep-alive
Pragma: no-cache
Location: https://tenant-base-url/idp/sso (Example URL)
Set-cookie: ORA_OCIS_REQ_1=+fxgW2P7bgQayiki5P;Version=1;Path=/;Secure;HttpOnly
Expires: Sat, 01 Jan 2000 00:00:00 GMT
X-xss-protection: 1; mode=block
X-content-type-options: nosniff
Oracle Identity Cloud Service processes the request and redirects the browser to the selected external IdP for authentication and authorization. When the external IdP is finished, it redirects the browser to Oracle Identity Cloud Service, which then redirects the browser to begin 2-Step Verification.
Step 3: Authenticate Using the Preferred Factor (SMS)
The initial steps to begin 2-Step Verification are similar to Step 1. Oracle Identity Cloud service creates and submits an HTML form that contains the encrypted loginCtx
and signature
parameters. See Step 1 for detailed information on the form POST and how to decrypt.
After the loginCtx
parameter is decrypted, the response should be similar to the following example:
{
"status": "success",
"displayName": "Joe's iPhone",
"nextAuthFactors": [
"SMS"
],
"SMS": {
"credentials": [
"otpCode"
]
},
"nextOp": [
"credSubmit",
"getBackupFactors",
"resendCode"
],
"requestState": "QjyV3ueFrGQCO.....84gQw2UUm2V7s",
"trustedDeviceSettings": {
"trustDurationInDays": 15
}
}
loginCtx
parameter contains some important attributes:
- requestState: The state of the authentication process. It needs to be used in future POSTs and GETs to Oracle Identity Cloud Service's Authentication API endpoints.
- nextOp: The next operation the custom sign-in application must perform.
- nextAuthFactors: The possible authentication factors the sign-in page must present.
The values of these attributes define which authentication factor (in this example it is SMS) to present on the sign-in page. The user enters the one-time passcode that they receive on their device.
op:
tells the server what kind of operation the client wantsotpCode:
the code sent to the user's devicerequestState:
received in the Step 2 response
Request Example
The following example shows the contents of the POST request in JSON format to complete authentication using the preferred method:
{
"op":"credSubmit",
"credentials":{
"otpCode":"108685"
},
"requestState":"{{requestState}}"
}
Response Example
The following example shows the contents of the response in JSON format:
{
"authnToken": "eyJraWQiOiJT.....kLbxxL97U_0Q",
"status": "success"
}
A session must then be created. After the session is created, the browser is redirected to the originally requested URL. See Creating a Session.