docs.intersystems.com
Home  /  Security Features of InterSystems IRIS  /  Security Administration Guide  /  Using Delegated Authentication


Security Administration Guide
Using Delegated Authentication
[Back]  [Next] 
InterSystems: The power behind what matters   
Search:  


InterSystems IRIS™ supports the use of user-defined authentication mechanisms. This is known as delegated authentication. Delegated authentication allows administrators to implement custom mechanisms to replace the authentication and role-management activities that are part of InterSystems security.
This chapter covers the following topics:
Overview of Delegated Authentication
To use delegated authentication, the steps are:
  1. Create the user-defined authentication code in the ZAUTHENTICATE routine. This can include the use of two-factor authentication. This routine can also perform basic setup for a user account, such as specifying roles and other user properties.
  2. Enable delegated authentication for the InterSystems IRIS instance on the Authentication Options page.
  3. Enable delegated authentication for the relevant services, applications, or both, as required.
  4. Optionally enable two-factor authentication for the InterSystems IRIS instance and, if required, for web applications and client/server applications.
For example, to use delegated authentication for an instance’s Management Portal, the steps are:
  1. Create the user-defined authentication code in ZAUTHENTICATE.
  2. Enable delegated authentication for the InterSystems IRIS instance as a whole.
  3. Enable delegated authentication for the set of /csp/sys* applications.
How Delegated Authentication Works
When a user attempts to log in and InterSystems IRIS invokes delegated authentication, the sequence of events is:
  1. When a service or application uses delegated authentication, a login attempt automatically results in a call to the ZAUTHENTICATE routine. The authentication code in this routine can be any user-defined ObjectScript, class methods, or $ZF callout code.
  2. The next step depends on whether or not authentication succeeds and whether or not this is the first login using ZAUTHENTICATE:
  3. If two-factor authentication is enabled for the instance and the relevant services, then there is a check that the user’s PhoneNumber and PhoneProvider properties have been set. If these properties are set, then two-factor authentication proceeds; if they are not set, two-factor authentication cannot proceed and the user is not authenticated.
  4. A delegated user is listed as such in the Type column of the list of users on the Users page (System Administration > Security > Users). The user’s properties are displayed read-only in the Management Portal and are not editable from within InterSystems IRIS (since all the information comes from outside InterSystems IRIS).
    Note:
    A delegated user cannot also be an InterSystems IRIS password user.
