Skip to main content
Version: Previous

Access control - username and password authentication

This page describes the configuration options for authentication. Remember that if you want to override the default configuration of the auth-preferences.kts, you need to modify or create the following file: application-name-script-config/src/main/resources/scripts/auth-preferences.kts.

info

Session tokens and refresh tokens Session tokens and refresh tokens work in pairs together to enable you to control secure user sessions. These tokens always have an associated expiry date. This is in DATETIME format, and is typically a number of minutes in the future.

The expiry date of the refresh token is always further in the future than the expiry date of the session token, so that session tokens can be refreshed.

Once a session token expires, you can use its associated refresh token to create a new user session - assuming the refresh token has not expired yet.

The security function

All the configuration settings in the auth-preferences.kts file are wrapped within the security function. From this top level, you can set the following variables:

  • sessionTimeoutMins specifies a time out (in minutes) for the session. Sessions are timed out (logged out) after the value defined here. The front end of your application can monitor web movement, page changes, etc. and perform an automatic refresh - in which case, the user is not aware of the logout and the start of the new session. Default: 30 minutes.
  • refreshTokenExpirationMins specifies a time out (in minutes) for the refresh token value that was provided on successful login. One refresh token is associated with one user session on a 1-to-1 basis; the value of the refresh token can be used to create a new user session after the session token has expired. Once the refresh token has expired, it can't be used to create a new user session. Default: 7200 minutes (5 days).
  • expiryCheckMins specifies the time interval (in minutes) used to check for idle sessions in the system. Default: 5 minutes.
  • maxSimultaneousUserLogins specifies the maximum number of concurrent active sessions a user can maintain. Once this limit has been reached, the user cannot activate additional sessions until one or more of the active sessions has been logged out. So, a value of 1 means that only one session can be logged in at any time; a value of two allows two sessions to be logged in concurrently, and so on. If the value is zero, is not defined, or is not a positive integer, then any number of sessions is permitted. Default: 0.
security {
sessionTimeoutMins = 60 //60 minutes (not the default 30 minutes)
refreshTokenExpirationMins = 2880 // 2880 minutes (not the default 7200 minutes)
expiryCheckMins = 10 //5 minutes (not the default 5 minutes)
maxSimultaneousUserLogins = 5 //5 active sessions (not the default unlimited)
}

Within security there is a further range of functions you can call in order to configure the username and password authentication. These are detailed below.

authentication

The authentication function is used to define which authenticator implementations will be used.

LDAP

Within the scope of the authentication function, you can insert an ldap block in order to define connections to one or more LDAP servers.

  • To define a connection to a single server, call the connection function and set the relevant details.
  • To define connections to more than one server, simply call the connection function multiple times.

When using multiple LDAP connections, the connections will be used in the order specified to authenticate a login request. Only one server need return a successful result for the login to be successful.

The following variables are used to configure an LDAP connection; these are only used when the type is either AuthType.LDAP or AuthType.HYBRID.

  • url specifies the LDAP server hostname. Default: localhost.
  • port specifies the LDAP server port. Default: 389.
  • searchBases defines the location(s) in the directory in which the LDAP search begins. Default: an organisational unit of temp with a domain component of temp (ou=temp,dc=temp).
    • This is set by first invoking the searchBases function, and repeatedly invoking searchBase(location) function(s) within it, where location is the exact name of the application on the LDAP server.
  • userGroups defines the group(s) that the user needs to belong to on the LDAP server in order to log in. Default: no groups.
    • This is set by first invoking the userGroups function, and repeatedly invoking userGroup(group) function(s) within it, where group is the specific name of a group.
  • userPrefix specifies a prefix added to every username when communicating with the LDAP server. Default: an empty string.
  • bindDn specifies the exact name of the application within the LDAP server. Normally, LDAP servers do not allow anonymous searches, so this name is essential. If bindDn is not specified, no bindings will be used. Default: null
  • bindPassword specifies the password for the bindDnaccount. If bindDn is not specified, this value is not used. Default: null.
  • userIdType defines the attribute to match in the directory search against the provided username. Default: cn.
    • Amongst the most common LDAP implementations, you can find three main ways of configuring usernames:
      • using the uid attribute (Userid)
      • using the cn attribute (Common Name)
      • using the sAMAccountName in Windows
  • bypassLoginInternalAuth is a boolean flag that prevents internal authorisation checks on login.
  • onFirstLogin is a function that is called the first time a user who doesn't already exist in the database has been authenticated. Here you can define two things:
    • how the User and its UserAttributes will be created from the token after the user has been authenticated, using the createUser function
    • which user permissions are allocated, using createUserPermissions
  • onLoginSuccess is a function that is invoked on a successful LDAP login; for example, it allows you to insert a user into the database when it exists in LDAP but not yet in your application's database.
  • useTLS is a boolean value indicating whether or not to use TLS encryption on the connection to the remote LDAP server.

