EITCO User Management Service

The User Service provides a user administration designed for different applications and systems. It is a database-based user administration.

User directories can also be connected via the Lightweight Directory Access Protocol (LDAP). Such a connection supports read synchronization regarding the user data of the user directory. Reading means that the user service reads the user data from the user directory and creates or modifies the corresponding user service user data for this purpose, but conversely does not write any data to the user directory.

Closely related to user administration is the issue of authentication and authorization. In this respect, the user service is a supporting service that offers functionalities such as storing the password in encrypted form or managing roles and rights.

For authentication and authorization, the Spring security framework would have to be used in addition to the user service, if necessary in conjunction with an authentication component. The concrete authentication and authorization scenario depends on the respective system context. Custom developments can also be integrated for authentication. As a note, it should be mentioned here that an adequate ACL implementation for access protection of concrete application objects is offered neither by the user service nor by Spring Security. This would require further solutions.

Basic functions

The user administration supports the creation, modification and deletion of:

  • users

  • user groups

  • roles

  • tokens

  • privileges

A token (or authority) is a loose definition of a right. By assigning such a loose definition of a right to a role, the role is granted a privilege. By means of a token-to-role assignment, a privilege can in turn also be withdrawn from the corresponding users.

Data model

The following figure outlines the relationship between users, roles, etc. based on the database tables of the user service.

diagram
Figure 1. Data model of the User service

Overview of the database tables

Table 1. Database tables
table purpose sample data set

usrv_user

contains the user records

-

usrv_user_extra_meta

contains the metadata of freely definable user data fields that supplement the fields of the usrv_user table

additional field date of birth: (1, DATE OF BIRTH, DATETIME, 0, "This is the…​")

usrv_user_extra

contains the values of the freely definable user data fields

String value record: (1, 1, 5, 1, NULL, NULL, NULL, "foo value")

usrv_group

Contains the user group records

-

usrv_group_extra_meta

contains the metadata of user-definable group data fields that complement the fields of the usrv_group table

-

usrv_group_extra

contains the values of the freely definable user group data fields

-

usrv_group_to_group

contains the records of the user group hierarchy

-

usrv_user_to_group

contains the user group mapping records

-

usrv_role

contains the role records. The fields of such a record are listed in the following table

-

usrv_user_to_role

contains the user role assignment records

-

usrv_group_to_role

contains the user group role mapping records

-

sec_token

contains the token or rights data records

-

sec_privilege

contains the role token mapping records

-

Integration of the user service artifacts

The user service can be used as a standalone component in the sense of a microservice, or it can be integrated directly into the context of the actual application.

Direct integration into the context of the actual application requires that the integration takes place within a Spring Boot context.

Deployment as a microservice, on the other hand, is done in a distributed microservice environment using the components recommended by Spring Cloud. The microservice itself is a Spring boot application (server). To use the microservice within a Spring Cloud infrastructure, the user service provides a Java-based microservice client component to be used by the clients of the microservice. By using this client component, load balancing etc. are automatically provided. Like the direct integration, the integration of the client component requires that the integration takes place within a Spring boot context.

Both direct integration and integration as a microservice client provide the same application programming interface (API). It should be noted, however, that microservice calls cannot be included in a transaction context that is open on the caller’s side.

Dependencies

Integration of the Microservice client

Maven
<dependency>
  <groupId>de.eitco.commons</groupId>
  <artifactId>cmn-user-management-client-spring-boot-starter</artifactId>
  <version>7.0.0</version>
</dependency>
Gradle
compile 'de.eitco.commons:cmn-user-management-client-spring-boot-starter:7.0.0'

Direct integration (embedded)

Maven
<dependency>
  <groupId>de.eitco.commons</groupId>
  <artifactId>cmn-user-management-embedded-spring-boot-starter</artifactId>
  <version>7.0.0</version>
</dependency>
Gradle
compile 'de.eitco.commons:cmn-user-management-embedded-spring-boot-starter:7.0.0'
Gradle-Dependency

User service configurations

Integration of the Microservice client

The following is an example of the user service configuration using a Spring YAML configuration file.

User service configuration
spring:
 # The configuration of a datasource is not user service specific; it should only be pointed out that
 # that the user service requires a datasource.
 datasource:
    url: jdbc:postgresql://localhost:5432/postgres?currentSchema=foo
    username: foouser
    password: foopassword
    driver-class-name: org.postgresql.Driver

