Jump to: navigation, search

Difference between revisions of "HowTo:Configure Users and User Rights"


 
(17 intermediate revisions by the same user not shown)
Line 13: Line 13:
 
* ''PASSWORD'': The password
 
* ''PASSWORD'': The password
 
* ''CONSUMER'': A link to the person this login is associated with (useful if there are multiple accounts per person)
 
* ''CONSUMER'': A link to the person this login is associated with (useful if there are multiple accounts per person)
 +
  
 
So, the steps to create a login are:
 
So, the steps to create a login are:
Line 33: Line 34:
  
 
== User rights ==
 
== User rights ==
There is no fully prepared feature for user- or group-specific rights in {{UBIK}}. However, you can customize user rights and their execution.
+
There is a programmatic framework for group-specific rights in {{UBIK}} that is highly customizable. Currently, {{UBIK}} requires you to add some logic for the evaluation of user rights, so get ready to do some coding!
  
 
=== Defining rights ===
 
=== Defining rights ===
First, it will be necessary to define what rights there should be. In general, it should be possible to control whether a user is allowed to view ("read"), edit ("write"), create and delete data. Creation and deletion rights usually can be subsumed into the right to manipulate ("write") data.  
+
First, it will be necessary to define what rights there should be. In general, it should be possible to control whether a user is allowed to view ("read"), edit ("write"), create and delete data. Creation and deletion rights usually can be subsumed into the right to manipulate ("write") data. Fortunately, there is already an enum ''UBIK.Kernel.UserRights'' describing the three possible rights and mapping them to integer values:
 +
* NoRight = 0
 +
* Read = 10
 +
* Write = 20
 +
So, nothing for you to do yet.
  
 
=== Configuring rights ===
 
=== Configuring rights ===
 
So we have the basic definitions for reading and writing. Now we have to apply them to use-cases, respectively, objects and users (or better, groups). E.g., if it should be possible to control the rights for editing an object's properties, one could relate the respective user group to the object and set the right on the relation data object. Then, the group is related to the target object, with the respective right as a property of their relation connection.
 
So we have the basic definitions for reading and writing. Now we have to apply them to use-cases, respectively, objects and users (or better, groups). E.g., if it should be possible to control the rights for editing an object's properties, one could relate the respective user group to the object and set the right on the relation data object. Then, the group is related to the target object, with the respective right as a property of their relation connection.
 +
 +
The next steps will be to create a [[Relation]] with a custom relation data meta class (configuring a derivation of the meta class ''RELATIONDATA'', assigning it to the equally named property; see also: [[HowTo:Create_a_new_Relation]]) defining a property for the rights configuration:
 +
# Create a new [[Relation]] plus relation data meta class.
 +
# Design the relation data meta class as follows:
 +
# The left target meta class should be any object (i.e., ''BASECLASS''), whereas the right target meta class should be ''USERGROUP'' or ''LOGIN'', depending on whether you're using groups or not.
 +
# Add a new [[MetaProperty]] for the user right to the relation data meta class, e.g., ''MP_USER_RIGHT''. It should be an integer property, so we can store values from the ''UserRights'' enum in it.
 +
 +
Now you have the possibility to describe rights between users (respectively, groups) and any object, just by creating a relation between them and setting the respective right on the relation data instance.
  
 
=== Evaluating rights ===
 
=== Evaluating rights ===
Now that we have defined and configured rights, we have to evaluate them. Assuming, you want to control the user rights for (mobile) applications, this is best done by customizing the ACM view. [[View_Item|View Items]] provide methods for delivering children, as well as for adding and removing children. These can be overwritten in order to evaluate the rights of the active login regarding a use-case. [[Query|Queries]] also can be customized to evaluate user rights. The [[Context]], which decides the best scope (ACM meta definition) for an object delivered to the client, can also be customized - e.g., in order to provide meta definitions with different property read/write rights depending on the user group.
+
Now that we have defined and configured rights, we have to evaluate them. This can be done by customizing the methods ''CustomGroupRights'' and ''CustomPropertyGroupRights'' for any meta class. {{UBIK}} will take care about the rest, i.e., applying the rights.  
  
 +
==== Controlling the visibility and editability of objects ====
 +
