Migration Guide
Migration Guide Red Hat build of Keycloak 26.0 Red Hat Customer Content Services
<datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true" statistics-enabled="true"> <connection-url>jdbc:postgresql://mypostgres:5432/mydb?currentSchema=myschema</connection-url> <driver>postgresql</driver> <pool> <min-pool-size>5</min-pool-size> <max-pool-size>50</max-pool-size> </pool> <security> <user-name>myuser</user-name> <password>myuser</password> </security> </datasource> kc.sh start --db postgres --db-url-host mypostgres --db-url-port 5432 --db-url-database mydb --db-schema myschema --db-pool-min-size 5 --db-pool-max-size 50 --db-username myser --db-password myuser <tls> <key-stores> <key-store name="applicationKS"> <credential-reference clear-text="password"/> <implementation type="JKS"/> <file path="/path/to/application.keystore"/> </key-store> </key-stores> <key-managers> <key-manager name="applicationKM" key-store="applicationKS"> <credential-reference clear-text="password"/> </key-manager> </key-managers> <server-ssl-contexts> <server-ssl-context name="applicationSSC" key-manager="applicationKM"/> </server-ssl-contexts> </tls> kc.sh start --https-key-store-file /path/to/application.keystore --https-key-store-password password kc.sh start --https-certificate-file /path/to/certfile.pem --https-certificate-key-file /path/to/keyfile.pem <subsystem xmlns="urn:jboss:domain:infinispan:13.0"> <cache-container name="keycloak" marshaller="JBOSS" modules="org.keycloak.keycloak-model-infinispan"> <local-cache name="realms"> <heap-memory size="10000"/> </local-cache> <local-cache name="users"> <heap-memory size="10000"/> </local-cache> <local-cache name="sessions"/> <local-cache name="authenticationSessions"/> <local-cache name="offlineSessions"/> </cache-container> </subsystem> kc.sh start --cache-config-file my-cache-file.xml <jgroups> <stack name="my-encrypt-udp" extends="udp"> ... </stack> </jgroups> <cache-container name="keycloak"> <transport stack="tcp"/> ... </cache-container> kc.sh start --cache-config-file my-cache-file.xml --cache-stack my-encrypt-udp <spi name="hostname"> <default-provider>default</default-provider> <provider name="default" enabled="true"> <properties> <property name="frontendUrl" value="myFrontendUrl"/> <property name="forceBackendUrlToFrontendUrl" value="true"/> </properties> </provider> </spi> kc.sh start --hostname myFrontendUrl kc.sh start --proxy-headers xforwarded <spi name="truststore"> <provider name="file" enabled="true"> <properties> <property name="file" value="path/to/myTrustStore.jks"/> <property name="password" value="password"/> <property name="hostname-verification-policy" value="WILDCARD"/> </properties> </provider> </spi> keytool -importkeystore -srckeystore path/to/myTrustStore.jks -destkeystore path/to/myTrustStore.p12 -srcstoretype jks -deststoretype pkcs12 -srcstorepass password -deststorepass temp-password openssl pkcs12 -in path/to/myTrustStore.p12 -out path/to/myTrustStore.pem -nodes -passin pass:temp-password openssl pkcs12 -export -in path/to/myTrustStore.pem -out path/to/myUnencryptedTrustStore.p12 -nokeys -passout pass: kc.sh start --truststore-paths path/to/myUnencryptedTrustStore.p12 --tls-hostname-verifier WILDCARD <spi name="vault"> <provider name="elytron-cs-keystore" enabled="true"> <properties> <property name="location" value="path/to/keystore.p12"/> <property name="secret" value="password"/> </properties> </provider> </spi> kc.sh start --vault keystore --vault-file /path/to/keystore.p12 --vault-pass password export JAVA_OPTS_APPEND=-XX:+HeapDumpOnOutOfMemoryError kc.sh start <spi name="<spi-id>"> <provider name="<provider-id>" enabled="true"> <properties> <property name="<property>" value="<value>"/> </properties> </provider> </spi> spi-<spi-id>-<provider-id>-<property>=<value> kc.sh start --spi-connections-jpa-legacy-migration-strategy manual kc.sh start --spi-connections-jpa-legacy-migration-export <path>/<file.sql> apiVersion: k8s.keycloak.org/v2alpha1 kind: Keycloak metadata: name: example-kc spec: instances: 1 db: vendor: postgres host: postgres-db usernameSecret: name: keycloak-db-secret key: username passwordSecret: name: keycloak-db-secret key: password http: tlsSecret: example-tls-secret hostname: hostname: test.keycloak.org additionalOptions: - name: spi-connections-http-client-default-connection-pool-size value: 20 ./kc.sh start --db=postgres --db-url-host=postgres-db --db-username=user --db-password=pass --https-certificate-file=mycertfile --https-certificate-key-file=myprivatekey --hostname=test.keycloak.org --spi-connections-http-client-default-connection-pool-size=20 apiVersion: v1 kind: Secret metadata: name: keycloak-db-secret namespace: keycloak labels: app: sso stringData: POSTGRES_DATABASE: kc-db-name POSTGRES_EXTERNAL_ADDRESS: my-postgres-hostname POSTGRES_EXTERNAL_PORT: 5432 POSTGRES_USERNAME: user POSTGRES_PASSWORD: pass type: Opaque apiVersion: k8s.keycloak.org/v2alpha1 kind: Keycloak metadata: name: example-kc spec: db: vendor: postgres host: my-postgres-hostname port: 5432 usernameSecret: name: keycloak-db-secret key: username passwordSecret: name: keycloak-db-secret key: password apiVersion: v1 kind: Secret metadata: name: keycloak-db-secret stringData: username: "user" password: "pass" type: Opaque apiVersion: k8s.keycloak.org/v2alpha1 kind: Keycloak metadata: name: example-kc spec: http: tlsSecret: example-tls-secret apiVersion: k8s.keycloak.org/v2alpha1 kind: Keycloak metadata: name: example-kc spec: ingress: enabled: false apiVersion: k8s.keycloak.org/v2alpha1 kind: Keycloak metadata: name: example-kc spec: image: quay.io/my-company/my-keycloak:latest apiVersion: k8s.keycloak.org/v2alpha1 kind: Keycloak metadata: name: example-kc spec: unsupported: podTemplate: metadata: labels: foo: "bar" spec: containers: - volumeMounts: - name: test-volume mountPath: /mnt/test volumes: - name: test-volume secret: secretName: test-secret apiVersion: keycloak.org/v1alpha1 kind: KeycloakRealm metadata: name: example-keycloakrealm spec: instanceSelector: matchLabels: app: sso realm: id: "basic" realm: "basic" enabled: True displayName: "Basic Realm" apiVersion: k8s.keycloak.org/v2alpha1 kind: KeycloakRealmImport metadata: name: example-keycloakrealm spec: keycloakCRName: example-kc realm: id: "basic" realm: "basic" enabled: True displayName: "Basic Realm" apiVersion: k8s.keycloak.org/v2alpha1 kind: Keycloak metadata: name: rhbk spec: instances: 1 db: vendor: postgres host: postgres-db usernameSecret: name: keycloak-db-secret key: username passwordSecret: name: keycloak-db-secret key: password http: tlsSecret: sso-x509-https-secret apiVersion: apps.openshift.io/v1 kind: DeploymentConfig metadata: name: rhsso spec: replicas: 1 template: spec: volumes: - name: sso-x509-https-volume secret: secretName: sso-x509-https-secret defaultMode: 420 containers: volumeMounts: - name: sso-x509-https-volume readOnly: true env: - name: DB_SERVICE_PREFIX_MAPPING value: postgres-db=DB - name: DB_USERNAME value: username - name: DB_PASSWORD value: password additionalOptions: name: proxy value: reencrypt 401 Unauthorized WWW-Authenticate: Bearer realm="myrealm" 400 Bad Request WWW-Authenticate: Bearer realm="myrealm", error="invalid_request", error_description="..." 403 Forbidden WWW-Authenticate: Bearer realm="myrealm", error="insufficient_scope", error_description="Missing openid scope" 500 Internal Server Error 401 Unauthorized WWW-Authenticate: Bearer realm="myrealm", error="invalid_token", error_description="..." { "realm": "quickstart", "auth-server-url": "http://localhost:8180", "ssl-required": "external", "resource": "jakarta-servlet-authz-client", "credentials": { "secret": "secret" } } <dependency> <groupId>org.keycloak</groupId> <artifactId>keycloak-policy-enforcer</artifactId> <version>USD{Red Hat build of Keycloak .version}</version> </dependency> @Context org.jboss.resteasy.spi.HttpRequest request; @Context org.jboss.resteasy.spi.HttpResponse response; KeycloakSession session = // obtain the session, which is usually available when creating a custom provider from a factory KeycloakContext context = session.getContext(); HttpRequest request = context.getHttpRequest(); HttpResponse response = context.getHttpResponse(); KeycloakSession session = // obtain the session KeycloakContext context = session.getContext(); MyContextualObject myContextualObject = context.getContextObject(MyContextualObject.class); @Deprecated List<GroupModel> getGroups(RealmModel realm); Stream<GroupModel> getGroupsStream(RealmModel realm); @Deprecated UserModel getUserById(String id, RealmModel realm); UserModel getUserById(RealmModel realm, String id) session .userLocalStorage() ; session .users() ; session .userLocalStorage() ; ((LegacyDatastoreProvider) session.getProvider(DatastoreProvider.class)) .userLocalStorage() ; realm .getClientStorageProvidersStream() ...; ((LegacyRealmModel) realm) .getClientStorageProvidersStream() ...; public class MyClass extends RealmModel { /* might not compile due to @Override annotations for methods no longer present in the interface RealmModel. / / ... */ } public class MyClass extends LegacyRealmModel { /* ... */ } session**.userCache()**.evict(realm, user); UserStorageUitl.userCache(session); UserCache cache = session.getProvider(UserCache.class); if (cache != null) cache.evict(realm)(); session.invalidate(InvalidationHandler.ObjectType.REALM, realm.getId()); session.userCredentialManager() .createCredential (realm, user, credentialModel) user.credentialManager() .createStoredCredential (credentialModel) public class MyUserStorageProvider implements UserLookupProvider, ... { /* ... */ protected UserModel createAdapter(RealmModel realm, String username) { return new AbstractUserAdapter(session, realm, model) { @Override public String getUsername() { return username; } }; } } public class MyUserStorageProvider implements UserLookupProvider, ... { /* ... */ protected UserModel createAdapter(RealmModel realm, String username) { return new AbstractUserAdapter(session, realm, model) { @Override public String getUsername() { return username; } @Override public SubjectCredentialManager credentialManager() { return new LegacyUserCredentialManager(session, realm, this); } }; } } <dependency> <groupId>org.keycloak</groupId> <artifactId>keycloak-admin-client-jakarta</artifactId> <version>18.0.0.redhat-00001</version> </dependency> <dependency> <groupId>org.keycloak</groupId> <artifactId>keycloak-admin-client</artifactId> <version>22.0.0.redhat-00001</version> </dependency> <dependency> <groupId>org.keycloak</groupId> <artifactId>keycloak-admin-client</artifactId> <version>18.0.0.redhat-00001</version> </dependency> <dependency> <groupId>org.keycloak</groupId> <artifactId>keycloak-admin-client-jee</artifactId> <version>22.0.0.redhat-00001</version> </dependency> kc.sh start --spi-user-profile-declarative-user-profile-max-email-local-part-length=100