Introduction

In this topic, you can find general information about the IdentityProvider app and its scope of functions, as well as helpful knowledge for programming functions and customizing.

About the IdentityProvider app

This documentation describes the individual interfaces that enable you to create custom functions (Customizing) for authentication.

Scope of functions of the IdentityProvider app

The IdentityProvider app authenticates users with various authentication methods, such as Windows authentication (Kerberos) or user login credentials. The IdentityProvider app supports a wide variety of user administration systems, including Active Directory (AD). The IdentityProvider app also provides user data that is required for use by other apps. Furthermore, it provides an API interface that permits authentication for apps.

Using the API functions

The IdentityProvider app provides an API interface for the following actions:

Background: Process of authentication and authorization

The chart below shows the process of authentication and authorization.

authentication-and-authorization-flowchart

Login

This function performs a login from an app.

Execute a redirect to the URI /identityprovider/login. Enter the URI in lowercase characters.

This resource has a valid Query parameter:

ParameterDescription
redirectMandatory parameter that contains the path and the query parameters of the custom URI. If the login was successful, the IdentityProvider app performs a redirect back to this URI.

warning: When the URI /identityprovider/login is called, the IdentityProvider app chooses an authentication method, depending on the configuration. Apps are therefore not permitted to call this URI themselves. Instead, the URI should be called by the browser. Client applications that want to log in must use a browser control and define a redirect URI that they can use in the browser control.

If only an API key is used for the login, the URI /identityprovider/login?basic=true can be used. In this case, the API key is submitted as the password.

Validating the login

You can use the validate function to check whether a request contains the correct login.

Validating the required information

  • Check whether the Authorization header is defined.
  • Check whether the header contains a Bearer token.
  • If no Bearer token is available, also check whether the cookie AuthSessionId is available.
  • If neither the token nor the cookie are available, perform a redirect to the login resource from the app.

Request

GET /identityprovider/validate[?allowExternalValidation=true]

By specifying allowExternalValidation=true as a query parameter, you instruct the IdentityProvider app to also validate external users that are not known through the IdentityProvider app providers, but that have logged in via OpenID Connect (alternative login). For external users, the returned SCIM user object contains only an e-mail address and the special group membership to the External User group with the ID 3E093BE5-CCCE-435D-99F8-544656B98681.

HTTP statusDescription
401 UnauthorizedInvalid token or no token transferred.
403 ForbiddenValid token for an external user: allowExternalValidation=false.
404 Not FoundValid token for a deleted user.
200 OKValid token.
Content-Type: application/hal+json
<SCIM-user-Objekt im JSON-Format>

With this HTTP GET request, the contents of the token or cookie are sent to the IdentityProvider app as either a token or a cookie. You can specify whether the contents are forwarded as a Bearer token or a cookie in the code.

To ensure that you do not have to call the Validate end point for each request, you should store the response temporarily. Use the SCIM user object for caching. The IdentityProvider app sends a CacheControl header and defines the validity period in it with MaxAge.

You should use the validity period specification to save the response for the specified number of seconds. Within this time, you do not need to call the Validate end point again if the AuthSessionId for a request is identical to the stored AuthSessionId.

info: A user can use an account in multiple sessions in which the AuthSessionId is different. If the SCIM user object is stored for the respective AuthSessionId, the object may exist multiple times in the memory. To optimize storage, you can use the part of the session ID before the ampersand (&) as the key for the SCIM user objects.

Using the SCIM protocol for authentication

For further authentication and additional functions, the IdentityProvider app provides information about users in accordance with the SCIM protocol (protocol versions 1.0 and 1.1). The System for Cross-domain Identity Management (SCIM) protocol is a manufacturer-independent standard that was developed to simplify user authentication in cloud-based applications and services.

info: You can find more information about the SCIM protocol in the Internet Engineering Task Force documentation: https://tools.ietf.org/html/rfc7643 bzw. https://tools.ietf.org/html/rfc7644 (jeweils in englischer Sprache).

The base address (URI) of the SCIM protocol is /identityprovider/scim. First, check whether a valid token was transferred in order to access the SCIM resource.

