KEYCLOAK-4187 Minor updates in API
This commit is contained in:
parent
badba7adaf
commit
ddcbee2bff
6 changed files with 24 additions and 17 deletions
|
@ -20,6 +20,7 @@ import org.keycloak.Config.Scope;
|
||||||
import org.keycloak.events.EventType;
|
import org.keycloak.events.EventType;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
|
import org.keycloak.representations.JsonWebToken;
|
||||||
import org.keycloak.services.managers.AuthenticationManager;
|
import org.keycloak.services.managers.AuthenticationManager;
|
||||||
import org.keycloak.sessions.AuthenticationSessionModel;
|
import org.keycloak.sessions.AuthenticationSessionModel;
|
||||||
|
|
||||||
|
@ -27,7 +28,7 @@ import org.keycloak.sessions.AuthenticationSessionModel;
|
||||||
*
|
*
|
||||||
* @author hmlnarik
|
* @author hmlnarik
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractActionTokenHander<T extends DefaultActionToken> implements ActionTokenHandler<T>, ActionTokenHandlerFactory<T> {
|
public abstract class AbstractActionTokenHander<T extends JsonWebToken> implements ActionTokenHandler<T>, ActionTokenHandlerFactory<T> {
|
||||||
|
|
||||||
private final String id;
|
private final String id;
|
||||||
private final Class<T> tokenClass;
|
private final Class<T> tokenClass;
|
||||||
|
@ -86,8 +87,8 @@ public abstract class AbstractActionTokenHander<T extends DefaultActionToken> im
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getAuthenticationSessionIdFromToken(T token) {
|
public String getAuthenticationSessionIdFromToken(T token, ActionTokenContext<T> tokenContext) {
|
||||||
return token == null ? null : token.getAuthenticationSessionId();
|
return token instanceof DefaultActionToken ? ((DefaultActionToken) token).getAuthenticationSessionId() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -64,7 +64,7 @@ public interface ActionTokenHandler<T extends JsonWebToken> extends Provider {
|
||||||
* @param token Token. Can be {@code null}
|
* @param token Token. Can be {@code null}
|
||||||
* @return authentication session ID
|
* @return authentication session ID
|
||||||
*/
|
*/
|
||||||
String getAuthenticationSessionIdFromToken(T token);
|
String getAuthenticationSessionIdFromToken(T token, ActionTokenContext<T> tokenContext);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a event type logged with {@link EventBuilder} class.
|
* Returns a event type logged with {@link EventBuilder} class.
|
||||||
|
|
|
@ -39,7 +39,7 @@ public class DefaultActionToken extends DefaultActionTokenKey implements ActionT
|
||||||
|
|
||||||
public static final String JSON_FIELD_AUTHENTICATION_SESSION_ID = "asid";
|
public static final String JSON_FIELD_AUTHENTICATION_SESSION_ID = "asid";
|
||||||
|
|
||||||
public static final Predicate<DefaultActionToken> ACTION_TOKEN_BASIC_CHECKS = t -> {
|
public static final Predicate<DefaultActionTokenKey> ACTION_TOKEN_BASIC_CHECKS = t -> {
|
||||||
if (t.getActionVerificationNonce() == null) {
|
if (t.getActionVerificationNonce() == null) {
|
||||||
throw new VerificationException("Nonce not present.");
|
throw new VerificationException("Nonce not present.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,9 @@ public class DefaultActionTokenKey extends JsonWebToken implements ActionTokenKe
|
||||||
@JsonProperty(value = JSON_FIELD_ACTION_VERIFICATION_NONCE, required = true)
|
@JsonProperty(value = JSON_FIELD_ACTION_VERIFICATION_NONCE, required = true)
|
||||||
private UUID actionVerificationNonce;
|
private UUID actionVerificationNonce;
|
||||||
|
|
||||||
|
public DefaultActionTokenKey() {
|
||||||
|
}
|
||||||
|
|
||||||
public DefaultActionTokenKey(String userId, String actionId, int absoluteExpirationInSecs, UUID actionVerificationNonce) {
|
public DefaultActionTokenKey(String userId, String actionId, int absoluteExpirationInSecs, UUID actionVerificationNonce) {
|
||||||
this.subject = userId;
|
this.subject = userId;
|
||||||
this.type = actionId;
|
this.type = actionId;
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.services.resources;
|
package org.keycloak.services.resources;
|
||||||
|
|
||||||
import org.keycloak.authentication.actiontoken.DefaultActionToken;
|
|
||||||
import org.keycloak.authentication.actiontoken.DefaultActionTokenKey;
|
import org.keycloak.authentication.actiontoken.DefaultActionTokenKey;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.jboss.resteasy.spi.HttpRequest;
|
import org.jboss.resteasy.spi.HttpRequest;
|
||||||
|
@ -27,6 +26,7 @@ import org.keycloak.authentication.RequiredActionContextResult;
|
||||||
import org.keycloak.authentication.RequiredActionFactory;
|
import org.keycloak.authentication.RequiredActionFactory;
|
||||||
import org.keycloak.authentication.RequiredActionProvider;
|
import org.keycloak.authentication.RequiredActionProvider;
|
||||||
import org.keycloak.TokenVerifier;
|
import org.keycloak.TokenVerifier;
|
||||||
|
import org.keycloak.authentication.ExplainedVerificationException;
|
||||||
import org.keycloak.authentication.actiontoken.*;
|
import org.keycloak.authentication.actiontoken.*;
|
||||||
import org.keycloak.authentication.actiontoken.resetcred.ResetCredentialsActionTokenHandler;
|
import org.keycloak.authentication.actiontoken.resetcred.ResetCredentialsActionTokenHandler;
|
||||||
import org.keycloak.authentication.authenticators.broker.AbstractIdpAuthenticator;
|
import org.keycloak.authentication.authenticators.broker.AbstractIdpAuthenticator;
|
||||||
|
@ -59,6 +59,7 @@ import org.keycloak.protocol.LoginProtocol.Error;
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||||
import org.keycloak.protocol.oidc.utils.OIDCResponseMode;
|
import org.keycloak.protocol.oidc.utils.OIDCResponseMode;
|
||||||
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
|
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
|
||||||
|
import org.keycloak.representations.JsonWebToken;
|
||||||
import org.keycloak.services.ErrorPage;
|
import org.keycloak.services.ErrorPage;
|
||||||
import org.keycloak.services.ServicesLogger;
|
import org.keycloak.services.ServicesLogger;
|
||||||
import org.keycloak.services.Urls;
|
import org.keycloak.services.Urls;
|
||||||
|
@ -405,7 +406,7 @@ public class LoginActionsService {
|
||||||
return handleActionToken(key, execution, clientId);
|
return handleActionToken(key, execution, clientId);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected <T extends DefaultActionToken> Response handleActionToken(String tokenString, String execution, String clientId) {
|
protected <T extends DefaultActionTokenKey> Response handleActionToken(String tokenString, String execution, String clientId) {
|
||||||
T token;
|
T token;
|
||||||
ActionTokenHandler<T> handler;
|
ActionTokenHandler<T> handler;
|
||||||
ActionTokenContext<T> tokenContext;
|
ActionTokenContext<T> tokenContext;
|
||||||
|
@ -430,8 +431,8 @@ public class LoginActionsService {
|
||||||
throw new ExplainedTokenVerificationException(null, Errors.NOT_ALLOWED, Messages.INVALID_REQUEST);
|
throw new ExplainedTokenVerificationException(null, Errors.NOT_ALLOWED, Messages.INVALID_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenVerifier<DefaultActionToken> tokenVerifier = TokenVerifier.create(tokenString, DefaultActionToken.class);
|
TokenVerifier<DefaultActionTokenKey> tokenVerifier = TokenVerifier.create(tokenString, DefaultActionTokenKey.class);
|
||||||
DefaultActionToken aToken = tokenVerifier.getToken();
|
DefaultActionTokenKey aToken = tokenVerifier.getToken();
|
||||||
|
|
||||||
event
|
event
|
||||||
.detail(Details.TOKEN_ID, aToken.getId())
|
.detail(Details.TOKEN_ID, aToken.getId())
|
||||||
|
@ -477,6 +478,8 @@ public class LoginActionsService {
|
||||||
return handleActionTokenVerificationException(null, ex, Errors.EXPIRED_CODE, Messages.EXPIRED_ACTION_TOKEN_NO_SESSION);
|
return handleActionTokenVerificationException(null, ex, Errors.EXPIRED_CODE, Messages.EXPIRED_ACTION_TOKEN_NO_SESSION);
|
||||||
} catch (ExplainedTokenVerificationException ex) {
|
} catch (ExplainedTokenVerificationException ex) {
|
||||||
return handleActionTokenVerificationException(null, ex, ex.getErrorEvent(), ex.getMessage());
|
return handleActionTokenVerificationException(null, ex, ex.getErrorEvent(), ex.getMessage());
|
||||||
|
} catch (ExplainedVerificationException ex) {
|
||||||
|
return handleActionTokenVerificationException(null, ex, ex.getErrorEvent(), ex.getMessage());
|
||||||
} catch (VerificationException ex) {
|
} catch (VerificationException ex) {
|
||||||
return handleActionTokenVerificationException(null, ex, eventError, defaultErrorMessage);
|
return handleActionTokenVerificationException(null, ex, eventError, defaultErrorMessage);
|
||||||
}
|
}
|
||||||
|
@ -485,7 +488,7 @@ public class LoginActionsService {
|
||||||
tokenContext = new ActionTokenContext(session, realm, uriInfo, clientConnection, request, event, handler, execution, this::processFlow, this::brokerLoginFlow);
|
tokenContext = new ActionTokenContext(session, realm, uriInfo, clientConnection, request, event, handler, execution, this::processFlow, this::brokerLoginFlow);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String tokenAuthSessionId = handler.getAuthenticationSessionIdFromToken(token);
|
String tokenAuthSessionId = handler.getAuthenticationSessionIdFromToken(token, tokenContext);
|
||||||
|
|
||||||
if (tokenAuthSessionId != null) {
|
if (tokenAuthSessionId != null) {
|
||||||
// This can happen if the token contains ID but user opens the link in a new browser
|
// This can happen if the token contains ID but user opens the link in a new browser
|
||||||
|
@ -541,7 +544,6 @@ public class LoginActionsService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Response processFlowFromPath(String flowPath, AuthenticationSessionModel authSession, String errorMessage) {
|
private Response processFlowFromPath(String flowPath, AuthenticationSessionModel authSession, String errorMessage) {
|
||||||
if (AUTHENTICATE_PATH.equals(flowPath)) {
|
if (AUTHENTICATE_PATH.equals(flowPath)) {
|
||||||
return processAuthentication(false, null, authSession, errorMessage);
|
return processAuthentication(false, null, authSession, errorMessage);
|
||||||
|
@ -555,7 +557,7 @@ public class LoginActionsService {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private <T extends DefaultActionToken> ActionTokenHandler<T> resolveActionTokenHandler(String actionId) throws VerificationException {
|
private <T extends JsonWebToken> ActionTokenHandler<T> resolveActionTokenHandler(String actionId) throws VerificationException {
|
||||||
if (actionId == null) {
|
if (actionId == null) {
|
||||||
throw new VerificationException("Action token operation not set");
|
throw new VerificationException("Action token operation not set");
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ package org.keycloak.services.resources;
|
||||||
|
|
||||||
import org.keycloak.TokenVerifier.Predicate;
|
import org.keycloak.TokenVerifier.Predicate;
|
||||||
import org.keycloak.authentication.AuthenticationProcessor;
|
import org.keycloak.authentication.AuthenticationProcessor;
|
||||||
import org.keycloak.authentication.actiontoken.DefaultActionToken;
|
import org.keycloak.authentication.actiontoken.DefaultActionTokenKey;
|
||||||
import org.keycloak.authentication.ExplainedVerificationException;
|
import org.keycloak.authentication.ExplainedVerificationException;
|
||||||
import org.keycloak.authentication.actiontoken.ActionTokenContext;
|
import org.keycloak.authentication.actiontoken.ActionTokenContext;
|
||||||
import org.keycloak.authentication.actiontoken.ExplainedTokenVerificationException;
|
import org.keycloak.authentication.actiontoken.ExplainedTokenVerificationException;
|
||||||
|
@ -152,7 +152,7 @@ public class LoginActionsServiceChecks {
|
||||||
* Verifies whether the user given by ID both exists in the current realm. If yes,
|
* Verifies whether the user given by ID both exists in the current realm. If yes,
|
||||||
* it optionally also injects the user using the given function (e.g. into session context).
|
* it optionally also injects the user using the given function (e.g. into session context).
|
||||||
*/
|
*/
|
||||||
public static <T extends DefaultActionToken> void checkIsUserValid(T token, ActionTokenContext<T> context) throws VerificationException {
|
public static <T extends DefaultActionTokenKey> void checkIsUserValid(T token, ActionTokenContext<T> context) throws VerificationException {
|
||||||
try {
|
try {
|
||||||
checkIsUserValid(context.getSession(), context.getRealm(), token.getUserId(), context.getAuthenticationSession()::setAuthenticatedUser);
|
checkIsUserValid(context.getSession(), context.getRealm(), token.getUserId(), context.getAuthenticationSession()::setAuthenticatedUser);
|
||||||
} catch (ExplainedVerificationException ex) {
|
} catch (ExplainedVerificationException ex) {
|
||||||
|
@ -178,7 +178,7 @@ public class LoginActionsServiceChecks {
|
||||||
* Verifies whether the client denoted by client ID in token's {@code iss} ({@code issuedFor})
|
* Verifies whether the client denoted by client ID in token's {@code iss} ({@code issuedFor})
|
||||||
* field both exists and is enabled.
|
* field both exists and is enabled.
|
||||||
*/
|
*/
|
||||||
public static <T extends DefaultActionToken> void checkIsClientValid(T token, ActionTokenContext<T> context) throws VerificationException {
|
public static <T extends JsonWebToken> void checkIsClientValid(T token, ActionTokenContext<T> context) throws VerificationException {
|
||||||
String clientId = token.getIssuedFor();
|
String clientId = token.getIssuedFor();
|
||||||
AuthenticationSessionModel authSession = context.getAuthenticationSession();
|
AuthenticationSessionModel authSession = context.getAuthenticationSession();
|
||||||
ClientModel client = authSession == null ? null : authSession.getClient();
|
ClientModel client = authSession == null ? null : authSession.getClient();
|
||||||
|
@ -297,8 +297,9 @@ public class LoginActionsServiceChecks {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends DefaultActionToken> void checkTokenWasNotUsedYet(T token, ActionTokenContext<T> context) throws VerificationException {
|
public static <T extends DefaultActionTokenKey> void checkTokenWasNotUsedYet(T token, ActionTokenContext<T> context) throws VerificationException {
|
||||||
ActionTokenStoreProvider actionTokenStore = context.getSession().getProvider(ActionTokenStoreProvider.class);
|
ActionTokenStoreProvider actionTokenStore = context.getSession().getProvider(ActionTokenStoreProvider.class);
|
||||||
|
|
||||||
if (actionTokenStore.get(token) != null) {
|
if (actionTokenStore.get(token) != null) {
|
||||||
throw new ExplainedTokenVerificationException(token, Errors.EXPIRED_CODE, Messages.EXPIRED_ACTION);
|
throw new ExplainedTokenVerificationException(token, Errors.EXPIRED_CODE, Messages.EXPIRED_ACTION);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue