Development Tasks

The configuration tasks described so far allow customers to fulfill the requirements listed in the example with the exception of requirement:

"7 - Users should be able to log into Universal Access
   as soon as they have registered with CentralID, there
   should be no delay waiting for id to propagate to other
   systems".

In order to function correctly, Cúram Universal Access requires each user to have an entry in the ExternalUser table. The customer could build a batch process to import users from the LDAP directory into the Cúram ExternalUser table but this would not satisfy requirement 7 since the user must be able to register with CentralID and then immediately use Universal Access. Another option would be to build a web service or similar mechanism that would be invoked when a new user registers with CentralID. The implementation of the web service would create the appropriate entry in the ExternalUser table.

This document however, now describes a simpler option which is to override the default login behavior to create new accounts on-the-fly, after checking that the relevant entry exists in the LDAP server.

Overriding the default login behavior in Universal Access can be done by extending the curam.citizenworkspace.security.impl.SecurityStrategy class and overriding the authenticate() method. The code below outlines how to use the SecurityStrategy and other security APIs to meet the requirements described above:

public class CustomSecurityStrategy extends SecurityStrategy {
  @Inject
  private CitizenWorkspaceAccountManager cwAccountManager;
  ...
  @Override
  public String authenticate(final String username, 
      final String password)
      throws AppException, InformationalException {
    final String retval = null;
    if (username.equals(PUBLIC_CITIZEN)) {
      return super.authenticate(username, password);
    }
    // Authenticate generated accounts as normal
    if (cwAccountManager.isGeneratedAccount(username)) {
      return super.authenticate(username, password);
    }
    // Check that the user exists in LDAP
    // This prevents hackers from registering a lot of bogus
    // accounts that exist in Curam but not in LDAP
    if (!isUserInLDAP(username)) {
      return SECURITYSTATUS.BADUSER;
    }
    // If there's no account for this user
    if (!cwAccountManager.hasAccount(username)) {
      createUserAccount(username);
    }
    return SECURITYSTATUS.LOGIN;
  }
  private void createUserAccount(final String username) 
      throws AppException, InformationalException {
    final CreateAccountDetails newAcctDetails;
    ...
    cwAccountManager.createStandardAccount(newAcctDetails);
  }
}

The code above checks to see if the user logging in is the publiccitizen user or a generated account. In both of these cases, authentication logic is delegated to the default SecurityStrategy. In the case of a registered user the Security Strategy checks the LDAP directory to ensure that the user exists there. If the user exists in the LDAP directory and does not exist yet in Cúram then a new user account is created. Note, the custom code does not need to authenticate the user against LDAP since the authentication is handled by the User Registry in Websphere or the LDAP JAAS Module in WebSphere. It is important to note that the password parameter of the authenticate() method is encrypted using a one-way hash. This ensures that it can be safely transmitted from the Client Side of the Cúram application to the Server Side of the application.

In order to install the CustomSecurityStrategy it must be bound in place of the Default Security Strategy. This can be done by using a Guice Module to bind the implementation:

public class CustomModule extends AbstractModule {
  @Override
  protected void configure() {
    binder().bind(SecurityStrategy.class).to(
      CustomSecurityStrategy.class);
  }
}

The CustomModule must be configured at startup. This can be achieved by adding a DMX file to the custom component as follows:

<CURAM_DIR>/EJBServer/custom/data/initial/MODULECLASSNAME.dmx

<?xml version="1.0" encoding="UTF-8"?>
<table name="MODULECLASSNAME">
    <column name="moduleClassName" type="text" />
    <row>
      <attribute name="moduleClassName">
        <value>gov.myorg.CustomModule</value>
      </attribute>
    </row>
</table>