For more information about the various authentication types, see the Authentication overview.

genesisPassword

The genesisPassword authenticator defines the configuration for validating user accounts that are stored locally in the application database.

passwordRetry

The passwordRetry function has been deprecated in favour of the retry function within the genesisPassword configuration.

validation

The validation function enables password validation, and is used to set the variables relating to this validation.

The following variables can be used to configure the application's password validation; these can only be used when type is either AuthType.INTERNAL or AuthType.HYBRID.

  • enabled is the key configuration variable; you must set this to true in order for the rest of the validation configuration to take effect.

  • passwordSalt defines a system-specific salt to be added to your password hashes. This is a security measure that ensures that the same combination of username and password on different applications built on the Genesis low-code platform are stored as different hashes. Default: empty string indicating no additional salting.

  • passwordStrength can be called to set a range of configuration variables. These enable you to specify in detail the mandatory characteristics for the password.

    • minimumLength specifies the minimum length of password. If null or undefined, this assumes there is no minimum limit. Default: null.
    • maximumLength specifies the maximum length of password. If null or undefined, this assumes there is no maximum limit. Default: null.
    • minDigits specifies the minimum number of numeric digits required in a password. If null or undefined, this assumes there is no minimum limit. Default: null.
    • maxRepeatCharacters specifies the maximum number of the same characters across an entire password. This does not just include consecutive repeat characters, which is controlled by the repeatCharacterRestrictSize variable, below. If null or undefined, this assumes there is no maximum limit. Default: null.
    • minUppercaseCharacters specifies the minimum number of upper-case characters in a password. If null or undefined, this assumes there is no minimum limit. Default: null.
    • minLowercaseCharacters specifies the minimum number of lower-case characters in a password. If null or undefined, this assumes there is no minimum limit. Default: null.
    • minNonAlphaNumericCharacters specifies the minimum number of non-alphanumeric characters, such as punctuation and other special characters. If null or undefined, this assumes there is no minimum limit. Default: null.
    • restrictWhitespace specifies if whitespace characters are prevented from being used in passwords. Default: true.
    • restrictAlphaSequences specifies if alphabetical sequences in passwords (e.g. abcdefg) are restricted. Sequences greater than or equal to five characters won't be permitted if this is true. Default: false.
    • restrictQWERTY specifies if QWERTY sequences in passwords (e.g. qwertyuiop) are restricted. Sequences greater or equal to five characters won't be permitted if this is true. Default: true.
    • restrictNumericalSequences specifies if numeric sequences in passwords (e.g. 123456) are restricted. Sequences greater or equal to five numbers won't be allowed if active. Default: true.
    • illegalCharacters specifies which characters are not permitted in user passwords. Default: empty.
    • historicalCheck specifies how many previous passwords to check against, in order to prevent password re-use. If null or undefined, no historical check is performed. Default: null.
    • restrictPassword specifies if the password should differ from a list of the worst passwords stored within the application. Default: false.
    • restrictDictionarySubstring specifies if any dictionary word of four or more characters can be included in a password (either forwards or backwards). Default: false.
    • restrictUserName specifies if the user's username is restricted as part of their password. Default: false.
    • repeatCharacterRestrictSize specifies the number of consecutive repeated characters that make a password restricted. If null or undefined, this assumes there is no limit. Default: null.
    • passwordExpiryDays specifies how many days before a password expires. If null or undefined, this assumes there is no limit. Default: null.
    • passwordExpiryNotificationDays specifies how many days before password expiry a user is notified. If null or undefined, the user is not notified in advance of their password expiry. Default: null.

retry

The retry function enables you to configure settings for limiting the rate at which a user can retry passwords. You can set the following variables:

  • maxAttempts specifies the maximum number of attempts allowed if a user enters a wrong password. Default: 3 attempts.
  • waitTimeMins specifies the time to wait in minutes when the maximum number of incorrect attempts is reached before allowing a user to try again. Default: 5 minutes.

User login attempts are stored in the USER_LOGIN_ATTEMPT table. If a user exceeds the allowed limit of password entry attempts, the system updates the corresponding record in the USER_LOGIN_ATTEMPT table, and locks the user.

To assist users who have exceeded their limit of password retries, an administrator can delete or amend the relevant record(s) in the USER_LOGIN_ATTEMPT table. The user can then try to login again.

selfServiceReset

