Merge pull request #873 from stianst/master

Use HmacSHA256 for code signatures
This commit is contained in:
Stian Thorgersen 2014-11-27 10:34:51 +01:00
commit 5c2e7df7de
8 changed files with 49 additions and 14 deletions

View file

@ -2,6 +2,7 @@ package org.keycloak.models;
import org.keycloak.enums.SslRequired; import org.keycloak.enums.SslRequired;
import java.security.Key;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
@ -99,6 +100,8 @@ public interface RealmModel extends RoleContainerModel {
String getCodeSecret(); String getCodeSecret();
Key getCodeSecretKey();
void setCodeSecret(String codeSecret); void setCodeSecret(String codeSecret);
X509Certificate getCertificate(); X509Certificate getCertificate();

View file

@ -15,6 +15,7 @@ import org.keycloak.models.UserModel;
import org.keycloak.util.CertificateUtils; import org.keycloak.util.CertificateUtils;
import org.keycloak.util.PemUtils; import org.keycloak.util.PemUtils;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.security.Key; import java.security.Key;
@ -77,6 +78,10 @@ public final class KeycloakModelUtils {
return null; return null;
} }
public static Key getSecretKey(String secret) {
return secret != null ? new SecretKeySpec(secret.getBytes(), "HmacSHA256") : null;
}
public static String getPemFromKey(Key key) { public static String getPemFromKey(Key key) {
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
PEMWriter pemWriter = new PEMWriter(writer); PEMWriter pemWriter = new PEMWriter(writer);

View file

@ -13,6 +13,7 @@ import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.cache.entities.CachedRealm; import org.keycloak.models.cache.entities.CachedRealm;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import java.security.Key;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
@ -34,6 +35,7 @@ public class RealmAdapter implements RealmModel {
protected RealmCache cache; protected RealmCache cache;
protected volatile transient PublicKey publicKey; protected volatile transient PublicKey publicKey;
protected volatile transient PrivateKey privateKey; protected volatile transient PrivateKey privateKey;
protected volatile transient Key codeSecretKey;
protected volatile transient X509Certificate certificate; protected volatile transient X509Certificate certificate;
public RealmAdapter(CachedRealm cached, CacheRealmProvider cacheSession) { public RealmAdapter(CachedRealm cached, CacheRealmProvider cacheSession) {
@ -379,6 +381,14 @@ public class RealmAdapter implements RealmModel {
return updated != null ? updated.getCodeSecret() : cached.getCodeSecret(); return updated != null ? updated.getCodeSecret() : cached.getCodeSecret();
} }
@Override
public Key getCodeSecretKey() {
if (codeSecretKey == null) {
codeSecretKey = KeycloakModelUtils.getSecretKey(getCodeSecret());
}
return codeSecretKey;
}
@Override @Override
public void setCodeSecret(String codeSecret) { public void setCodeSecret(String codeSecret) {
getDelegateForUpdate(); getDelegateForUpdate();

View file

@ -21,6 +21,7 @@ import org.keycloak.models.utils.KeycloakModelUtils;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.TypedQuery; import javax.persistence.TypedQuery;
import java.security.Key;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
@ -46,6 +47,7 @@ public class RealmAdapter implements RealmModel {
protected volatile transient PublicKey publicKey; protected volatile transient PublicKey publicKey;
protected volatile transient PrivateKey privateKey; protected volatile transient PrivateKey privateKey;
protected volatile transient X509Certificate certificate; protected volatile transient X509Certificate certificate;
protected volatile transient Key codeSecretKey;
protected KeycloakSession session; protected KeycloakSession session;
private PasswordPolicy passwordPolicy; private PasswordPolicy passwordPolicy;
@ -439,6 +441,14 @@ public class RealmAdapter implements RealmModel {
return realm.getCodeSecret(); return realm.getCodeSecret();
} }
@Override
public Key getCodeSecretKey() {
if (codeSecretKey == null) {
codeSecretKey = KeycloakModelUtils.getSecretKey(getCodeSecret());
}
return codeSecretKey;
}
@Override @Override
public void setCodeSecret(String codeSecret) { public void setCodeSecret(String codeSecret) {
realm.setCodeSecret(codeSecret); realm.setCodeSecret(codeSecret);

View file

@ -23,6 +23,7 @@ import org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity; import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import java.security.Key;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
@ -43,14 +44,13 @@ import java.util.Set;
*/ */
public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> implements RealmModel { public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> implements RealmModel {
private static final Logger logger = Logger.getLogger(RealmAdapter.class);
private final MongoRealmEntity realm; private final MongoRealmEntity realm;
private final RealmProvider model; private final RealmProvider model;
protected volatile transient PublicKey publicKey; protected volatile transient PublicKey publicKey;
protected volatile transient PrivateKey privateKey; protected volatile transient PrivateKey privateKey;
protected volatile transient X509Certificate certificate; protected volatile transient X509Certificate certificate;
protected volatile transient Key codeSecretKey;
private volatile transient PasswordPolicy passwordPolicy; private volatile transient PasswordPolicy passwordPolicy;
private volatile transient KeycloakSession session; private volatile transient KeycloakSession session;
@ -424,6 +424,14 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
return realm.getCodeSecret(); return realm.getCodeSecret();
} }
@Override
public Key getCodeSecretKey() {
if (codeSecretKey == null) {
codeSecretKey = KeycloakModelUtils.getSecretKey(getCodeSecret());
}
return codeSecretKey;
}
@Override @Override
public void setCodeSecret(String codeSecret) { public void setCodeSecret(String codeSecret) {
realm.setCodeSecret(codeSecret); realm.setCodeSecret(codeSecret);

View file

@ -108,7 +108,7 @@
<module>events</module> <module>events</module>
<module>model</module> <module>model</module>
<module>integration</module> <module>integration</module>
<module>proxy/proxy-server</module> <module>proxy</module>
<module>picketlink</module> <module>picketlink</module>
<module>federation</module> <module>federation</module>
<module>services</module> <module>services</module>

View file

@ -8,7 +8,8 @@ import org.keycloak.models.UserModel.RequiredAction;
import org.keycloak.util.Base64Url; import org.keycloak.util.Base64Url;
import org.keycloak.util.Time; import org.keycloak.util.Time;
import java.security.MessageDigest; import javax.crypto.Mac;
import java.security.Key;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
@ -147,13 +148,13 @@ public class ClientSessionCode {
private static String createHash(RealmModel realm, ClientSessionModel clientSession) { private static String createHash(RealmModel realm, ClientSessionModel clientSession) {
try { try {
MessageDigest digest = MessageDigest.getInstance("sha-256"); Key codeSecretKey = realm.getCodeSecretKey();
digest.update(realm.getCodeSecret().getBytes()); Mac mac = Mac.getInstance(codeSecretKey.getAlgorithm());
digest.update(HASH_SEPERATOR); mac.init(codeSecretKey);
digest.update(clientSession.getId().getBytes()); mac.update(clientSession.getId().getBytes());
digest.update(HASH_SEPERATOR); mac.update(HASH_SEPERATOR);
digest.update(clientSession.getNote(ACTION_KEY).getBytes()); mac.update(clientSession.getNote(ACTION_KEY).getBytes());
return Base64Url.encode(digest.digest()); return Base64Url.encode(mac.doFinal());
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View file

@ -73,9 +73,7 @@ import java.security.Principal;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.regex.Matcher; import java.util.regex.Matcher;
/** @Ignore
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class ProxyTest { public class ProxyTest {
static String logoutUri = OpenIDConnectService.logoutUrl(UriBuilder.fromUri("http://localhost:8081/auth")) static String logoutUri = OpenIDConnectService.logoutUrl(UriBuilder.fromUri("http://localhost:8081/auth"))
.queryParam(OAuth2Constants.REDIRECT_URI, "http://localhost:8080/customer-portal").build("demo").toString(); .queryParam(OAuth2Constants.REDIRECT_URI, "http://localhost:8080/customer-portal").build("demo").toString();