Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Old hmac-generated (32bit) is recreated when order is changed in realm keys ui #42405

@yanxch

Description

@yanxch

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?

  1. Start Keycloak
  2. Create a test realm
  3. Run following script to insert old hmac-generated 32bit 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');
  1. Go to master realm. Clear realm cache and keys cache
  2. Go to test realm
  3. Go to keys tab.
  4. Change the order of the keys under Tab "Add providers" (drag&drop)
  5. 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 AbstractGeneratedSecretKeyProviderFactory and it's validateConfiguration method.
    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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions