Authenticating users

This document covers all aspects of user authentication in Eclipse Che, both on the Che server and in workspaces. This includes securing all REST API endpoints, WebSocket or JSON RPC connections, and some web resources.

All authentication types use the JWT open standard as a container for transferring user identity information. In addition, Che server authentication is based on the OpenID Connect protocol implementation, which is provided by default by Keycloak.

Authentication in workspaces implies the issuance of self-signed per-workspace JWT tokens and their verification on a dedicated service based on JWTProxy.

Authentication modes

Che supports multiuser and single-user mode.

Single-user mode

Single-user mode requires no authentication and anyone can access all cluster resources. In single-user mode, the server performs all operations as the predefined user, regardless of who accesses the server. Therefore, this mode is suitable only for use in a private instance for testing product possibilities and configurations.

  • H2 database is used.

Che deployed in single-user mode has no authentication and anyone who can access the URL of the Che deployment sees all workspaces and owns all resources. Because the deployment in this mode requires fewer containers, RAM and CPU requirements are lower. This mode is useful when the whole Che deployment is used by a single person or for lowering resources used. As the server does not authenticate, actions of multiple users logged in the same workspace can interfere with each other.

Use third-party services, such as HAproxy or NGINX, to secure Che in single-user mode.

Multiuser mode

Multiuser mode is the default mode for Che. It requires user authentication and offers isolated workspaces and their resources. In multiuser mode, workspaces are used in the scope of registered users and workspace definitions, and devfiles of particular workspaces can be shared and reused between many users.

  • Keycloak is used to authenticate users.

  • PostgreSQL database is used.

Changing the authentication mode

This procedure describes how to change authentication mode for various deployment types.

Procedure

Che deployed using the Che Operator defaults to multiuser mode. To change to sing-user mode:

  1. Update the CheCluster Custom Resource (CR) to set the CHE_MULTIUSER property to false:

    spec:
     server:
       customCheProperties:
          CHE_MULTIUSER: "false"

Che deployed using the Helm installer defaults to single-user mode. To change to multiuser mode:

  1. Set the multiuser Helm chart field to true:

    $ helm upgrade --install che --force --namespace eclipse-che --set global.cheDomain=<che-host>  -f multi-user.yaml

Che deployed using the chectl command-line tool defaults to single-user mode. To change to multiuser mode:

  1. Use the --multiuser (-m) option with the chectl server:deploy command:

    $ chectl server:deploy --platfrom=minikube --installer=helm --multiuser

Authenticating to the Che server

Authenticating to the Che server using OpenID

OpenID authentication on the Che server implies the presence of an external OpenID Connect provider and has the following main steps:

  • Authenticate the user through a JWT token that is retrieved from an HTTP request or, in case of a missing or invalid token, redirect the user to the Keycloak login page.

  • Send authentication tokens in an Authorization header. In limited cases, when it is impossible to use the Authorization header, the token can be sent in the token query parameter. Example: OAuth authentication initialization.

  • Compose an internal subject object that represents the current user inside the Che server code.

The only supported and tested OpenID provider is Keycloak.
Procedure

To authenticate to the Che server using OpenID authentication:

  1. Request the OpenID settings service where clients can find all the necessary URLs and properties of the OpenId provider, such as jwks.endpoint, token.endpoint, logout.endpoint, realm.name, or client_id returned in the JSON format.

  2. The service URL is \https://che-host:che-port/api/keycloak/settings, and it is only available in the Che multiuser mode. The presence of the service in the URL confirms that the authentication is enabled in the current deployment.

    Example output:

    {
        "che.keycloak.token.endpoint": "http://172.19.20.9:5050/auth/realms/che/protocol/openid-connect/token",
        "che.keycloak.profile.endpoint": "http://172.19.20.9:5050/auth/realms/che/account",
        "che.keycloak.client_id": "che-public",
        "che.keycloak.auth_server_url": "http://172.19.20.9:5050/auth",
        "che.keycloak.password.endpoint": "http://172.19.20.9:5050/auth/realms/che/account/password",
        "che.keycloak.logout.endpoint": "http://172.19.20.9:5050/auth/realms/che/protocol/openid-connect/logout",
        "che.keycloak.realm": "che"
    }

    The service allows downloading the JavaScript client library to interact with the provider using the \https://che-host:che-port/api/keycloak/OIDCKeycloak.js URL.

  3. Redirect the user to the appropriate provider’s login page with all the necessary parameters, including client_id and the return redirection path. This can be done with any client library (JS or Java).

  4. When the user is logged in to the provider, the client side-code is obtained, and the JWT token has validated the token, the creation of the subject begins.

