Skip to main content

Using Delegated Authorization

Caché supports the use of user-defined authorization code. This is known as delegated authorization. Topics in this chapter include:

Overview of Delegated Authorization

Delegated authorization allows administrators to implement custom mechanisms to replace the role-assignment activities that are part of Caché security. For example, user-defined authorization code might look up a user’s roles in an external database and provide that information to Caché.

To use delegated authorization, there are the following steps:

  1. Creating Delegated (User-defined) Authorization Code in the ZAUTHORIZE routine.

  2. Configuring an Instance to Use Delegated Authorization for the Caché instance.

Note:

Delegated authorization is only supported with Kerberos and Operating-System–based authentication.

Interactions between Delegated Authentication and Delegated Authorization

Delegated authorization through ZAUTHORIZE.mac is not supported for use with delegated authentication. The routine for delegated authentication (ZAUTHENTICATE, which is described in the chapter “Using Delegated Authentication”) provides support for authorization. When using ZAUTHENTICATE, you have the option to segregate authentication and authorization code.

Creating Delegated (User-defined) Authorization Code

Topics associated with creating delegated authorization code include:

Working from the ZAUTHORIZE.mac Template

A system-supplied copy of the ZAUTHORIZE routine is available in the SAMPLES namespace in the routine ZAUTHORIZE.mac for instances with the manager utility source code installed. To install the manager utility source code, select an installation type of Development, Server, or a Custom installation that includes the Caché Database Engine.

To create your own ZAUTHORIZE.mac:

  1. To use ZAUTHORIZE.mac as a template, copy its contents and save them into a ZAUTHORIZE.mac routine in the %SYS namespace.

  2. Review the comments in the system-supplied code for ZAUTHORIZE. These provide important guidance about how to implement a custom version of the routine.

  3. Edit the routine by adding custom authorization code and any desired code to set user account characteristics.

Caution:

Because Caché places no constraints on the authorization code in ZAUTHORIZE, the application programmer is responsible for ensuring that this code is sufficiently secure.

Upgrading Delegated Authorization Code

Before upgrading to a new version of Caché, check ZAUTHORIZE.mac to determine if your current authorization code needs any changes to support new functionality.

ZAUTHORIZE Signature

When configured for delegated authorization, the system automatically calls ZAUTHORIZE after authentication occurs. Caché supplies values for the parameters defined in the ZAUTHORIZE signature as necessary. The signature of ZAUTHORIZE is:

ZAUTHORIZE(ServiceName, Namespace, Username, Password, 
        Credentials, Properties) PUBLIC {

  // authorization code
  // optional code to specify user account properties and roles
}

where:

  • ServiceName — A string specifying the name of the service through which the user is connecting to Caché, such as %Service_Console or %Service_CSP.

  • Namespace — A string specifying the namespace on the Caché server to which a connection is being established. This is for use only with %Service_Bindings, such as connections for Studio or ODBC; for any other service, the value should be "" (the empty quoted string).

  • Username — A string specifying the user whose privileges are being determined.

  • Password — A string specifying the password associated with account in use. This is for use only with the Kerberos K5API authentication mechanism; for any other mechanism, the value should be "" (the empty quoted string).

  • CredentialsPassed by reference. Not implemented in this version of Caché.

  • PropertiesPassed by reference. An array of returned values that specifies characteristics of the account named by Username. For more information, see “ZAUTHORIZE and User Properties.”

Authorization Code with ZAUTHORIZE

The purpose of ZAUTHORIZE is to establish or update the roles and other characteristics for the authenticated user. The content of authorization code is application-specific. It can include any user-written ObjectScript code, class method, or $ZF callout.

ZAUTHORIZE specifies role information by setting the values of the Properties array, which is passed by reference to ZAUTHORIZE. Typically, the source for the values being set is a repository of user information that is available to ZAUTHORIZE.

Caution:

Because Caché does not and cannot place any constraints on the authorization code in ZAUTHORIZE, the application programmer is responsible for ensuring that this code is sufficiently secure.

ZAUTHORIZE and User Properties