user-service:

  group:
    # a user group is to be typified; possible types can be
    # deposited comma-separated at this point
    #
    # If the type "Standard" is specified, no type must be specified when saving a user group record.
    # In such a case the type "Standard" will be set automatically.
    #
    types: Standard, OU, Job
    #
    # A user group can have freely definable attributes assigned to it; such
    # definitions can be made here in a semicolon-separated way.
    # The values of a definition are comma-separated.
    # The first value specifies the attribute name, the second the type and
    # the third, whether the attribute value is a mandatory value.
    # Possible types are: boolean, decimal, long, datetime, string, blob;
    #
    extra-fields: selectable,boolean,false;fooDate,datetime,false;

  user:
    # Specify the superuser based on a comma-separated list of user names; if the value -dbFlag- is entered here,
    # then the superuser will be determined by a flag in the
    # user database table
    #
    superuser: -dbFlag-
    #
    # A user can be assigned freely definable attributes.
    # further description see above under user-service.group.extra-fields
    extra-fields: fooDecimal,decimal,false;fooString1,string,false;fooString2,string,false

  auth:
    # The user service supports the integration of Spring security. With the following
    # configuration you can specify the implementation of the Spring Spring-Security-Userdetail-Interfaces.
    # (Default is de.eitco.commons.user.management.common.auth.UserDetailsDB)
    #
    user-details-path: de.eitco.commons.user.management.common.auth.UserDetailsDB
    #
    # The following configuration specifies which key is used to identify the user
    # to whom the request is assigned via request token is to be
    # determined by the user service. The request token can contain the user name or the external
    # user ID. Possible configuration values are NAME or EXTERNAL_ID (default is NAME).
    #
    user-identification-field: NAME

Auditing

The User Management Service supports auditing of changes made to the user management data. The auditing support must be activated by setting user-service.audit-support-enabled=true in the service’s configuration. Auditing can then be enabled by creating audit rules for the tables to be audited. For example, to audit changes made to users an audit rule with tableName=usrv_user must be created. The rule’s settings for deleteUserIdField, deleteUserIdSetting, updateUserIdField and updateUserIdSetting can be left empty to use the default values. The documentation of the audit service contains more information on how to create audit rules.

API Overview

The user service contains so-called managers in the form of interfaces and their implementations for user administration. The central manager class or interface is de.eitco.commons.user.management.common.manager.CrudManager. By means of this interface the methods for creating, reading, changing and deleting records are declared (CRUD = Create, Read, Update, Delete). The following CRUD methods are declared in it:

  • T getEntity(Long entityId) - read a record based on the unique record ID.

  • QueryResult<T> listEntities(ServiceQuery query) - read records based on filtering, if any, by means of a query

  • T saveEntity(T entity) - create and modify a record

  • void deleteEntity(Long entityId) - delete a record based on the unique record ID

Other managers are assignment managers to assign the corresponding entities. For example, assigning a user to a user group. There is also the AuthManager which is described in the API Security chapter.

diagram

To manage the data using the CRUD Manager, model classes are declared in the form of POJOs in each case. These are:

  • de.eitco.commons.user.management.common.model.UserGroup

  • de.eitco.commons.user.management.common.model.UserRole

  • de.eitco.commons.user.management.common.model.SecToken

  • de.eitco.commons.user.management.common.model.SecPrivilege

  • de.eitco.commons.user.management.common.model.User

Create, modify and delete a user

Create a user
@Autowired
UserManager userMgr;
User user = new User();
user.setUsername("user@foo.foo");
user = userMgr.saveEntity(user);
Modify a user
@Autowired
UserManager userMgr;
// Read user record by means of e.g. getEntityByUsername()
User user = userMgr.getEntityByUsername("user@foo.foo");
// change email address
user.setEmail("user@foo.foo");
user = userMgr.saveEntity(user);
Delete a user
@Autowired
UserManager userMgr;
// Delete existing user by system ID
userMgr.deleteEntity(user.getId());

Create, modify and delete a role, group, token, privilege

Creating, changing and deleting roles, groups, tokens and privileges is done in the same way as described in the previous section for users. For this, of course, the respective manager and the corresponding POJO must be used. In the case of roles, for example, this would be the UserRole manager and the UserRole POJO.