The selfServiceReset function enables the self-service reset workflow for users. In this, users authenticated with the internal auth type can request an email to reset their password. For this workflow, you must have Genesis Notify configured with a working email gateway. When a user requests a reset, an email with a link to a password reset page is sent to their configured email address. This link is valid for a preconfigured timeout.

note

In the interest of security, this response will always receive an ACK, even if there is a problem in identifying the user or email address. In the case of a problem with the request, details will be provided in the auth manager log file.

The selfServiceReset function has the following options:

  • timeoutInMinutes - the time in minutes for which a reset link remains valid
  • coolDownInMinutes - the time in minutes before the next password reset can be made
  • notifyTopic - the email topic in Genesis Notify to be used
  • redirectUrl - the url that will direct the user to the web page containing the form used for them to input their new password using the token provided in the email notification.

This is normally set to https://$HOSTNAME/login/reset-password

  • acceptClientUrl - boolean flag; if true, the reset will use the client-provided reset url
warning

You can set acceptClientUrl to true in a development environment. For security, always set it to false in all other environments. Always.

resetMessage

The resetMessage function enables your application's users to configure the email sent when a reset is requested. It has the following options:

  • subject the subject line of the email
  • body the body of the email

Both the subject and the body support templating. Values surrounded by double curly braces {{ }} will be replaced when the email is sent. The following values are available:

  • RESET_URL the reset url
  • TIMEOUT the time the url is valid for
  • USER the user record, properties on this record should be accessed using lowerCamelCase, e.g. {{ USER.firstName }}
  • any system definition or environment variable available

example:

authentication {
genesisPassword {
selfServiceReset {
timeoutInMinutes = 20
notifyTopic = "smtpEmail"
redirectUrl = "https://genesis.global/login/password-reset"
}
}
}

mfa

The mfa function enables you to configure Multi-factor Authentication (MFA). From within the mfa function, you can choose between different implementations of MFA providers.

qrCode

This method of MFA generates a qrCode that can be imported into apps such as Google and Microsfoft authenticator; the code generates a one-time-only time-based password to use as multi-factor codes to login. This block exposes the following configuration items:

  • codePeriodSeconds specifies how many seconds a Time-based One-time Password (TOTP) remains valid. Default: 30 seconds.
  • codePeriodDiscrepancy specifies the allowed discrepancy to the TOTP. 1 would mean a single block of each codePeriodSeconds either side of the time window. Default: 1.
  • codeDigits specifies the number of digits used in the TOTP. Default: 6 digits.
  • hashingAlgorithm specifies the Hashing Algorithm to use. Available choices are: HashingFunction.SHA1, HashingFunction.SHA256 or HashingFunction.SHA512. Default: HashingFunction.SHA1.
  • issuer specifies a reference to the organisation or entity issuing the MFA. Default: Genesis.
  • label specifies a label for the MFA. This is typically an email address of the issuing entity or organisation. Default: genesis.global.
  • confirmWaitPeriodSecs specifies the time period in seconds before a secret has to be confirmed. Default: 300 seconds.
  • secretEncryptKey specifies the key that is used to encrypt Secrets in the database. If this is null or undefined, Secrets will not be encrypted in the database. Default: null.
  • usernameTableLookUpSalt specifies the salt with which a username is hashed when stored in the database with the above Secret. If this is null or undefined, the username will not be hashed in the database. Default: null.

notify

This method of MFA generates a one-time login link that is sent via the Genesis Notify module.

Each time a login is unsuccessful, a new one-time link is generated, using a temporary code with a short-timed expiry.

When login is successful using a temporary code, an active code is generated with the configured expiry. This can either be stored or saved as a cookie, preventing the need for the user to perform a second-factor authentication again until it has expired.

This block exposes the following configuration items:

  • loginUrl specifies the base URL to open in the one-time login link.
  • tempCodeExpiryDuration specifies a duration for temporary generated codes. Default is 15 minutes.
  • activeCodeExpiryDuration specifies a duration for active generated codes. Default is 30 days.
  • notifyTopic is the topic to publish to the notify module on. Default is 'MFA'.
  • messageHeader is the header of the resulting message.
  • messageBody is the body of the resulting message.

loginAck

The loginAck function enables you to define additional values to be sent back to the client as part of the LOGIN_ACK message. When you call the loginAck function, you have to supply a table or view as a parameter.