The verification of the token signature occurs in two main steps:

  1. Authentication: The token is extracted from the Authorization header or from the token query parameter and is parsed using the public key retrieved from the provider. In case of expired, invalid, or malformed tokens, a 403 error is sent to the user. The minimal use of the query parameter is recommended, due to its support limitations or complete removal in upcoming versions.

    If the validation is successful, the parsed form of the token is passed to the environment initialization step:

  2. Environment initialization: The filter extracts data from the JWT token claims, creates the user in the local database if it is not yet available, and constructs the subject object and sets it into the per-request EnvironmentContext object, which is statically accessible everywhere.

    If the request was made using only a JWT token, the following single authentication filter is used:

    org.eclipse.che.multiuser.machine.authentication.server.MachineLoginFilter: The filter finds the user that the userId token belongs to, retrieves the user instance, and sets the principal to the session. The Che server-to-server requests are performed using a dedicated request factory that signs every request with the current subject token obtained from the EnvironmentContext object.

Providing user-specific data

Since Keycloak may store user-specific information (first and last name, phone number, job title), there is a special implementation of the ProfileDao that can provide this data to consumers. The implementation is read-only, so users cannot perform create and update operations.

Obtaining the token from credentials through Keycloak

Clients that cannot run JavaScript or other clients (such as command-line clients or Selenium tests) must request the authorization token directly from Keycloak.

To obtain the token, send a request to the token endpoint with the username and password credentials. This request can be schematically described as the following cURL request:

$ curl --insecure --data "grant_type=password&client_id=che-public&username=<USERNAME>&password=<PASSWORD>" \ (1) (2)
https://<keyckloak_host>/auth/realms/che/protocol/openid-connect/token (3)
1 Eclipse Che username
2 Eclipse Che user’s password
3 Keycloak host

The Che dashboard uses a customized Keycloak login page and an authentication mechanism based on grant_type=authorization_code. It is a two-step authentication process:

  1. Logging in and obtaining the authorization code.

  2. Obtaining the token using this authorization code.

Obtaining the token from the OpenShift token through Keycloak

When Che was installed on OpenShift using the Operator, and the OpenShift OAuth integration is enabled, as it is by default, the user’s Che authentication token can be retrieved from the user’s OpenShift token.

To retrieve the authentication token from the OpenShift token, send a schematically described cURL request to the OpenShift token endpoint:

$ curl --insecure -X POST  \
-d "client_id=che-public" \
-d "subject_token=<USER_OPENSHIFT_TOKEN>" \ (1)
-d "subject_issuer=<OPENSHIFT_IDENTITY_PROVIDER_NAME>" \ (2)
--data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
--data-urlencode "subject_token_type=urn:ietf:params:oauth:token-type:access_token" \
https://<KEYCKLOAK_HOST>/auth/realms/che/protocol/openid-connect/token (3)
1 The token retrieved by the end-user with the command oc whoami --show-token
2 openshift-v4 for OpenShift 4.x and openshift-v3 for OpenShift 3.11
3 Keycloak host
Before using this token exchange feature, it is required for an end user to be interactively logged in at least once to the Che Dashboard using the OpenShift login page. This step is needed to link the OpenShift and Keycloak user accounts properly and set the required user profile information.

Authenticating to the Che server using other authentication implementations

This procedure describes how to use an OpenID Connect (OIDC) authentication implementation other than Keycloak.

