My little Keycloak Book © 2024 by Dirk Strauss is licensed under CC BY-NC-SA 4.0. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/
|
Warning
|
Disclaimer: this is a work in progress and may contain errors. If you find any, please report them to this project’s issue tracker. A preview version can be found here. |
Introduction
Hi, all.
This small book here is a summary of knowledge I gathered during my time spending with Keycloak.
Keycloak is a server software written in Java, running in Quarkus, to allow authentication and authorization against other identity providers, like Github, Google, Facebook etc., or use another backing database, such as Postgresql or LDAP.
It can be used for your own application to perform authentication and authorization so that you can secure your application.
Keycloak can act as a wrapper to so called identity providers. For example, if you want to use Google as an identity provider, you can do so by configuring Keycloak to use the Google identity provider. Whenever you want to have a user authenticated against Google, you just need to use the Keycloak login page, and you will be redirected to Google. Here you have to authenticate against Google, and then you will be redirected back to Keycloak where it will create a new user in your Keycloak instance. You can then apply several permissions to this user, and you will be able to use it in your application. And, you can create an access token for this user against Google, so that you can perform actions on behalf of this user.
Wording
Keycloak uses specific words to describe objects and flows. Here are some explainations of them.
| Object | Description |
|---|---|
Realm |
A realm is a collection of users, clients, and groups. |
Client |
A client is a representation of an application that can use Keycloak to authenticate users. |
User |
A user is a representation of a person that can log into an application. |
Group |
A group is a collection of users. |
Identity Provider |
A system/website that can authenticate users. Famous examples are Google, Facebook, GitHub etc. |
Principal |
Mostly for Kerberos, this is a user account |
So, from a top-down view:
-
a realm contains users, clients, and groups.
-
a Keycloak instance can have multiple realms (usually you have only two: a master realm, and your own application realm).
From a developer’s point of view:
-
you define a realm for your application
-
you create permissions for your application (what a user can do/is allowed to do)
Basics
Here we want to talk about the fundamentals.
JWT
The JSON Web Token, or jwt for short, is a string, having three base64 encoded parts, concattenated via a dot, as defined in RFC-7519. So, a JWT looks like:
abc123.def123.ghi123
The first part is the header json and tells about the encryption algorithm for the checksum (part 3).
Example:
{
"alg": "HS256",
"typ": "JWT",
"kid": "n81WW5LhmLKgEyMcAxAhxUV_c6s9WEWnwngQY_-PXH0"
}
-
alg = the algorithm used to create the checksum
-
typ = the type of the token
-
kid = the key id/thumbprint of the public key, which is a reference to the key used to create the checksum
The second json defines the content or payload:
{
"sub": "user01",
"name": "Max Mustermann",
"iat": 1516239022,
"exp": 1516239322,
"jti":"f7d3f86f-7841-41a9-96ef-8a6e3998676c"
"iss":"https://172.21.0.100/auth/realms/MyRealm01",
"aud": ["account", "my.client.01"],
"typ": "Bearer",
"azp": "my.client.01",
"scope": "openid email profile",
"session_state": "81b6e804-2414-42be-931d-ffecbcbb8616",
"acr": "1",
...
}
Each root field in this object is called a claim. For example user.roles, or my-field-id. You can add claims by yourself if needed.
There are some pre-defined claims in jwt:
-
sub = the subject identifier, also known as the user id
-
name = the subject display name
-
iat = the time this token got created
-
exp = the time this token expires
-
jti = the unique identifier of this token
-
iss = the issuer of this token
-
aud = the audience of this token (basically, which client this token belongs to)
-
typ = the type of this token (Bearer)
-
azp = the authorized party of this token (basically, which client this token was created for)
-
acr = the authentication context class reference of this token
-
scope = the scopes this token was created for
As you can see, there are also additional "claims", like session_state and acr. This is a Keycloak specific claim. And you can add more claims by yourself. Like my-field-id in the example above.
The third part is a checksum of the header and the content:
checksum = HMACSHA256(base64urlEncode(header as string) + "." + base64urlEncode(payload as string), secret)
The checksum is simply added to both the base64 of the header and the content, added with a dot.
In Keycloak, the dot has a special definition: it defines sub objects in Json. So, user.roles with a value of "myrole01" will end up in a json object in the jwt as:
{
"user": {
"roles": "myrole01"
}
}
So, be careful when you have dots in a name. If you still need dots, they need to be escaped with a backslash: \.
You can read more about JWT on their homepage.
Kerberos
Kerberos is a protocol to authenticate users over an unencrypted network, using encryption. Nowadays also the network is usually encrypted.
Directory Services
Here we talk about LDAP and Active Directory.
Keycloak
In this chapter I want to talk about Keycloak itself. All of its meaning, its wordings, procedures etc.
Permissions and Roles
The first thing we have to clarify is the concept of permissions and roles. And the security model of the application.
A role is a type of a user.
A permission can be something like can-read-newspage.
Flows
Flows define what authentication mechanisms can be used. Basically, what is required during authentication, like a password, or a specific token, or what fallback mechanisms are allowed during authentication. Also, steps like "send verification email" can be defined per flow. And, if these steps are "Required", or "Alternative".
Standard Flow
This is really the standard flow. The user uses a web browser on a website. To authenticate, the user is redirected from the website to the Keycloak login site. There the user authenticates against a configured source for the realm. For any result, the user gets redirected back to the website with the authentication result, be it success or failed.
Direct Access Grants Flow
Implicit Flow
Service Accounts Roles
OAuth2 Device Authorization Grant
OpenID Connect CIBA Grant
Clients
A client is an application that is allowed to work with Keycloak. It is associated to a Realm. In our later examples, one such client is our website. Or our backend server. Users must use a client to authenticate against a Realm in Keycloak.
User → Client → Keycloak → Realm → User Federation or Identity Provider
class A<T> <<singleton>> {
{abstract} -int x
{static} #void meta()
}
class B
A <|-- B
Clients can be public or confidential.
If public, the client can be accessed without a client secret. If confidential, the client gets a client secret that the caller must provide in order to use the client.
Roles
Roles are types of users, like Reader, Author, RaidLeader, Administrator, or SuperAdministrator etc. They all might have different permissions.
Realm Roles
These are roles belonging to a realm.
A role can have some attributes (key-value pairs).
Client Roles
Roles associated to a client.
Role mapping
Role mapping describes a way to map a role from an IDP or User Federation into a Realm Role (or Client Role).
This can be converting a given single string from the external token to a specific role within the realm.
Dealing with special characters
Sometimes, external roles might contain special characters. Like a dot. In this case, your role mapper must replace these characters with another character. Perhaps an underscore.
User Federation
This is just another buzzword for authenticating the user against a database. The database can either be:
-
a database (Postgresql?)
-
LDAP/ActiveDirectory
For failover, you can define a sequence of federations. By default, the first match wins. If all federations fail, the user is unauthenticated. This is usually done by having the Connection URL using spaces between the connection strings. At least for the LDAP.
Be aware that Keycloak uses an internal database to store all of its configurations, as well as user accounts based on the external reference. Which means, if User A is known via an LDAP lookup, Keycloak will create an internal account for this user to store the reference to LDAP, as well as to allow adding additional keycloak related attributes to this account.
Using Kerberos
You can use Kerberos for user and service authentication against Keycloak. For this, the Kerberos server must exist, have a principal, and a keytab.
For Kerberos, you need to provide some information about the Kerberos Realm and the server principal (as well as its keytab file).
-
the Kerberos realm; example: DS2.LAN (yes, uppercase!!)
-
the server principal; example: HTTP/www.ds2@DS2.LAN (the service identifier HTTP, then the dns name where the Keycloak server can be found, followed by the realm name)
-
the keytab file of this principal; can be generated when setting up the principal in Kerberos
|
Note
|
The keytab file contains the symmetric key of the principal, and the signing key of the realm. |
Using LDAP
You can use an LDAP server for user authentication. Since Active Directory is a Windows server, you can use the Active Directory server as an LDAP server.
Integration into Keycloak
LDAP vs LDAPS
Using ActiveDirectory
This is Microsofts answer to LDAP, also containing Kerberos interfaces. Since an AD server is usually a domain controller, it also runs a DNS server, IIS etc.
AD defines a domain name, for example ds2. This can be also then used, together with the dns name, for the Kerberos realm. For example, if your network domain is called fritz.box, your Kerberos realm might be known as DS2.FRITZ.BOX (be aware of the uppercase name for Kerberos realms!).
In the AD you define users and groups.
There is a special user called krbtgt which acts as the Kerberos "user" (or "Key Distribuction Center Service Account") to receive ticket-granting-ticket queries. This user is deactivated by default to avoid logging in as this user. Since this is a system user, there are no issues here.
Via PowerShell you can create the required keytab file for Kerberos if you need one. In case of Keycloak, it depends on whether Kerberos authentication is required or not.
To show all service principals related to a user, run:
setspn -l USERNAME
# for example: setspn -l administrator
Scopes
Scopes are units that contain specific attributes. In Keycloak, a scope defines what attributes a client can get and/or request. It defines a set of mappers.
Client Scopes
Client scopes are scopes that are specific to clients only. That means, a client can have a scope that returns specific data back to the caller that usually are not needed in realm scope.
Configure Keycloak
In this chapter, we want to discuss how to configure Keycloak.
Setting timeouts to connections
There are several ways to set timeouts to connections. You have the initial connection from your client to the server. And from within the server to other IdPs. And database connections, ldap connections etc.
So, famous flow is:
You → Keycloak → IdP → Database/LDAP/etc.
You have the timeout between you and Keycloak. Then internally Keycloak to speak to the Idp. And the Idp may have another timeout accessing its database. So, quite some things to configure here. Usually you want the last part of this chain to have a smaller timeout than the first ones.
When talking between you and Keycloak, or Keycloak to another Idp, there is an http client involved.
Here is a list of properties that can be set:
-
spi-connections-http-client-default-socket-timeout-millis(5000) the default http socket timeout -
spi-connections-http-client-default-connection-timeout-millis(5000) the default http connection timeout -
spi-connections-http-client-default-connection-request-timeout-millis(5000) the default http connection request timeout -
spi-connections-http-client-default-connection-pool-size(100) the default http connection pool size
Some properties can be also represented as environment variables. Usually, you take the property name, replace - with an underscore and convert it to upper case, prefixing it with KC_. So, to match one property from above, you would use KC_SPI_CONNECTIONS_HTTP_CLIENT_DEFAULT_SOCKET_TIMEOUT_MILLIS, setting it to 10000.
Setting timeouts for LDAP
Besides that you can configure the timeouts via API, you can also configure them via the admin console. Just go to the realm settings, and then to the LDAP settings (in user federations). There you can set the Connection Timeout for the specific ldap user federation.
Running Keycloak
The very simplest way to run Keycloak is to run it as container.
|
Note
|
I prefer Podman over Docker. In my examples I will use Podman, but you can use Docker as well. |
# pull the image
podman pull quay.io/keycloak/keycloak:24.0
# run the image
podman run --rm -d -p 18080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=myadminpw quay.io/keycloak/keycloak:24.0 start-dev
Now you can open Keycloak at http://localhost:18080/.
Using Keycloak for your application
So, you have an application. And you want that people can sign in to it and do some stuff they are allowed to do. That means, you need to put these users into specific groups. And these groups get specific permissions. Your application knows about the permissions and can either allow or deny specific actions the user can do. Then you should get a server that can authenticate users and get their permissions. Something like, I don’t know: Keycloak.
So, this chapter deals about setting up Keycloak for your application.
Our Angular App with Keycloak
For our sample app we will use Angular, and Keycloak as our authentication provider. This will be a simple guild web site, where people can login, create posts, and comment on them. Some users might be able to change the layout, or edit posts of others.
Using Rust with Keycloak
In this chapter we will use the Rust language to interact with Keycloak. Especially by using Actix-Web for a simple REST CRUD API.
The API of Keycloak
In this chapter we will talk about how to configure Keycloak remotely via its own API.
Sources
Here is a list of some of the web sites I used to gather information from:
Legal stuff
All the names here are owned by their respective owners.
I am not a developer of Keycloak, I am just a user who has a Keycloak server.
Version of this document: ebc55c28638fe7f56fc8841f16c7ed843f59ce53