Sie sind auf Seite 1von 5

The dissected Node Js application flow can be followed as below.

The application
can be download at https://github.com/oracle/idm-samples. From the master, select
“idcs-authn-api-signin-app”.

Step 1 – The user tries to access an IDCS protected resource/SAML Integrated


application SP URL

Step 2 – Since IDCS is the IDP, the users are routed to IDCS for authentication. As
the custom login page is setup as the authentication page(http://localhost:3000 for
example), the user is redirected to http://localhost:3000/index.html

Step 3 – The code that traps this request should be able to look for
the loginCtx and Signature in the header and should be able to decrypt it. Once the
body has been decrypted, it needs to be redirected to the page/code that will handle
the authentication request

router.post("/", function (req, res, next) {


// take loginCtx from the the POST data and decode it
logger.log("POST received.")

logger.log("POST body:\n" + JSON.stringify(req.body,null,2));

// in 18.3.+ /social/callback sends us back here


// social user is in IDCS and no MFA
if (req.body.authnToken) {
redirectBrowser( req, res, "../../signin.html", {
"IDPAuthnToken": req.body.authnToken
});

Once the body is decrypted and the control routed to the page signin.html, for the
custom authentication piece to work successfully, the sign in application needs to
know the initial state of IDCS. This initial state is the decrypted body(loginContext)
from the request in above code.

In our case, the initial state would be a successful oauth token generation from the
client id and secret. The application will look for an attribute “requeststate” from the
json object and verify whether the attribute status is “success”

{
this.app.logMsg('[IdcsAuthnSDK] Initializing authentication with
existing initial state from IDCS.');
var initialData = JSON.parse( this.app.getInitialState() );
this.app.logMsg('[IdcsAuthnSDK] InitialData:
' + this.app.getInitialState());

if (initialData.status === 'success') {


this.app.setRequestState(initialData.requestState);
this.app.logMsg('[IdcsAuthnSDK] status==success');
this.app.logMsg(initialData.requestState);
this.app.logMsg(initialData.nextOp);
this.app.logMsg(initialData.nextAuthFactors);
if ((initialData.requestState) &&
(initialData.nextOp.indexOf('credSubmit') >= 0) &&
(initialData.nextAuthFactors.indexOf('USERNAME_PASSWORD')
>= 0)) {
this.app.logMsg('[IdcsAuthnSDK] Displaying signin form');
this.app.displayForm("USERNAME_PASSWORD","submitCreds",initial
Data.IDP);
//inject error coming back from social/callback endpoint if
IDCS is not able to match
//external user to locally deactivated user.... plus other
errors like eg if user cancels
//external idp authentication... etc... this error is relayed
to this page via /v1/error endpoint
//which injects it into sessionStorage...
if (error != null){
this.app.setLoginErrorMessage(JSON.parse(error));
}
}

Step 4: If the status is “success” then the next step is to formulate the payload for
the /sso/v1/sdk/authenticate API. This API requires a bearer token obtained from the
steps above, the username and password entered in the login form provided at
signin.html. Once the user enters the username and password, the application
captures the input.

Step 5: As per the regulations used for XMLHttpRequest object, the first step is to
get the options allowed for /sso/v1/sdk/authenticate API. Once it receives the
options, it selects the option with “Username” and “Password” and attaches a bearer
token to the API request

xhr.open("POST", app.baseUri + "/sso/v1/sdk/authenticate");


xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Authorization", "Bearer
" + this.app.getAccessToken());

// xhr.setRequestHeader("Cookie","Testing=Testing");
console.log('This is where the authentication request is sent
idcsAuthnSDK.js');
//xhr.withCredentials=true;
xhr.send(data);
}
catch(e) { //this should never happen
self.app.logMsg(e);
self.app.setLoginErrorMessage(self.sdkErrors.error9999);
}
Payload data looks like below:

LoginApp: [IdcsAuthnSDK] Authenticating with:


{"op":"credSubmit","authFactor":"USERNAME_PASSWORD","credentials":{"userna
me":"***","password":"***"},"requestState":"***"}

Step 6: If the authentication is successful, the API returns the control back to the
application with a 200 OK status and a response header as Authentication Token. At
this point the user is authenticated successfully. Now, the next step is to create an
IDCS session for the user who was able to authenticate successfully using the
Authentication Token received.

xhr.addEventListener("readystatechange", function () {
if (this.readyState === 4) {
console.log("The response received is " + this.responseText);
self.app.logMsg ('Authenticate response:
' + self.app.mask(this.responseText));
const jsonResponse = JSON.parse(this.responseText);

if (jsonResponse.status === 'success') {


if (jsonResponse.authnToken) { // User is successfully
authenticated!
self.app.logMsg('[IdcsAuthnSDK] Credentials successfully
validated.');
document.cookie = "user_authenticated=true;secure";
self.createSession(jsonResponse);
}

this.createSession = function(payload) {

var addParam = function(myform, paramName, paramValue) {


param = document.createElement("input");
param.value = paramValue;
param.name = paramName;
console.log(param.value + ' ' + param.name);
param.hidden=true;
myform.appendChild(param);
};

this.app.logMsg('[IdcsAuthnSDK] Creating session with


authnToken:' + this.app.mask(payload) + ' ' + payload);
console.log('Creating Session');

var myform = document.createElement("form");


myform.method = "POST";
myform.action = app.baseUri + "/sso/v1/sdk/session";
myform.target = "_top";
addParam(myform, "authnToken", payload.authnToken);
if (payload.trustToken) {
this.app.logMsg('[IdcsAuthnSDK] trustToken added.');
addParam(myform, "trustToken", payload.trustToken);
}
document.body.appendChild(myform);
console.log(myform.action);
//adding this to flush session after successful login...
sessionStorage.clear();
myform.submit();

This is done by a dynamic form submission for the API "/sso/v1/sdk/session”. The
response is a 302 redirect to the Redirect URL of the Application after which the user
is presented with the application’s redirect url setup in the configuration.

This ends a successful authentication.

Simple explanation of this flow is attached:

The basic username/password Authentication API log in flow consists of the


following REST calls:
1. Instead of presenting the default sign-in page, Oracle Identity Cloud Service
responds to the authorization code URL request with an HTML code that
contains hidden HTML form with two parameters: signature and loginCtx.
2. The browser receives the HTML code, which contains JavaScript to
automatically submits the form to the sample sign-in application.
3. The sample sign-in application decrypts the loginCtx parameter. This
parameter contains some important attributes:
o requestState: Defines 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.
o nextOp: Defines the next operation the custom sign-in application
must perform.
o nextAuthFactors: Lists the possible authentication factors the sign-in
page must present.
The values of these attributes decides which authentication factor, identity providers,
and social providers must be presented on the page.
4. The browser displays the sign-in page and presents the authentication
factors. The sign-in page includes JavaScript code that is used to perform
AJAX calls to Oracle Identity Cloud Service.
5. After the user enters the USERNAME and PASSWORD, and clicks SIGN
IN, the browser sends a POST request to
the/sso/v1/sdk/authenticate endpoint with the following payload:
o requestState: The value received in a previous response.
o op: The operation being executed. In this example, credSubmit.
o authFactor: The authentication factor being used. In this
example, USERNAME_PASSWORD.
o The user credentials. In this example, as value for
the username and password parameters.
The access token that was retrieved at the application's startup is sent as a Bearer
Authorization header.
Note: Before posting the data to Oracle Identity Cloud Service via AJAX, the browser
sends an OPTIONS request to the/sso/v1/sdk/authenticate endpoint to verify if the
browser is authorized to post data to Oracle Identity Cloud Service.
6. The application receives a status code of 200 and an authnToken from the
previous post.
7. The application then sends a POST request to
the /sso/v1/sdk/session endpoint to create the user session in Oracle
Identity Cloud Service.
8. The application receives a 302 or 303 status code and a Location response
header that contains the callback URL with a valid authorization code.
9. The browser then redirects to the specified location, so that the application
can finish its authentication process with Oracle Identity Cloud Service.
By this time, the OpenID Connect flow is finished, and the application can
exchange the authorization code for an ID token.