Uploaded image for project: 'Red Hat build of Keycloak'
  1. Red Hat build of Keycloak
  2. RHBK-3602

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

XMLWordPrintable

    • False
    • Hide

      None

      Show
      None
    • False

      Before reporting an issue

      [x] 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');
      

      4. Go to master realm. Clear realm cache and keys cache
      5. Go to test realm
      6. Go to keys tab.
      7. Change the order of the keys under Tab "Add providers" (drag&drop)
      8. 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); {code}
          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

              Unassigned Unassigned
              pvlha Pavel Vlha
              Keycloak Core Clients
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

                Created:
                Updated:
                Resolved: