users
« Previous section Next section »
UCloud Developer Guide / Core / Users / Authentication / User Authentication
User Authentication
User authentication is done using one of several different backends.
Authenticating with UCloud
UCloud provides various backends for authentication. These are all implemented in the authentication service. As of 27/06/23 the following backends are supported:
Authentication with username/password
Authentication via WAYF
Optional backend for OpenID (disabled in current production env)
Below we will be covering the technical details of each backend.
All authentication information for a user is stored in a PostgreSQL table and is managed only by the authentication service. We will cover the concrete data stored later. A column in the table is used for differentiating which authentication backend is used.
WAYF is considered the primary authentication backend.
Password
Users can login with a simple username/password combination. Only administrators of the system can create new users. These are created in the "Admin" panel of the UCloud web interface.
We allow users to change their password through the web interface (by going to "Settings" in the user menu). Users are required to provide their current password in order to change to a new one.
Currently no password policy is implemented.
Login attempts are logged through normal auditing. We limit number of incorrect login attempts according to the following recommendations.
Passwords are stored following recommendations by OWASP. Password hashing is provided via OpenJDK. Specifically we use PBKDF2WithHmacSHA512
with the following parameters:
Salt length: 16 bytes (Generated via
SecureRandom
)Iterations: 10000
Key length: 256
WAYF
WAYF (Where Are You From) is a danish identity federation for research and infrastructure. WAYF provides authentication via the local organization (e.g. SDU). At a technical level this is implemented with SAML.
UCloud implements the SAML integration by using Onelogin's library for SAML (com.onelogin:java-saml-core
, see the build.gradle
of auth-service
for the specific version). Minor modifications to the library were made to support a different webserver (ktor). These changes are implemented in dk.sdu.cloud.auth.services.saml.SamlRequestProcessor
.
The SAML library is configured according to WAYF's own recommendations.
Sessions and Tokens
Once a user has been successfully authenticated with UCloud a number of tokens are issued for the user. These tokens are used during the authentication workflow.
The table below summarizes the tokens and where they are stored when the web interface is being used.
Name | Token Type | Storage Type | Purpose |
| Local Storage | Authenticate API calls | |
| Opaque | HTTP Only Cookie | Used for creating new |
| Opaque | Local Storage | Used in combination with |
The accessToken
is used to authenticate all API calls. It is passed as a bearer token in the Authorization
header. The token contains a JSON web token. These are tokens which contain a JSON encoded payload and are signed by the authority issuing them. The JWTs in UCloud are signed with the SHA256withRSA
algorithm. Each microservice can verify a JWT (without contacting a central server) by using the authentication's service public certificate and additionally verifying that the issuer is set to cloud.sdu.dk
.
We store the accessToken
in local storage. This is a technical requirement given that our JavaScript code must be able to attach the token to each request in the Authorization
header. However, storing secret tokens, such as the accessToken
, in local storage can be problematic since it can easily be stolen by malicious JavaScript. This could happen in case of a successful XSS attack. To minimize the impact of a successful attack we ensure that the JWTs are relatively short lived (10 minutes). We do not implement a JWT blacklist and rely only on the short expiry time of the JWTs.
Given that JWTs expire after 10 minutes we need a different mechanism for keeping the user logged in. For this we use the refreshToken
. The refresh token is an opaque token which can be used to generate a new accessToken
. A user can keep using the same refresh token for creating new access tokens until the refresh token is invalidated. A refresh token will be invalidated once the user logs out.
In order to protect against XSS attacks the refreshToken
is stored as a cookie with the following flags:
HttpOnly
SameSite Strict
Secure
Expires after 30 days
When refreshing the token via a cookie the csrfToken
must be passed in the X-CSRFToken
header. If the CSRF token is not present or does not match the server's records the token will not be refreshed.
JWT Payload
The following is an example of a JWT payload. This payload is decodable by anyone who has a JWT. As a result it is crucial that we do not store sensitive data in it.
Token Properties
These properties are about the token itself and are used as part of the verification process.
Property | Description |
| Unix timestamp indicating when the token was issued at |
| Unix timestamp indicating when the token will expire |
| The issuer of this token. For UCloud this should always be |
| A unique ID of this token. If this field is present then this JWT is used as a one-time token. |
One-Time Tokens
All users are allowed to use their normal JWT to create a one-time token. This one-time token is designed to be used only once and we keep a list of already claimed JWTs to ensure this. A one-time token is created for a specific security scope and this scope must be covered by the JWT requesting it. The JWT created will only last for thirty seconds.
Authorization in UCloud
These properties are related to the authorization mechanisms of UCloud. This is tightly related to how the RPC layer is defined.
Property | Description |
| The role of this user. See table and description below. |
| A list of security scopes. See below. |
Roles
UCloud contains a few basic roles used for global authorization. These attributes only refer to the global authorization, more fine-grained authorization is done at the service level. A microservice can declare that a single API endpoint should only be accessible to users with a given role.
The table below shows the global roles in UCloud:
Role | Description |
| A 'normal' end-user |
| An administrator of system. Has access to certain privileged actions. |
| An internal (micro)service. Has access to certain privileged actions. |
| A UCloud provider used to deliver services. |
The deployment script (see k8-manager
) is responsible for the creation of service accounts. Service accounts can only authenticate via their refreshToken
/accessToken
. Compromised refreshToken
s can manually be regenerated. Note that the same restrictions apply for accessToken
s as normal users, they need to expire before access is denied. This happens within 30 minutes. Every microservice has an associated service account.
Security Scopes
A security scope in UCloud puts a limit on which calls a JWT can be used for. In order to understand security scopes in UCloud we must first understand some of the metadata associated with API endspoints. All API endpoints in UCloud have metadata associated with them, the table below summarizes the important metadata:
Property | Description |
| Each endpoint belongs to a collection. We refer to the collection's name as the namespace. Namespaces can be hierarchical and are separated by a |
| A unique name for the API endpoint within it's collection. |
|
|
A security scope is a string combining these three properties in the following format: ${path}:${accessRight}:${metadata}
. The path
can be some part of the namespace or it can refer to just a specific call by combining the namespace with the name. The security scope grants the accessRight
for all calls that are children of the path
. A special namespace exists called all
which can be used for any and all namespaces.
Below are some examples:
Scope | Grants |
| Grants read/write access to all endpoints. |
| Grants read only access to all endpoints within the |
| Grants read/write access to all endpoints within the |
| Grants read access to the |
| Grants read access to the hierarchy at |
The metadata
section of the security scope is optional. It encodes a dictionary. Entries are separated by a ,
and each entry is encoded as: ${base64encode(key)}!${base64encode(value)}
. The metadata
section can be used to store call specific metadata. This could for example be used to create an accessToken
which can only be used to read files from a specific directory.
The default scope for tokens created by the web interface is all:write
. Security scopes are an important part of token extension.
Token Extension
Token extension is a mechanism used for when a service needs to perform actions on behalf of a user that cannot be performed immediately. For example, an application service might need to upload files back into the system after a long computation. The service cannot use the user's JWT since that will have expired by the time the computation is done.
Services are allowed to extend a user JWT for a set of security scopes. The extended token will be a tuple of accessToken
and optionally a refreshToken
. The accessToken
(either returned directly or created later) will only be valid for the given security scope.
The authentication service contains a whitelist of security scopes each service is allowed to ask for. Any request not covered by this whitelist will be rejected. This minimizes the dangers of a single service being compromised.
The service that extended the token is added to extendedByChain
. This allows us to track requests performed by a service on behalf of a user.
Session References
A session reference is an opaque token which has a 1:1 mapping with a refreshToken
. This allows us, in combination with auditing information, to determine from which request a JWT was minted. The session reference is not considered secret and does not allow a user to create new JWTs.
User Metadata
Property | Description |
| The username of this user. |
| The type of users. (wayf/password/service) |
| First name(s). |
| Last name. |
| Unique user ID |
| Organization ID (provided by WAYF) |
| Indicates if the ToS agreement has been agreed |
| Indicates if 2FA is enabled |
Table of Contents
Remote Procedure Calls
browseIdentityProviders
browseIdentityProviders
Request | Response | Error |
---|---|---|
listUserSessions
listUserSessions
Request | Response | Error |
---|---|---|
passwordLogin
passwordLogin
Request | Response | Error |
---|---|---|
startLogin
startLogin
Request | Response | Error |
---|---|---|
bulkInvalidate
bulkInvalidate
Request | Response | Error |
---|---|---|
claim
claim
Request | Response | Error |
---|---|---|
invalidateSessions
invalidateSessions
Request | Response | Error |
---|---|---|
logout
logout
refresh
refresh
Request | Response | Error |
---|---|---|
requestOneTimeTokenWithAudience
requestOneTimeTokenWithAudience
Request | Response | Error |
---|---|---|
tokenExtension
tokenExtension
Request | Response | Error |
---|---|---|
webLogout
webLogout
Request | Response | Error |
---|---|---|
webRefresh
webRefresh
Request | Response | Error |
---|---|---|
Data Models
AccessToken
AccessToken
AccessTokenAndCsrf
AccessTokenAndCsrf
ClaimOneTimeToken
ClaimOneTimeToken
IdentityProvider
IdentityProvider
OneTimeAccessToken
OneTimeAccessToken
OptionalAuthenticationTokens
OptionalAuthenticationTokens
Session
Session
BulkInvalidateRequest
BulkInvalidateRequest
ListUserSessionsRequest
ListUserSessionsRequest
RequestOneTimeToken
RequestOneTimeToken
TokenExtensionRequest
TokenExtensionRequest
Last updated