Under the specified URI, the IdentityProvider app provides only read access to the two SCIM resources Users and Groups.

Available routes

RouteDescription
/identityprovider/scim/UsersLists the users from all the user providers.
/identityprovider/scim/Users/{id}Lists one specific user. The placeholder id stands for the ID of the specific user.
/identityprovider/scim/GroupsLists the groups from all the user providers.
/identityprovider/scim/Groups/{id}Lists one specific group. The placeholder id represents the ID of the specific group.

The following SCIM user object properties are supported and can be used for filtering:

  • Id
  • UserName
  • Name (familyName, givenName)
  • DisplayName
  • Title
  • Locale
  • PreferredLanguage
  • Emails (value)
  • PhoneNumbers (value)
  • Groups (value, display)
  • Photos (value, type)
  • SCIM2.0 Enterprise User Extension

The following SCIM user object properties are supported and can be used for filtering:

  • Id
  • DisplayName
  • Members (value, display)

The following SCIM operators are supported for filtering:

  • equals (eq)
  • contains (co)
  • startsWith (sw)

Paging of SCIM objects is supported. You can find more information in the definition of the SCIM protocol.

Example of a query of users, including filtering

GET /identityprovider/scim/Users?filter=DisplayName%20co%20Smith
Host: example.com


HTTP/1.1 200 OK
Content-Type: application/json

{
    "schemas": [ "urn:scim:schemas:core:1.0" ],
    "totalResults": 37,
    "itemsPerPage": 37,
    "startIndex": 1,
    "resources": [
        {
            "id": "2b04bb70-10fa-4892-a62a-97627f0fc67f",
            "userName": "example\\smithj",
            "name": {
                "familyName": "Smith",
                "givenName": "John"
            },
            "displayName": "Smith, John",
            "title": "Senior Support Specialist",
            "emails": [
                {
                    "value": "smithj@example.org"
                }
            ],
            "phoneNumbers": [
                {
                    "value": "+1-234-56789-123456789"
                }
            ],
            "photos": [
                {
                    "value": "/identityprovider/scim/photo/2b04bb70-10fa-4892-a62a-97627f0fc67f"
                }
            ]
        },
        ...
    ]
}

info: When you retrieve multiple users, only the information about the individual users is transferred. You do not receive information about the groups in which these users are members. To identify the groups in which a user is a member, retrieve the information for the relevant user.

Example of a query of a specific user

GET /identityprovider/scim/Users/2b04bb70-10fa-4892-a62a-97627f0fc67f
Host: example.com


HTTP/1.1 200 OK
Content-Type: application/json

{
    "id": "2b04bb70-10fa-4892-a62a-97627f0fc67f",
    "userName": "example\\smithj",
    "name": {
        "familyName": "Smith",
        "givenName": "John"
    },
    "displayName": "Smith, John",
    "title": "Senior Support Specialist",
    "emails": [
        {
            "value": "smithj@example.org"
        }
    ],
    "phoneNumbers": [
        {
            "value": "+1-234-56789-123456789"
        }
    ],
    "groups": [
        {
            "value": "972a75b9-15fb-4a66-a3cf-299e29ac6f25",
            "display": "Development Department"
        }
    ],
    "photos": [
        {
            "value": "/identityprovider/scim/photo/2b04bb70-10fa-4892-a62a-97627f0fc67f"
        }
    ]
}

Some user providers supply more information than the SCIM protocol allows for (e.g. the LDAP user provider).
To receive all the information about a user, add the parameter detailLevel=1 to the call of the SCIM resource for a specific user. You can add the parameter detailLevel=1 to add the details property to the SCIM user object. You cannot use this property for filtering.

Example of a query of a specific user with all the available information

GET /identityprovider/scim/Users/2b04bb70-10fa-4892-a62a-97627f0fc67f?detailLevel=1
Host: example.com


HTTP/1.1 200 OK
Content-Type: application/json