Elements of the Properties array specify values of attributes associated with the user specified by the Username parameter. Typically, code within ZAUTHORIZE sets values for these elements. The elements in the Properties array are:

  • Properties("Comment") — Any text.

  • Properties("FullName") — The first and last name of the user.

  • Properties("NameSpace") — The default namespace for a Terminal login.

  • Properties("Roles") — The comma-separated list of roles that the user holds in Caché.

  • Properties("Routine") — The routine that is executed for a Terminal login. A value of "" specifies that the Terminal run in programmer mode.

  • Properties("Password") — The user’s password.

  • Properties("Username") — The user’s username.

Each of these elements is described in more detail in one of the following sections.

Note:

It is not possible to manipulate the value of any member of the Properties array after authorization.

Comment

If ZAUTHORIZE returns a value for Properties("Comment"), then that string becomes the value of the user account’s Comment property in Caché. (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 holds no content.

FullName

If ZAUTHORIZE returns a value for Properties("FullName"), then that string becomes the value of the user account’s Full name property in Caché. (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 holds no content.

NameSpace

If ZAUTHORIZE sets the value of Properties("Namespace"), then that string becomes the value of the user account’s Startup Namespace property in Caché. (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 holds no content.

Once connected to Caché, the value of Startup Namespace — as specified by the value 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, 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 ZAUTHORIZE sets the value of Properties("Password"), then that string becomes the value of the user account’s Password property in Caché. (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.

If ZAUTHORIZE returns a password, this allows the user to log into the system via Password authentication if it is enabled. This is a possible mechanism to help migrate from delegated authentication to Password authentication, though with the usual cautions associated with the use of multiple authentication mechanisms; see “Cascading Authentication” in the Authentication chapter for more details.

Roles

If ZAUTHORIZE 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 there are no roles associated with the user account and the Management Portal indicates this. Information about a user’s roles is available on the Roles tab of a user’s Edit User page and a user’s profile.

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:

  • If a role is listed in Properties("Roles") and is defined by the Caché instance, then the user is assigned to the role.

  • If a role is listed in Properties("Roles") and is not defined by the Caché instance, then the user is not assigned to the role.

  • A user is always assigned to those roles associated with the _PUBLIC user. A user also has access to all public resources. For information on the _PUBLIC user, see the section “The _PUBLIC Account” in the “Users” chapter; for information on public resources, see the section “Services and Their Resources” in the “Resources” chapter.

Routine

If ZAUTHORIZE sets the value of Properties("Routine"), then that string becomes the value of the user account’s Startup Tag^Routine property in Caché. (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 Console, Terminal, or Telnet). If Properties("Routine") has no value or a value of "", then login starts the Terminal session in programmer mode, subject to whether they have the privilege to access programmer mode or not.

Username

If ZAUTHORIZE sets the value of Properties("Username"), then that string becomes the value of the user account’s Name property in Caché. (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 (while ensuring that the normalized username only differ by case).

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.

The User Information Repository

ZAUTHORIZE 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, ZAUTHORIZE code must make that information available to Caché.

If information in the repository changes, this information is only propagated back into the Caché user information if there is code in ZAUTHORIZE 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 reset by ZAUTHORIZE.

ZAUTHORIZE Return Value and Error Messages

The routine returns one of the following values:

  • Success — $SYSTEM.Status.OK(). This indicates that ZAUTHORIZE has successfully executed. Depending on the code in the routine, this can indicate successful authentication of the user associated with Username and Password, successful authorization of the user associated Username, or both.

  • Failure — $SYSTEM.Status.Error($$$ERRORMESSAGE). This indicates that authorization failed. When ZAUTHORIZE returns an error message, it appears in the audit log if the LoginFailure event auditing is enabled; the end-user only sees the $SYSTEM.Status.Error($$$AccessDenied) error message.

ZAUTHORIZE can return system-defined or application-specific error messages. All these messages use the Error method of the %SYSTEM.StatusOpens in a new tab 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:

  • $SYSTEM.Status.Error($$$AccessDenied) — Error message of “Access Denied”

  • $SYSTEM.Status.Error($$$InvalidUsernameOrPassword) — Error message of “Invalid Username or Password”

  • $SYSTEM.Status.Error($$$UserNotAuthorizedOnSystem,Username) — Error message of “User username is not authorized”

  • $SYSTEM.Status.Error($$$UserAccountIsDisabled,Username) — Error message of “User username account is disabled”

  • $SYSTEM.Status.Error($$$UserInvalidUsernameOrPassword,Username) — Error message of “User username invalid name or password”

  • $SYSTEM.Status.Error($$$UserLoginTimeout) — Error message of “Login timeout”

  • $SYSTEM.Status.Error($$$UserCTRLC) — Error message of “Login aborted”

  • $SYSTEM.Status.Error($$$UserDoesNotExist,Username) — Error message of “User username does not exist”

  • $SYSTEM.Status.Error($$$UserInvalid,Username) — Error message of “Username username is invalid”

  • $SYSTEM.Status.Error($$$PasswordChangeRequired) — Error message of “Password change required”

  • $SYSTEM.Status.Error($$$UserAccountIsExpired,Username) — Error message of “User username account has expired”

  • $SYSTEM.Status.Error($$$UserAccountIsInactive,Username) — Error message of “User username account is inactive”

  • $SYSTEM.Status.Error($$$UserInvalidPassword) — Error message of “Invalid password”

  • $SYSTEM.Status.Error($$$ServiceDisabled,ServiceName) — Error message of “Logins for Service username are disabled”

  • $SYSTEM.Status.Error($$$ServiceLoginsDisabled) — Error message of “Logins are disabled”

  • $SYSTEM.Status.Error($$$ServiceNotAuthorized,ServiceName) — Error message of “User not authorized for service”

To use these error codes, uncomment the #include %occErrors statement that appears in ZAUTHORIZE.mac.

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.

Configuring an Instance to Use Delegated Authorization

Once you have created a customized ZAUTHORIZE routine, the next step is to enable it for the instance’s relevant services or applications. This procedure is:

  1. Run the ^SECURITY routine from the %SYS namespace in a Terminal or Console window.

  2. In ^SECURITY, choose System parameter setup; under that, choose Edit authentication options; and under that, choose either Allow Kerberos authentication or Allow Operating System authentication. (Delegated authorization is only supported for these two authentication mechanisms.).

  3. If you have selected Allow Operating System authentication, choose Allow Delegated Authorization for O/S authentication. If you have selected Allow Kerberos authentication, choose Allow Delegated Authorization for Kerberos authentication.

Selecting either of these choices causes Caché to invoke the ZAUTHORIZE.mac routine, if one exists, in the %SYS namespace.

Important:

Caché only calls ZAUTHORIZE after user authentication.

Delegated Authorization and User Types

When a user first logs in to Caché with an authentication mechanism that uses delegated authorization, the system creates a user account either of Type OS (for Operating System) or Kerberos. (Note that this value does not appear in the Type column of the table of users on the Users page (System Administration > Security > Users).) At the time of account creation and, for subsequent logins, the ZAUTHORIZE routine specifies the roles for the user.

Any attempt to log in without using delegated authorization will result in a login failure. This is because only delegated authorization specifies the user Type as OS or Kerberos. When using these authentication mechanisms without delegated authorization, the user is authenticated as being of Type "Caché Password User"; the login fails because a user can only have one type and a user of one type cannot log in using mechanisms associated with another type. (Delegated authentication and LDAP authentication also both fail for the same reason.)

For general information about user types, see the section “About User Types” in the “Users” chapter.

After Authorization — The State of the System

If the user is successfully authorized, the Cache security database is updated in one of the following ways:

  1. If this is the first time the user has logged in, a user record is created in the security database for the entered username, using properties returned by ZAUTHORIZE.

  2. If the user has logged in before, the user record is updated in the security database, using properties returned by this function.

Whether for a first-time user or not, the process that logs in has the value of the $ROLES system variable set to the value of Properties("Roles"). For a terminal login, the namespace is set to the value of Properties("NameSpace") and the startup routine is set to the value of Properties("Routine").

FeedbackOpens in a new tab