The following functions will be invoked on this table or view:

  • The loadRecord within the loginAck function loads a single record from the previously supplied table or view.
  • The fields function within the loginAck function specifies which additional fields should be sent back to the client as part of the LOGIN_ACK message.
  • The customLoginAck function enables you to modify the list of permissions, profiles and user preferences returned to the client as part of the LOGIN_ACK message. For this purpose, the User entity is provided as a parameter, as well as three properties:
    • permissions - a mutable list containing all the right codes associated with the user. Given its mutability, codes can be added or removed.
    • profiles - a mutable list containing all the profiles associated with the user. Given its mutability, profiles can be added or removed.
    • userPreferences - a GenesisSet object containing additional fields provided as part of the loginAck function. This GenesisSet can be modified to provide additional fields or remove existing ones.

Here is an example configuration:

import global.genesis.auth.manager.AuthType
import global.genesis.auth.manager.data.HashingFunction
import global.genesis.auth.manager.security.sso.jwt.NewUserMode
import global.genesis.db.entity.DbEntity
import global.genesis.dictionary.pal.view.IndexedDataStructure
import global.genesis.gen.config.tables.USER_ATTRIBUTES.ACCESS_TYPE
import global.genesis.gen.config.tables.USER_ATTRIBUTES.ADDRESS_LINE1
import global.genesis.gen.config.tables.USER_ATTRIBUTES.USER_TYPE

security {
sessionTimeoutMins = 30
expiryCheckMins = 5
maxSimultaneousUserLogins = 0

authentication {
type = AuthType.LDAP
ldap {
connection {
url = "localhost"
port = 389
searchBase {
searchBase("ou=temp,dc=temp")
}
userGroups {
}
userPrefix = ""
bindDn = null
bindPassword = null
userIdType = "cn"
}
}

genesisPassword {
validation {
enabled = true
passwordSalt = ""
passwordStrength {
minimumLength = null
maximumLength = null
minDigits = null
maxRepeatCharacters = null
minUppercaseCharacters = null
minLowercaseCharacters = null
minNonAlphaNumericCharacters = null
restrictWhiteSpace = true
restrictAlphaSequences = false
restrictQWERTY = true
restrictNumericalSequences = true
illegalCharacters = "\$£^"
historicalCheck = 0
restrictDictionarySubstring = false
restrictUserName = false
repeatCharacterRestrictSize = null
passwordExpiryDays = null
passwordExpiryNotificationDays = null
}
}

retry {
maxAttempts = 3
waitTimeMins = 5
}
}
}

sso {
enabled = false
}

mfa {
codePeriodSeconds = 30
codePeriodDiscrepency = 1
codeDigits = 6
usernameTableLookUpSalt = null
secretEncryptKey = null
hashingAlgorithm = HashingFunction.SHA1
issuer = "Genesis"
label = "genesis.global"
confirmWaitPeriodSecs = 300
}

loginAck(USER_ATTRIBUTES) {
loadRecord { UserAttributes.byUserName(userName) }
fields {
USER_TYPE
ACCESS_TYPE withPrefix "USER"
ADDRESS_LINE1
}
}

customLoginAck { user ->
if(user.userName == "TestUser"){
permissions += listOf("TEST_USER_INSERT", "TEST_USER_AMEND", "TEST_USER_DELETE")
profiles += listOf("TEST_ADMIN")
userPreferences = userPreferences.apply {
setString("TEST_VALUE", "TEST")
}
}
}
}

Message flows

Security messages can be split into three categories.

  • Pre-authentication
  • Authentication
  • Post-authentication

All requests below are capable of returning an error with a code of INTERNAL_ERROR, which will be used as a last resort.


Pre-authentication

Pre-authentication messages can be sent by a client without the user being logged in. There are three messages that can be used without being logged in.

Self-service password reset

It is possible to initiate a self-service password message workflow, assuming it is configured appropriately.

The message to request a self-service password reset looks like this:

MESSAGE_TYPE = EVENT_SELF_SERVICE_PASSWORD_RESET DETAILS.USER_NAME = JohnWolf

It is also possible to provide a RETURN_URL field as part of the details block if the URL used by the back-end configuration is not suitable.

Once this event has been triggered, the password reset link will be sent through the appropriate channels (e.g. e-mail) and the password reset action can be triggered.

MESSAGE_TYPE = EVENT_PASSWORD_RESET_ACTION DETAILS.USER_NAME = JohnWolf DETAILS.RESET_TOKEN = 1329048120a0sdf DETAILS.NEW_PASSWORD = ******* DETAILS.INVALIDATE_ACTIVE_SESSIONS = true

In the example message above, you can see that:

  • the RESET_TOKEN field has the code provided to the user when the reset operation was requested
  • the NEW_PASSWORD field has the new password to be used for the user
  • the optional INVALIDATE_ACTIVE_SESSIONS field has been set to true, to log out any currently logged in sessions