# Find the meta class of objects you want to control the rights for.
 +
# Customize its method ''CustomGroupRights''.
 +
# Find relation instances between the current object (or its meta class) and user groups.
 +
# Read the custom rights from the relation data objects connecting the target object and a user group.
 +
# For each combination, create a new instance of ''UBIK.Service.DTO.V240.GroupRight'' and assign both the group and the right.
 +
# Add all ''GroupRight'' instances to a result list and return it.
  
 +
 +
Here's an exemplary code snippet:
 +
 +
<source lang="csharp">
 +
public override IEnumerable<UBIK.Service.DTO.V240.GroupRight> CustomGroupRights(IEnumerable<UBIK.Service.DTO.V240.GroupRight> defaultRights)
 +
{
 +
// The goal of this method is to collect all rights defined for groups on this object.
 +
// UBIK will take care of finding out what rights apply to the active user.
 +
 +
// First, let's define our result collection containing the group rights.
 +
List<UBIK.Service.DTO.V240.GroupRight> results = new List<UBIK.Service.DTO.V240.GroupRight>();
 +
 +
if(defaultRights != null) 
 +
{
 +
// We'll add the default rights in case we don't have defined any specific rights for the active user's group.
 +
results.AddRange(defaultRights);
 +
}
 +
 +
// Now we try to find the rights defined for this object.
 +
// For this code snippet, the author assumes that the rights are defined on the relation data between user groups and this object.
 +
 +
// Getting the relation...
 +
Guid relationId = Guid.Parse("Replace this text with the UID of your custom rights relation");
 +
Relationship rightsRelation = this.Environment.UBIKDataFactory().Relation(relationId);
 +
 +
// Using the relation to find all related groups
 +
UBIKClassList<RelationalObject> userGroups = this.RelatesFrom(rightsRelation);
 +
 +
string rightsPropertyName = "Replace this text with the name of the property on the relation data object containing the rights, e.g. GROUPRIGHT";
 +
 +
// For every linked group, we want to get the rights defined for this object.
 +
foreach (RelationalObject userGroup in userGroups)
 +
{
 +
 +
// Getting the relation data object linking the userGroup to this object
 +
RelationData rd = userGroup.GetRelationDataObject(rightsRelation, this);
 +
 +
// Getting the right defined on the relation data
 +
int? right = rd.GetValue<int?>(rightsPropertyName);
 +
 +
// If the right value is not null, we can use it!
 +
if (right != null)
 +
{
 +
// Let's create a new groupRight object and set the group and right
 +
UBIK.Service.DTO.V240.GroupRight groupRight = new UBIK.Service.DTO.V240.GroupRight()
 +
{
 +
GroupID = userGroup.UID,
 +
Right = right.Value
 +
};
 +
 +
// Adding the groupRight object to the result list
 +
results.Add(groupRight);
 +
}
 +
}
 +
 +
// Now that we collected all group rights, return the results.
 +
return results;
 +
}
 +
</source>
 +
 +
 +
If you want to control the rights not per instance individually, but for all instances of a meta class at once, the following adaptions are required:
 +
* The ''TARGETTYPERIGHT'' of the rights relation must be MetaMetaClass, because this is the meta class (i.e., the type) of meta classes (which we want to relate to user groups in this case). It's a bit tricky to get the MetaMetaClass using Studio. You'll have to do it using Whobert, fetching and assigning the MetaMetaClass with the following code:
 +
** First, we'll ask the Environment for the meta meta class system object. We'll get the Environment from any (''BaseClass'') object, e.g., the parameter object for Whobert.
 +
** UBIK.Kernel.MetaMetaClass mmc = anyObject.Environment.GetSystemMetaClass(UBIK.Kernel.SystemObjects.METACLASS); // replace anyObject with a UBIK object at hand
 +
** Then assign ''mmc'' to the right target type of the relation:
 +
** Relationship relation = anyObject.Environment.UBIKDataFactory().Relation(relationUid);
 +
** relation.SetLinkedObject(UBIK.Kernel.SystemStrings.TARGETTYPERIGHT, mmc);
 +
** Then save the relation using relation.Save().
 +
* In the code snippet, instead of asking for objects and relation data for ''this'', we have to use ''this.MetaClass'':
 +
