Merge pull request #3576 from stianst/KEYCLOAK-4006
KEYCLOAK-4006 Fix performance drop caused by changes to client sessio…
This commit is contained in:
commit
f9db687385
2 changed files with 15 additions and 39 deletions
|
@ -18,22 +18,16 @@
|
||||||
package org.keycloak.services.managers;
|
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.Time;
|
import org.keycloak.common.util.Time;
|
||||||
import org.keycloak.jose.jws.Algorithm;
|
|
||||||
import org.keycloak.jose.jws.crypto.RSAProvider;
|
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.ClientSessionModel;
|
import org.keycloak.models.ClientSessionModel;
|
||||||
import org.keycloak.models.ClientTemplateModel;
|
import org.keycloak.models.ClientTemplateModel;
|
||||||
import org.keycloak.models.KeyManager;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.ProtocolMapperModel;
|
import org.keycloak.models.ProtocolMapperModel;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.security.Signature;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -43,6 +37,8 @@ import java.util.Set;
|
||||||
*/
|
*/
|
||||||
public class ClientSessionCode {
|
public class ClientSessionCode {
|
||||||
|
|
||||||
|
private static final String ACTIVE_CODE = "active_code";
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(ClientSessionCode.class);
|
private static final Logger logger = Logger.getLogger(ClientSessionCode.class);
|
||||||
|
|
||||||
private static final String NEXT_CODE = ClientSessionCode.class.getName() + ".nextCode";
|
private static final String NEXT_CODE = ClientSessionCode.class.getName() + ".nextCode";
|
||||||
|
@ -99,7 +95,7 @@ public class ClientSessionCode {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!verifyCode(code, session, realm, result.clientSession)) {
|
if (!verifyCode(code, result.clientSession)) {
|
||||||
result.illegalHash = true;
|
result.illegalHash = true;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -119,7 +115,7 @@ public class ClientSessionCode {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!verifyCode(code, session, realm, clientSession)) {
|
if (!verifyCode(code, clientSession)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,7 +211,7 @@ public class ClientSessionCode {
|
||||||
public String getCode() {
|
public String getCode() {
|
||||||
String nextCode = (String) session.getAttribute(NEXT_CODE + "." + clientSession.getId());
|
String nextCode = (String) session.getAttribute(NEXT_CODE + "." + clientSession.getId());
|
||||||
if (nextCode == null) {
|
if (nextCode == null) {
|
||||||
nextCode = generateCode(session, realm, clientSession);
|
nextCode = generateCode(clientSession);
|
||||||
session.setAttribute(NEXT_CODE + "." + clientSession.getId(), nextCode);
|
session.setAttribute(NEXT_CODE + "." + clientSession.getId(), nextCode);
|
||||||
} else {
|
} else {
|
||||||
logger.debug("Code already generated for session, using code from session attributes");
|
logger.debug("Code already generated for session, using code from session attributes");
|
||||||
|
@ -223,30 +219,18 @@ public class ClientSessionCode {
|
||||||
return nextCode;
|
return nextCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String generateCode(KeycloakSession session, RealmModel realm, ClientSessionModel clientSession) {
|
private static String generateCode(ClientSessionModel clientSession) {
|
||||||
try {
|
try {
|
||||||
KeyManager.ActiveKey keys = session.keys().getActiveKey(realm);
|
String actionId = KeycloakModelUtils.generateSecret();
|
||||||
|
|
||||||
String secret = KeycloakModelUtils.generateSecret();
|
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(secret);
|
sb.append(actionId);
|
||||||
sb.append('.');
|
sb.append('.');
|
||||||
sb.append(clientSession.getId());
|
sb.append(clientSession.getId());
|
||||||
|
|
||||||
String code = sb.toString();
|
String code = sb.toString();
|
||||||
|
|
||||||
Signature signature = RSAProvider.getSignature(Algorithm.RS256);
|
clientSession.setNote(ACTIVE_CODE, code);
|
||||||
signature.initSign(keys.getPrivateKey());
|
|
||||||
signature.update(code.getBytes("utf-8"));
|
|
||||||
|
|
||||||
sb = new StringBuilder();
|
|
||||||
|
|
||||||
sb.append(Base64Url.encode(signature.sign()));
|
|
||||||
sb.append('.');
|
|
||||||
sb.append(keys.getKid());
|
|
||||||
|
|
||||||
clientSession.setNote(ClientSessionModel.ACTION_SIGNATURE, sb.toString());
|
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -254,24 +238,17 @@ public class ClientSessionCode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean verifyCode(String code, KeycloakSession session, RealmModel realm, ClientSessionModel clientSession) {
|
private static boolean verifyCode(String code, ClientSessionModel clientSession) {
|
||||||
try {
|
try {
|
||||||
String note = clientSession.getNote(ClientSessionModel.ACTION_SIGNATURE);
|
String activeCode = clientSession.getNote(ACTIVE_CODE);
|
||||||
if (note == null) {
|
if (activeCode == null) {
|
||||||
logger.debug("Action signature not found in client session");
|
logger.debug("Active code not found in client session");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
clientSession.removeNote(ClientSessionModel.ACTION_SIGNATURE);
|
clientSession.removeNote(ACTIVE_CODE);
|
||||||
|
|
||||||
String[] signed = note.split("\\.");
|
return code.equals(activeCode);
|
||||||
|
|
||||||
PublicKey publicKey = session.keys().getPublicKey(realm, signed[1]);
|
|
||||||
|
|
||||||
Signature verifier = RSAProvider.getSignature(Algorithm.RS256);
|
|
||||||
verifier.initVerify(publicKey);
|
|
||||||
verifier.update(code.getBytes("utf-8"));
|
|
||||||
return verifier.verify(Base64Url.decode(signed[0]));
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ import java.util.Set;
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public interface ClientSessionModel {
|
public interface ClientSessionModel {
|
||||||
public static final String ACTION_SIGNATURE = "action_signature";
|
|
||||||
|
|
||||||
public String getId();
|
public String getId();
|
||||||
public RealmModel getRealm();
|
public RealmModel getRealm();
|
||||||
|
|
Loading…
Reference in a new issue