{
    "id": "2b04bb70-10fa-4892-a62a-97627f0fc67f",
    "userName": "example\\smithj",
    ...,
    "details": [
        {
            "key": "distinguishedname",
            "values": [
                "CN=John Smith,DC=example,DC=org"
            ]
        },
        {
            "key": "givenname",
            "values": [
                "Smith"
            ]
        },
        {
            "key": "sn",
            "values": [
                "John"
            ]
        },
        {
            "key": "displayname",
            "values": [
                "Smith, John"
            ]
        },
        ...
    ]
}

Example of a query of the groups

GET /identityprovider/scim/Groups/
Host: example.com


HTTP/1.1 200 OK
Content-Type: application/json

{
    "schemas": [ "urn:scim:schemas:core:1.0" ],
    "totalResults": 81,
    "itemsPerPage": 81,
    "startIndex": 1,
    "resources": [
        {
            "id": "0e36c878-4d17-44c5-9eac-9ad8cb03274a",
            "displayName": "Administrators"
        },
        {
            "id": "3399e87a-32d5-4db5-a934-1c3e285d7e71",
            "displayName": "Development Department"
        },
        ...
    ]
}

info: When you retrieve multiple groups, the members of the individual groups are not transferred. To identify the members of a group, retrieve the information for the relevant group.

Example of a query of a specific group

GET /identityprovider/scim/Groups/3399e87a-32d5-4db5-a934-1c3e285d7e71
Host: example.com


HTTP/1.1 200 OK
Content-Type: application/json

{
    "id": "3399e87a-32d5-4db5-a934-1c3e285d7e71",
    "displayName": "Development Department",
    "members": [
        {
            "value": "3daa0360-8f02-4bde-bfd3-ac8f21e38107",
            "display": "Diaz, Sanford"
        },
        {
            "value": "4779fd78-f6de-4110-9b11-6e91195754e0",
            "display": "Larson, Priscilla"
        },
        {
            "value": "7e513868-1edc-446a-a042-83428addd663",
            "display": "Sanchez, Jessie"
        },
        ...
    ]
}

Authenticating an app with requests outside the user context

Apps can also be authenticated if requests are required that do not take place in the context of a logged-in user (e.g. processing in the background). In this case, you generate an API key in the IdentityProvider app and use it to generate an AuthSessionId with the aid of the IdentityProvider app.

Authentication using the API key initially takes place using a Bearer token. Use the API key in the Authorization header with the Bearer schema and set the Accept header to application/json. The Login route of the IdentityProvider app then returns a data transfer object with the values AuthSessionId and Expire. You can use the ID AuthSessionId for further authentication until the expiry date specified in the Expire value. For this purpose, fill the Authorization header with the Bearer schema with the ID returned earlier for the AuthSessionId value and call the desired resource.

Example in C#

using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Net.Http.Headers;

private class AuthSessionInfoDto
{
    public string AuthSessionId { get; set; }
    public DateTime Expire { get; set; }
}

public static void AuthTest()
{
    string apiKey = "<API key>";
    string baseUri = "https://<baseUri>";
    using (HttpClient client = new HttpClient() {BaseAddress = new Uri(baseUri)})
    {
        //Use d.ecs identity provider to convert the API key into an AuthSessionID
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
        client.DefaultRequestHeaders.Add("Accept", "application/json");
        HttpResponseMessage result = client.GetAsync("/identityprovider/login").Result;
        result.EnsureSuccessStatusCode();
        AuthSessionInfoDto authSessionInfo = JsonConvert.DeserializeObject<AuthSessionInfoDto>(result.Content.ReadAsStringAsync().Result);

        //Set the AuthSessionID as a bearer token and retrieve the resource
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authSessionInfo.AuthSessionId);
        client.DefaultRequestHeaders.Add("Accept", "application/hal+json");
        result = client.GetAsync("/exampleapp").Result;
        result.EnsureSuccessStatusCode();
        string content = result.Content.ReadAsStringAsync().Result;
        Console.WriteLine(content);
    }
}

Inter-app communication with app sessions

Apps may require an AuthSessionId that they can use to authenticate themselves with other apps. To do so, an app sends a JSON object with an HTTP-POST request to the end point /identityprovider/appsession. The JSON object contains the following values:

ParameterDescription
appnameThe name of the app.
callbackPath of the URI to which the AuthSessionId is to be sent (relative URI).
requestidRequest ID for checking whether the HTTP-POST request originates from this request.

warning: All three parameters must be sent and the callback URI must begin with a forward slash, followed by the app name.

Example

POST /identityprovider/appsession
Host: example.com
Content-Type: application/json

{
    "appname": "exampleapp",
    "callback": "/exampleapp/appsessioncallback",
    "requestid": "UbWN..."
}

Before the identityprovider-app responds to the request, it calls the specified callback URI. This callback is an HTTP-POST request with a JSON object with the following values:

ParameterDescription
authSessionIdAuthSessionId for the app.
expireExpiry date of the AuthSessionId in ISO 8601 format.
signSignature with the parameters appname, authSessionId, expire and requestid.
Format: Hex(Sha256(<appname><authSessionId><expire><requestid>)).

info: The parameter requestid should be a 256-bit random number. You should use a cryptographically secure random number generator to generate the number.

When calling the callback URI, the same HTTP status code is returned which is returned in the response of the app session request. This does not include status codes that indicate server errors (HTTP 5xx). If a status code for a server error is received, the identityprovider-app sends a 400 Bad Request resonse.

The callback URI call by the identityprovider-app does not contain any authentication in the headers. The validation of the data takes place exclusively on the basis of the signature.

Sample JSON object:

{
    "authSessionId": "KC5r...",
    "expire": "1970-01-01T00:00:00Z",
    "sign": "FDED..."
}

info: The parameter authSessionId can be used only for the app that issued the authSessionId.

To check whether the request belongs to your request when calling the callback URI, the app must calculate the signature (sign value from the JSON object) based on the specified pattern and compare it to the received signature.

When the validate end point is called, id and userName=<appname>@app.idp.d-velop.local are returned, which allows you to identify which app is sending the request. In addition, a group with the name App and the ID 6F3DEBD0-DB38-4061-A085-AD81D6ACF316 is specified.

Authenticating an app with requests in the user context without a user login

Apps can also be authenticated if requests are required that do not take place in the context of a logged-in user (e.g. processing in the background). The administrator must enable this function for the applicable app in the IdentityProvider app (Manage app trusts). Apps authorized in this way can then use an app session created earlier to request a temporarily valid impersonation session for a specific user. The session is valid for 30 minutes.

Example in C#

using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Net.Http.Headers;

private class ImpersonateSessionDto
{
    public string AuthSessionId { get; set; }
}

public static void AuthTest()
{
    string appSession = "<App session ID>";
    string userId = "<User ID>";
    string baseUri = "https://<baseUri>";
    using (HttpClient client = new HttpClient() {BaseAddress = new Uri(baseUri)})
    {
        //Use d.ecs identity provider to create an impersonation session 
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", appSession);
        HttpResponseMessage result = client.GetAsync("/identityprovider/impersonatesession?userId=" + userId).Result;
        result.EnsureSuccessStatusCode();
        ImpersonateSessionDto authSessionInfo = JsonConvert.DeserializeObject<ImpersonateSessionDto>(result.Content.ReadAsStringAsync().Result);

        //Set the AuthSessionId as a bearer token and retrieve the resource
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authSessionInfo.AuthSessionId);
        client.DefaultRequestHeaders.Add("Accept", "application/hal+json");
        result = client.GetAsync("/customapp").Result;
        result.EnsureSuccessStatusCode();
        string content = result.Content.ReadAsStringAsync().Result;
        Console.WriteLine(content);
    }
}

Special groups

The IdentityProvider app is also responsible for identifying administrators. If a user has administrative rights, a specific group with a fixed id value is added to the user when the SCIM user object is delivered. There are two ways to grant administrative rights to a user. The user is either a member of the administrator group of a provider or a member of the group Administrative group for the tenant. You can use the user's membership of these groups to check whether the user is an administrator.

The fixed administrator group

If a user has administrator authorizations, the user is added to the group Built-In-Admin-Group. This administrator group has the fixed ID DC4885EF-A72C-4489-95A1-F37269D6E48D.