** UBIKClassList<RelationalObject> userGroups = this.'''MetaClass'''.RelatesFrom(rightsRelation);
 +
** RelationData rd = userGroup.GetRelationDataObject(rightsRelation, this.'''MetaClass''');
 +
 +
 +
 +
 +
==== Controlling the visibility and editability of properties ====
 +
This works basically the same way as for whole objects, just with a different method to override:
 +
# Find the meta class of objects you want to control the rights for.
 +
# Customize its method ''CustomPropertyGroupRights''. Note that there is a parameter ''metaPropertyName'', so this is about a specific property. Now it becomes interesting, because you have multiple options depending on the degree of detail you want to control the property rights for:
 +
#* '''On meta class level''': If the rights for every property are the same for all instances of a meta class, but differ by user, you should evaluate the relation between the meta class and the user group.
 +
#* '''On meta property level''': If the rights for a property are the same for all instances of a meta class, but differ by meta property and user, you should evaluate the relation between the meta property and the user group. If a meta property is used on multiple meta classes with different rights, you may have to evaluate the relation between: A) the relation data between meta class and meta property and B) the user.
 +
#* '''On content object level''': If the rights for every property are the same for the same content object, you should evaluate the relation between the object and the user group.
 +
#* '''On property level''': If the rights for a property depend only on the user, you should evaluate the relation between an attribute on the property and the user group (an attribute is needed because you can't relate a property to anything).
 +
# Read the custom rights from the relation data objects connecting the target object and a user group.
 +
# For each combination, create a new instance of ''UBIK.Service.DTO.V240.GroupRight'' and assign both the group and the right.
 +
# Add all ''GroupRight'' instances to a result list and return it.
 +
 +
 +
 +
{{Attention|Rights are evaluated by the server; so for the mobile client, there is no offline support for the dynamic evaluation of user rights yet (when this article was created).}}
 
<!-- DO NOT REMOVE THIS -->{{Template:HowTo/Begin}}<!-- DO NOT REMOVE THIS -->
 
<!-- DO NOT REMOVE THIS -->{{Template:HowTo/Begin}}<!-- DO NOT REMOVE THIS -->
 
<!--
 
<!--
Line 51: Line 162:
 
<Give step-by-step instructions, use images, ...>
 
<Give step-by-step instructions, use images, ...>
 
  -->
 
  -->
 
 
<!-- DO NOT REMOVE THIS -->{{Template:HowTo/End}}<!-- DO NOT REMOVE THIS -->
 
<!-- DO NOT REMOVE THIS -->{{Template:HowTo/End}}<!-- DO NOT REMOVE THIS -->
 +
 +
 +
  
 
==See also==
 
==See also==

Latest revision as of 17:00, 17 January 2020

In many projects, it is important to distinguish the active user, mainly for the mobile client. Mostly, it is required to just restrict access to certain users. Often, there are also different groups of users that should have different rights to view, edit, create or delete objects. In some cases, the content provided to the mobile client should depend on the active user. This How-To explains how to configure users and how to customize a UBIK® application depending on the active user.

Managing user accounts

The first step in any case is to create and organize accounts for users. In some case, users have to be imported from an external system, which is best done using Proxies (see also how to Configure Proxies). However, accounts can also be created manually or programmatically. In any case, the following information is relevant.

Login

In UBIK®, an account object is called Login, with the system MetaClass LOGIN. Theoretically, a user can have multiple such login credentials, but normally, you'd have one per user. If there are multiple logins for one user, you can create a custom meta class for the users and link the login objects to them via the CONSUMER Reference property (see also how to Relate Objects). You can also create a derivation of the LOGIN system meta class to add further details for the instances. A login object has the following important properties:

  • LOGINNAME: The account name
  • DOMAINNAME: The domain name
  • SYSADMINRIGHTS: Whether the user has administrator privileges in UBIK® Studio
  • USE_DOMAIN_CREDENTIALS: Whether to use Active Directory for authentication
  • PASSWORD: The password
  • CONSUMER: A link to the person this login is associated with (useful if there are multiple accounts per person)


So, the steps to create a login are:

  1. Find the system meta class LOGIN and drag it into a new bulk editor.
  2. Create a new instance, filling in at least the LOGINNAME, the DOMAINNAME and the PASSWORD.
  3. Save the new instance.