Change password

The change password message is available whether the user is currently logged in or not. This is important, because the first time a user logs in, their newly created one-time password will be in a PASSWORD_EXPIRED state; this forces a "Change password" workflow before they can actually log in for the first time.

The message structure for a change password message looks like this:

MESSAGE_TYPE = EVENT_CHANGE_USER_PASSWORD DETAILS.USER_NAME = JohnWolf DETAILS.OLD_PASSWORD = ******* DETAILS.NEW_PASSWORD = *******

The naming convention for the fields is also self-explanatory.

Logout

A logout request can be triggered before a user has logged in, if limits have been set for a maximum number of user sessions. This message workflow enables you to terminate an existing active session so that a new session can be created.

A sample message would look like this:

MESSAGE_TYPE = EVENT_LOGOUT DETAILS.USER_NAME = JohnWolf DETAILS.SESSION_ID = *******


Authentication

The password is provided in plain text, as it is expected that you will secure the connection using TLS.

Login request

MESSAGE_TYPE = EVENT_LOGIN_AUTH DETAILS.USER_NAME = JohnWolf DETAILS.PASSWORD = ******

Login response

If successful, a message could look like this:

MESSAGE_TYPE = EVENT_LOGIN_AUTH_ACK SESSION_AUTH_TOKEN = ******** REFRESH_AUTH_TOKEN = ******** SESSION_ID = c4eb5f62-2d11-4028-98cb-018ff45d7035 USER_NAME = JohnWolf DETAILS.HEARTBEAT_INTERVAL_SECONDS = 30 DETAILS.SESSION_TIMEOUT_MINS = 20 DETAILS.REFRESH_TOKEN_EXPIRATION_MINS = 7200 DETAILS.FAILED_LOGIN_ATTEMPTS = 0 DETAILS.REJECTED_LOGIN_ATTEMPTS = 0 DETAILS.LAST_LOGIN_DATE_TIME = 2024-01-25 15:48:33.413 (1706197713413) DETAILS.DAYS_TO_PASSWORD_EXPIRY = 730 DETAILS.NOTIFY_EXPIRY = 8 DETAILS.MFA_CODE = null DETAILS.MFA_CODE_EXPIRY_MINS = null DETAILS.SYSTEM.DATE = Thu Jan 25 15:48:33 UTC 2024 PERMISSION[0] = AMEND_PROFILE PERMISSION[1] = AMEND_USER PERMISSION[2] = CHANGE_PWD PERMISSION[3] = DELETE_PROFILE PERMISSION[4] = DELETE_USER PERMISSION[5] = DISABLE_USER PERMISSION[6] = ENABLE_USER PERMISSION[7] = EXPIRE_PWD PERMISSION[8] = INSERT_PROFILE PERMISSION[9] = INSERT_USER PERMISSION[10] = MFA_CONFIRM PERMISSION[11] = MFA_CREATE PERMISSION[12] = MFA_DISABLE PERMISSION[13] = MFA_ENABLE PROFILE[0] = ADMIN PROFILE[1] = USER_ADMIN

If there is a problem, the server returns the standard error set with CODE/TEXT details and the error code LOGIN_AUTH_NACK. The following error codes can be provided:

  • UNKNOWN_ACCOUNT - User is unknown
  • MAX_ACTIVE_SESSIONS_REACHED - Maximum number of sessions reached.
  • INCORRECT_CREDENTIALS - User/password combination is invalid
  • LOCKED_ACCOUNT - Account is locked and needs to be re-activated by administrator
  • PASSWORD_EXPIRED - Password must be changed
  • LOGIN_FAIL - Generic error code

Password change

As explained in the previous section, if the response for the login attempt is PASSWORD_EXPIRED, then the GUI can allow the user to change the password - provided they know their existing password.

Change request

MESSAGE_TYPE = EVENT_CHANGE_USER_PASSWORD DETAILS.USER_NAME = JohnWolf DETAILS.OLD_PASSWORD = ****** DETAILS.NEW_PASSWORD = ******

Change response

If successful:

MESSAGE_TYPE = EVENT_CHANGE_USER_PASSWORD_ACK

If there's a problem, you will receive a standard error set with type CHANGE_USER_PASSWORD_NACK.

The error codes that can be returned are currently:

  • TOO_SHORT - password length too short.
  • TOO_LONG - password length too long.
  • INSUFFICIENT_CHARACTERS - covers a few cases, so text field may be required, used for things like no digits provided when 1 digit is required.
  • ILLEGAL_MATCH - covers a few cases so text field may be required, used for things like repeating characters in password.
  • ILLEGAL_WHITESPACE - if password contains white space.
  • INSUFFICIENT_CHARACTERISTICS - can be provided if you have configured passwords to be successful only if a predetermined set of strength checks pass. Should be provided alongside "real" error codes.
  • ILLEGAL_SEQUENCE - Numeric/alphabetic sequence detected.