Assignment management

For assignment management, the assignment managers are used. These are:

  • UserToUserGroupManager - manager to assign users to groups.

  • UserRoleToUserManager - manager to assign roles to users.

  • UserRoleToGroupManager - manager to assign roles to groups.

  • UserGroupTreeManager - manager to assign groups to groups (in the sense of a tree or hierarchy).

  • (SecPrivilegeManager - The SecPrivilegeManager is to be used for the assignment of tokens to roles).

The following code examples show the four essential methods (add, remove, list a and list b) of the UserToUserGroupManager, UserRoleToUserManager and UserRoleToGroupManager based on the UserToUserGroupManager.

Add user to group
@Autowired
UserToUserGroupManager userToGroupMgr;
// such assignment is done by user id and group id
userToGroupMgr.addUserToGroup(userId, groupId);
Remove user from group
@Autowired
UserToUserGroupManager userToGroupMgr;
// remove user from group is done using user id and group id
userToGroupMgr.removeUserFromGroup(userId, groupId);
List user of a group
@Autowired
UserToUserGroupManager userToGroupMgr;
// Note: method accesses the database directly; so no cache usage.
List<User> userToGroupMgr.listUsersOfGroup(Long groupId);
List groups of a user
@Autowired
UserToUserGroupManager userToGroupMgr;
// Note: method accesses the database directly; so no cache usage
List<UserGroup> userToGroupMgr.listGroupsOfUser(Long userId);

Create and modify group hierarchies

The creation and modification of group hierarchies are supported by the methods of the UserGroupToGroupManager. Following are code examples for this.

Add a subgroup to a group
@Autowired
UserGroupToGroupManager userGroupToGroupMgr;
// add a subgroup to a group
groupToGroupMgr.addSubGroup(groupId, subGroupId);
Remove a subgroup from a group
@Autowired
UserGroupToGroupManager userGroupToGroupMgr;
// remove a subgroup from a group
groupToGroupMgr.removeSubGroup(groupId, subGroupId);
List subgroups/supergroups of a group
@Autowired
UserGroupToGroupManager userGroupToGroupMgr;
// list the direct subgroups of a group
List<UserGroup> directSubGroupList = groupToGroupMgr.getDirectSubGroups(Long groupId);

// list the direct subgroups of a group
List<UserGroup> directSuperGroupList = groupToGroupMgr.getDirectSuperGroups(Long groupId);

Role/privilege inheritance through the group hierarchy

Queries using service query

Using a service query implementation, simple database queries can be created and executed, which are usually sufficient for entity management. A service query is based on a root entity (user, group, role, privilege or token).

In a concrete query formulation, the occurring select, filter and sort attributes are to be marked with the corresponding entity prefix (see also examples below). The following prefixes are defined:

Entity Prefix

Group

g

GroupExtra (Extension of the Group entity - freely definable attributes)

ge

Privilege

p

Role

r

Token

t

User

u

UserExtra (Extension of the User entity - freely definable attributes)

ue

In the following example the u.username identifies the username attribute of the User entity.

Query user
@Autowired
UserManager userMgr;
// Create ServiceQuery instance
ServiceQuery serviceQuery = userMgr.newQuery();

// RETRIEVE ALL USERS WITH ALL DIRECT AND FREELY DEFINABLE ATTRIBUTES

// call the listEntities method based on the created ServiceQuery instance;
// in the simple case, i.e. without specifying any select, filter or sort attributes
// all users with all direct and freely definable attributes are returned; in
// such a case, null could also be passed instead of the ServiceQuery instance
QueryResult<User> userResult = userMgr.listEntities(serviceQuery);

// The QueryResult instance contains the result list.
List<User> userList = userResult.getList();

// SELECT SPECIFIC ATTRIBUTES
serviceQuery .addSelect("u.username", "ue.foo", "r.name");

// FILTER BY SPECIFIC ATTRIBUTES
serviceQuery.addFilterEq("u.username", "mustermann"); // exact match filter
serviceQuery.addFilterEq("u.username", "mus", ServiceQuery.TXT_MATCH_STYLE_STARTS_WITH) // starts with match filter
serviceQuery.addFilterEq("u.username", "uster", ServiceQuery.TXT_MATCH_STYLE_SUBSTRING) // substring match filter
serviceQuery.addFilterEq("ue.fooDate", myDate); // equals filter
serviceQuery.addFilterEq("ue.fooLong", 1L); // equals filter
serviceQuery.addToOrFilterEq("u.firstname", "Erika");
serviceQuery.addToOrFilterEq("u.firstname", "Max") // exact match Erika or Max
serviceQuery.addFilterIn("ue.fooLong", myLongCollection); // in condition
etc.