User groups

Login accounts are best managed in groups corresponding to roles, e.g., "Administrator" or "Engineer". This is important if you don't want to distinguish by account individually, but more generally by their role. This allows you to add new logins (to existing groups) without having to adapt your customizing. There is a system meta class USERGROUP that can be used for this. Similar to the way you would link multiple logins to a user, you can also relate multiple users to one or many groups (there is a system relation for that, SYSREL_GROUP_LOGIN).

If you have just one group of users (i.e., all the users have the same rights or highly individual rights), it is not necessary to configure groups.

The steps to create and apply a group are:

  1. Find the system meta class USERGROUP and drag it into a new bulk editor.
  2. Create a new instance, filling in the name
  3. Save the new instance.
  4. Drag the new group into a relation browser.
  5. Find the login(s) you want to associate with the group and drag it onto the relation node for SYSREL_GROUP_LOGIN (relation between groups and logins).
  6. Save the changes.

User rights

There is a programmatic framework for group-specific rights in UBIK® that is highly customizable. Currently, UBIK® requires you to add some logic for the evaluation of user rights, so get ready to do some coding!

Defining rights

First, it will be necessary to define what rights there should be. In general, it should be possible to control whether a user is allowed to view ("read"), edit ("write"), create and delete data. Creation and deletion rights usually can be subsumed into the right to manipulate ("write") data. Fortunately, there is already an enum UBIK.Kernel.UserRights describing the three possible rights and mapping them to integer values:

  • NoRight = 0
  • Read = 10
  • Write = 20

So, nothing for you to do yet.

Configuring rights

So we have the basic definitions for reading and writing. Now we have to apply them to use-cases, respectively, objects and users (or better, groups). E.g., if it should be possible to control the rights for editing an object's properties, one could relate the respective user group to the object and set the right on the relation data object. Then, the group is related to the target object, with the respective right as a property of their relation connection.

The next steps will be to create a Relation with a custom relation data meta class (configuring a derivation of the meta class RELATIONDATA, assigning it to the equally named property; see also: Create a new Relation) defining a property for the rights configuration:

  1. Create a new Relation plus relation data meta class.
  2. Design the relation data meta class as follows:
  3. The left target meta class should be any object (i.e., BASECLASS), whereas the right target meta class should be USERGROUP or LOGIN, depending on whether you're using groups or not.
  4. Add a new MetaProperty for the user right to the relation data meta class, e.g., MP_USER_RIGHT. It should be an integer property, so we can store values from the UserRights enum in it.

Now you have the possibility to describe rights between users (respectively, groups) and any object, just by creating a relation between them and setting the respective right on the relation data instance.

Evaluating rights

Now that we have defined and configured rights, we have to evaluate them. This can be done by customizing the methods CustomGroupRights and CustomPropertyGroupRights for any meta class. UBIK® will take care about the rest, i.e., applying the rights.

Controlling the visibility and editability of objects

  1. Find the meta class of objects you want to control the rights for.
  2. Customize its method CustomGroupRights.
  3. Find relation instances between the current object (or its meta class) and user groups.
  4. Read the custom rights from the relation data objects connecting the target object and a user group.
  5. For each combination, create a new instance of UBIK.Service.DTO.V240.GroupRight and assign both the group and the right.
  6. Add all GroupRight instances to a result list and return it.