Logout

As explained in the previous section, if the response for the login attempt is MAX_ACTIVE_SESSIONS_REACHED, the server will reply with a list of active sessions; this gives the client the option to terminate one of them. In this scenario, the client would need to send a LOGOUT message with the specific SESSION_ID value of the session to terminate.

The response message for this scenario would look like this:

MESSAGE_TYPE = EVENT_LOGIN_AUTH_NACK
ERROR[0].@type = LoginError
ERROR[0].CODE = MAX_ACTIVE_SESSIONS_REACHED
ERROR[0].TEXT = Problem logging in
ERROR[0].STATUS_CODE = 403 Forbidden
ERROR[0].DETAILS.SESSION[0].SESSION_ID = abb8f6be-8009-4370-a474-3a0ded4dc2cf
ERROR[0].DETAILS.SESSION[0].HOST = host1
ERROR[0].DETAILS.SESSION[0].LAST_ACCESS_TIME = 2024-01-25 14:27:54.925 (1706192874925)
ERROR[0].DETAILS.SESSION[1].SESSION_ID = c8c04ba5-d450-48f7-a863-2a500fe0a4e7
ERROR[0].DETAILS.SESSION[1].HOST = host2
ERROR[0].DETAILS.SESSION[1].LAST_ACCESS_TIME = 2024-01-25 14:27:55.037 (1706192875037)
ERROR[0].DETAILS.SESSION[2].SESSION_ID = f6255056-952f-4985-b984-6e48c822c3a4
ERROR[0].DETAILS.SESSION[2].HOST = host3
ERROR[0].DETAILS.SESSION[2].LAST_ACCESS_TIME = 2024-01-25 14:27:55.235 (1706192875235)
ERROR[0].DETAILS.SESSION[3].SESSION_ID = 29220a26-0753-4408-9c28-9f00457e98ac
ERROR[0].DETAILS.SESSION[3].HOST = host4
ERROR[0].DETAILS.SESSION[3].LAST_ACCESS_TIME = 2024-01-25 14:27:55.438 (1706192875438)

A logout message to terminate the first session would look like this:

MESSAGE_TYPE = EVENT_LOGOUT
DETAILS.USER_NAME = JohnWolf
DETAILS.SESSION_ID = abb8f6be-8009-4370-a474-3a0ded4dc2cf

Post-authentication

Expire password

A password can expire in three different ways:

  • time-based
  • user-based
  • admin-based

The end result is always the same, the user will need to change the password on the next login, as their previous one has now expired.

Expire password request

The password expiry mechanism can be triggered by sending a message like this:

MESSAGE_TYPE = EVENT_EXPIRE_USER_PASSWORD DETAILS.USER_NAME = JohnWolf

It is common for administrators to help users recover their account credentials by expiring the current User record STATUS with a new one-time password; this action forces users to change it on their first login. In this case, the message can optionally receive a one-time password, as shown below:

MESSAGE_TYPE = EVENT_EXPIRE_USER_PASSWORD DETAILS.USER_NAME = JohnWolf DETAILS.PASSWORD = ******

Login details

If the client needs to re-receive the information provided by the login response for some reason (such as re-reading user preferences), it is possible to send an EVENT_LOGIN_DETAILS message to the server. The response will be equivalent to the response received by the login message, without actively logging in the system for a second time.

Login details request

MESSAGE_TYPE = EVENT_LOGIN_DETAILS DETAILS.SESSION_AUTH_TOKEN = *******

The SESSION_AUTH_TOKEN value is returned as part of the first login operation, so it is only possible to call EVENT_LOGIN_DETAILS after a successful login.

Login details reply