// SORT BY SPECIFIC ATTRIBUTES
serviceQuery.addOrderBy("u.username", ServiceQuery.SORT_DESC); // sort in descending order
etc.

// START-ROW, END-ROW and COUNT
serviceQuery.setStartRow(0); // "start row" included
serviceQuery.setEndRow(10); // "end row" not included (compare Java substring method)
serviceQuery.withCount(); // in addition to the partial hit list "start/end" the actual total hit count
                             // of the formulated query, which is then supplied in the result when calling withCount

The above examples for querying users also apply accordingly to Role, Group, Privilege and Token.

Create, assign and modify events

User Service Events serve to implement their own logic before, during or after actions of the User Service. Three types of events have been defined for this purpose:

  • Before - Before an action of the user service

  • On - During an action of the User Service

  • After - After an action of the User Service.

Example of of an event call
@Async
@EventListener
public void handleEvent(BeforeGroupCreateEvent event) {
// do something
}

With the help of the Async annotation, the method Asynchronous is called. By default, the methods are called synchronously.

NOTE

At this stage, all contexts are lost when the method is called using the Async annotation (e.g. tenant context etc.). To be able to call an event, the annotation EventListener must always be specified above the method. The desired logic can then be implemented within the method.

API Lookup / Cache

The user service provides a lookup implementation. It can be used for queries whether a user is a member of a certain group, or whether a user is assigned a certain role, etc. In contrast to the queries of the manager classes, which access the database directly, the queries via lookup implementation are based on a cache implementation.

API methods of AuthLookup implementation
//---------------------------------------------------------------------
// Subsequent queries whether a user is superuser, is in role x, etc.
//---------------------------------------------------------------------
AuthLookup.isSuperuser();
AuthLookup.isSuperuser(String username);

AuthLookup.isInRole(String roleName);
AuthLookup.isInRole(String username, String roleName);

AuthLookup.isInGroup(String groupShortname);
AuthLookup.isInGroup(String username, String groupShortname);

AuthLookup.isPrivilegeGranted(String tokenName);
AuthLookup.isPrivilegeGranted(String username, String tokenName);

AuthLookup.areAllPrivilegesGranted(String... tokenNameList);
AuthLookup.areAllPrivilegesGranted(String username, String... tokenNameList);

AuthLookup.isOnePrivilegesGranted(String...tokenNameList),
AuthLookup.isOnePrivilegeGranted(String username, String...tokenNameList),

AuthLookup.isPrivilegeGrantedGroup(String tokenName, String groupShortname);
AuthLookup.isPrivilegeGrantedGroup(String username, String tokenName, String groupShortname);

 ....

//-----------------------------------------------------------------------------------------------
// Following lookup queries for a user's group, role, etc. listings.
//
// The following lookup methods are not intended for user management. For this purpose the
// managers should be used for that. The lookup methods are intended to support the formulation of corresponding queries
// such as e.g., the formulation of ACL queries, to support e.g., joins
// related to e.g. group hierarchies.
//
// If the user is a superuser, then the following methods return null; otherwise
// always return a collection, i.e., also an empty collection.
//-----------------------------------------------------------------------------------------------

Collection<String> roleNameList = AuthLookup.listRoles();
Collection<String> roleNameList = AuthLookup.listRoles(String username);

Collection<String> groupShortnameList = AuthLookup.listGroups();
Collection<String> groupShortnameList = AuthLookup.listGroups(String username);

Collection<String> tokeNameList = AuthLookup.listPrivilegesGranted();
Collection<String> tokeNameList = AuthLookup.listPrivilegesGranted(String username);