Here's an exemplary code snippet:

        public override IEnumerable<UBIK.Service.DTO.V240.GroupRight> CustomGroupRights(IEnumerable<UBIK.Service.DTO.V240.GroupRight> defaultRights)
        {
                // The goal of this method is to collect all rights defined for groups on this object.
                // UBIK will take care of finding out what rights apply to the active user.

                // First, let's define our result collection containing the group rights.
                List<UBIK.Service.DTO.V240.GroupRight> results = new List<UBIK.Service.DTO.V240.GroupRight>();

                if(defaultRights != null)  
                {
                        // We'll add the default rights in case we don't have defined any specific rights for the active user's group.
                        results.AddRange(defaultRights);
                }

                // Now we try to find the rights defined for this object.
                // For this code snippet, the author assumes that the rights are defined on the relation data between user groups and this object.

                // Getting the relation...             
                Guid relationId = Guid.Parse("Replace this text with the UID of your custom rights relation");
                Relationship rightsRelation = this.Environment.UBIKDataFactory().Relation(relationId);

                // Using the relation to find all related groups
                UBIKClassList<RelationalObject> userGroups = this.RelatesFrom(rightsRelation);

                string rightsPropertyName = "Replace this text with the name of the property on the relation data object containing the rights, e.g. GROUPRIGHT";

                // For every linked group, we want to get the rights defined for this object.
                foreach (RelationalObject userGroup in userGroups)
                {

                        // Getting the relation data object linking the userGroup to this object
                        RelationData rd = userGroup.GetRelationDataObject(rightsRelation, this);

                        // Getting the right defined on the relation data
                        int? right = rd.GetValue<int?>(rightsPropertyName);

                        // If the right value is not null, we can use it!
                        if (right != null)
                        {
                                // Let's create a new groupRight object and set the group and right
                                UBIK.Service.DTO.V240.GroupRight groupRight = new UBIK.Service.DTO.V240.GroupRight()
                                {
                                        GroupID = userGroup.UID,
                                        Right = right.Value
                                };

                                // Adding the groupRight object to the result list
                                results.Add(groupRight);
                        }
                }

                // Now that we collected all group rights, return the results.
                return results;
        }


If you want to control the rights not per instance individually, but for all instances of a meta class at once, the following adaptions are required:

  • The TARGETTYPERIGHT of the rights relation must be MetaMetaClass, because this is the meta class (i.e., the type) of meta classes (which we want to relate to user groups in this case). It's a bit tricky to get the MetaMetaClass using Studio. You'll have to do it using Whobert, fetching and assigning the MetaMetaClass with the following code:
    • First, we'll ask the Environment for the meta meta class system object. We'll get the Environment from any (BaseClass) object, e.g., the parameter object for Whobert.
    • UBIK.Kernel.MetaMetaClass mmc = anyObject.Environment.GetSystemMetaClass(UBIK.Kernel.SystemObjects.METACLASS); // replace anyObject with a UBIK object at hand
    • Then assign mmc to the right target type of the relation:
    • Relationship relation = anyObject.Environment.UBIKDataFactory().Relation(relationUid);
    • relation.SetLinkedObject(UBIK.Kernel.SystemStrings.TARGETTYPERIGHT, mmc);
    • Then save the relation using relation.Save().
  • In the code snippet, instead of asking for objects and relation data for this, we have to use this.MetaClass:
    • UBIKClassList<RelationalObject> userGroups = this.MetaClass.RelatesFrom(rightsRelation);
    • RelationData rd = userGroup.GetRelationDataObject(rightsRelation, this.MetaClass);



Controlling the visibility and editability of properties

This works basically the same way as for whole objects, just with a different method to override:

  1. Find the meta class of objects you want to control the rights for.
  2. Customize its method CustomPropertyGroupRights. Note that there is a parameter metaPropertyName, so this is about a specific property. Now it becomes interesting, because you have multiple options depending on the degree of detail you want to control the property rights for:
    • On meta class level: If the rights for every property are the same for all instances of a meta class, but differ by user, you should evaluate the relation between the meta class and the user group.
    • On meta property level: If the rights for a property are the same for all instances of a meta class, but differ by meta property and user, you should evaluate the relation between the meta property and the user group. If a meta property is used on multiple meta classes with different rights, you may have to evaluate the relation between: A) the relation data between meta class and meta property and B) the user.
    • On content object level: If the rights for every property are the same for the same content object, you should evaluate the relation between the object and the user group.
    • On property level: If the rights for a property depend only on the user, you should evaluate the relation between an attribute on the property and the user group (an attribute is needed because you can't relate a property to anything).
  3. Read the custom rights from the relation data objects connecting the target object and a user group.
  4. For each combination, create a new instance of UBIK.Service.DTO.V240.GroupRight and assign both the group and the right.
  5. Add all GroupRight instances to a result list and return it.


IC Attention.pngRights are evaluated by the server; so for the mobile client, there is no offline support for the dynamic evaluation of user rights yet (when this article was created).




See also