MESSAGE_TYPE = EVENT_LOGIN_DETAILS_ACK SESSION_AUTH_TOKEN = ******** REFRESH_AUTH_TOKEN = ******** SESSION_ID = c4eb5f62-2d11-4028-98cb-018ff45d7035 USER_NAME = JohnWolf DETAILS.HEARTBEAT_INTERVAL_SECONDS = 30 DETAILS.SESSION_TIMEOUT_MINS = 20 DETAILS.REFRESH_TOKEN_EXPIRATION_MINS = 7200 DETAILS.FAILED_LOGIN_ATTEMPTS = 0 DETAILS.REJECTED_LOGIN_ATTEMPTS = 0 DETAILS.LAST_LOGIN_DATE_TIME = 2024-01-25 15:48:33.413 (1706197713413) DETAILS.DAYS_TO_PASSWORD_EXPIRY = 730 DETAILS.NOTIFY_EXPIRY = 8 DETAILS.MFA_CODE = null DETAILS.MFA_CODE_EXPIRY_MINS = null DETAILS.SYSTEM.DATE = Thu Jan 25 15:48:33 UTC 2024 PERMISSION[0] = AMEND_PROFILE PERMISSION[1] = AMEND_USER PERMISSION[2] = CHANGE_PWD PERMISSION[3] = DELETE_PROFILE PERMISSION[4] = DELETE_USER PERMISSION[5] = DISABLE_USER PERMISSION[6] = ENABLE_USER PERMISSION[7] = EXPIRE_PWD PERMISSION[8] = INSERT_PROFILE PERMISSION[9] = INSERT_USER PERMISSION[10] = MFA_CONFIRM PERMISSION[11] = MFA_CREATE PERMISSION[12] = MFA_DISABLE PERMISSION[13] = MFA_ENABLE PROFILE[0] = ADMIN PROFILE[1] = USER_ADMIN

Rights polling

The GUI can receive rights from a process called GENESIS_AUTH_DATASERVER. The view ALL_USER_RIGHTS displays all users and codes. A logged-in user should automatically set the Filter expression to be USER_NAME=='xxx' to receive push updates to user privileges.

Working with heartbeats (non-web applications only)

If you are building a desktop application that does not connect to a web host, the server can be set up to receive heartbeat messages after the user has been authenticated (as defined in the interval setting on the ACK message).

In response to a heartbeat, the GUI receives a list of available services to connect to, along with their details; if the environment is configured not to use Consul as the cluster mode, this can include multiple hostnames.

If the back end of your non-web application is not using the Consul cluster mode, a client can use the services in this list in the order that they are defined. Existing connections can simply ignore the order changes, but in the event of failover or reconnection, the order must be adhered to.

Heartbeat request

MESSAGE_TYPE = EVENT_HEARTBEAT USER_NAME = JohnWolf

Heartbeat response

MESSAGE_TYPE = EVENT_HEARTBEAT_ACK DETAILS.SERVICE[0].NAME = SBL_EVENT_HANDLER DETAILS.SERVICE[0].ENCRYPTED = false DETAILS.SERVICE[0].HOST[0].NAME = genesisserv1 DETAILS.SERVICE[0].HOST[0].PORT = 9001 DETAILS.SERVICE[0].HOST[1].NAME = genesisserv2 DETAILS.SERVICE[0].HOST[1].PORT = 9001 DETAILS.SERVICE[1].NAME = SBL_DATA_SERVER DETAILS.SERVICE[1].ENCRYPTED = false DETAILS.SERVICE[1].HOST[0].NAME = genesisserv1 DETAILS.SERVICE[1].HOST[0].PORT = 9002 DETAILS.SERVICE[1].HOST[1].NAME = genesisserv2 DETAILS.SERVICE[1].HOST[1].PORT = 9002

Entity management

In the Genesis low-code platform, there are profiles, users and rights. A profile is a group of users, which can be permissioned. For example, you could have a SALES_TRADER group in which all users have the same permissions. In all cases where you specify either a right for a user/profile, or a user in a profile, the event represents what you want the entity to look like; i.e. if you amend a profile and don't supply a user that previously was part of that profile, then that user will be removed from that profile on the server.

Note the following:

  • The User STATUS field can be set to ENABLED, DISABLED or PASSWORD_EXPIRED. A User set up with PASSWORD_EXPIRED should prompt the user to enter a new password on next login.
  • The Profile STATUS field can be set to ENABLED or DISABLED.

Insert profile

Insert request

MESSAGE_TYPE = EVENT_INSERT_PROFILE USER_NAME = JohnWolf DETAILS.NAME = SALES_TRADERS DETAILS.DESCRIPTION = Sales Traders DETAILS.STATUS = ENABLED DETAILS.RIGHT_CODES[0].CODE = ORDEN DETAILS.RIGHT_CODES[1].CODE = ORDAM DETAILS.USER_NAMES[0].USER_NAME = JohnWolf DETAILS.USER_NAMES[1].USER_NAME = james

Insert response

MESSAGE_TYPE = EVENT_INSERT_PROFILE_ACK

Amend profile

Amend request

This amend request supplies a new set of details that changes the SALES_TRADERS profile (inserted in the previous example) in two ways:

  • There is no ORDAMright code.
  • There is no "james" user name.
    MESSAGE_TYPE = EVENT_AMEND_PROFILE
