Email Activation When Using SCIM

Email Activation When Using SCIM

tutorials

This tutorial explains how to configure Event Listeners to send an activation email to an end-user when managing the account via SCIM.

Event Listeners are actions launched by certain events in the Curity Identity Server. An Event Listener can consume Facilities like an HTTP client or an Email sender.

Prerequisites

You will need an installation of the Curity Identity Server with the basic setup completed. You can achieve this by following the Getting Started Guides. Alternatively, if you have a system up and running with your own configuration, you can use that as well.

You should also have user management with SCIM set up.

Background

This tutorial assumes that only SCIM handles user management for your environment. User self-registration in combination with this is not covered.

When a user is created or disabled via SCIM, the user should receive an email to activate their account. To achieve this, you must set up event listeners to trigger upon these events. When that happens, the system will email an activation link to the user. When the user clicks on the link, the account will be set to active, and the user can then authenticate.

Activation is handled by the html-form authenticator with an Account Manager with registration enabled. This tutorial uses a separate Authenticator and a separate Account Manager to avoid intervening with your current system.

Setup

Email

Since the Event Listener will send emails, it will require an Email Provider. If you don’t already have one, create a new Email Provider in the Admin UI by clicking on Facilities->Email->New. Give it a name and enter the properties of your SMTP server.

Account Manager

Next, create a separate Account Manager, as this configuration may not exactly apply to other authenticators.

Create a new Account Manager by clicking on Facilities->Account Managers->New. Give it the name activation-account-manager. Make sure it points to the same Account Data Source as User Management. Enable Registration, select email-verification and select your email provider.

Authenticator

html-form is the only Authenticator that can perform the activation. Therefore, you must create a new one, even if other Authenticators are used for the actual authentication. Even if you already have an html-form Authenticator, make sure to create a new one specifically for this purpose.

Follow this tutorial to learn how to Create an html-form Authenticator. Make sure to use the activation-account-manager Account Manager. You can use any Credential Manager. Give it the name html-activation.

Event Listener

Create a new Event Listener by clicking System->Event Listeners->New Event Listener. Give it a name and select script-event-listener type. Click on New next to Procedure. Give that a name and enter the following script:

/**
 * This procedure initializes activation for newly created SCIM accounts.
 *
 * @param context instance of ScriptEventListenerContext.
 * @param event the received AccountCreatedScimEvent.
 */
function activateCreatedAccount(context, event) {
    if (typeof event.postedAccount.active === 'undefined' || event.postedAccount.active === false) {
        activateAccount(context, event.storedAccount);
    }
}

/**
 * This procedure initializes activation for updated SCIM accounts, if the update causes
 * the account's 'active' attribute to be set to 'false'.
 *
 * @param context instance of ScriptEventListenerContext
 * @param event the received AccountUpdatedScimEvent
 */
function activateUpdatedAccount(context, event) {
    if (isAccountDeactivated(event)) {
        activateAccount(context, event.updatedAccount);
    }
}

function isAccountDeactivated(event) {
    var deactivated = false;

    if (event.httpMethod === 'PUT') {
        // If PUT was used for updating the account, the entire account will be in the request
        // and we can trivially check the 'active' attribute.

        logger.trace("Account was updated using PUT");

        deactivated = typeof event.updateMap.active === 'undefined' || event.updateMap.active === false;
    } else if (event.httpMethod === 'PATCH') {
        // If PATCH was used for updating the account, we must check all requested operations
        // to see if any of them updates the 'active' attribute.

        logger.trace("Account was updated using PATCH");

        event.updateMap.Operations.forEach(function(operation) {
            if (operation.op === 'add' || operation.op === 'replace') {
                if (operation.path === 'active') {
                    deactivated = operation.value === false;
                } else if (typeof operation.path === 'undefined' || operation.path === null) {
                    deactivated = operation.value.active === false;
                }
            }
        });
    }

    if (deactivated) {
        logger.trace("Account was deactivated");
    }

    return deactivated;
}

function activateAccount(context, account) {
    logger.trace("Initializing activation of account: {}", account.userName);

    context.accountManager.initializeActivation(account.asMap(), {
        "template": "authenticator/html-form/email/verify-account/email",
        "_activationUrl": "https://example.com/authn/anonymous/html-authentication/activate"
    });
}

var listeners = {
    "AccountCreatedScimEvent": activateCreatedAccount,
    "AccountUpdatedScimEvent": activateUpdatedAccount
};

Make sure to update the _activationUrl to match your system. The URL consists of your Base URL, auth-anonymous endpoint, authenticator name, and /activate in the end.

Enable an Account Manager for your Event Listener and select activation-account-manager.

Polishing

With the setup above, the flow should work, but you can polish the experience a bit before considering it complete.

Branding

After the user has activated their account, they arrive at a Success Page. By default, this page contains a link back to the Authenticator. Since this Authenticator is not being used, this link will result in an error message. You can change this link to point to your webpage instead.

If you are new to branding in Curity Identity Server, have a look at the branding article for more in-depth knowledge of how the template system works.

To update your branding, create a Template Area and override the success template.

To create a new template area, create a new directory in $IDSVR_HOME/usr/share/templates/template-areas

# Create template area called "activation"
mkdir $IDSVR_HOME/usr/share/templates/template-areas/activation
cd $IDSVR_HOME/usr/share/templates/template-areas/activation

# Create folder structure
mkdir -p authenticator/html-form/account-activation/

# Copy orginal template to template area
cp \
    ../../core/authenticator/html-form/account-activation/success.vm \
    authenticator/html-form/account-activation/success.vm

Open success.vm in your template area and scroll down until you see:

<a href="$_authUrl">

Replace it with your URL:

<a href="https://example.com">

Should look something like this:

.
.
        #parse("fragments/auto-login")
        <div class="center py2 login-actions">
            <a href="https://example.com">
.
.

Once it is saved, configure the Authenticator to use this template instead.

In the Admin UI, click on Profiles->Authentication Service->Authenticators->html-authentication->Advanced->Template Area. Here you should be able to select activation in the dropdown.

Disable Registration

If the Account Manager is enabled, it is possible for an end-user to self-register using the html-form authenticator. Since the Account Manager and Authenticator is just for activation, you probably don’t want to allow self-registration. One way to disable this is to set up a validator to deny the request.

Create a validator by System->Procedures->Validation Procedures->New. Give it the name deny-validator and make sure validation-proceduresis selected.

Since it will always deny requests, set the validator to always return an error:

function result(validationContext) {
    return {"reason": "disabled"};
}

Press Save to store your settings.

Now add this validator twice, one per method, to your authenticator by clicking on Profiles->Authentication Service->Authenticators->html-authentication->Advanced->Request Validation->Add

Request SubpathEndpointHTTP MethodValidation Procedure
indexauthentication-service-registrationgetdeny-validator
indexauthentication-service-registrationpostdeny-validator

By now, you have effectively blocked all access to the registration endpoint since your validation procedure always returns an error.

Try It Out

With everything set up, you can now try it out by creating a new user or disabling an existing user. Immediately after, the user will receive an email to activate their account. Once they click the link in the email, their account will be activated, and they can use any authenticator to authenticate.

Conclusion

Event Listeners are a versatile way to handle various events that happen in the Curity Identity Server. This script listens for two events, but there are more available. This tutorial used Script Event Listener, but it is also possible to create plugins using the SDK. Lastly, in addition to changing the URL for post-activation, you can also brand everything the end-user sees, including the email itself.

Let’s Stay in Touch!

Get the latest on identity management, API Security and authentication straight to your inbox.

Keep up with our latest articles and how-tos using RSS feeds