Procedure
  1. Update the authentication configuration parameters that are stored in the multiuser.properties file (such as client ID, authentication URL, realm name).

  2. Write a single filter or a chain of filters to validate tokens, create the user in the Che dashboard, and compose the subject object.

  3. If the new authorization provider supports the OpenID protocol, use the OIDC JS client library available at the settings endpoint because it is decoupled from specific implementations.

  4. If the selected provider stores additional data about the user (first and last name, job title), it is recommended to write a provider-specific ProfileDao implementation that provides this information.

Authenticating to the Che server using OAuth

For easy user interaction with third-party services, the Che server supports OAuth authentication. OAuth tokens are also used for GitHub-related plug-ins.

OAuth authentication has two main flows:

delegated

Default. Delegates OAuth authentication to Keycloak server.

embedded

Uses built-in Che server mechanism to communicate with OAuth providers.

To switch between the two implementations, use the che.oauth.service_mode=<embedded|delegated> configuration property.

The main REST endpoint in the OAuth API is /api/oauth, which contains:

  • An authentication method, /authenticate, that the OAuth authentication flow can start with.

  • A callback method, /callback, to process callbacks from the provider.

  • A token GET method, /token, to retrieve the current user’s OAuth token.

  • A token DELETE method, /token, to invalidated the current user’s OAuth token.

  • A GET method, /, to get the list of configured identity providers.

Using Swagger or REST clients to execute queries

The user’s Keycloak token is used to execute queries to the secured API on the user’s behalf through REST clients. A valid token must be attached as the Request header or the ?token=$token query parameter.

Access the Che Swagger interface at \https://che-host:che-port/swagger. The user must be signed in through Keycloak, so that the access token is included in the Request header.

Authenticating in a Che workspace

Workspace containers may contain services that must be protected with authentication. Such protected services are called secure. To secure these services, use a machine authentication mechanism.

JWT tokens avoid the need to pass Keycloak tokens to workspace containers (which can be insecure). Also, Keycloak tokens may have a relatively shorter lifetime and require periodic renewals or refreshes, which is difficult to manage and keep in sync with the same user session tokens on clients.

che authentication inside the workspace
Figure 1. Authentication inside a workspace

Creating secure servers

To create secure servers in Che workspaces, set the secure attribute of the endpoint to true in the dockerimage type component in the devfile.

Devfile snippet for a secure server
components:
  - type: dockerimage
    endpoints:
      - attributes:
          secure: 'true'

Workspace JWT token

Workspace tokens are JSON web tokens (JWT) that contain the following information in their claims:

  • uid: The ID of the user who owns this token

  • uname: The name of the user who owns this token

  • wsid: The ID of a workspace which can be queried with this token

Every user is provided with a unique personal token for each workspace. The structure of a token and the signature are different than they are in Keycloak. The following is an example token view:

# Header
{
  "alg": "RS512",
  "kind": "machine_token"
}
# Payload
{
  "wsid": "workspacekrh99xjenek3h571",
  "uid": "b07e3a58-ed50-4a6e-be17-fcf49ff8b242",
  "uname": "john",
  "jti": "06c73349-2242-45f8-a94c-722e081bb6fd"
}
# Signature
{
  "value": "RSASHA256(base64UrlEncode(header) + . +  base64UrlEncode(payload))"
}

The SHA-256 cipher with the RSA algorithm is used for signing JWT tokens. It is not configurable. Also, there is no public service that distributes the public part of the key pair with which the token is signed.

Machine token validation

The validation of machine tokens (JWT tokens) is performed using a dedicated per-workspace service with JWTProxy running on it in a separate Pod. When the workspace starts, this service receives the public part of the SHA key from the Che server. A separate verification endpoint is created for each secure server. When traffic comes to that endpoint, JWTProxy tries to extract the token from the cookies or headers and validates it using the public-key part.

To query the Che server, a workspace server can use the machine token provided in the CHE_MACHINE_TOKEN environment variable. This token is the user’s who starts the workspace. The scope of such requests is restricted to the current workspace only. The list of allowed operations is also strictly limited.