USER_NAME = JohnWolf
DETAILS.NAME = SALES_TRADERS
DETAILS.DESCRIPTION = Sales Traders
DETAILS.STATUS = ENABLED
DETAILS.RIGHT_CODES[0].CODE = ORDEN
DETAILS.USER_NAMES[0].USER_NAME = JohnWolf

Amend response

    MESSAGE_TYPE = EVENT_ACK

Delete profile

Delete request

MESSAGE_TYPE = EVENT_DELETE_PROFILE USER_NAME = JohnWolf DETAILS.NAME = SALES_TRADERS

Delete response

MESSAGE_TYPE = EVENT_ACK

Insert User

Insert request

MESSAGE_TYPE = EVENT_INSERT_USER USER_NAME = JohnDoe DETAILS.USER_NAME = JohnWolf DETAILS.FIRST_NAME = John DETAILS.LAST_NAME = Wolf DETAILS.EMAIL_ADDRESS = john.wolf@genesis.global DETAILS.STATUS = ENABLED DETAILS.USER_PROFILES[0] = USER_ADMIN

Insert response

MESSAGE_TYPE = EVENT_ACK

Amend user

In the example below, the logged-in user (in the second line) is JohnDoe, who is modifying the profile of JohnWolf to give him the last name: Smith.

Amend request

MESSAGE_TYPE = EVENT_AMEND_USER USER_NAME = JohnDoe DETAILS.USER_NAME = JohnWolf DETAILS.FIRST_NAME = John DETAILS.LAST_NAME = Smith DETAILS.EMAIL_ADDRESS = john.wolf@genesis.global DETAILS.STATUS = ENABLED DETAILS.USER_PROFILES[0] = USER_ADMIN

Amend response

MESSAGE_TYPE = EVENT_ACK

Delete user

Delete request

MESSAGE_TYPE = EVENT_DELETE_USER USER_NAME = JohnDoe DETAILS.USER_NAME = JohnWolf

Delete response

MESSAGE_TYPE = EVENT_ACK

Full permissions list

Most of the message workflows described on this page are permissioned on the basis of a set of default rights. These are provided in the form of a CSV file as part of the platform authentication distribution. Most permissions and their relationship to events have been explained in their own sections. For reference, here is the whole table:

CodeDescription
INSERT_PROFILEAdd a new Profile
INSERT_USERAdd a new User
AMEND_PROFILEAmend an existing Profile
AMEND_USERAmend an existing User
CHANGE_PWDChange another User's password
DELETE_PROFILEDelete a Profile
DELETE_USERDelete a User
DISABLE_USERDisable a User
ENABLE_USEREnable a User
EXPIRE_PWDExpire another User's password

A default Profile record named USER_ADMIN is also provided. This contains all the previous rights.

info

Users can change their own password as well as expire their own password (assuming they are logged in). However, it is only possible to change/expire another user's password if you have administrator rights.

Event auditing

Each authentication event is audited in one way or another, either using the automatic mechanism provided at the table definition level (e.g. PROFILE, PROFILE_RIGHT, PROFILE_USER, PASSWORD_RESET, USER and USER_ATTRIBUTES), or by providing custom tables with the audit information.

In the first case scenario, auditing works as it would do for any other Genesis table: AUDIT_EVENT_TYPE reflects the event message type (i.e. EVENT_INSERT_USER), AUDIT_EVENT_TEXT may contain a free text field provided by the user calling the event, AUDIT_EVENT_DATETIME is autogenerated with the current date and time the change happened and AUDIT_EVENT_USER corresponds to the user who triggered the event in question.

In the second case scenario, we have automatic events to log changes in USER_AUDIT and USER_ATTRIBUTES when a password expires. And we also have specific handling for USER_LOGIN audits. The USER_LOGIN_AUDIT table will contain entries for the following events: LOGIN, LOGOUT, SESSION_EXPIRED, REJECTED (only available if a maximum number of user sessions has been configured), FAILED_LOGIN, and FAILED_LOGOUT (if an incorrect session ID or user name has been provided).

Additionally, all USER_LOGIN audit events are logged to a file at INFO level in the following format:

[25 Jan 2024 16:31:18.823 12729 [dbCoroutinesContext-4 @coroutine#994] INFO global.genesis.auth.manager.controller.LoginAuditController - AuditLoginEvent: UserLoginAudit{serialVersionUID='1',userLoginAuditId={not-set}, userName=JohnDoe, authAction=LOGIN, ipAddress=/127.0.0.1, reason=, recordId={not-set}, timestamp={not-set}}]