Creating Delegated (User-Defined) Authentication Code
This section describes various aspects of creating your own ZAUTHENTICATE routine:
Authentication Code Fundamentals
InterSystems provides a sample routine, ZAUTHORIZE.mac, that you can copy and modify. This routine is part of the Samples-Security sample on GitHub (https://github.com/intersystems/Samples-Security). You can download the entire sample as described in Downloading Samples for Use with InterSystems IRIS , but it may be more convenient to simply open the routine on GitHub and copy its contents.
To create your own ZAUTHENTICATE.mac:
  1. To use ZAUTHENTICATE.mac as a template, copy its contents and save them into a ZAUTHENTICATE.mac routine in the %SYS namespace.
  2. Review the comments in the ZAUTHENTICATE.mac sample. These provide important guidance about how to implement a custom version of the routine.
  3. Edit your routine by adding custom authentication code and any desired code to set user account characteristics.
Caution:
Because InterSystems IRIS places no constraints on the authentication code in ZAUTHENTICATE, the application programmer is responsible for ensuring that this code is sufficiently secure.
Signature
The signature of ZAUTHENTICATE is:
ZAUTHENTICATE(ServiceName, Namespace, Username, Password, Credentials, 
        Properties) PUBLIC {

    // authentication code
    // optional code to specify user account properties and roles
}
where:
When InterSystems IRIS calls ZAUTHENTICATE, it has values for these arguments and supplies them to the routine.
Authentication Code
The content of authentication code is application specific. If authentication succeeds, the routine should return the $$$OK macro; otherwise, it should return an error code. See the section Return Value and Error Messages for more information on return values.
Caution:
Because InterSystems IRIS does not and cannot place any constraints on the authentication code in ZAUTHENTICATE, the application programmer is responsible for ensuring that this code is sufficiently secure.
The GetCredentials Entry Point
ZAUTHENTICATE includes an GetCredentials entry point. This entry point is called whenever delegated authentication is enabled for a service, and is called before the user is prompted for a username and password. Instead of getting a username and password from the user, code in the function (created by the application developer) specifies the username and password. The username and password returned are then authenticated in the normal manner as if the user entered them. A possible use of this mechanism is to provide a username and password within the entry point and then, within authentication code, to $roles for the process.
The username and password returned from this entry point can be obtained by any mechanism that the application developer chooses. They can come from a global, come from an external DLL or LDAP call, or simply be set within the routine. The application developer could even provide code to prompt for the username and password, such as in a terminal connection or with a login page.
When there is a call to the GetCredentials entry point, the return value and other factors determine what happens next:
In the following example of a GetCredentials entry point, the code performs different actions for different services:
Finally, the Error entry point performs clean-up as necessary.
The code is:
GetCredentials(ServiceName,Namespace,Username,Password,Credentials) Public {

  // For console sessions, authenticate as _SYSTEM.
  If ServiceName="%Service_Console" {
    Set Username="_SYSTEM"
    Set Password="SYS"
    Quit $SYSTEM.Status.OK()
  }

  // For a web application, authenticate as AdminUser.
  If $isobject($get(%request)) { 
    If %request.Application="/csp/samples/" {
      Set Username="AdminUser"
      Set Password="Test"
      Quit $System.Status.OK()
    }
  }

  // For bindings connections, use regular prompting.
  If ServiceName="%Service_Bindings" {
    Quit $SYSTEM.Status.Error($$$GetCredentialsFailed)
  }

  // For all other connections, deny access.
  Quit $SYSTEM.Status.Error($$$AccessDenied)
}
For more details, see the comments for this entry point in ZAUTHENTICATE.mac.
The SendTwoFactorToken Entry Point
ZAUTHENTICATE includes an SendTwoFactorToken entry point. This entry point is for use with two-factor authentication. If it is defined and the InterSystems IRIS instance has two-factor authentication enabled, then you can override the default system setting for the format of the message and token that the instance sends to the user’s mobile phone. This allows for messages that can vary by application even on the same InterSystems IRIS instance.
For more details and an example of how to use this entry point, see this entry point in the sample ZAUTHENTICATE.mac.
Setting Values for Roles and Other User Characteristics
If initial authentication succeeds, ZAUTHENTICATE can establish the roles and other characteristics for the authenticated user. For subsequent logins, ZAUTHENTICATE can update these elements of the user record.
For this to happen, code in ZAUTHENTICATE sets the values of the Properties array. (Properties is passed by reference to ZAUTHENTICATE.) Typically, the source for the values being set is a repository of user information that is available to ZAUTHENTICATE.
User Properties
The elements in the Properties array are:
Each of these elements is described in more detail in one of the following sections.
Note:
The value of each element in the properties array determines the value of its associated property for the user being authenticated. It is not possible to use only a subset of the properties or to manipulate their values after authentication.
Comment
If ZAUTHENTICATE sets the value of Properties("Comment"), then that string becomes the value of the user account’s Comment property in InterSystems IRIS. (This property is described in the section Properties of Users,” in the “Users” chapter.) If no value is passed back to the calling routine, then the value of Comment for the user account is a null string and the relevant field in the Management Portal then holds no content.
FullName
If ZAUTHENTICATE sets the value of Properties("FullName"), then that string becomes the value of the user account’s Full name property in InterSystems IRIS. (This property is described in the section Properties of Users,” in the “Users” chapter.) If no value is passed back to the calling routine, then the value of Full name for the user account is a null string and the relevant field in the Management Portal then holds no content.
NameSpace
If ZAUTHENTICATE sets the value of Properties("Namespace"), then that string becomes the value of the user account’s Startup Namespace property in InterSystems IRIS. (This property is described in the section Properties of Users,” in the “Users” chapter.) If no value is passed back to the calling routine, then the value of Startup Namespace for the user account is a null string and the relevant field in the Management Portal then holds no content.
Once connected to InterSystems IRIS, the value of Startup Namespace (hence, that of Properties("Namespace")) determines the initial namespace for any user authenticated for local access (such as for Console, Terminal, or Telnet). If Startup Namespace has no value (since Properties("Namespace") has no value), then the initial namespace for any user authenticated for local access is determined as follows:
  1. If the USER namespace exists, that is the initial namespace.
  2. If the USER namespace does not exist, the initial namespace is the %SYS namespace.
Note:
If the user does not have the appropriate privileges for the initial namespace, access is denied.
Password
If ZAUTHENTICATE sets the value of Properties("Password"), then that string becomes the value of the user account’s Password property in InterSystems IRIS. (This property is described in the section Properties of Users,” in the “Users” chapter.) If no value is passed back to the calling routine, then the value of Password for the user account is a null string and the relevant field in the Management Portal then holds no content.
Roles
If ZAUTHENTICATE sets the value of Properties("Roles"), then that string specifies the Roles to which a user is assigned; this value is a string containing a comma-delimited list of roles. If no value is passed back to the calling routine, then the value of Roles for the user account is a null string and the relevant field in the Management Portal then holds no content. Information about a user’s roles is available on the Roles tab of a user’s Edit User page.
If any roles returned in Properties("Roles") are not defined, then the user is not assigned to the role.
Hence, the logged-in user is assigned to roles as follows:
Routine
If ZAUTHENTICATE sets the value of Properties("Routine"), then that string becomes the value of the user account’s Startup Tag^Routine property in InterSystems IRIS. (This property is described in the section Properties of Users,” in the “Users” chapter.) If no value is passed back to the calling routine, then the value of Startup Tag^Routine for the user account is a null string and the relevant field in the Management Portal then holds no content.
If Properties("Routine") has a value, then this value specifies the routine to execute automatically following login on a terminal-type service (such as for Console, Terminal, or Telnet). If Properties("Routine") has no value, then login starts the Terminal session in programmer mode.
Username
If the username property is returned by this function, then that username is written to the InterSystems IRIS database. This gives the user a chance to normalize what was entered by the user at the username prompt. Note that the normalized username must only differ by case. If the Username property is not passed back to the calling routine, then the username entered by the user at the username prompt will be used as the username written to the InterSystems security databases (that is, it is not normalized).
If ZAUTHENTICATE sets the value of Properties("Username"), then that string becomes the value of the user account’s Name property in InterSystems IRIS. (This property is described in the section Properties of Users, in the “Users” chapter.) This provides the application programmer with an opportunity to normalize content provided by the end-user at the login prompt.
If there is no explicit call that passes the value of Properties("Username") back to the calling routine, then there is no normalization and the value entered by the end-user at the prompt serves as the value of the user account’s Name property without any modification.
PhoneNumber and PhoneProvider
These are properties associated with two-factor authentication.
If ZAUTHENTICATE sets the value of Properties("PhoneNumber") and Properties("PhoneProvider"), then these then these are written to the InterSystems IRIS database for the user as the user’s mobile phone number and mobile phone service provider. If these are not passed back to the calling routine, then the phone number and service provider written to the InterSystems IRIS database are a null string. Hence, to use two-factor authentication with delegated authentication, you must supply both of these.
The User Information Repository
ZAUTHENTICATE can refer to any kind of repository of user information, such as a global or an external file. It is up to the code in the routine to set any external properties in the Properties array so that the authenticated user can be created or updated with this information. For example, while a repository can include information such as roles and namespaces, ZAUTHENTICATE code must make that information available to InterSystems IRIS.
If information in the repository changes, this information is only propagated back into the InterSystems IRIS user information if there is code in ZAUTHENTICATE to perform this action. Also, if there is such code, changes to users’ roles must occur in the repository; if you change a user’s roles during a session, the change does not become effective until the next login, at which point the user’s roles are re-set by ZAUTHENTICATE.
Return Value and Error Messages
The routine returns one of the following values:
ZAUTHENTICATE can return system-defined or application-specific error messages. All these messages use the Error method of the %SYSTEM.Status class. This method is invoked as $SYSTEM.Status.Error and takes one or two arguments, depending on the error condition.
The available system-defined error messages are:
To generate a custom message, use the $SYSTEM.Status.Error() method, passing it the $$$GeneralError macro and specifying any custom text as the second argument. For example:
$SYSTEM.Status.Error($$$GeneralError,"Any text here")
Note that when an error message is returned to the caller, it is logged in the audit database (if LoginFailure event auditing is turned on). However, the only error message the user sees is $SYSTEM.Status.Error($$$AccessDenied). However, the user also sees the message for the $$$PasswordChangeRequired error. Return this error if you want the user to change from the current to a new password.
Setting Up Delegated Authentication
Once you have created a ZAUTHENTICATE routine to perform authentication (and, optionally, authorization tasks), the next step is to enable it for the instance’s relevant services or applications. This procedure is:
  1. Enable delegated authentication for entire instance. On the Authentication/Web Session Options page (System Administration > Security > System Security > Authentication/Web Session Options), select Allow Delegated authentication and click Save.
    With delegated authentication enabled for the instance, a Delegated check box appears on the Edit Service page for relevant services and the Edit Web Application page for those applications.
  2. Enable delegated authenticated for services and applications, as appropriate.
The following services support delegated authentication:
These fall into several categories of access modes:
After Delegated Authentication Succeeds
Once the user has authenticated, two important topics are:
The State of the System
Any user who is initially authenticated using delegated authentication is listed in the table of users on the Users page (System Administration > Security > Users) as having a type of “Delegated user”. If a system administrator has explicitly created a user through the Management Portal (or using any other native InterSystems IRIS facility), that user has a type of “InterSystems IRIS password user”. If a user attempts to log in using delegated authentication and is successfully authenticated, InterSystems IRIS determines that this user already exists as an InterSystems IRIS user — not a Delegated user — and so login fails.
Changing Passwords
The ZAUTHENTICATE routine also includes an entry point, ChangePassword, to include code to change a user’s password. The signature of this entry point is:
ChangePassword(Username,NewPassword,OldPassword,Status) Public {}
where