Authorization Policy examples
This article presents example Authorization Policy configurations for some typical uses cases. For SSO Authorization Policy documentation, please refer to:
Manage authorization policies - SSO
These configuration examples have been tested with Ubisecure SSO 8.8.1.
Contents
User and method attributes
In a typical configuration, either user attributes (attributes from Ubisecure Directory, external LDAP directory or external SQL database) or method attributes (claims from external Identity Providers) are passed on to applications with the Authorization Policy configuration. Simple examples are shown below:
Group | Name | Value |
---|---|---|
eIDMUser | given_name | ${user['givenName']} |
FTN Users | given_name | ${method['urn:oid:1.2.246.575.1.14']} |
Azure Users | ${method['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress']} |
When external identities are mapped to Ubisecure identities (see Management UI Directory User Mappings - SSO and User driven federation - SSO), both user attributes and method attributes may be available. In this case, the method attributes can be accessed by using a local user group, typically eIDMUser, instead of a group configured for the Identity Provider. For example, name is taken form the local user directory and job title from an Azure AD claim as follows:
Group | Name | Value |
---|---|---|
eIDMUser | given_name | ${user['givenName']} |
eIDMUser | family_name | ${user['sn']} |
eIDMUser | job_title | ${method['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/title']} |
Single-value and multi-value attributes
By default, all attributes are processed as multi-value attributes. Attributes can be defined as single-value attributes on the main screen of the Authorization Policy configuration:
In JWT tokens, single-value attributes are passed as string values and multi-value attributes as string lists. Boolean and numeric values are converted to strings. Whenever an attribute is known to take only one value, it is recommended to define the attribute as a single-value attribute. Below, an example JWT is presented with a default configuration and with single-value attributes defined:
{ "sub": "ubisecure.demo@example.com", "iss": "https://login.ubidemo.com:8443/uas", "amr": [ "https://login.ubidemo.com:8443/uas/saml2/names/ac/password.2" ], "aud": [ "0baaf7ce-8df8-4cb9-9ecc-de9a6e00a792" ], "azp": "0baaf7ce-8df8-4cb9-9ecc-de9a6e00a792", "auth_time": 1640871824, "iat": 1640871827, "exp": 1640875426, "session_index": "_208fb80205c891f3ec45cf4e5cd0379e403c211e", "email": [ "ubisecure.demo@example.com" ], "family_name": [ "Demo" ], "given_name": [ "Ubisecure" ], "roles": [ "services/RoleRequester", "eIDM/eIDMMainUser" ], "surname": "Demo" }
{ "sub": "ubisecure.demo@example.com", "iss": "https://login.ubidemo.com:8443/uas", "amr": [ "https://login.ubidemo.com:8443/uas/saml2/names/ac/password.2" ], "aud": [ "0baaf7ce-8df8-4cb9-9ecc-de9a6e00a792" ], "azp": "0baaf7ce-8df8-4cb9-9ecc-de9a6e00a792", "auth_time": 1640871518, "iat": 1640871524, "exp": 1640875124, "session_index": "_af24c0650721e4795ee796a2e567779ad846144a", "email": "ubisecure.demo@example.com", "given_name": "Ubisecure", "roles": [ "services/RoleRequester", "eIDM/eIDMMainUser" ], "family_name": "Demo" }
String value operations
String value attributes can be modified by using Java EL statements with Java String methods. Information on Java String methods can be found, for example, at https://www.w3schools.com/java/java_ref_string.asp. Some configuration examples are presented below:
Name | Value | Example Data | Example Result |
---|---|---|---|
given_name | ${user['givenName'][0].toUpperCase()} | givenName=Michael | "MICHAEL" |
full_name | ${user['givenName'][0].concat(' ').concat(user['sn'][0])} | givenName=Michael, sn=Jones | "Michael Jones" |
is_employee | ${user['mail'][0].toLowerCase().endsWith('@ubisecure.com')} | mail=user.demo@customer.com | "false" |
email_domain | ${user['mail'][0].substring(user['mail'][0].indexOf('@')+1)} | mail=ubisecure.demo@example.com | "example.com" |
test_account | ${user['givenName'][0].toLowerCase().contains('application_test')} | givenName=Application_Test | "true" |
birthdate | ${method['urn:oid:1.2.246.21'][0].contains('-') ? "19".concat(method['urn:oid:1.2.246.21'][0].substring(4, 6)).concat("-").concat(method['urn:oid:1.2.246.21'][0].substring(2, 4)).concat("-").concat(method['urn:oid:1.2.246.21'][0].substring(0, 2)) : "20".concat(method['urn:oid:1.2.246.21'][0].substring(4, 6)).concat("-").concat(method['urn:oid:1.2.246.21'][0].substring(2, 4)).concat("-").concat(method['urn:oid:1.2.246.21'][0].substring(0, 2))} | 150990-304Y 100302A017X | 1990-09-15 2002-03-10 |
mobile | ${user['mobile'][0].startsWith('0') ? '+358'.concat(user['mobile'][0].substring(1)) : user['mobile'][0]} | 0401234567 +4422334456 | +358401234567 +4422334456 |
String values can also be modified by using regular expressions with the re:replace function, for example as follows:
Name | Value | Comment | Example Data | Example Result |
---|---|---|---|---|
given_name | ${re:replace(method['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/displayname'], ".*, ", "")} | Replace all characters until the first comma followed by a space, by a null string | Jones, Michael | "Michael" |
family_name | ${re:replace(method['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/displayname'], ", .*", "")} | Replace the comma and anything after that by a null string | Jones, Michael | "Jones" |
employee_id | ${re:replace(method['employee_id'], ".*-", "")} | Replace all characters until '-' by a null string | Operations-123456 | "123456" |
email_domain | ${re:replace(user['mail'][0], ".*@", "")} | Replace all characters until '@' by a null string | ubisecure.demo@example.com | "example.com" |
given_name | ${re:replace(method['name'], "^([^ ]+) (.+)$", "$1")} | Define anything until the first space as the 1st capturing group and the remaining characters as the 2nd group | Michael Jones | "Michael" |
family_name | ${re:replace(method['name'], "^([^ ]+) (.+)$", "$2")} | Define anything until the first space as the 1st capturing group and the remaining characters as the 2nd group | Michael Jones Michael De Jong | "Jones" "De Jong" |
given_name | ${re:replace(method['name'], "^(.*) (.+)$", "$1")} | Define anything until the last space as the 1st capturing group and the remaining characters as the 2nd group | Michael Jones Michael M Jones | "Michael" "Michael M" |
List value matching and filtering
Note: Ubisecure CustomerID SSO Adapter can also be used for filtering the roles, see Authorization configuration - CustomerID.
Typical claims presented as lists are users' role and group assignments. If there are a limited number of known groups or roles, and there is a need to filter out any other groups/roles, it is straightforward to use the contains function for filtering. This way the generic group/role names can also be mapped to application specific names when needed. Some examples are given below.
Name | Value | Comment | Example Data | Example Result |
---|---|---|---|---|
groups | ${user['memberOf'].contains('CN=SEAdmins,OU=abc,DC=example,DC=com') ? 'SEAdmins' : null} | Use CN instead of the whole Distinguished Name | CN=SEAdmins,OU=abc,DC=example,DC=com, CN=PrintUsers,OU=abc,DC=example,DC=com | ["SEAdmins", "PrintUsers"] |
groups | ${user['memberOf'].contains('CN=SEAdmins,OU=abc,DC=example,DC=com') ? 'Admin_Group' : null} | Map the group name to an application specific name, filter out all other groups | CN=SEAdmins,OU=abc,DC=example,DC=com, CN=PrintUsers,OU=abc,DC=example,DC=com | ["Admin_Group"] |
roles | ${eidm['roles'].contains('services/extranet/User') ? 'services/extranet/User' : null} | Filter out all but the application specific roles | SmartPlan/OrganizationMainUser, SmartPlan/OrganizationUser, services/extranet/Mainuser | ["services/extranet/Mainuser"] |
roles | ${eidm['roles'].contains('services/extranet/User') ? 'ExtranetUser' : null} ${eidm['roles'].contains('services/extranet/MainUser') ? 'ExtranetMainUser' : null} | Map role names to application specific roles, filter out all but the application specific roles | SmartPlan/OrganizationMainUser, SmartPlan/OrganizationUser, services/extranet/Mainuser | ["ExtranetMainuser"] |
If the groups or roles are not known (for example, defined by an external Identity Provider) or there can be a big or unlimited number of them (for example, roles with organization name as prefix), a more generic way for filtering is required. In this case, Java EL streams can be used for matching and filtering the string lists. For more detailed information, please refer to Java EL documentation: https://download.oracle.com/otndocs/jcp/el-3_0-fr-eval-spec/index.html. Some example configurations are presented below.
Name | Value | Comment | Example Data | Example Result |
---|---|---|---|---|
user_type | ${eidm['roles'].stream().anyMatch(r -> r.endsWith('OrganizationMainUser')).orElse(false) ? 'adminuser' : 'normaluser'} | User is adminuser if they have OrganizationMainUser role in any organization | SmartPlan/OrganizationMainUser, SmartPlan/OrganizationUser | "adminuser" |
is_admin | ${eidm['roles'].stream().anyMatch(r -> r.contains('OrganizationMainUser')).get()} | True / False based on OrganizationMainUser role in any organization | SmartPlan/OrganizationUser | "false" |
enduser_roles | ${eidm['roles'].stream().filter(r -> not r.contains('OrganizationMainUser')).toList()} | All roles excluding OrganizationMainUser roles | SmartPlan/OrganizationMainUser, SmartPlan/OrganizationUser | ["SmartPlan/OrganizationUser"] |
service_admin_roles | ${eidm['roles'].stream().filter(r -> r.toLowerCase().contains('mainuser')).filter(r -> not r.contains('OrganizationMainUser')).toList()} | All roles containing "mainuser" regardless of case, excluding "OrganizationMainUser" | SmartPlan/OrganizationMainUser, SmartPlan/OrganizationUser, extranet/Mainuser | ["extranet/Mainuser"] |
roles | ${eidm['roles'].stream().filter(r -> not (r.startsWith('Users/') or r.startsWith('eIDM/'))).toList()} | All roles excluding roles in organizations "Users" and "eIDM" | SmartPlan/OrganizationMainUser, SmartPlan/OrganizationUser, eIDM/eIDMMainUser, Users/VerifiedUser | ["SmartPlan/OrganizationMainUser", "SmartPlan/OrganizationUser"] |
nr_of_roles | ${eidm['roles'].stream().filter(r -> not (r.startsWith('Users/') or r.startsWith('eIDM/'))).toList().size()} | Number of roles, excluding roles in organizations "Users" and "eIDM" | SmartPlan/OrganizationMainUser, SmartPlan/OrganizationUser, eIDM/eIDMMainUser, Users/VerifiedUser | "2" |
roles | ${eidm['roles'].stream().sorted().toList()} | All roles sorted alphabetically | SmartPlan/OrganizationMainUser, SmartPlan/OrganizationUser, extranet/Mainuser | ["SmartPlan/OrganizationMainUser", "SmartPlan/OrganizationUser", "extranet/Mainuser"] |
roles | ${eidm['roles'].stream().sorted().substream(1).toList()} | All roles sorted alphabetically, then excluding the first one | SmartPlan/OrganizationMainUser, SmartPlan/OrganizationUser, extranet/Mainuser | ["SmartPlan/OrganizationUser", "extranet/Mainuser"] |
List value modifications
For modifying string values within the lists, a new list can be created with the Java split function. In the examples below, we use split("&") for converting a string to a list with one element. Here we assume that the data does not contain any '&' characters.
Name | Value | Comment | Example Data | Example Result |
---|---|---|---|---|
roles | ${eidm['roles'].stream().flatMap(r -> r.toLowerCase().split("&").stream()).toList()} | Convert all role names to lower case | SmartPlan/OrganizationMainUser, SmartPlan/OrganizationUser | ["smartplan/organizationmainuser", "smartplan/organizationuser"] |
roles | ${eidm['roles'].stream().flatMap(r -> r.substring(r.lastIndexOf('/')+1).split("&").stream()).toList()} | Exclude the path of role names | SmartPlan/OrganizationMainUser, SmartPlan/OrganizationUser | ["OrganizationMainUser", "OrganizationUser"] |
roles | ${eidm['roles'].stream().flatMap(r -> r.substring(r.lastIndexOf('/')+1).toLowerCase().split("&").stream()).sorted().distinct().toList()} | Exclude the path of role names, convert to lower case, sort and remove duplicates | SmartPlan/OrganizationMainUser, SmartPlan/OrganizationUser, Citygroup/OrganizationUser | ["organizationmainuser", "organizationuser"] |
groups | ${user['memberOf'].stream().flatMap(r -> r.substring(3, r.indexOf(',')).split("&").stream()).toList()} | Extract CN from the DN strings: take the characters from the 4th position until the next comma | CN=SEAdmins,OU=abc,DC=example,DC=com, CN=PrintUsers,OU=abc,DC=example,DC=com | ["SEAdmins", "PrintUsers"] |
groups | ${user['ubiloginMemberOf'].stream().flatMap(r -> r.split(",").stream()).filter(r -> r.contains('CN=') and not r.contains('CN=Ubilogin')).toList()} | Extract CN from the DN strings, exclude "CN=Ubilogin" | CN=Test Group,OU=Test,CN=Ubilogin,DC=login,DC=smartplan,DC=com, CN=Test Group 2,OU=Test,CN=Ubilogin,DC=login,DC=smartplan,DC=com | ["CN=Test Group", "CN=Test Group 2"] |
Hashing and encoding examples
The following examples show hashing and encoding. Note data type requirements for hashing and encoding functions.
Name | Value | Comment | Example Data | Example Result |
---|---|---|---|---|
${attribute.name("email").values(sha256.text('exampleAppString'.concat(user.telephoneNumber[0])).toString().concat('@example.com'))} | Generate a virtual email address formed by hashing user attributes. Here a hash is a made of application specific string concatenated together a custom userId that is stored in user.telephoneNumber. The email domain is added to the resulting string. | 123456 | 794f037115472dd0831df46a01e300a970507b6632a493915c8e1e59fa1a0d47@example.com | |
uidbase64 | ${base64:encode(utf8:bytes(user['uid'][0]))} | Base64 encode user.uid . Because base64:encode() function requires a bytearray as input parameter, and user.uid is String, it needs to be converted to bytearray using utf8:bytes() . | jsmith | anNtaXRo |
Role Based Access Control
The Ubisecure SSO Authorization Policies can be used for implementing Role Based Access Control (RBAC). With RBAC, only users having application specific role(s) assigned, are allowed to access the application. Other users see an error message which is configurable for each application.
Note: RBAC can be enforced either by Ubisecure SSO or by the application user is trying to access. When access is denied, it may be more straightforward to configure the application to give user-friendly instructions for requesting access rights.
To enforce RBAC in Ubisecure SSO, define a required attribute on the main screen of the Authorization Policy configuration, for example "extranet-access":
Then use the "Attributes" tab to define the required attribute, for example as follows:
Name | Value | Example Data | Example Result |
---|---|---|---|
extranet-access | ${eidm['roles'].contains('services/extranet/User') ? 'true' : null} ${eidm['roles'].contains('services/extranet/MainUser') ? 'true' : null} | SmartPlan/OrganizationMainUser, SmartPlan/OrganizationUser, services/extranet/Mainuser SmartPlan/OrganizationMainUser, SmartPlan/OrganizationUser | "true" not set |
For instructions on defining application specific error messages and other user interface properties, please refer to:
Login user interface customization files - SSO
Show different help text depending on the application used