IBM Verify

 View Only

SCIM Password Update using Infomap

By KERRY GUNN posted Tue December 19, 2023 08:40 PM

  

This article describes an IBM Security Verify Access (ISVA) configuration whereby an end user can change their own password:

  1. Using an infomap authentication policy to make the SCIM calls.
  2. Without needing to enable BA authentication on the reverse proxy instance.
  3. Using the HttpClientV2 cookie support added in ISVA 10.0.7.0.
  4. While the scenario does not include a 2nd phase authorization step this could be added as part of the created authentication policy. For example MAC OTP, MMFA, etc.


The scenario has been tested using ISVA 10.0.7.0.

Note: The steps documented here assume a clean install of ISVA with:

  • IBM Security Verify Access Base Appliance activated.
  • IBM Security Verify Access Advanced Access Control activated.
  • The Runtime Component configured.
  • A reverse proxy instance created with the name “default”.
  • An ISVA user exists with the name “testuser”.
  • SCIM Configured with:
    • Verify Access Runtime server connection.
    • Verify Access Integration enabled.

Procedure

1. Create the new mapping rule that will perform the password update.

    In the LMI open the authentication advanced page:

    AAC —> Policy —> Authentication —> Advanced

a. Click the Add button 

    Note: In the contents make sure to change the value of <reverse_proxy> to the hostname or IP address of the reverse proxy in your environment.

    Name: changepwd
    Category: InfoMap
    Contents:

importClass(Packages.com.tivoli.am.fim.trustserver.sts.utilities.IDMappingExtUtils);
importClass(Packages.com.ibm.security.access.httpclient.HttpClientV2);
importClass(Packages.com.ibm.security.access.httpclient.RequestParameters);
importClass(Packages.com.ibm.security.access.httpclient.Parameters);
importPackage(Packages.com.ibm.security.access.scimclient);

var username = context.get(Scope.SESSION, "urn:ibm:security:asf:response:token:attributes", "username");

IDMappingExtUtils.traceString("Username: " + username);

var password = context.get(Scope.REQUEST, "urn:ibm:security:asf:request:parameter", "password");
var newPassword = context.get(Scope.REQUEST, "urn:ibm:security:asf:request:parameter", "newpassword");
var passwordConfirm = context.get(Scope.REQUEST, "urn:ibm:security:asf:request:parameter", "confirmpassword");

macros.put("@USERNAME@", username);

if (passwordConfirm != null && passwordConfirm != "") {

    // First do the webseal login to get the session cookie.
    // This login is as the actual user for which the password is being updated.
    IDMappingExtUtils.traceString("First login using forms to webseal");

    let params = new RequestParameters();
    params.setUrlString("https://<reverse_proxy>/pkmslogin.form");
    params.setTrustStore("pdsrv");

    let postparams = new Parameters();
    postparams.addParameter("username", username);
    postparams.addParameter("password", password);
    postparams.addParameter("login-form-type", "pwd");
    postparams.addParameter("token", "Unknown");

    params.setParameters(postparams);

    resp = getResponse(params, true);

    if (resp.getCode() != 200) {
        macros.put("@ERROR_MESSAGE@", "Invalid existing password");
        page.setValue('/authsvc/authenticator/changepwd/getpwd.html');
    } else {
        // Next get the ID for scim user
        var id = ScimClient.computeIDForUsername(username);
        IDMappingExtUtils.traceString("ID: " + id);

        // Now update the password by a PATCH request using the cookie store
        params = new RequestParameters();
        params.setUrlString("https://<reverse_proxy>/scim/Users/" + id);
        params.setTrustStore("pdsrv");
        params.setCookieStore(resp.getCookieStore());

        let patchData = '{"schemas":["urn:ietf:params:scim:api:messages:2.0:PatchOp"],"Operations":[{"op":"replace","value":{"urn:ietf:params:scim:schemas:extension:isam:1.0:Password": {"newPassword": "' + newPassword + '","currentPassword": "' + password + '"}}}]}';

        postparams = new Parameters();
        postparams.addParameter("+_+BODY+_+", patchData);
        params.setParameters(postparams);

        resp = getResponse(params, false);

        if (resp.getCode() != 200) {
            macros.put("@ERROR_MESSAGE@", "Invalid new password");
            page.setValue('/authsvc/authenticator/changepwd/getpwd.html');
        } else {
            page.setValue('/authsvc/authenticator/changepwd/success.html');
        }
    }
} else {
    if (password != null && password != "") {
        macros.put("@ERROR_MESSAGE@", "Invalid new password");
    }
    page.setValue('/authsvc/authenticator/changepwd/getpwd.html');
}

