Add documentation to monitoring and openID (#19285)

* added documentation files

Signed-off-by: xbaran4 <pbaran@redhat.com>
7.28.x
Pavol Baran 2021-03-19 13:52:14 +01:00 committed by GitHub
parent 1f1c43875d
commit 85f4b135ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 163 additions and 0 deletions

View File

@ -0,0 +1,109 @@
// authenticating-to-the-che-server
[id="authenticating-to-the-che-server-using-openid_che"]
= 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.
NOTE: The only supported and tested OpenID provider is Keycloak.
.Procedure
To authenticate to the Che server using OpenID authentication:
. 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.
. The service URL is `pass:c,a,q[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:
+
[source,json]
----
{
"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 `pass:c,a,q[https://che-host:che-port/api/keycloak/OIDCKeycloak.js]` URL.
. 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).
. 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:
. 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:
. 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.
[NOTE]
====
.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.
====
[id="obtaining-the-token-from-keycloak_che"]
== 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:
[subs="+quotes,+attributes"]
----
$ 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&#160;Che username
<2> Eclipse&#160;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:
. Logging in and obtaining the authorization code.
. Obtaining the token using this authorization code.
[id="obtaining-the-token-from-openshift-token-through-keycloak_che"]
== 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:
[subs="+quotes,+attributes"]
----
$ 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
WARNING: 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.

View File

@ -0,0 +1,54 @@
// monitoring-che
[id="extending-che-monitoring-metrics_che"]
= Extending Che monitoring metrics
This section describes how to create a metric or a group of metrics to extend the monitoring metrics that Che is exposing.
Che has two major modules metrics:
* `che-core-metrics-core` -- contains core metrics module
* `che-core-api-metrics` -- contains metrics that are dependent on core Che components, such as workspace or user managers
.Procedure
* Create a class that extends the `MeterBinder` class. This allows to register the created metric in the overridden `bindTo(MeterRegistry registry)` method.
+
The following is an example of a metric that has a function that supplies the value for it:
+
.Example metric
[source,java]
----
public class UserMeterBinder implements MeterBinder {
private final UserManager userManager;
@Inject
public UserMeterBinder(UserManager userManager) {
this.userManager = userManager;
}
@Override
public void bindTo(MeterRegistry registry) {
Gauge.builder("che.user.total", this::count)
.description("Total amount of users")
.register(registry);
}
private double count() {
try {
return userManager.getTotalCount();
} catch (ServerException e) {
return Double.NaN;
}
}
----
+
Alternatively, the metric can be stored with a reference and updated manually in other place in the code.
.Additional resources
* link:https://prometheus.io/docs/practices/naming/[Metric and label naming for Prometheus]
* link:https://prometheus.io/docs/concepts/metric_types/[Metric types for Prometheus]