Collection<String> tokeNameList = AuthLookup.listPrivilegesGrantedGroup(String groupShortname);
Collection<String> tokeNameList = AuthLookup.listPrivilegesGrantedGroup(String username, String groupShortname);
Find current user
// the current user can be retrieved via UserContext
User user = UserContext.getCurrentUser();
For authentication/authorization: The current user is determined using the Spring Security context. so this must be set accordingly by means of e.g. servlet filters. The following is the current implementation of the user service to determine the current user.
Implementation of the user service to determine the current user
public static User getCurrentUser() {
    SecurityContext secCtx = SecurityContextHolder.getContext();
    if (secCtx == null) {
        // using the user context of the user service a user can also be set independently of the
        // security context; e.g. to set backend job executions // within a user context.
        // within a user context; this context is returned with getUser()
        return getUser();
    }

    Authentication auth = secCtx.getAuthentication();
    if (auth == null) {
        return getUser();
    }

    if (auth instanceof CommonAuthentication) {
        UUID userIdentifier = ((CommonAuthentication) auth).getUserIdentifier();
        UserManager userManager = BeanLookup.getBean(UserManager.class);
        return userManager.getEntityByUuid(userIdentifier.toString());
    }

    Object principal = auth.getPrincipal();
    if (principal instanceof UserDetails) {
        // Note: The user service provides a user-details implementation that can be used
        // can be used to create an authentication instance.
        return ((UserDetails) principal).getUser();
    }
    return UserContext.getUser();
}

Cache implementation

This document is based on the user service version 1.2. The cache implementation used for the above lookup methods is Infinispan. To use the Infinispan cache, the following Spring configuration and the Infinispan configuration itself must be specified with respect to the user service.

Infinispan-Spring-Configuration
# Spring configuration: reference to the actual infinispan configuration file.
# This reference can be a direct reference to the file system or an indirect one
# via classpath.
# See also: 'https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-caching-provider-infinispan'

infinispan:
   embedded:
     configXml: infinispan.xml

