KEYCLOAK-19408 Better client secrets

This commit is contained in:
stianst 2021-09-28 09:01:02 +02:00 committed by Stian Thorgersen
parent d606da9065
commit f471a110cd
20 changed files with 113 additions and 114 deletions

View file

@ -30,7 +30,6 @@ import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Deque; import java.util.Deque;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@ -57,7 +56,7 @@ import org.keycloak.adapters.rotation.AdapterTokenVerifier;
import org.keycloak.common.VerificationException; import org.keycloak.common.VerificationException;
import org.keycloak.common.util.Base64Url; import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.KeycloakUriBuilder; import org.keycloak.common.util.KeycloakUriBuilder;
import org.keycloak.common.util.RandomString; import org.keycloak.common.util.SecretGenerator;
import org.keycloak.representations.AccessToken; import org.keycloak.representations.AccessToken;
import org.keycloak.representations.AccessTokenResponse; import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.IDToken; import org.keycloak.representations.IDToken;
@ -770,7 +769,7 @@ public class KeycloakInstalled {
public static Pkce generatePkce() { public static Pkce generatePkce() {
try { try {
String codeVerifier = new RandomString(PKCE_CODE_VERIFIER_MAX_LENGTH, new SecureRandom()).nextString(); String codeVerifier = SecretGenerator.getInstance().randomString(PKCE_CODE_VERIFIER_MAX_LENGTH);
String codeChallenge = generateS256CodeChallenge(codeVerifier); String codeChallenge = generateS256CodeChallenge(codeVerifier);
return new Pkce(codeVerifier, codeChallenge); return new Pkce(codeVerifier, codeChallenge);
} catch (Exception ex){ } catch (Exception ex){

View file

@ -1,66 +0,0 @@
package org.keycloak.common.util;
import java.security.SecureRandom;
import java.util.Locale;
import java.util.Objects;
import java.util.Random;
public class RandomString {
/**
* Generate a random string.
*/
public String nextString() {
for (int idx = 0; idx < buf.length; ++idx)
buf[idx] = symbols[random.nextInt(symbols.length)];
return new String(buf);
}
public static final String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static final String lower = upper.toLowerCase(Locale.ROOT);
public static final String digits = "0123456789";
public static final String alphanum = upper + lower + digits;
private final Random random;
private final char[] symbols;
private final char[] buf;
public RandomString(int length, Random random, String symbols) {
if (length < 1) throw new IllegalArgumentException();
if (symbols.length() < 2) throw new IllegalArgumentException();
this.random = Objects.requireNonNull(random);
this.symbols = symbols.toCharArray();
this.buf = new char[length];
}
/**
* Create an alphanumeric string generator.
*/
public RandomString(int length, Random random) {
this(length, random, alphanum);
}
/**
* Create an alphanumeric strings from a secure generator.
*/
public RandomString(int length) {
this(length, new SecureRandom());
}
/**
* Create session identifiers.
*/
public RandomString() {
this(21);
}
public static String randomCode(int length) {
return new RandomString(length).nextString();
}
}

View file

@ -0,0 +1,71 @@
package org.keycloak.common.util;
import java.security.SecureRandom;
import java.util.Random;
public class SecretGenerator {
public static final int DEFAULT_LENGTH = 32;
public static final char[] UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
public static final char[] DIGITS = "0123456789".toCharArray();
public static final char[] ALPHANUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".toCharArray();
private static final SecretGenerator instance = new SecretGenerator();
private ThreadLocal<Random> random = new ThreadLocal<Random>() {
@Override
protected Random initialValue() {
return new SecureRandom();
}
};
private SecretGenerator() {
}
public static SecretGenerator getInstance() {
return instance;
}
public String randomString() {
return randomString(DEFAULT_LENGTH, ALPHANUM);
}
public String randomString(int length) {
return randomString(length, ALPHANUM);
}
public String randomString(int length, char[] symbols) {
if (length < 1) {
throw new IllegalArgumentException();
}
if (symbols == null || symbols.length < 2) {
throw new IllegalArgumentException();
}
Random r = random.get();
char[] buf = new char[length];
for (int idx = 0; idx < buf.length; ++idx) {
buf[idx] = symbols[r.nextInt(symbols.length)];
}
return new String(buf);
}
public byte[] randomBytes() {
return randomBytes(DEFAULT_LENGTH);
}
public byte[] randomBytes(int length) {
if (length < 1) {
throw new IllegalArgumentException();
}
byte[] buf = new byte[length];
random.get().nextBytes(buf);
return buf;
}
}

View file

@ -25,6 +25,7 @@ import java.util.concurrent.TimeUnit;
import org.infinispan.Cache; import org.infinispan.Cache;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.common.util.Base64Url; import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.SecretGenerator;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
@ -35,7 +36,6 @@ import org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent;
import org.keycloak.models.sessions.infinispan.events.SessionEventsSenderTransaction; import org.keycloak.models.sessions.infinispan.events.SessionEventsSenderTransaction;
import org.keycloak.models.sessions.infinispan.stream.RootAuthenticationSessionPredicate; import org.keycloak.models.sessions.infinispan.stream.RootAuthenticationSessionPredicate;
import org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator; import org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.RealmInfoUtil; import org.keycloak.models.utils.RealmInfoUtil;
import org.keycloak.sessions.AuthenticationSessionCompoundId; import org.keycloak.sessions.AuthenticationSessionCompoundId;
import org.keycloak.sessions.AuthenticationSessionProvider; import org.keycloak.sessions.AuthenticationSessionProvider;
@ -186,6 +186,6 @@ public class InfinispanAuthenticationSessionProvider implements AuthenticationSe
protected String generateTabId() { protected String generateTabId() {
return Base64Url.encode(KeycloakModelUtils.generateSecret(8)); return Base64Url.encode(SecretGenerator.getInstance().randomBytes(8));
} }
} }

View file

@ -17,11 +17,11 @@
package org.keycloak.models.map.authSession; package org.keycloak.models.map.authSession;
import org.keycloak.common.util.Base64Url; import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.SecretGenerator;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.sessions.AuthenticationSessionModel; import org.keycloak.sessions.AuthenticationSessionModel;
import java.util.Map; import java.util.Map;
@ -123,6 +123,6 @@ public class MapRootAuthenticationSessionAdapter extends AbstractRootAuthenticat
} }
private String generateTabId() { private String generateTabId() {
return Base64Url.encode(KeycloakModelUtils.generateSecret(8)); return Base64Url.encode(SecretGenerator.getInstance().randomBytes(8));
} }
} }