function getResponse(params, post) {

    var resp = {};
    if(post == true) {
        resp = HttpClientV2.httpPost(params);
    } else {
        resp = HttpClientV2.httpPatch(params);
    }

    IDMappingExtUtils.traceString("Response code: " + resp.getCode());

    return resp;
}


b. Click the Save button.
c. Deploy the changes.


2. Create a new HTML template page to retrieve the password details.

    In the LMI open the template pages page:

    AAC —> Global Settings —> Template Pages

a. In the directory listing traverse to and select C/authsvc/authenticator.
b. Click New —> Directory.

    Name: changepwd

c. Click Save.
d. In the directory listing traverse to and select C/authsvc/authenticator/changepwd.
e. Click New —> File.

    Name: getpwd.html
    Contents:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Change Password</title>
    <link  type="text/css" rel="stylesheet" href="/sps/static/styles.css"></link>
    <script type="text/javascript" src="/sps/static/scripts/changepwd/getpwd.js" data-error-message="@ERROR_MESSAGE@"></script>
  </head>
  <body>
    <div class="header">
      <div class="brandingLogo"><img src="@JUNCTION@/sps/static/ibm-logo.png"></img></div>
    </div>
    <div class="content">
      <div class="userid"> Username: @USERNAME@ </div>
    </div>
      <br />
      <div class="contentHeader">
        <h1 class="pageTitle">Change Password</h1>
        <div id="errId">@ERROR_MESSAGE@</div>
      </div>
      <div class="pageContent">
        <form action="@ACTION@" method="POST">
          <input type="hidden" name="operation" value="" />
          <table border="0" cellspacing="5" cellpadding="10">
            <tbody>
              <tr>
                <td>
                  <label class="vertical" for="password">Existing password:</label>
                </td>
                <td>
                  <input type="password" name="password" id="password" />
                </td>
              </tr>
              <tr>
                <td>
                  <label class="vertical" for="newpassword">New password:</label>
                </td>
                <td>
                  <input type="password" name="newpassword" id="newpassword" />
                </td>
              </tr>
              <tr>
                <td>
                  <label class="vertical" for="confirmpassword">Confirm new password:</label>
                </td>
                <td>
                  <input type="password" name="confirmpassword" id="confirmpassword" />
                </td>
              </tr>
            </tbody>
          </table>
          <div class="controls">
            <input id="changePwd" class="submitButton" type="submit" value="Change Password" />
          </div>
        </form>
      </div>
    </div>
  </body>
</html>


f. Click Save.
g. In the directory listing traverse to and select C/static/scripts.
h. Click New —> Directory.

    Name: changepwd

i. Click Save.
j. In the directory listing traverse to and select C/static/scripts/changepwd.
h. Click New —> File.

    Name: getpwd.js
    Contents:

window.addEventListener('load', (event) => {
    onLoadPage();
    document.getElementById("changePwd").addEventListener('click', function() {
        this.form.operation.value = 'verify';
    });
});

var ldap_cp_dataVals = document.currentScript.dataset;
var ldap_cp_errormsg = ldap_cp_dataVals.errorMessage;

function onLoadPage() {
    showError();
    setFocus();
}

function showError() {
    var elem = document.getElementById("errId");
    if (ldap_cp_errormsg == "") {
        elem.className = "";
    } else {
        elem.className = "errorMessage";
    }
}

function setFocus() {
    document.getElementById("password").focus();
}

k. Click Save.


3. Create a new HTML template page to show the success of the password change.

    In the LMI open the template pages page:

    AAC —> Global Settings —> Template Pages

a. In the directory listing traverse to and select C/authsvc/authenticator/changepwd.
b. Click New —> File.

    Name: success.html
    Contents:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>Password Change Completed</title>

  <link rel="stylesheet" type="text/css" href="/sps/static/styles.css">
  <link rel="stylesheet" type="text/css" href="/sps/static/usc.css">