The minimum infinispan configuration for the user service is listed below. Either a configuration for a local so-called simple cache (name: 'user-cache-local') or a configuration for a distributed cache ('user-cache-cluster') in the form of an invalidation cache (see also https://infinispan.org/docs/stable/user_guide/user_guide.html) must be specified.

Actual infinispan configuration (form: XML document)
<?xml version="1.0" encoding="UTF-8"?>
<infinispan
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:infinispan:config:9.4 http://www.infinispan.org/schemas/infinispan-config-9.4.xsd"
xmlns="urn:infinispan:config:9.4">

    <!--
         Notes for the following expiration configuration:
         lifespan, interval and max-idle in millis
         lifespan: the time that an entity is kept in the cache before it is evicted
         max-idle: the idle time of an entity before it is evicted; -1 means ignoring max-idle
         interval: the check period for eviction
     -->

     <cache-container>

         <!-- - - - - - - - - - - - - - - - - - - - -->
         <!-- simple cache for single node systems  -->
         <!-- - - - - - - - - - - - - - - - - - - - -->
         <local-cache-configuration name="user-cache-local" simple-cache="true">
            <expiration lifespan="43200000" interval="300000" max-idle="-1"/>
         </local-cache-configuration>


         <!-- - - - - - - - - - - - - - - - - - - - - -->
         <!-- invalidation cache for cluster systems  -->
         <!-- - - - - - - - - - - - - - - - - - - - - -->
         <!--        <transport cluster="cmn-cache-cluster"/>                                   -->
         <!--        <invalidation-cache-configuration name="user-cache-cluster" mode="ASYNC">  -->
         <!--            <expiration lifespan="43200000" interval="300000" max-idle="-1"/>      -->
         <!--        </invalidation-cache-configuration>-->

     </cache-container>
</infinispan>

Alternative cache implementation

In order to use a different cache implementation than Infinispan, the following entry must be made in the yaml configuration:

spring:
   cache:
      type: CUSTOM

If the cache configuration is missing, then Infinispan is used; Infinispan can also be configured explicitly as follows (however, this is optional):

spring:
   cache:
      type: INFINISPAN

If the cache type CUSTOM is configured, a bean of the type de.eitco.commons.user.management.common.cache.CustomCacheManager is expected in the Spring application context, defined as follows:

Example of a bean definition when configuring a custom cache type
    @Bean
    @Conditional(CustomCacheManagerChecker.class)
    public CustomCacheManager customCacheManager() {
        return new MyCacheManager();
    }
The conditional annotation is not necessary; however, if the cache type is not CUSTOM, then the annotation will not create the bean.

The following is the CustomCacheManager interface:

public interface CustomCacheManager {
    Cache getCache(String cacheName);
    Cache getCache(String cacheName, @Nullable Map<String, Object> cacheConfiguration);
}

So a bean that implements the CustomCacheManager is to be provided in the application context.

The return value Cache in the interface methods is org.springframework.cache.Cache.

LDAP Synchronization

LDAP synchronisation configuration
user-service:
  ldap:
    tenants:
      - tenant-id: master
        server-urls:
          - ldap://eit-bln-svdom1.eitco.de:389
        auth-user-name: tpruefen@eitco.de
        auth-user-password: changeit
        date-format: yyyyMMddHHmmss
        user-search-bases:
          - ou=mitarbeiter,ou=bremen,ou=eitco,dc=eitco,dc=de
          - ou=mitarbeiter,ou=bonn,ou=eitco,dc=eitco,dc=de
          - ou=mitarbeiter,ou=berlin,ou=eitco,dc=eitco,dc=de
        user-filter: objectclass=person
        user-mappings:
          - username, sAMAccountName
          - externalId, objectGUID;binary
          - email, mail
          - firstname, givenName
          - lastname, sn
          - tmpList-memberOf, memberOf
        group-search-bases:
          - cn=Builtin,dc=eitco,dc=de
          - cn=Users,dc=eitco,dc=de
          - ou=gruppen,ou=eitco,dc=eitco,dc=de
        group-filter: objectclass=group
        group-mappings:
          - shortname, sAMAccountName
          - externalId, objectGUID;binary
          - longname, cn
          - tmpList-memberOf, memberOf

Unit testing

The User Service can be used to set a user context for unit tests. It is also possible to use the Spring Security on-board tools, such as the WithMockUser annotation. However, the full range of functions of the User Service is not available with the on-board tools and, in addition, they cannot be used in part in connection with a Spring boot test. Therefore, it is recommended to use the user service itself to set a user context. For this purpose, the following dependency must be specified for Maven and Gradle:

Maven-Dependency: .Integration of user service and test users

<dependency>
     <groupId>de.eitco.commons</groupId>
     <artifactId>cmn-user-management-test-with-user</artifactId>
     <version>entsprechende Version</version>
     <scope>test</scope>
 </dependency>

Gradle-Dependency:

Integration of user service and test users
test 'de.eitco.commons: cmn-user-management-test-with-user:<yourVersion>'

WithTestUser annotation

The @WithTestUser annotation has two parameters. These are the value parameter and the resetData parameter. The value parameter is used to define the user context and the resetData parameter is used to indicate whether all user, group, role and privilege data should be deleted before setting up the corresponding user context.

The value parameter contains the user context definitions in comma-separated form. The values of a user definition always contain a prefix. The following table lists the possible definitions.

prefix description

g

Specification of a group to be assigned to the user (e.g. g.fooGroup.oe, i.e. the group fooGroup of type oe; note: each group is to be typed OU, job, team etc.).

gfg

Indication of a group which can be indirectly assigned to the user; indirectly via group hierarchy (e.g. gfg. fooGroupParent.oe, i.e. the group fooGroupParent of type oe; assignment see next line via prefix sg)

p

Assignment of a privilege to a role (e.g. p.AKTE_ERSTELLEN.fooRole, i.e. the privilege AKTE_ERSTELLEN, which is assigned to the role fooRole). Using the prefix, an explicit non-granting of a privilege can also be defined. For this purpose, a notGranted must be appended to the definition (e.g. p.ACTE_ERSTELLEN.fooRole.notGranted). rg Specification of a role that is assigned to a group (e.g. rg.fooRoleGroup.fooGroupParent, i.e. the role fooRoleGroup assigned to the group fooGroupParent)

ru

Specification of a role that is assigned to the user (e.g. ru.fooRole, i.e. the role fooRole)

sg

Assignment of a subgroup to a group (e.g. sg.fooGroup.fooGroupParent, i.e. the group fooGroup is assigned to the group fooGroupParent as a subgroup)

u

Specification of the user (e.g. u.fooUser defines the user fooUser). Exactly one user definition must be specified. By means of the postfix superuser, the user becomes the superuser (e.g. u.fooUser.superuser).

Client context

The client context of a test class or a test method can be set with the @WithTenant annotation. If no annotation is set, the master tenant is automatically used. For this purpose, the FullTestExecutionListener must be set as TestExecutionListener by means of the class annotation TestExecutionListeners (even if the annotation is not to be used).

Setup import

The setup import is used to import configured tokens, roles, groups, users and their assignments. In the same way, OAuth client configurations can be imported via setup import.

The configurations to be imported are to be stored as Spring Boot configurations.

The import takes place during the start of a standalone user service instance or during the start of an application instance in which the user service is embedded.

Token import

The following exemplary YAML configuration shows the structure of a configuration for the token import. The two tokens fooToken1 and fooToken2 are defined.

To set a token value, the name of the SecToken pojo attribute is to be used in the configuration.
Token import
user-service:
  config-data:
    tenants:
      # Setup imports are configured on a client-by-client basis. The client ID "all" means that the
      # configuration applies to all clients. The client ID "all" must also be specified if
      # no client has been explicitly configured. This is because the application then starts under the so-called
      # default client.
      - tenant-id: all
        token:
          - type: function
            path: fooToken1
            description: This is...

            # the token is assigned to the role fooRole1 as guaranteed
            privilegeGrantedToRoles: fooRole1

            # the token is assigned to the role fooRole2 as not guaranteed;
            # such an assignment is relevant in relation to group hierarchies,
            # to revoke a token (privilege) granted by the hierarchy.
            privilegeNotGrantedToRoles: fooRole2

          - type: function
            path: fooToken2
            description: This is...

            # the token is assigned to the two roles fooRole1 and fooRole
            privilegeGrantedToRoles: fooRole1,fooRole2

Role Import

The following exemplary YAML configuration shows the structure of a configuration for role import. The two roles fooRole1 and fooRole2 are defined.

To set a role value, the name of the UserRole pojo attribute must be used in the configuration.
Role import
user-service:
   config-data:
     tenants:
      # see explanation of tenant-id for token import
      - tenant-id: all
        roles:
          - name: fooRole1
            description: This is…

          - name: fooRole2
            description: This is…

Group import

The following exemplary YAML configuration shows the structure of a configuration for the group import. The two groups fooGroup1 and fooGroup2 are defined.

To set a group value, the name of the UserGroup pojo attribute must be used in the configuration.
Group import
user-service:
   config-data:
     tenants:
      # see explanation of tenant-id for token import
      - tenant-id: all

      groups:
          # z.B. GUID from Active Directory
        - externalId: C7FE1854-9428-44B6-9A77-3FADE10C1BCF
          # z.B. DN from Active Directory
          externalPath: groups.employee
          type: Standard
          shortname: fooGroup1
          longname: fooGroup1Longname
          division: fooGroup1Division
          area: fooGroup1Area
          enabled: true
          escription: This is...
          # the role fooRole1 is assigned to the group
          memberOfRoles: fooRole1

        - externalId: D7FE1854-9428-44B6-9A77-3FADE10C1BCF
          externalPath: groups.developer
          type: Standard
          shortname: fooGroup2
          longname: fooGroup2Longname
          division: fooGroup2Division
          area: fooGroup2Area
          enabled: true
          description: This is...

          # the group is assigned to the roles fooRole1 and fooRole2
          memberOfRoles: fooRole1,fooRole2

          # the group is classified as a subgroup of the group fooGroup1
          subGroupOfGroups: fooGroup1

User Import

The following exemplary yaml configuration shows the structure of a configuration for the user import. The user fooUser1 is defined.

To set a user value, the name of the user pojo attribute must be used in the configuration.
User import
user-service:
   config-data:
     tenants:
      # see explanation of tenant-id for token import
      - tenant-id: all

        users:
          - uuid: 822bd19a-6104-4cae-a7ef-8380c1e8e6c5
            externalId: B7FE1854-9428-44B6-9A77-3FADE10C1BCF
            username: fooUser1
            password: fooPassword
            title: Dr.
            salutation: Mrs.
            lastname: Mustermann
            firstname: Erika
            email: emustermann@foo.foo
            superuser: false
            validFrom: 2000-01-01T00:00:00Z
            validUntil: 2050-12-31T00:00:00Z
            enabled: true
            description: This is…

            # the user is assigned to the groups fooGroup1 and fooGroup2
            memberOfGroups: fooGroup1,fooGroup2

            # the user is assigned to the roles fooRole1 and fooRole2
            memberOfRoles: fooRole1,fooRole2