-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Description
Before reporting an issue
- I have read and understood the above terms for submitting issues, and I understand that my issue may be closed without action if I do not follow them.
Area
core
Describe the bug
For us the problem occured on 26.0.12 but I could reproduce it with 26.3.3 as well.
We had an old 32 bit hmac-generated key hanging around, which was still used for signing refresh tokens.
After generating a new rsa key (totally unrelated to the hmac) and changing the order of the keys in the ui, the old 32bit hmac was recreated with a new kid, algorithm, size and priority. The old one was gone.
This was a very unfortunate event, bc we did not notice it and it took us a while to figure out what was happening.
In the meanwhile all users with a "old" refresh token got a "invalid refresh token" error when performing a token refresh, which led to a lot of users beeing logged out (at least in our frontend app implementation)
Version
26.3.3
Regression
- The issue is a regression
Expected behavior
When changing the order of the keys in the ui, old hmac-generated 32bit keys are not re-created.
Actual behavior
When changing the order of the keys in the ui, old hmac-generated 32bit keys are re-created.
How to Reproduce?
- Start Keycloak
- Create a test realm
- Run following script to insert old
hmac-generated32bit key: (values from a test environment)
INSERT INTO component(id, name, parent_id, provider_id, provider_type, realm_id, sub_type)
VALUES (
'da946d6f-c989-4e57-a642-782b734bfdc6',
'hmac-generated',
(select id from realm where name='test'),
'hmac-generated',
'org.keycloak.keys.KeyProvider',
(select id from realm where name='test'),
null);
INSERT INTO component_config(id, component_id, name, value)
VALUES ('9e8f4ad8-81f3-40ef-9392-82ef423f7270', 'da946d6f-c989-4e57-a642-782b734bfdc6', 'priority', '100');
INSERT INTO component_config(id, component_id, name, value)
VALUES ('1eeba382-06f5-4912-8926-107eee6d8a88', 'da946d6f-c989-4e57-a642-782b734bfdc6', 'secret', 'Vm4tTcOyVQdoXZAXSDf9EoIsVk5BhF0bMw56ogpO6e0');
INSERT INTO component_config(id, component_id, name, value)
VALUES ('6ad0954d-5760-4c5e-a61e-f2cb07533860', 'da946d6f-c989-4e57-a642-782b734bfdc6', 'kid', '6ccd546a-968e-44fa-adff-3df342c059bb');
- Go to master realm. Clear realm cache and keys cache
- Go to test realm
- Go to keys tab.
- Change the order of the keys under Tab "Add providers" (drag&drop)
- Notice that the kid of the hmac-generated key changed.
Dockerfile:
FROM quay.io/keycloak/keycloak
ENV KC_DB=postgres
RUN /opt/keycloak/bin/kc.sh build \
--http-relative-path /auth \
--health-enabled=true \
--metrics-enabled=true \
--features scripts
ENTRYPOINT [ "/opt/keycloak/bin/kc.sh", "--debug", "start", "--http-enabled=true", "--hostname-strict=false"]
docker-compose.yaml:
version: '3.8'
services:
keycloak_local:
build:
context: .
dockerfile: ./Dockerfile
environment:
- KC_BOOTSTRAP_ADMIN_USERNAME=admin
- KC_BOOTSTRAP_ADMIN_PASSWORD=admin
- KC_DB=postgres
- KC_DB_URL_HOST=postgres_keycloak_local
- KC_DB_URL_DATABASE=keycloak
- KC_DB_PASSWORD=password
- KC_DB_USERNAME=keycloak
- KC_DB_SCHEMA=public
- KC_HTTP_RELATIVE_PATH=/auth
- KC_METRICS_ENABLED=true
- DEBUG_PORT='*:8787'
ports:
- 8080:8080
- 9000:9000
- 8787:8787
- 9000:9000
depends_on:
postgres_keycloak_local:
condition: service_healthy
postgres_keycloak_local:
image: postgres:16.2
command:
- postgres
volumes:
- ./keycloak_local/postgres:/var/lib/postgresql/data
environment:
- POSTGERS_DB=keycloak
- POSTGRES_USER=keycloak
- POSTGRES_PASSWORD=password
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U keycloak -d keycloak" ]
interval: 10s
timeout: 10s
retries: 5
ports:
- 5432:5432
Anything else?
Looking in the code there a several things i would like to highlight:
-
Before changing the order in the ui all keys had a priority of 100. With the change of the order of one key all keys got a new priority and were updated. I would not expect that.
-
The root of the problem lays within this class
AbstractGeneratedSecretKeyProviderFactoryand it'svalidateConfigurationmethod.
I would not expect a an update of a key in a validate method.
public abstract class AbstractGeneratedSecretKeyProviderFactory<T extends KeyProvider> implements KeyProviderFactory<T> {
@Override
public void validateConfiguration(KeycloakSession session, RealmModel realm, ComponentModel model) throws ComponentValidationException {
ConfigurationValidationHelper validation = SecretKeyProviderUtils.validateConfiguration(model);
validation.checkList(Attributes.SECRET_SIZE_PROPERTY, false);
int size = model.get(Attributes.SECRET_SIZE_KEY, getDefaultKeySize()); // <---
if (!(model.contains(Attributes.SECRET_KEY))) {
generateSecret(model, size);
logger().debugv("Generated secret for {0}", realm.getName());
} else {
int currentSize = Base64Url.decode(model.get(Attributes.SECRET_KEY)).length;
if (currentSize != size) { // <---
generateSecret(model, size); // <---
logger().debugv("Secret size changed, generating new secret for {0}", realm.getName());
}
}
}
getDefaultKeySize() returns 64/128 since 2017, but the old key only has 32bit