View file

@ -24,7 +24,7 @@ import org.keycloak.Config;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.common.Version; import org.keycloak.common.Version;
import org.keycloak.common.util.Base64Url; import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.RandomString; import org.keycloak.common.util.SecretGenerator;
import org.keycloak.migration.MigrationModel; import org.keycloak.migration.MigrationModel;
import org.keycloak.migration.ModelVersion; import org.keycloak.migration.ModelVersion;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
@ -52,7 +52,7 @@ public class MapDeploymentStateProviderFactory implements DeploymentStateProvide
Logger.getLogger(DeploymentStateProviderFactory.class) Logger.getLogger(DeploymentStateProviderFactory.class)
.warnf("It is recommended to set '%s' property in the %s provider config of %s SPI", RESOURCES_VERSION_SEED, PROVIDER_ID, DeploymentStateSpi.NAME); .warnf("It is recommended to set '%s' property in the %s provider config of %s SPI", RESOURCES_VERSION_SEED, PROVIDER_ID, DeploymentStateSpi.NAME);
//generate random string for this installation //generate random string for this installation
seed = RandomString.randomCode(10); seed = SecretGenerator.getInstance().randomString(10);
} }
try { try {
Version.RESOURCES_VERSION = Base64Url.encode(MessageDigest.getInstance("MD5") Version.RESOURCES_VERSION = Base64Url.encode(MessageDigest.getInstance("MD5")

View file

@ -22,8 +22,8 @@ import org.keycloak.common.ClientConnection;
import org.keycloak.common.Version; import org.keycloak.common.Version;
import org.keycloak.common.util.Base64Url; import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.MimeTypeUtil; import org.keycloak.common.util.MimeTypeUtil;
import org.keycloak.common.util.SecretGenerator;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.services.ForbiddenException; import org.keycloak.services.ForbiddenException;
import org.keycloak.services.ServicesLogger; import org.keycloak.services.ServicesLogger;
import org.keycloak.services.managers.ApplianceBootstrap; import org.keycloak.services.managers.ApplianceBootstrap;
@ -251,7 +251,7 @@ public class QuarkusWelcomeResource {
} }
private String setCsrfCookie() { private String setCsrfCookie() {
String stateChecker = Base64Url.encode(KeycloakModelUtils.generateSecret()); String stateChecker = Base64Url.encode(SecretGenerator.getInstance().randomBytes());
String cookiePath = session.getContext().getUri().getPath(); String cookiePath = session.getContext().getUri().getPath();
boolean secureOnly = session.getContext().getUri().getRequestUri().getScheme().equalsIgnoreCase("https"); boolean secureOnly = session.getContext().getUri().getRequestUri().getScheme().equalsIgnoreCase("https");
CookieHelper.addCookie(KEYCLOAK_STATE_CHECKER, stateChecker, cookiePath, null, null, 300, secureOnly, true); CookieHelper.addCookie(KEYCLOAK_STATE_CHECKER, stateChecker, cookiePath, null, null, 300, secureOnly, true);

View file

@ -17,9 +17,7 @@
package org.keycloak.models; package org.keycloak.models;
import org.keycloak.common.util.RandomString; import org.keycloak.common.util.SecretGenerator;
import java.security.SecureRandom;
/** /**
* The default implementation for generating/formatting user code of OAuth 2.0 Device Authorization Grant. * The default implementation for generating/formatting user code of OAuth 2.0 Device Authorization Grant.
@ -36,7 +34,7 @@ public class DefaultOAuth2DeviceUserCodeProvider implements OAuth2DeviceUserCode
@Override @Override
public String generate() { public String generate() {
// For case-insensitive, use uppercase // For case-insensitive, use uppercase
return new RandomString(LENGTH, new SecureRandom(), RandomString.upper).nextString(); return SecretGenerator.getInstance().randomString(LENGTH, SecretGenerator.UPPER);
} }
@Override @Override

View file

@ -24,6 +24,7 @@ import org.keycloak.broker.social.SocialIdentityProviderFactory;
import org.keycloak.common.util.CertificateUtils; import org.keycloak.common.util.CertificateUtils;
import org.keycloak.common.util.KeyUtils; import org.keycloak.common.util.KeyUtils;
import org.keycloak.common.util.PemUtils; import org.keycloak.common.util.PemUtils;
import org.keycloak.common.util.SecretGenerator;
import org.keycloak.component.ComponentModel; import org.keycloak.component.ComponentModel;
import org.keycloak.models.AuthenticationExecutionModel; import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.AuthenticationFlowModel; import org.keycloak.models.AuthenticationFlowModel;
@ -40,7 +41,6 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RealmProvider; import org.keycloak.models.RealmProvider;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.ScopeContainerModel; import org.keycloak.models.ScopeContainerModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.CertificateRepresentation; import org.keycloak.representations.idm.CertificateRepresentation;
import org.keycloak.storage.UserStorageProviderModel; import org.keycloak.storage.UserStorageProviderModel;
@ -54,7 +54,6 @@ import java.security.Key;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
@ -85,16 +84,6 @@ public final class KeycloakModelUtils {
return UUID.randomUUID().toString(); return UUID.randomUUID().toString();
} }
public static byte[] generateSecret() {
return generateSecret(32);
}
public static byte[] generateSecret(int bytes) {
byte[] buf = new byte[bytes];
new SecureRandom().nextBytes(buf);
return buf;
}
public static PublicKey getPublicKey(String publicKeyPem) { public static PublicKey getPublicKey(String publicKeyPem) {
if (publicKeyPem != null) { if (publicKeyPem != null) {
try { try {
@ -156,9 +145,9 @@ public final class KeycloakModelUtils {
return rep; return rep;
} }
public static UserCredentialModel generateSecret(ClientModel client) { public static String generateSecret(ClientModel client) {
UserCredentialModel secret = UserCredentialModel.generateSecret(); String secret = SecretGenerator.getInstance().randomString();
client.setSecret(secret.getChallengeResponse()); client.setSecret(secret);
return secret; return secret;
} }

View file

@ -17,6 +17,7 @@
package org.keycloak.models; package org.keycloak.models;
import org.keycloak.common.util.SecretGenerator;
import org.keycloak.credential.CredentialInput; import org.keycloak.credential.CredentialInput;
import org.keycloak.credential.CredentialModel; import org.keycloak.credential.CredentialModel;
import org.keycloak.models.credential.OTPCredentialModel; import org.keycloak.models.credential.OTPCredentialModel;
@ -25,7 +26,6 @@ import org.keycloak.models.credential.PasswordUserCredentialModel;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.UUID;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -123,7 +123,7 @@ public class UserCredentialModel implements CredentialInput {
} }
public static UserCredentialModel generateSecret() { public static UserCredentialModel generateSecret() {
return new UserCredentialModel("", SECRET, UUID.randomUUID().toString()); return new UserCredentialModel("", SECRET, SecretGenerator.getInstance().randomString());
} }
@Override @Override

View file

@ -21,7 +21,7 @@ import org.jboss.logging.Logger;
import org.keycloak.authentication.RequiredActionContext; import org.keycloak.authentication.RequiredActionContext;
import org.keycloak.authentication.RequiredActionProvider; import org.keycloak.authentication.RequiredActionProvider;
import org.keycloak.authentication.ConsoleDisplayMode; import org.keycloak.authentication.ConsoleDisplayMode;
import org.keycloak.common.util.RandomString; import org.keycloak.common.util.SecretGenerator;
import org.keycloak.email.EmailException; import org.keycloak.email.EmailException;
import org.keycloak.email.EmailTemplateProvider; import org.keycloak.email.EmailTemplateProvider;
import org.keycloak.events.Details; import org.keycloak.events.Details;
@ -116,7 +116,7 @@ public class ConsoleVerifyEmail implements RequiredActionProvider {
UserModel user = context.getUser(); UserModel user = context.getUser();
AuthenticationSessionModel authSession = context.getAuthenticationSession(); AuthenticationSessionModel authSession = context.getAuthenticationSession();
EventBuilder event = context.getEvent().clone().event(EventType.SEND_VERIFY_EMAIL).detail(Details.EMAIL, user.getEmail()); EventBuilder event = context.getEvent().clone().event(EventType.SEND_VERIFY_EMAIL).detail(Details.EMAIL, user.getEmail());
String code = RandomString.randomCode(8); String code = SecretGenerator.getInstance().randomString(8);
authSession.setAuthNote(Constants.VERIFY_EMAIL_CODE, code); authSession.setAuthNote(Constants.VERIFY_EMAIL_CODE, code);
RealmModel realm = session.getContext().getRealm(); RealmModel realm = session.getContext().getRealm();

View file

@ -28,6 +28,7 @@ import org.keycloak.broker.provider.ExchangeExternalToken;
import org.keycloak.broker.provider.IdentityBrokerException; import org.keycloak.broker.provider.IdentityBrokerException;
import org.keycloak.broker.provider.util.SimpleHttp; import org.keycloak.broker.provider.util.SimpleHttp;
import org.keycloak.common.util.Base64Url; import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.SecretGenerator;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.events.Details; import org.keycloak.events.Details;
import org.keycloak.events.Errors; import org.keycloak.events.Errors;
@ -778,7 +779,7 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider<OIDCIde
@Override @Override
protected UriBuilder createAuthorizationUrl(AuthenticationRequest request) { protected UriBuilder createAuthorizationUrl(AuthenticationRequest request) {
UriBuilder uriBuilder = super.createAuthorizationUrl(request); UriBuilder uriBuilder = super.createAuthorizationUrl(request);
String nonce = Base64Url.encode(KeycloakModelUtils.generateSecret(16)); String nonce = Base64Url.encode(SecretGenerator.getInstance().randomBytes(16));
AuthenticationSessionModel authenticationSession = request.getAuthenticationSession(); AuthenticationSessionModel authenticationSession = request.getAuthenticationSession();
authenticationSession.setClientNote(BROKER_NONCE_PARAM, nonce); authenticationSession.setClientNote(BROKER_NONCE_PARAM, nonce);

View file

@ -19,6 +19,7 @@ package org.keycloak.keys;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.common.util.Base64Url; import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.SecretGenerator;
import org.keycloak.component.ComponentModel; import org.keycloak.component.ComponentModel;
import org.keycloak.component.ComponentValidationException; import org.keycloak.component.ComponentValidationException;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
@ -52,7 +53,7 @@ public abstract class AbstractGeneratedSecretKeyProviderFactory<T extends KeyPro
private void generateSecret(ComponentModel model, int size) { private void generateSecret(ComponentModel model, int size) {
try { try {
byte[] secret = KeycloakModelUtils.generateSecret(size); byte[] secret = SecretGenerator.getInstance().randomBytes(size);
model.put(Attributes.SECRET_KEY, Base64Url.encode(secret)); model.put(Attributes.SECRET_KEY, Base64Url.encode(secret));
String kid = KeycloakModelUtils.generateId(); String kid = KeycloakModelUtils.generateId();

View file

@ -23,6 +23,7 @@ import org.keycloak.OAuth2Constants;
import org.keycloak.OAuthErrorException; import org.keycloak.OAuthErrorException;
import org.keycloak.authentication.AuthenticationProcessor; import org.keycloak.authentication.AuthenticationProcessor;
import org.keycloak.common.util.Base64Url; import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.SecretGenerator;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.constants.AdapterConstants; import org.keycloak.constants.AdapterConstants;
import org.keycloak.events.Details; import org.keycloak.events.Details;
@ -38,7 +39,6 @@ import org.keycloak.models.OAuth2DeviceTokenStoreProvider;
import org.keycloak.models.OAuth2DeviceUserCodeModel; import org.keycloak.models.OAuth2DeviceUserCodeModel;
import org.keycloak.models.OAuth2DeviceUserCodeProvider; import org.keycloak.models.OAuth2DeviceUserCodeProvider;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.SystemClientUtil; import org.keycloak.models.utils.SystemClientUtil;
import org.keycloak.protocol.AuthorizationEndpointBase; import org.keycloak.protocol.AuthorizationEndpointBase;
import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper; import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
@ -144,7 +144,7 @@ public class DeviceEndpoint extends AuthorizationEndpointBase implements RealmRe
int interval = realm.getOAuth2DeviceConfig().getPoolingInterval(client); int interval = realm.getOAuth2DeviceConfig().getPoolingInterval(client);
OAuth2DeviceCodeModel deviceCode = OAuth2DeviceCodeModel.create(realm, client, OAuth2DeviceCodeModel deviceCode = OAuth2DeviceCodeModel.create(realm, client,
Base64Url.encode(KeycloakModelUtils.generateSecret()), request.getScope(), request.getNonce(), expiresIn, interval, null, null, Base64Url.encode(SecretGenerator.getInstance().randomBytes()), request.getScope(), request.getNonce(), expiresIn, interval, null, null,
request.getAdditionalReqParams()); request.getAdditionalReqParams());
OAuth2DeviceUserCodeProvider userCodeProvider = session.getProvider(OAuth2DeviceUserCodeProvider.class); OAuth2DeviceUserCodeProvider userCodeProvider = session.getProvider(OAuth2DeviceUserCodeProvider.class);
String secret = userCodeProvider.generate(); String secret = userCodeProvider.generate();

View file

@ -2,7 +2,7 @@ package org.keycloak.protocol.oidc.utils;
import org.keycloak.OAuth2Constants; import org.keycloak.OAuth2Constants;
import org.keycloak.common.util.Base64Url; import org.keycloak.common.util.Base64Url;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.common.util.SecretGenerator;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
@ -10,7 +10,7 @@ import java.security.MessageDigest;
public class PkceUtils { public class PkceUtils {
public static String generateCodeVerifier() { public static String generateCodeVerifier() {
return Base64Url.encode(KeycloakModelUtils.generateSecret(64)); return Base64Url.encode(SecretGenerator.getInstance().randomBytes(64));
} }
public static String encodeCodeChallenge(String codeVerifier, String codeChallengeMethod) { public static String encodeCodeChallenge(String codeVerifier, String codeChallengeMethod) {

View file

@ -38,6 +38,7 @@ import org.keycloak.broker.provider.IdentityProvider;
import org.keycloak.common.ClientConnection; import org.keycloak.common.ClientConnection;
import org.keycloak.common.VerificationException; import org.keycloak.common.VerificationException;
import org.keycloak.common.util.Base64Url; import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.SecretGenerator;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.crypto.SignatureProvider; import org.keycloak.crypto.SignatureProvider;
import org.keycloak.crypto.SignatureVerifierContext; import org.keycloak.crypto.SignatureVerifierContext;
@ -712,7 +713,7 @@ public class AuthenticationManager {
String stateChecker = (String) keycloakSession.getAttribute("state_checker"); String stateChecker = (String) keycloakSession.getAttribute("state_checker");
if (stateChecker == null) { if (stateChecker == null) {
stateChecker = Base64Url.encode(KeycloakModelUtils.generateSecret()); stateChecker = Base64Url.encode(SecretGenerator.getInstance().randomBytes());
keycloakSession.setAttribute("state_checker", stateChecker); keycloakSession.setAttribute("state_checker", stateChecker);
} }
token.getOtherClaims().put("state_checker", stateChecker); token.getOtherClaims().put("state_checker", stateChecker);

View file

@ -19,6 +19,7 @@ package org.keycloak.services.managers;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.common.util.Base64Url; import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.SecretGenerator;
import org.keycloak.events.EventBuilder; import org.keycloak.events.EventBuilder;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
@ -99,7 +100,7 @@ class CodeGenerateUtil {
public String retrieveCode(KeycloakSession session, AuthenticationSessionModel authSession) { public String retrieveCode(KeycloakSession session, AuthenticationSessionModel authSession) {
String nextCode = authSession.getAuthNote(ACTIVE_CODE); String nextCode = authSession.getAuthNote(ACTIVE_CODE);
if (nextCode == null) { if (nextCode == null) {
String actionId = Base64Url.encode(KeycloakModelUtils.generateSecret()); String actionId = Base64Url.encode(SecretGenerator.getInstance().randomBytes());
authSession.setAuthNote(ACTIVE_CODE, actionId); authSession.setAuthNote(ACTIVE_CODE, actionId);
// We need to set the active code to the authSession in the separate sub-transaction as well // We need to set the active code to the authSession in the separate sub-transaction as well

View file

@ -21,8 +21,8 @@ import org.keycloak.common.ClientConnection;
import org.keycloak.common.Version; import org.keycloak.common.Version;
import org.keycloak.common.util.Base64Url; import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.MimeTypeUtil; import org.keycloak.common.util.MimeTypeUtil;
import org.keycloak.common.util.SecretGenerator;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.services.ForbiddenException; import org.keycloak.services.ForbiddenException;
import org.keycloak.services.ServicesLogger; import org.keycloak.services.ServicesLogger;
import org.keycloak.services.managers.ApplianceBootstrap; import org.keycloak.services.managers.ApplianceBootstrap;
@ -256,7 +256,7 @@ public class WelcomeResource {
} }
private String setCsrfCookie() { private String setCsrfCookie() {
String stateChecker = Base64Url.encode(KeycloakModelUtils.generateSecret()); String stateChecker = Base64Url.encode(SecretGenerator.getInstance().randomBytes());
String cookiePath = session.getContext().getUri().getPath(); String cookiePath = session.getContext().getUri().getPath();
boolean secureOnly = session.getContext().getUri().getRequestUri().getScheme().equalsIgnoreCase("https"); boolean secureOnly = session.getContext().getUri().getRequestUri().getScheme().equalsIgnoreCase("https");
CookieHelper.addCookie(KEYCLOAK_STATE_CHECKER, stateChecker, cookiePath, null, null, 300, secureOnly, true); CookieHelper.addCookie(KEYCLOAK_STATE_CHECKER, stateChecker, cookiePath, null, null, 300, secureOnly, true);

View file

@ -247,8 +247,12 @@ public class ClientResource {
auth.clients().requireConfigure(client); auth.clients().requireConfigure(client);
logger.debug("regenerateSecret"); logger.debug("regenerateSecret");
UserCredentialModel cred = KeycloakModelUtils.generateSecret(client); String secret = KeycloakModelUtils.generateSecret(client);
CredentialRepresentation rep = ModelToRepresentation.toRepresentation(cred);
CredentialRepresentation rep = new CredentialRepresentation();
rep.setType(CredentialRepresentation.SECRET);
rep.setValue(secret);
adminEvent.operation(OperationType.ACTION).resourcePath(session.getContext().getUri()).representation(rep).success(); adminEvent.operation(OperationType.ACTION).resourcePath(session.getContext().getUri()).representation(rep).success();
return rep; return rep;
} }

View file

@ -25,7 +25,7 @@ import org.keycloak.WebAuthnConstants;
import org.keycloak.authentication.requiredactions.WebAuthnRegisterFactory; import org.keycloak.authentication.requiredactions.WebAuthnRegisterFactory;
import org.keycloak.authentication.requiredactions.WebAuthnPasswordlessRegisterFactory; import org.keycloak.authentication.requiredactions.WebAuthnPasswordlessRegisterFactory;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.common.util.RandomString; import org.keycloak.common.util.SecretGenerator;
import org.keycloak.events.Details; import org.keycloak.events.Details;
import org.keycloak.events.EventType; import org.keycloak.events.EventType;
import org.keycloak.models.credential.WebAuthnCredentialModel; import org.keycloak.models.credential.WebAuthnCredentialModel;
@ -133,7 +133,7 @@ public class WebAuthnRegisterAndLoginTest extends AbstractTestRealmKeycloakTest
loginPage.clickRegister(); loginPage.clickRegister();
registerPage.assertCurrent(); registerPage.assertCurrent();
String authenticatorLabel = RandomString.randomCode(24); String authenticatorLabel = SecretGenerator.getInstance().randomString(24);
registerPage.register("firstName", "lastName", email, username, password, password); registerPage.register("firstName", "lastName", email, username, password, password);
// User was registered. Now he needs to register WebAuthn credential // User was registered. Now he needs to register WebAuthn credential