</head>
<body>
  <div class="header">
    <div class="prodname">IBM Security Verify Access - SCIM Password Change</div>
    <span class="headerLogo"><div></div></span>
  </div>
  <div class="content">
    <div class="contentHeader">
      <h1 class="pageTitle">Password Change</h1>
      <div class="instructions">Hi @USERNAME@!</div>
    </div>
    <div class="pageContent">
      <!-- Do not translate the macro USERNAME -->
      <p>The password for your account has been updated.</p>
    </div>
  </div>
</body>
</html>

c. Click Save.
d. Deploy the changes.

4. Create the new authentication mechanism.

    In the LMI open the authentication mechanisms page:

    AAC —> Policy —> Authentication —> Mechanisms

a. Click the Add Info Map Authentication menu item.

Name: changepwd
Identifier: changepwd
Mapping Rule: changepwd

b. Click Save.
c. Deploy the changes.


5. Configure the Username Password authentication mechanism.

    In the LMI open the authentication mechanism page:

    AAC —> Policy —> Authentication —> Mechanisms

a. Find and select the Username Password entry.
b. Click the Edit menu item.

    Update the Properties as required to match your environment. In particular update the LDAP properties (eg: Bind DN, Bind Password, Hostname, etc).

c. Click Save.
d. Deploy the changes.


6. Create the new authentication policy.

    In the LMI open the authentication policies page:

    AAC —> Policy —> Authentication —> Policies.

a. Click the Add button.

    Name: changepwd
    Identifier: changepwd
    Steps:
        1. Username Password
        2. changepwd

b. Click Save.
c. Deploy the changes.


7. Configure the Authentication and Context Based Access for the reverse proxy.

    In the LMI open the reverse proxy page:

    Web —> Manage —> Reverse Proxy.

a. Select the reverse proxy entry ie: “default” unless another instance is being used.
b. Click Manage —> AAC and Federation Configuration —> Authentication and Context Based Access Configuration.
c. Update the fields as required:

    Main —> No changes.
    AAC Runtime —> Set the easuser password.
    FIDO2 PAIR —> No changes.
    Reuse Options —> No changes.

d. Click Finish.
e. Deploy the changes.
f. Restart the reverse proxy instance.


8. Create a new junction to SCIM on the reverse proxy instance.

    In the LMI open the reverse proxy page:

    Web —> Manage —> Reverse Proxy.

a. Select the reverse proxy entry ie: “default” unless another instance is being used.
b. Click Manage —> Junction Management
c. Click New —> Standard Junction

    Junction
        Junction Point Name: /scim
        Junction Type: SSL
        Create Transparent Path Junction: yes
    Servers
        localhost:443 (ie location of the AAC runtime server)
    Basic Authentication
        Enable Basic Authentication: yes
        Username: easuser
        Password: <easuser password>
    Identity
       IV-USER: yes
       IV-GROUPS: yes
       IV-CREDS: yes

d. Click Save.

9. If this is a clean ISVA install using default reverse proxy certificates there is an extra step required here such that the HttpClientV2 will ignore certificate errors.

    Note: This is only for demo/testing purposes and should not be done in a production environment.

    In the LMI open the advanced configuration page:

    AAC —> Global Settings —> Advanced Configuration.

a. Find and select the util.httpClientV2.enableHostNameVerification entry.
b. Click the inline Edit button to update the value.

     Value: *=false

c. Click Save.
d. Deploy the changes.


10. Access the new authentication policy to change the users password.

    https://<reverse_proxy>/mga/sps/authsvc/policy/changepwd

a. Login as testuser.

b. Enter the password change details and click Change Password.

c. The success page is displayed.

11. If any issues were encountered try enabling trace on the runtime server and examine the logs.

    In the LMI open the runtime tracing page:

    AAC —> Runtime Parameters —> Runtime Tracing

a. Set the trace specification to:

    com.tivoli.am.fim.trustserver.sts.utilities.*=ALL:com.tivoli.am.fim.trustserver.sts.modules.*=ALL:com.ibm.security.access.httpclient.*=ALL

b. Click Save.
c. Deploy the changes.
d. The log file can be seen in the Application log files page.

    Monitor —> Application Log Files —> access_control —> runtime —> trace.log

0 comments
7 views

Permalink