KEYCLOAK-15533 Client Policy : Extends Policy Interface to Migrate Client Registration Policies
Co-authored-by: Hryhorii Hevorkian <hhe@adorsys.com.ua> Co-authored-by: Andrii Murashkin <amu@adorsys.com.ua>
This commit is contained in:
parent
b83064b142
commit
882f5ffea4
51 changed files with 971 additions and 301 deletions
|
@ -20,7 +20,11 @@ package org.keycloak.services.clientpolicy;
|
||||||
public enum ClientPolicyEvent {
|
public enum ClientPolicyEvent {
|
||||||
|
|
||||||
REGISTER,
|
REGISTER,
|
||||||
|
REGISTERED,
|
||||||
UPDATE,
|
UPDATE,
|
||||||
|
UPDATED,
|
||||||
|
VIEW,
|
||||||
|
UNREGISTER,
|
||||||
AUTHORIZATION_REQUEST,
|
AUTHORIZATION_REQUEST,
|
||||||
TOKEN_REQUEST,
|
TOKEN_REQUEST,
|
||||||
TOKEN_REFRESH,
|
TOKEN_REFRESH,
|
||||||
|
|
|
@ -44,10 +44,10 @@ import org.keycloak.protocol.oidc.utils.RedirectUtils;
|
||||||
import org.keycloak.services.ErrorPageException;
|
import org.keycloak.services.ErrorPageException;
|
||||||
import org.keycloak.services.ServicesLogger;
|
import org.keycloak.services.ServicesLogger;
|
||||||
import org.keycloak.services.Urls;
|
import org.keycloak.services.Urls;
|
||||||
import org.keycloak.services.clientpolicy.AuthorizationRequestContext;
|
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
import org.keycloak.services.clientpolicy.DefaultClientPolicyManager;
|
import org.keycloak.services.clientpolicy.DefaultClientPolicyManager;
|
||||||
|
import org.keycloak.services.clientpolicy.context.AuthorizationRequestContext;
|
||||||
import org.keycloak.services.messages.Messages;
|
import org.keycloak.services.messages.Messages;
|
||||||
import org.keycloak.services.resources.LoginActionsService;
|
import org.keycloak.services.resources.LoginActionsService;
|
||||||
import org.keycloak.services.util.CacheControlUtil;
|
import org.keycloak.services.util.CacheControlUtil;
|
||||||
|
|
|
@ -46,7 +46,7 @@ import org.keycloak.representations.RefreshToken;
|
||||||
import org.keycloak.services.ErrorPage;
|
import org.keycloak.services.ErrorPage;
|
||||||
import org.keycloak.services.ErrorResponseException;
|
import org.keycloak.services.ErrorResponseException;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
import org.keycloak.services.clientpolicy.LogoutRequestContext;
|
import org.keycloak.services.clientpolicy.context.LogoutRequestContext;
|
||||||
import org.keycloak.services.managers.AuthenticationManager;
|
import org.keycloak.services.managers.AuthenticationManager;
|
||||||
import org.keycloak.services.managers.UserSessionManager;
|
import org.keycloak.services.managers.UserSessionManager;
|
||||||
import org.keycloak.services.messages.Messages;
|
import org.keycloak.services.messages.Messages;
|
||||||
|
|
|
@ -85,8 +85,8 @@ import org.keycloak.services.CorsErrorResponseException;
|
||||||
import org.keycloak.services.ServicesLogger;
|
import org.keycloak.services.ServicesLogger;
|
||||||
import org.keycloak.services.Urls;
|
import org.keycloak.services.Urls;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
import org.keycloak.services.clientpolicy.TokenRefreshContext;
|
import org.keycloak.services.clientpolicy.context.TokenRefreshContext;
|
||||||
import org.keycloak.services.clientpolicy.TokenRequestContext;
|
import org.keycloak.services.clientpolicy.context.TokenRequestContext;
|
||||||
import org.keycloak.services.managers.AppAuthManager;
|
import org.keycloak.services.managers.AppAuthManager;
|
||||||
import org.keycloak.services.managers.AuthenticationManager;
|
import org.keycloak.services.managers.AuthenticationManager;
|
||||||
import org.keycloak.services.managers.AuthenticationSessionManager;
|
import org.keycloak.services.managers.AuthenticationSessionManager;
|
||||||
|
|
|
@ -33,7 +33,7 @@ import org.keycloak.services.CorsErrorResponseException;
|
||||||
import org.keycloak.services.ErrorResponseException;
|
import org.keycloak.services.ErrorResponseException;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
import org.keycloak.services.clientpolicy.DefaultClientPolicyManager;
|
import org.keycloak.services.clientpolicy.DefaultClientPolicyManager;
|
||||||
import org.keycloak.services.clientpolicy.TokenIntrospectContext;
|
import org.keycloak.services.clientpolicy.context.TokenIntrospectContext;
|
||||||
|
|
||||||
import javax.ws.rs.POST;
|
import javax.ws.rs.POST;
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
|
|
|
@ -48,7 +48,7 @@ import org.keycloak.protocol.oidc.utils.AuthorizeClientUtil;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.services.CorsErrorResponseException;
|
import org.keycloak.services.CorsErrorResponseException;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
import org.keycloak.services.clientpolicy.TokenRevokeContext;
|
import org.keycloak.services.clientpolicy.context.TokenRevokeContext;
|
||||||
import org.keycloak.services.managers.UserSessionCrossDCManager;
|
import org.keycloak.services.managers.UserSessionCrossDCManager;
|
||||||
import org.keycloak.services.managers.UserSessionManager;
|
import org.keycloak.services.managers.UserSessionManager;
|
||||||
import org.keycloak.services.resources.Cors;
|
import org.keycloak.services.resources.Cors;
|
||||||
|
|
|
@ -49,7 +49,7 @@ import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.services.CorsErrorResponseException;
|
import org.keycloak.services.CorsErrorResponseException;
|
||||||
import org.keycloak.services.Urls;
|
import org.keycloak.services.Urls;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
import org.keycloak.services.clientpolicy.UserInfoRequestContext;
|
import org.keycloak.services.clientpolicy.context.UserInfoRequestContext;
|
||||||
import org.keycloak.services.managers.AppAuthManager;
|
import org.keycloak.services.managers.AppAuthManager;
|
||||||
import org.keycloak.services.managers.AuthenticationManager;
|
import org.keycloak.services.managers.AuthenticationManager;
|
||||||
import org.keycloak.services.managers.UserSessionCrossDCManager;
|
import org.keycloak.services.managers.UserSessionCrossDCManager;
|
||||||
|
|
|
@ -17,7 +17,10 @@
|
||||||
|
|
||||||
package org.keycloak.services.clientpolicy;
|
package org.keycloak.services.clientpolicy;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
|
@ -30,12 +30,12 @@ import org.keycloak.models.AuthenticatedClientSessionModel;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequest;
|
import org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequest;
|
||||||
import org.keycloak.services.clientpolicy.AuthorizationRequestContext;
|
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
|
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyVote;
|
import org.keycloak.services.clientpolicy.ClientPolicyVote;
|
||||||
import org.keycloak.services.clientpolicy.TokenRequestContext;
|
import org.keycloak.services.clientpolicy.context.AuthorizationRequestContext;
|
||||||
|
import org.keycloak.services.clientpolicy.context.TokenRequestContext;
|
||||||
|
|
||||||
public class ClientScopesCondition extends AbstractClientPolicyConditionProvider {
|
public class ClientScopesCondition extends AbstractClientPolicyConditionProvider {
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
|
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyVote;
|
import org.keycloak.services.clientpolicy.ClientPolicyVote;
|
||||||
import org.keycloak.services.clientpolicy.ClientUpdateContext;
|
import org.keycloak.services.clientpolicy.context.ClientCRUDContext;
|
||||||
import org.keycloak.services.clientregistration.ClientRegistrationTokenUtils;
|
import org.keycloak.services.clientregistration.ClientRegistrationTokenUtils;
|
||||||
import org.keycloak.util.TokenUtil;
|
import org.keycloak.util.TokenUtil;
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ public class ClientUpdateContextCondition extends AbstractClientPolicyConditionP
|
||||||
switch (context.getEvent()) {
|
switch (context.getEvent()) {
|
||||||
case REGISTER:
|
case REGISTER:
|
||||||
case UPDATE:
|
case UPDATE:
|
||||||
if (isAuthMethodMatched((ClientUpdateContext)context)) return ClientPolicyVote.YES;
|
if (isAuthMethodMatched((ClientCRUDContext)context)) return ClientPolicyVote.YES;
|
||||||
return ClientPolicyVote.NO;
|
return ClientPolicyVote.NO;
|
||||||
default:
|
default:
|
||||||
return ClientPolicyVote.ABSTAIN;
|
return ClientPolicyVote.ABSTAIN;
|
||||||
|
@ -72,7 +72,7 @@ public class ClientUpdateContextCondition extends AbstractClientPolicyConditionP
|
||||||
return isMatched;
|
return isMatched;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAuthMethodMatched(ClientUpdateContext context) {
|
private boolean isAuthMethodMatched(ClientCRUDContext context) {
|
||||||
String authMethod = null;
|
String authMethod = null;
|
||||||
|
|
||||||
if (context.getToken() == null) {
|
if (context.getToken() == null) {
|
||||||
|
|
|
@ -29,15 +29,15 @@ import org.keycloak.models.GroupModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.representations.JsonWebToken;
|
import org.keycloak.representations.JsonWebToken;
|
||||||
import org.keycloak.services.clientpolicy.AdminClientRegisterContext;
|
|
||||||
import org.keycloak.services.clientpolicy.AdminClientUpdateContext;
|
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
|
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyVote;
|
import org.keycloak.services.clientpolicy.ClientPolicyVote;
|
||||||
import org.keycloak.services.clientpolicy.ClientUpdateContext;
|
import org.keycloak.services.clientpolicy.context.AdminClientRegisterContext;
|
||||||
import org.keycloak.services.clientpolicy.DynamicClientRegisterContext;
|
import org.keycloak.services.clientpolicy.context.AdminClientUpdateContext;
|
||||||
import org.keycloak.services.clientpolicy.DynamicClientUpdateContext;
|
import org.keycloak.services.clientpolicy.context.ClientCRUDContext;
|
||||||
|
import org.keycloak.services.clientpolicy.context.DynamicClientRegisterContext;
|
||||||
|
import org.keycloak.services.clientpolicy.context.DynamicClientUpdateContext;
|
||||||
|
|
||||||
public class ClientUpdateSourceGroupsCondition extends AbstractClientPolicyConditionProvider {
|
public class ClientUpdateSourceGroupsCondition extends AbstractClientPolicyConditionProvider {
|
||||||
|
|
||||||
|
@ -52,17 +52,17 @@ public class ClientUpdateSourceGroupsCondition extends AbstractClientPolicyCondi
|
||||||
switch (context.getEvent()) {
|
switch (context.getEvent()) {
|
||||||
case REGISTER:
|
case REGISTER:
|
||||||
if (context instanceof AdminClientRegisterContext) {
|
if (context instanceof AdminClientRegisterContext) {
|
||||||
return getVoteForGroupsMatched(((ClientUpdateContext)context).getAuthenticatedUser());
|
return getVoteForGroupsMatched(((ClientCRUDContext)context).getAuthenticatedUser());
|
||||||
} else if (context instanceof DynamicClientRegisterContext) {
|
} else if (context instanceof DynamicClientRegisterContext) {
|
||||||
return getVoteForGroupsMatched(((ClientUpdateContext)context).getToken());
|
return getVoteForGroupsMatched(((ClientCRUDContext)context).getToken());
|
||||||
} else {
|
} else {
|
||||||
throw new ClientPolicyException(OAuthErrorException.SERVER_ERROR, "unexpected context type.");
|
throw new ClientPolicyException(OAuthErrorException.SERVER_ERROR, "unexpected context type.");
|
||||||
}
|
}
|
||||||
case UPDATE:
|
case UPDATE:
|
||||||
if (context instanceof AdminClientUpdateContext) {
|
if (context instanceof AdminClientUpdateContext) {
|
||||||
return getVoteForGroupsMatched(((ClientUpdateContext)context).getAuthenticatedUser());
|
return getVoteForGroupsMatched(((ClientCRUDContext)context).getAuthenticatedUser());
|
||||||
} else if (context instanceof DynamicClientUpdateContext) {
|
} else if (context instanceof DynamicClientUpdateContext) {
|
||||||
return getVoteForGroupsMatched(((ClientUpdateContext)context).getToken());
|
return getVoteForGroupsMatched(((ClientCRUDContext)context).getToken());
|
||||||
} else {
|
} else {
|
||||||
throw new ClientPolicyException(OAuthErrorException.SERVER_ERROR, "unexpected context type.");
|
throw new ClientPolicyException(OAuthErrorException.SERVER_ERROR, "unexpected context type.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,15 +30,15 @@ import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.representations.JsonWebToken;
|
import org.keycloak.representations.JsonWebToken;
|
||||||
import org.keycloak.services.clientpolicy.AdminClientRegisterContext;
|
|
||||||
import org.keycloak.services.clientpolicy.AdminClientUpdateContext;
|
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
|
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyVote;
|
import org.keycloak.services.clientpolicy.ClientPolicyVote;
|
||||||
import org.keycloak.services.clientpolicy.ClientUpdateContext;
|
import org.keycloak.services.clientpolicy.context.AdminClientRegisterContext;
|
||||||
import org.keycloak.services.clientpolicy.DynamicClientRegisterContext;
|
import org.keycloak.services.clientpolicy.context.AdminClientUpdateContext;
|
||||||
import org.keycloak.services.clientpolicy.DynamicClientUpdateContext;
|
import org.keycloak.services.clientpolicy.context.ClientCRUDContext;
|
||||||
|
import org.keycloak.services.clientpolicy.context.DynamicClientRegisterContext;
|
||||||
|
import org.keycloak.services.clientpolicy.context.DynamicClientUpdateContext;
|
||||||
|
|
||||||
public class ClientUpdateSourceRolesCondition extends AbstractClientPolicyConditionProvider {
|
public class ClientUpdateSourceRolesCondition extends AbstractClientPolicyConditionProvider {
|
||||||
|
|
||||||
|
@ -53,17 +53,17 @@ public class ClientUpdateSourceRolesCondition extends AbstractClientPolicyCondit
|
||||||
switch (context.getEvent()) {
|
switch (context.getEvent()) {
|
||||||
case REGISTER:
|
case REGISTER:
|
||||||
if (context instanceof AdminClientRegisterContext) {
|
if (context instanceof AdminClientRegisterContext) {
|
||||||
return getVoteForRolesMatched(((ClientUpdateContext)context).getAuthenticatedUser());
|
return getVoteForRolesMatched(((ClientCRUDContext)context).getAuthenticatedUser());
|
||||||
} else if (context instanceof DynamicClientRegisterContext) {
|
} else if (context instanceof DynamicClientRegisterContext) {
|
||||||
return getVoteForRolesMatched(((ClientUpdateContext)context).getToken());
|
return getVoteForRolesMatched(((ClientCRUDContext)context).getToken());
|
||||||
} else {
|
} else {
|
||||||
throw new ClientPolicyException(OAuthErrorException.SERVER_ERROR, "unexpected context type.");
|
throw new ClientPolicyException(OAuthErrorException.SERVER_ERROR, "unexpected context type.");
|
||||||
}
|
}
|
||||||
case UPDATE:
|
case UPDATE:
|
||||||
if (context instanceof AdminClientUpdateContext) {
|
if (context instanceof AdminClientUpdateContext) {
|
||||||
return getVoteForRolesMatched(((ClientUpdateContext)context).getAuthenticatedUser());
|
return getVoteForRolesMatched(((ClientCRUDContext)context).getAuthenticatedUser());
|
||||||
} else if (context instanceof DynamicClientUpdateContext) {
|
} else if (context instanceof DynamicClientUpdateContext) {
|
||||||
return getVoteForRolesMatched(((ClientUpdateContext)context).getToken());
|
return getVoteForRolesMatched(((ClientCRUDContext)context).getToken());
|
||||||
} else {
|
} else {
|
||||||
throw new ClientPolicyException(OAuthErrorException.SERVER_ERROR, "unexpected context type.");
|
throw new ClientPolicyException(OAuthErrorException.SERVER_ERROR, "unexpected context type.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2020 Red Hat, Inc. and/or its affiliates
|
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||||
* and other contributors as indicated by the @author tags.
|
* and other contributors as indicated by the @author tags.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -15,36 +15,21 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.services.clientpolicy;
|
package org.keycloak.services.clientpolicy.context;
|
||||||
|
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.representations.JsonWebToken;
|
import org.keycloak.representations.JsonWebToken;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
|
||||||
import org.keycloak.services.resources.admin.AdminAuth;
|
import org.keycloak.services.resources.admin.AdminAuth;
|
||||||
|
|
||||||
public class AdminClientRegisterContext implements ClientUpdateContext {
|
abstract class AbstractAdminClientCRUDContext implements ClientCRUDContext {
|
||||||
|
|
||||||
private final ClientRepresentation clientRepresentation;
|
protected final AdminAuth adminAuth;
|
||||||
private final AdminAuth adminAuth;
|
|
||||||
|
|
||||||
public AdminClientRegisterContext(ClientRepresentation clientRepresentation,
|
public AbstractAdminClientCRUDContext(AdminAuth adminAuth) {
|
||||||
AdminAuth adminAuth) {
|
|
||||||
this.clientRepresentation = clientRepresentation;
|
|
||||||
this.adminAuth = adminAuth;
|
this.adminAuth = adminAuth;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ClientPolicyEvent getEvent() {
|
|
||||||
return ClientPolicyEvent.REGISTER;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ClientRepresentation getProposedClientRepresentation() {
|
|
||||||
return clientRepresentation;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientModel getAuthenticatedClient() {
|
public ClientModel getAuthenticatedClient() {
|
||||||
return adminAuth.getClient();
|
return adminAuth.getClient();
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.services.clientpolicy.context;
|
||||||
|
|
||||||
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.representations.JsonWebToken;
|
||||||
|
|
||||||
|
abstract class AbstractDynamicClientCRUDContext implements ClientCRUDContext {
|
||||||
|
|
||||||
|
private final JsonWebToken token;
|
||||||
|
private ClientModel authenticatedClient;
|
||||||
|
private UserModel authenticatedUser;
|
||||||
|
|
||||||
|
public AbstractDynamicClientCRUDContext(KeycloakSession session, JsonWebToken token, RealmModel realm) {
|
||||||
|
this.token = token;
|
||||||
|
if (token == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (token.getIssuedFor() != null) {
|
||||||
|
this.authenticatedClient = realm.getClientByClientId(token.getIssuedFor());
|
||||||
|
}
|
||||||
|
if (token.getSubject() != null) {
|
||||||
|
this.authenticatedUser = session.users().getUserById(token.getSubject(), realm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientModel getAuthenticatedClient() {
|
||||||
|
return authenticatedClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserModel getAuthenticatedUser() {
|
||||||
|
return authenticatedUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonWebToken getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.services.clientpolicy.context;
|
||||||
|
|
||||||
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
|
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
||||||
|
import org.keycloak.services.resources.admin.AdminAuth;
|
||||||
|
|
||||||
|
public class AdminClientRegisterContext extends AbstractAdminClientCRUDContext {
|
||||||
|
|
||||||
|
private final ClientRepresentation proposedClientRepresentation;
|
||||||
|
|
||||||
|
public AdminClientRegisterContext(ClientRepresentation proposedClientRepresentation, AdminAuth adminAuth) {
|
||||||
|
super(adminAuth);
|
||||||
|
this.proposedClientRepresentation = proposedClientRepresentation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientPolicyEvent getEvent() {
|
||||||
|
return ClientPolicyEvent.REGISTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientRepresentation getProposedClientRepresentation() {
|
||||||
|
return proposedClientRepresentation;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.services.clientpolicy.context;
|
||||||
|
|
||||||
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
||||||
|
import org.keycloak.services.resources.admin.AdminAuth;
|
||||||
|
|
||||||
|
public class AdminClientRegisteredContext extends AbstractAdminClientCRUDContext {
|
||||||
|
|
||||||
|
private final ClientModel registeredClient;
|
||||||
|
|
||||||
|
public AdminClientRegisteredContext(ClientModel registeredClient, AdminAuth adminAuth) {
|
||||||
|
super(adminAuth);
|
||||||
|
this.registeredClient = registeredClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientPolicyEvent getEvent() {
|
||||||
|
return ClientPolicyEvent.REGISTERED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientModel getTargetClient() {
|
||||||
|
return registeredClient;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.services.clientpolicy.context;
|
||||||
|
|
||||||
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
||||||
|
import org.keycloak.services.resources.admin.AdminAuth;
|
||||||
|
|
||||||
|
public class AdminClientUnregisterContext extends AbstractAdminClientCRUDContext {
|
||||||
|
|
||||||
|
private final ClientModel targetClient;
|
||||||
|
|
||||||
|
public AdminClientUnregisterContext(ClientModel targetClient, AdminAuth adminAuth) {
|
||||||
|
super(adminAuth);
|
||||||
|
this.targetClient = targetClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientPolicyEvent getEvent() {
|
||||||
|
return ClientPolicyEvent.UNREGISTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientModel getTargetClient() {
|
||||||
|
return this.targetClient;
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,26 +15,22 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.services.clientpolicy;
|
package org.keycloak.services.clientpolicy.context;
|
||||||
|
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.UserModel;
|
|
||||||
import org.keycloak.representations.JsonWebToken;
|
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
||||||
import org.keycloak.services.resources.admin.AdminAuth;
|
import org.keycloak.services.resources.admin.AdminAuth;
|
||||||
|
|
||||||
public class AdminClientUpdateContext implements ClientUpdateContext {
|
public class AdminClientUpdateContext extends AbstractAdminClientCRUDContext {
|
||||||
|
|
||||||
private final ClientRepresentation clientRepresentation;
|
private final ClientRepresentation proposedClientRepresentation;
|
||||||
private final AdminAuth adminAuth;
|
private final ClientModel targetClient;
|
||||||
private final ClientModel client;
|
|
||||||
|
|
||||||
public AdminClientUpdateContext(ClientRepresentation clientRepresentation,
|
public AdminClientUpdateContext(ClientRepresentation proposedClientRepresentation, ClientModel targetClient, AdminAuth adminAuth) {
|
||||||
AdminAuth adminAuth, ClientModel client) {
|
super(adminAuth);
|
||||||
this.clientRepresentation = clientRepresentation;
|
this.proposedClientRepresentation = proposedClientRepresentation;
|
||||||
this.adminAuth = adminAuth;
|
this.targetClient = targetClient;
|
||||||
this.client = client;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -44,26 +40,11 @@ public class AdminClientUpdateContext implements ClientUpdateContext {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientRepresentation getProposedClientRepresentation() {
|
public ClientRepresentation getProposedClientRepresentation() {
|
||||||
return clientRepresentation;
|
return proposedClientRepresentation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientModel getClientToBeUpdated() {
|
public ClientModel getTargetClient() {
|
||||||
return client;
|
return targetClient;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ClientModel getAuthenticatedClient() {
|
|
||||||
return adminAuth.getClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserModel getAuthenticatedUser() {
|
|
||||||
return adminAuth.getUser();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JsonWebToken getToken() {
|
|
||||||
return adminAuth.getToken();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.services.clientpolicy.context;
|
||||||
|
|
||||||
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
|
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
||||||
|
import org.keycloak.services.resources.admin.AdminAuth;
|
||||||
|
|
||||||
|
public class AdminClientUpdatedContext extends AbstractAdminClientCRUDContext {
|
||||||
|
|
||||||
|
private final ClientRepresentation proposedClientRepresentation;
|
||||||
|
private final ClientModel updatedClient;
|
||||||
|
|
||||||
|
public AdminClientUpdatedContext(ClientRepresentation roposedClientRepresentation, ClientModel updatedClient, AdminAuth adminAuth) {
|
||||||
|
super(adminAuth);
|
||||||
|
this.proposedClientRepresentation = roposedClientRepresentation;
|
||||||
|
this.updatedClient = updatedClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientPolicyEvent getEvent() {
|
||||||
|
return ClientPolicyEvent.UPDATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientRepresentation getProposedClientRepresentation() {
|
||||||
|
return proposedClientRepresentation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientModel getTargetClient() {
|
||||||
|
return updatedClient;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.services.clientpolicy.context;
|
||||||
|
|
||||||
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
||||||
|
import org.keycloak.services.resources.admin.AdminAuth;
|
||||||
|
|
||||||
|
public class AdminClientViewContext extends AbstractAdminClientCRUDContext {
|
||||||
|
|
||||||
|
private final ClientModel targetClient;
|
||||||
|
|
||||||
|
public AdminClientViewContext(ClientModel targetClient, AdminAuth adminAuth) {
|
||||||
|
super(adminAuth);
|
||||||
|
this.targetClient = targetClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientPolicyEvent getEvent() {
|
||||||
|
return ClientPolicyEvent.VIEW;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientModel getTargetClient() {
|
||||||
|
return targetClient;
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.services.clientpolicy;
|
package org.keycloak.services.clientpolicy.context;
|
||||||
|
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2020 Red Hat, Inc. and/or its affiliates
|
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||||
* and other contributors as indicated by the @author tags.
|
* and other contributors as indicated by the @author tags.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -15,31 +15,35 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.services.clientpolicy;
|
package org.keycloak.services.clientpolicy.context;
|
||||||
|
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.representations.JsonWebToken;
|
import org.keycloak.representations.JsonWebToken;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
|
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the context in the client registration/update by Dynamic Client Registration or Admin REST API.
|
* Represents the context in the request to register/read/update/unregister client by Dynamic Client Registration or Admin REST API.
|
||||||
*/
|
*/
|
||||||
public interface ClientUpdateContext extends ClientPolicyContext {
|
public interface ClientCRUDContext extends ClientPolicyContext {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns {@link ClientRepresentation} for creating or updating the current client.
|
* returns {@link ClientRepresentation} for creating the new client or updating the existing client.
|
||||||
*
|
*
|
||||||
* @return {@link ClientRepresentation}
|
* @return {@link ClientRepresentation}
|
||||||
*/
|
*/
|
||||||
ClientRepresentation getProposedClientRepresentation();
|
default ClientRepresentation getProposedClientRepresentation() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns {@link ClientModel} of the current client to be updated.
|
* returns {@link ClientModel} of the existing client to be updated/read/updated/deleted.
|
||||||
|
* on REGISTER event, it returns null.
|
||||||
*
|
*
|
||||||
* @return {@link ClientModel}
|
* @return {@link ClientModel}
|
||||||
*/
|
*/
|
||||||
default ClientModel getClientToBeUpdated() {
|
default ClientModel getTargetClient() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,19 +52,25 @@ public interface ClientUpdateContext extends ClientPolicyContext {
|
||||||
*
|
*
|
||||||
* @return {@link UserModel}
|
* @return {@link UserModel}
|
||||||
*/
|
*/
|
||||||
UserModel getAuthenticatedUser();
|
default UserModel getAuthenticatedUser() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns {@link UserModel} of the authenticated client.
|
* returns {@link UserModel} of the authenticated client.
|
||||||
*
|
*
|
||||||
* @return {@link UserModel}
|
* @return {@link UserModel}
|
||||||
*/
|
*/
|
||||||
ClientModel getAuthenticatedClient();
|
default ClientModel getAuthenticatedClient() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns {@link JsonWebToken} of the token accompanied with registration/update client
|
* returns {@link JsonWebToken} of the token accompanied with the request to register/read/update/unregister client
|
||||||
*
|
*
|
||||||
* @return {@link JsonWebToken}
|
* @return {@link JsonWebToken}
|
||||||
*/
|
*/
|
||||||
JsonWebToken getToken();
|
default JsonWebToken getToken() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -15,35 +15,21 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.services.clientpolicy;
|
package org.keycloak.services.clientpolicy.context;
|
||||||
|
|
||||||
import org.keycloak.models.ClientModel;
|
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
|
||||||
import org.keycloak.representations.JsonWebToken;
|
import org.keycloak.representations.JsonWebToken;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
||||||
import org.keycloak.services.clientregistration.ClientRegistrationContext;
|
import org.keycloak.services.clientregistration.ClientRegistrationContext;
|
||||||
|
|
||||||
public class DynamicClientRegisterContext implements ClientUpdateContext {
|
public class DynamicClientRegisterContext extends AbstractDynamicClientCRUDContext {
|
||||||
|
|
||||||
private final ClientRegistrationContext context;
|
private final ClientRepresentation proposedClientRepresentation;
|
||||||
private JsonWebToken token;
|
|
||||||
private UserModel user;
|
|
||||||
private ClientModel client;
|
|
||||||
|
|
||||||
public DynamicClientRegisterContext(ClientRegistrationContext context,
|
public DynamicClientRegisterContext(ClientRegistrationContext context, JsonWebToken token, RealmModel realm) {
|
||||||
JsonWebToken token, RealmModel realm) {
|
super(context.getSession(), token, realm);
|
||||||
this.context = context;
|
this.proposedClientRepresentation = context.getClient();
|
||||||
this.token = token;
|
|
||||||
if (token != null) {
|
|
||||||
if (token.getSubject() != null) {
|
|
||||||
this.user = context.getSession().users().getUserById(realm, token.getSubject());
|
|
||||||
}
|
|
||||||
if (token.getIssuedFor() != null) {
|
|
||||||
this.client = realm.getClientByClientId(token.getIssuedFor());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -53,21 +39,6 @@ public class DynamicClientRegisterContext implements ClientUpdateContext {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientRepresentation getProposedClientRepresentation() {
|
public ClientRepresentation getProposedClientRepresentation() {
|
||||||
return context.getClient();
|
return proposedClientRepresentation;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ClientModel getAuthenticatedClient() {
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserModel getAuthenticatedUser() {
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JsonWebToken getToken() {
|
|
||||||
return token;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.services.clientpolicy.context;
|
||||||
|
|
||||||
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.representations.JsonWebToken;
|
||||||
|
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
||||||
|
import org.keycloak.services.clientregistration.ClientRegistrationContext;
|
||||||
|
|
||||||
|
public class DynamicClientRegisteredContext extends AbstractDynamicClientCRUDContext {
|
||||||
|
|
||||||
|
private final ClientModel registeredClient;
|
||||||
|
|
||||||
|
public DynamicClientRegisteredContext(ClientRegistrationContext context, ClientModel registeredClient, JsonWebToken token, RealmModel realm) {
|
||||||
|
super(context.getSession(), token, realm);
|
||||||
|
this.registeredClient = registeredClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientPolicyEvent getEvent() {
|
||||||
|
return ClientPolicyEvent.REGISTERED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientModel getTargetClient() {
|
||||||
|
return registeredClient;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.services.clientpolicy.context;
|
||||||
|
|
||||||
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.representations.JsonWebToken;
|
||||||
|
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
||||||
|
|
||||||
|
public class DynamicClientUnregisterContext extends AbstractDynamicClientCRUDContext {
|
||||||
|
|
||||||
|
private final ClientModel targetClient;
|
||||||
|
|
||||||
|
public DynamicClientUnregisterContext(KeycloakSession session, ClientModel targetClient, JsonWebToken token, RealmModel realm) {
|
||||||
|
super(session, token, realm);
|
||||||
|
this.targetClient = targetClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientPolicyEvent getEvent() {
|
||||||
|
return ClientPolicyEvent.UNREGISTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientModel getTargetClient() {
|
||||||
|
return this.targetClient;
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,37 +15,24 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.services.clientpolicy;
|
package org.keycloak.services.clientpolicy.context;
|
||||||
|
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
|
||||||
import org.keycloak.representations.JsonWebToken;
|
import org.keycloak.representations.JsonWebToken;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
||||||
import org.keycloak.services.clientregistration.ClientRegistrationContext;
|
import org.keycloak.services.clientregistration.ClientRegistrationContext;
|
||||||
|
|
||||||
public class DynamicClientUpdateContext implements ClientUpdateContext {
|
public class DynamicClientUpdateContext extends AbstractDynamicClientCRUDContext {
|
||||||
|
|
||||||
private final ClientRegistrationContext context;
|
|
||||||
private final ClientModel clientToBeUpdated;
|
private final ClientModel clientToBeUpdated;
|
||||||
private JsonWebToken token;
|
private final ClientRepresentation proposedClientRepresentation;
|
||||||
private UserModel user;
|
|
||||||
private ClientModel client;
|
|
||||||
|
|
||||||
public DynamicClientUpdateContext(ClientRegistrationContext context,
|
public DynamicClientUpdateContext(ClientRegistrationContext context, ClientModel proposedClientRepresentation, JsonWebToken token, RealmModel realm) {
|
||||||
ClientModel client, JsonWebToken token, RealmModel realm) {
|
super(context.getSession(), token, realm);
|
||||||
this.context = context;
|
this.clientToBeUpdated = proposedClientRepresentation;
|
||||||
this.clientToBeUpdated = client;
|
this.proposedClientRepresentation = context.getClient();
|
||||||
this.token = token;
|
|
||||||
if (token != null) {
|
|
||||||
if (token.getSubject() != null) {
|
|
||||||
this.user = context.getSession().users().getUserById(realm, token.getSubject());
|
|
||||||
}
|
|
||||||
if (token.getIssuedFor() != null) {
|
|
||||||
this.client = realm.getClientByClientId(token.getIssuedFor());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -55,26 +42,11 @@ public class DynamicClientUpdateContext implements ClientUpdateContext {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientRepresentation getProposedClientRepresentation() {
|
public ClientRepresentation getProposedClientRepresentation() {
|
||||||
return context.getClient();
|
return proposedClientRepresentation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientModel getClientToBeUpdated() {
|
public ClientModel getTargetClient() {
|
||||||
return clientToBeUpdated;
|
return clientToBeUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ClientModel getAuthenticatedClient() {
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserModel getAuthenticatedUser() {
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JsonWebToken getToken() {
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.services.clientpolicy.context;
|
||||||
|
|
||||||
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.representations.JsonWebToken;
|
||||||
|
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
||||||
|
|
||||||
|
public class DynamicClientUpdatedContext extends AbstractDynamicClientCRUDContext {
|
||||||
|
|
||||||
|
private final ClientModel updatedClient;
|
||||||
|
|
||||||
|
public DynamicClientUpdatedContext(KeycloakSession session, ClientModel updatedClient, JsonWebToken token, RealmModel realm) {
|
||||||
|
super(session, token, realm);
|
||||||
|
this.updatedClient = updatedClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientPolicyEvent getEvent() {
|
||||||
|
return ClientPolicyEvent.UPDATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientModel getTargetClient() {
|
||||||
|
return updatedClient;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.services.clientpolicy.context;
|
||||||
|
|
||||||
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.representations.JsonWebToken;
|
||||||
|
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
||||||
|
|
||||||
|
public class DynamicClientViewContext extends AbstractDynamicClientCRUDContext {
|
||||||
|
|
||||||
|
private final ClientModel targetClient;
|
||||||
|
|
||||||
|
public DynamicClientViewContext(KeycloakSession session, ClientModel targetClient, JsonWebToken token, RealmModel realm) {
|
||||||
|
super(session, token, realm);
|
||||||
|
this.targetClient = targetClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientPolicyEvent getEvent() {
|
||||||
|
return ClientPolicyEvent.VIEW;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientModel getTargetClient() {
|
||||||
|
return targetClient;
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.services.clientpolicy;
|
package org.keycloak.services.clientpolicy.context;
|
||||||
|
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.services.clientpolicy;
|
package org.keycloak.services.clientpolicy.context;
|
||||||
|
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.services.clientpolicy;
|
package org.keycloak.services.clientpolicy.context;
|
||||||
|
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.services.clientpolicy;
|
package org.keycloak.services.clientpolicy.context;
|
||||||
|
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.services.clientpolicy;
|
package org.keycloak.services.clientpolicy.context;
|
||||||
|
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.services.clientpolicy;
|
package org.keycloak.services.clientpolicy.context;
|
||||||
|
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
|
@ -23,7 +23,7 @@ import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
import org.keycloak.services.clientpolicy.ClientUpdateContext;
|
import org.keycloak.services.clientpolicy.context.ClientCRUDContext;
|
||||||
import org.keycloak.services.clientpolicy.executor.ClientPolicyExecutorProvider;
|
import org.keycloak.services.clientpolicy.executor.ClientPolicyExecutorProvider;
|
||||||
|
|
||||||
public abstract class AbstractAugumentingClientRegistrationPolicyExecutor implements ClientPolicyExecutorProvider {
|
public abstract class AbstractAugumentingClientRegistrationPolicyExecutor implements ClientPolicyExecutorProvider {
|
||||||
|
@ -46,7 +46,7 @@ public abstract class AbstractAugumentingClientRegistrationPolicyExecutor implem
|
||||||
switch (context.getEvent()) {
|
switch (context.getEvent()) {
|
||||||
case REGISTER:
|
case REGISTER:
|
||||||
case UPDATE:
|
case UPDATE:
|
||||||
ClientUpdateContext clientUpdateContext = (ClientUpdateContext)context;
|
ClientCRUDContext clientUpdateContext = (ClientCRUDContext)context;
|
||||||
augment(clientUpdateContext.getProposedClientRepresentation());
|
augment(clientUpdateContext.getProposedClientRepresentation());
|
||||||
validate(clientUpdateContext.getProposedClientRepresentation());
|
validate(clientUpdateContext.getProposedClientRepresentation());
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -27,7 +27,12 @@ import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.representations.RefreshToken;
|
import org.keycloak.representations.RefreshToken;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.services.clientpolicy.*;
|
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||||
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
|
import org.keycloak.services.clientpolicy.context.LogoutRequestContext;
|
||||||
|
import org.keycloak.services.clientpolicy.context.TokenRefreshContext;
|
||||||
|
import org.keycloak.services.clientpolicy.context.TokenRevokeContext;
|
||||||
|
import org.keycloak.services.clientpolicy.context.UserInfoRequestContext;
|
||||||
import org.keycloak.services.util.MtlsHoKTokenUtil;
|
import org.keycloak.services.util.MtlsHoKTokenUtil;
|
||||||
|
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
|
@ -75,29 +80,26 @@ public class HolderOfKeyEnforceExecutor extends AbstractAugumentingClientRegistr
|
||||||
HttpRequest request = session.getContext().getContextObject(HttpRequest.class);
|
HttpRequest request = session.getContext().getContextObject(HttpRequest.class);
|
||||||
|
|
||||||
switch (context.getEvent()) {
|
switch (context.getEvent()) {
|
||||||
|
|
||||||
case TOKEN_REQUEST:
|
case TOKEN_REQUEST:
|
||||||
AccessToken.CertConf certConf = MtlsHoKTokenUtil.bindTokenWithClientCertificate(request, session);
|
AccessToken.CertConf certConf = MtlsHoKTokenUtil.bindTokenWithClientCertificate(request, session);
|
||||||
if (certConf == null) {
|
if (certConf == null) {
|
||||||
throw new ClientPolicyException(OAuthErrorException.INVALID_REQUEST, "Client Certification missing for MTLS HoK Token Binding");
|
throw new ClientPolicyException(OAuthErrorException.INVALID_REQUEST, "Client Certification missing for MTLS HoK Token Binding");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOKEN_REFRESH:
|
case TOKEN_REFRESH:
|
||||||
checkTokenRefresh((TokenRefreshContext) context, request);
|
checkTokenRefresh((TokenRefreshContext) context, request);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOKEN_REVOKE:
|
case TOKEN_REVOKE:
|
||||||
checkTokenRevoke((TokenRevokeContext) context, request);
|
checkTokenRevoke((TokenRevokeContext) context, request);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USERINFO_REQUEST:
|
case USERINFO_REQUEST:
|
||||||
checkUserInfo((UserInfoRequestContext) context, request);
|
checkUserInfo((UserInfoRequestContext) context, request);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LOGOUT_REQUEST:
|
case LOGOUT_REQUEST:
|
||||||
checkLogout((LogoutRequestContext) context, request);
|
checkLogout((LogoutRequestContext) context, request);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,10 +38,10 @@ import org.keycloak.protocol.oidc.utils.OAuth2Code;
|
||||||
import org.keycloak.protocol.oidc.utils.OAuth2CodeParser;
|
import org.keycloak.protocol.oidc.utils.OAuth2CodeParser;
|
||||||
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
|
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.services.clientpolicy.AuthorizationRequestContext;
|
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
import org.keycloak.services.clientpolicy.TokenRequestContext;
|
import org.keycloak.services.clientpolicy.context.AuthorizationRequestContext;
|
||||||
|
import org.keycloak.services.clientpolicy.context.TokenRequestContext;
|
||||||
import org.keycloak.services.clientpolicy.executor.AbstractAugumentingClientRegistrationPolicyExecutor;
|
import org.keycloak.services.clientpolicy.executor.AbstractAugumentingClientRegistrationPolicyExecutor;
|
||||||
|
|
||||||
public class PKCEEnforceExecutor extends AbstractAugumentingClientRegistrationPolicyExecutor {
|
public class PKCEEnforceExecutor extends AbstractAugumentingClientRegistrationPolicyExecutor {
|
||||||
|
|
|
@ -24,15 +24,15 @@ import org.jboss.logging.Logger;
|
||||||
import org.keycloak.OAuthErrorException;
|
import org.keycloak.OAuthErrorException;
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.services.clientpolicy.AdminClientRegisterContext;
|
|
||||||
import org.keycloak.services.clientpolicy.AdminClientUpdateContext;
|
|
||||||
import org.keycloak.services.clientpolicy.AuthorizationRequestContext;
|
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
|
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
|
||||||
import org.keycloak.services.clientpolicy.ClientUpdateContext;
|
import org.keycloak.services.clientpolicy.context.AdminClientRegisterContext;
|
||||||
import org.keycloak.services.clientpolicy.DynamicClientRegisterContext;
|
import org.keycloak.services.clientpolicy.context.AdminClientUpdateContext;
|
||||||
import org.keycloak.services.clientpolicy.DynamicClientUpdateContext;
|
import org.keycloak.services.clientpolicy.context.AuthorizationRequestContext;
|
||||||
|
import org.keycloak.services.clientpolicy.context.ClientCRUDContext;
|
||||||
|
import org.keycloak.services.clientpolicy.context.DynamicClientRegisterContext;
|
||||||
|
import org.keycloak.services.clientpolicy.context.DynamicClientUpdateContext;
|
||||||
|
|
||||||
public class SecureRedirectUriEnforceExecutor implements ClientPolicyExecutorProvider {
|
public class SecureRedirectUriEnforceExecutor implements ClientPolicyExecutorProvider {
|
||||||
|
|
||||||
|
@ -61,14 +61,14 @@ public class SecureRedirectUriEnforceExecutor implements ClientPolicyExecutorPro
|
||||||
switch (context.getEvent()) {
|
switch (context.getEvent()) {
|
||||||
case REGISTER:
|
case REGISTER:
|
||||||
if (context instanceof AdminClientRegisterContext || context instanceof DynamicClientRegisterContext) {
|
if (context instanceof AdminClientRegisterContext || context instanceof DynamicClientRegisterContext) {
|
||||||
confirmSecureRedirectUris(((ClientUpdateContext)context).getProposedClientRepresentation().getRedirectUris());
|
confirmSecureRedirectUris(((ClientCRUDContext)context).getProposedClientRepresentation().getRedirectUris());
|
||||||
} else {
|
} else {
|
||||||
throw new ClientPolicyException(OAuthErrorException.INVALID_REQUEST, "not allowed input format.");
|
throw new ClientPolicyException(OAuthErrorException.INVALID_REQUEST, "not allowed input format.");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case UPDATE:
|
case UPDATE:
|
||||||
if (context instanceof AdminClientUpdateContext || context instanceof DynamicClientUpdateContext) {
|
if (context instanceof AdminClientUpdateContext || context instanceof DynamicClientUpdateContext) {
|
||||||
confirmSecureRedirectUris(((ClientUpdateContext)context).getProposedClientRepresentation().getRedirectUris());
|
confirmSecureRedirectUris(((ClientCRUDContext)context).getProposedClientRepresentation().getRedirectUris());
|
||||||
} else {
|
} else {
|
||||||
throw new ClientPolicyException(OAuthErrorException.INVALID_REQUEST, "not allowed input format.");
|
throw new ClientPolicyException(OAuthErrorException.INVALID_REQUEST, "not allowed input format.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,10 +32,10 @@ import org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequest
|
||||||
import org.keycloak.protocol.oidc.endpoints.request.AuthzEndpointRequestParser;
|
import org.keycloak.protocol.oidc.endpoints.request.AuthzEndpointRequestParser;
|
||||||
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
|
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
|
||||||
import org.keycloak.services.Urls;
|
import org.keycloak.services.Urls;
|
||||||
import org.keycloak.services.clientpolicy.AuthorizationRequestContext;
|
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
|
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
|
||||||
|
import org.keycloak.services.clientpolicy.context.AuthorizationRequestContext;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
|
||||||
|
|
|
@ -23,10 +23,10 @@ import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequest;
|
import org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequest;
|
||||||
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
|
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
|
||||||
import org.keycloak.services.clientpolicy.AuthorizationRequestContext;
|
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
|
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
|
||||||
|
import org.keycloak.services.clientpolicy.context.AuthorizationRequestContext;
|
||||||
|
|
||||||
public class SecureResponseTypeExecutor implements ClientPolicyExecutorProvider {
|
public class SecureResponseTypeExecutor implements ClientPolicyExecutorProvider {
|
||||||
|
|
||||||
|
|
|
@ -23,10 +23,10 @@ import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequest;
|
import org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequest;
|
||||||
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
|
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
|
||||||
import org.keycloak.services.clientpolicy.AuthorizationRequestContext;
|
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
|
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
|
||||||
|
import org.keycloak.services.clientpolicy.context.AuthorizationRequestContext;
|
||||||
import org.keycloak.util.TokenUtil;
|
import org.keycloak.util.TokenUtil;
|
||||||
|
|
||||||
public class SecureSessionEnforceExecutor implements ClientPolicyExecutorProvider {
|
public class SecureSessionEnforceExecutor implements ClientPolicyExecutorProvider {
|
||||||
|
|
|
@ -28,13 +28,13 @@ import org.keycloak.crypto.Algorithm;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
|
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.services.clientpolicy.AdminClientRegisterContext;
|
|
||||||
import org.keycloak.services.clientpolicy.AdminClientUpdateContext;
|
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
|
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
|
||||||
import org.keycloak.services.clientpolicy.DynamicClientRegisterContext;
|
import org.keycloak.services.clientpolicy.context.AdminClientRegisterContext;
|
||||||
import org.keycloak.services.clientpolicy.DynamicClientUpdateContext;
|
import org.keycloak.services.clientpolicy.context.AdminClientUpdateContext;
|
||||||
|
import org.keycloak.services.clientpolicy.context.DynamicClientRegisterContext;
|
||||||
|
import org.keycloak.services.clientpolicy.context.DynamicClientUpdateContext;
|
||||||
|
|
||||||
public class SecureSigningAlgorithmEnforceExecutor implements ClientPolicyExecutorProvider {
|
public class SecureSigningAlgorithmEnforceExecutor implements ClientPolicyExecutorProvider {
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,9 @@ import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.representations.oidc.OIDCClientRepresentation;
|
import org.keycloak.representations.oidc.OIDCClientRepresentation;
|
||||||
import org.keycloak.services.ErrorResponseException;
|
import org.keycloak.services.ErrorResponseException;
|
||||||
import org.keycloak.services.ForbiddenException;
|
import org.keycloak.services.ForbiddenException;
|
||||||
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
|
import org.keycloak.services.clientpolicy.context.DynamicClientRegisteredContext;
|
||||||
|
import org.keycloak.services.clientpolicy.context.DynamicClientUpdatedContext;
|
||||||
import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyManager;
|
import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyManager;
|
||||||
import org.keycloak.services.clientregistration.policy.RegistrationAuth;
|
import org.keycloak.services.clientregistration.policy.RegistrationAuth;
|
||||||
import org.keycloak.services.managers.ClientManager;
|
import org.keycloak.services.managers.ClientManager;
|
||||||
|
@ -70,6 +73,7 @@ public abstract class AbstractClientRegistrationProvider implements ClientRegist
|
||||||
RepresentationToModel.createResourceServer(clientModel, session, true);
|
RepresentationToModel.createResourceServer(clientModel, session, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session.clientPolicy().triggerOnEvent(new DynamicClientRegisteredContext(context, clientModel, auth.getJwt(), realm));
|
||||||
ClientRegistrationPolicyManager.triggerAfterRegister(context, registrationAuth, clientModel);
|
ClientRegistrationPolicyManager.triggerAfterRegister(context, registrationAuth, clientModel);
|
||||||
|
|
||||||
client = ModelToRepresentation.toRepresentation(clientModel, session);
|
client = ModelToRepresentation.toRepresentation(clientModel, session);
|
||||||
|
@ -90,6 +94,8 @@ public abstract class AbstractClientRegistrationProvider implements ClientRegist
|
||||||
return client;
|
return client;
|
||||||
} catch (ModelDuplicateException e) {
|
} catch (ModelDuplicateException e) {
|
||||||
throw new ErrorResponseException(ErrorCodes.INVALID_CLIENT_METADATA, "Client Identifier in use", Response.Status.BAD_REQUEST);
|
throw new ErrorResponseException(ErrorCodes.INVALID_CLIENT_METADATA, "Client Identifier in use", Response.Status.BAD_REQUEST);
|
||||||
|
} catch (ClientPolicyException cpe) {
|
||||||
|
throw new ErrorResponseException(cpe.getError(), cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,6 +140,11 @@ public abstract class AbstractClientRegistrationProvider implements ClientRegist
|
||||||
rep.setRegistrationAccessToken(registrationAccessToken);
|
rep.setRegistrationAccessToken(registrationAccessToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
session.clientPolicy().triggerOnEvent(new DynamicClientUpdatedContext(session, client, auth.getJwt(), client.getRealm()));
|
||||||
|
} catch (ClientPolicyException cpe) {
|
||||||
|
throw new ErrorResponseException(cpe.getError(), cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
|
||||||
|
}
|
||||||
ClientRegistrationPolicyManager.triggerAfterUpdate(context, registrationAuth, client);
|
ClientRegistrationPolicyManager.triggerAfterUpdate(context, registrationAuth, client);
|
||||||
|
|
||||||
event.client(client.getClientId()).success();
|
event.client(client.getClientId()).success();
|
||||||
|
|
|
@ -37,8 +37,10 @@ import org.keycloak.protocol.oidc.utils.AuthorizeClientUtil;
|
||||||
import org.keycloak.representations.JsonWebToken;
|
import org.keycloak.representations.JsonWebToken;
|
||||||
import org.keycloak.services.ErrorResponseException;
|
import org.keycloak.services.ErrorResponseException;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
import org.keycloak.services.clientpolicy.DynamicClientRegisterContext;
|
import org.keycloak.services.clientpolicy.context.DynamicClientRegisterContext;
|
||||||
import org.keycloak.services.clientpolicy.DynamicClientUpdateContext;
|
import org.keycloak.services.clientpolicy.context.DynamicClientUnregisterContext;
|
||||||
|
import org.keycloak.services.clientpolicy.context.DynamicClientUpdateContext;
|
||||||
|
import org.keycloak.services.clientpolicy.context.DynamicClientViewContext;
|
||||||
import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyException;
|
import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyException;
|
||||||
import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyManager;
|
import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyManager;
|
||||||
import org.keycloak.services.clientregistration.policy.RegistrationAuth;
|
import org.keycloak.services.clientregistration.policy.RegistrationAuth;
|
||||||
|
@ -199,8 +201,9 @@ public class ClientRegistrationAuth {
|
||||||
|
|
||||||
if (authenticated) {
|
if (authenticated) {
|
||||||
try {
|
try {
|
||||||
|
session.clientPolicy().triggerOnEvent(new DynamicClientViewContext(session, client, jwt, realm));
|
||||||
ClientRegistrationPolicyManager.triggerBeforeView(session, provider, authType, client);
|
ClientRegistrationPolicyManager.triggerBeforeView(session, provider, authType, client);
|
||||||
} catch (ClientRegistrationPolicyException crpe) {
|
} catch (ClientRegistrationPolicyException | ClientPolicyException crpe) {
|
||||||
throw forbidden(crpe.getMessage());
|
throw forbidden(crpe.getMessage());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -230,8 +233,9 @@ public class ClientRegistrationAuth {
|
||||||
RegistrationAuth chainType = requireUpdateAuth(client);
|
RegistrationAuth chainType = requireUpdateAuth(client);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
session.clientPolicy().triggerOnEvent(new DynamicClientUnregisterContext(session, client, jwt, realm));
|
||||||
ClientRegistrationPolicyManager.triggerBeforeRemove(session, provider, chainType, client);
|
ClientRegistrationPolicyManager.triggerBeforeRemove(session, provider, chainType, client);
|
||||||
} catch (ClientRegistrationPolicyException crpe) {
|
} catch (ClientRegistrationPolicyException | ClientPolicyException crpe) {
|
||||||
throw forbidden(crpe.getMessage());
|
throw forbidden(crpe.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,8 +50,11 @@ import org.keycloak.representations.idm.UserRepresentation;
|
||||||
import org.keycloak.representations.idm.UserSessionRepresentation;
|
import org.keycloak.representations.idm.UserSessionRepresentation;
|
||||||
import org.keycloak.services.ErrorResponse;
|
import org.keycloak.services.ErrorResponse;
|
||||||
import org.keycloak.services.ErrorResponseException;
|
import org.keycloak.services.ErrorResponseException;
|
||||||
import org.keycloak.services.clientpolicy.AdminClientUpdateContext;
|
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
|
import org.keycloak.services.clientpolicy.context.AdminClientUnregisterContext;
|
||||||
|
import org.keycloak.services.clientpolicy.context.AdminClientUpdateContext;
|
||||||
|
import org.keycloak.services.clientpolicy.context.AdminClientUpdatedContext;
|
||||||
|
import org.keycloak.services.clientpolicy.context.AdminClientViewContext;
|
||||||
import org.keycloak.services.clientregistration.ClientRegistrationTokenUtils;
|
import org.keycloak.services.clientregistration.ClientRegistrationTokenUtils;
|
||||||
import org.keycloak.services.clientregistration.policy.RegistrationAuth;
|
import org.keycloak.services.clientregistration.policy.RegistrationAuth;
|
||||||
import org.keycloak.services.managers.ClientManager;
|
import org.keycloak.services.managers.ClientManager;
|
||||||
|
@ -130,12 +133,8 @@ public class ClientResource {
|
||||||
auth.clients().requireConfigure(client);
|
auth.clients().requireConfigure(client);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
session.clientPolicy().triggerOnEvent(new AdminClientUpdateContext(rep, auth.adminAuth(), client));
|
session.clientPolicy().triggerOnEvent(new AdminClientUpdateContext(rep, client, auth.adminAuth()));
|
||||||
} catch (ClientPolicyException cpe) {
|
|
||||||
throw new ErrorResponseException(cpe.getError(), cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
updateClientFromRep(rep, client, session);
|
updateClientFromRep(rep, client, session);
|
||||||
|
|
||||||
ValidationUtil.validateClient(session, client, false, r -> {
|
ValidationUtil.validateClient(session, client, false, r -> {
|
||||||
|
@ -146,10 +145,14 @@ public class ClientResource {
|
||||||
Response.Status.BAD_REQUEST);
|
Response.Status.BAD_REQUEST);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
session.clientPolicy().triggerOnEvent(new AdminClientUpdatedContext(rep, client, auth.adminAuth()));
|
||||||
|
|
||||||
adminEvent.operation(OperationType.UPDATE).resourcePath(session.getContext().getUri()).representation(rep).success();
|
adminEvent.operation(OperationType.UPDATE).resourcePath(session.getContext().getUri()).representation(rep).success();
|
||||||
return Response.noContent().build();
|
return Response.noContent().build();
|
||||||
} catch (ModelDuplicateException e) {
|
} catch (ModelDuplicateException e) {
|
||||||
return ErrorResponse.exists("Client already exists");
|
return ErrorResponse.exists("Client already exists");
|
||||||
|
} catch (ClientPolicyException cpe) {
|
||||||
|
throw new ErrorResponseException(cpe.getError(), cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,6 +165,12 @@ public class ClientResource {
|
||||||
@NoCache
|
@NoCache
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public ClientRepresentation getClient() {
|
public ClientRepresentation getClient() {
|
||||||
|
try {
|
||||||
|
session.clientPolicy().triggerOnEvent(new AdminClientViewContext(client, auth.adminAuth()));
|
||||||
|
} catch (ClientPolicyException cpe) {
|
||||||
|
throw new ErrorResponseException(cpe.getError(), cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
auth.clients().requireView(client);
|
auth.clients().requireView(client);
|
||||||
|
|
||||||
ClientRepresentation representation = ModelToRepresentation.toRepresentation(client, session);
|
ClientRepresentation representation = ModelToRepresentation.toRepresentation(client, session);
|
||||||
|
@ -206,6 +215,12 @@ public class ClientResource {
|
||||||
throw new NotFoundException("Could not find client");
|
throw new NotFoundException("Could not find client");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
session.clientPolicy().triggerOnEvent(new AdminClientUnregisterContext(client, auth.adminAuth()));
|
||||||
|
} catch (ClientPolicyException cpe) {
|
||||||
|
throw new ErrorResponseException(cpe.getError(), cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
new ClientManager(new RealmManager(session)).removeClient(realm, client);
|
new ClientManager(new RealmManager(session)).removeClient(realm, client);
|
||||||
adminEvent.operation(OperationType.DELETE).resourcePath(session.getContext().getUri()).success();
|
adminEvent.operation(OperationType.DELETE).resourcePath(session.getContext().getUri()).success();
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,8 +34,9 @@ import org.keycloak.representations.idm.authorization.ResourceServerRepresentati
|
||||||
import org.keycloak.services.ErrorResponse;
|
import org.keycloak.services.ErrorResponse;
|
||||||
import org.keycloak.services.ErrorResponseException;
|
import org.keycloak.services.ErrorResponseException;
|
||||||
import org.keycloak.services.ForbiddenException;
|
import org.keycloak.services.ForbiddenException;
|
||||||
import org.keycloak.services.clientpolicy.AdminClientRegisterContext;
|
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
|
import org.keycloak.services.clientpolicy.context.AdminClientRegisterContext;
|
||||||
|
import org.keycloak.services.clientpolicy.context.AdminClientRegisteredContext;
|
||||||
import org.keycloak.services.managers.ClientManager;
|
import org.keycloak.services.managers.ClientManager;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||||
|
@ -163,11 +164,7 @@ public class ClientsResource {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
session.clientPolicy().triggerOnEvent(new AdminClientRegisterContext(rep, auth.adminAuth()));
|
session.clientPolicy().triggerOnEvent(new AdminClientRegisterContext(rep, auth.adminAuth()));
|
||||||
} catch (ClientPolicyException cpe) {
|
|
||||||
throw new ErrorResponseException(cpe.getError(), cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
ClientModel clientModel = ClientManager.createClient(session, realm, rep);
|
ClientModel clientModel = ClientManager.createClient(session, realm, rep);
|
||||||
|
|
||||||
if (TRUE.equals(rep.isServiceAccountsEnabled())) {
|
if (TRUE.equals(rep.isServiceAccountsEnabled())) {
|
||||||
|
@ -200,9 +197,13 @@ public class ClientsResource {
|
||||||
Response.Status.BAD_REQUEST);
|
Response.Status.BAD_REQUEST);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
session.clientPolicy().triggerOnEvent(new AdminClientRegisteredContext(clientModel, auth.adminAuth()));
|
||||||
|
|
||||||
return Response.created(session.getContext().getUri().getAbsolutePathBuilder().path(clientModel.getId()).build()).build();
|
return Response.created(session.getContext().getUri().getAbsolutePathBuilder().path(clientModel.getId()).build()).build();
|
||||||
} catch (ModelDuplicateException e) {
|
} catch (ModelDuplicateException e) {
|
||||||
return ErrorResponse.exists("Client " + rep.getClientId() + " already exists");
|
return ErrorResponse.exists("Client " + rep.getClientId() + " already exists");
|
||||||
|
} catch (ClientPolicyException cpe) {
|
||||||
|
throw new ErrorResponseException(cpe.getError(), cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.testsuite.services.clientpolicy.executor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.component.ComponentModel;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||||
|
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
||||||
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
|
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
|
||||||
|
import org.keycloak.services.clientpolicy.executor.ClientPolicyExecutorProvider;
|
||||||
|
|
||||||
|
public class TestRaiseExeptionExecutor implements ClientPolicyExecutorProvider {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(TestRaiseExeptionExecutor.class);
|
||||||
|
|
||||||
|
protected final KeycloakSession session;
|
||||||
|
protected final ComponentModel componentModel;
|
||||||
|
|
||||||
|
public TestRaiseExeptionExecutor(KeycloakSession session, ComponentModel componentModel) {
|
||||||
|
this.session = session;
|
||||||
|
this.componentModel = componentModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return componentModel.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getProviderId() {
|
||||||
|
return componentModel.getProviderId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void executeOnEvent(ClientPolicyContext context) throws ClientPolicyException {
|
||||||
|
if (isThrowExceptionNeeded(context.getEvent())) throw new ClientPolicyException(context.getEvent().toString(), "Exception thrown intentionally");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isThrowExceptionNeeded(ClientPolicyEvent event) {
|
||||||
|
ClientPolicyLogger.log(logger, "Client Policy Trigger Event = " + event);
|
||||||
|
List<String> l = componentModel.getConfig().get(TestRaiseExeptionExecutorFactory.TARGET_CP_EVENTS);
|
||||||
|
return l != null && l.stream().anyMatch(i->i.equals(event.toString()));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.testsuite.services.clientpolicy.executor;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.keycloak.Config.Scope;
|
||||||
|
import org.keycloak.component.ComponentModel;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
import org.keycloak.services.clientpolicy.executor.ClientPolicyExecutorProvider;
|
||||||
|
import org.keycloak.services.clientpolicy.executor.ClientPolicyExecutorProviderFactory;
|
||||||
|
|
||||||
|
public class TestRaiseExeptionExecutorFactory implements ClientPolicyExecutorProviderFactory {
|
||||||
|
|
||||||
|
public static final String PROVIDER_ID = "test-raise-exception-executor";
|
||||||
|
|
||||||
|
public static final String TARGET_CP_EVENTS = "target-cp-events";
|
||||||
|
private static final ProviderConfigProperty TARGET_CP_EVENTS_PROPERTY = new ProviderConfigProperty(
|
||||||
|
TARGET_CP_EVENTS, null, null, ProviderConfigProperty.MULTIVALUED_STRING_TYPE, null);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientPolicyExecutorProvider create(KeycloakSession session, ComponentModel model) {
|
||||||
|
return new TestRaiseExeptionExecutor(session, model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Scope config) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postInit(KeycloakSessionFactory factory) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return PROVIDER_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHelpText() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
|
return Arrays.asList(TARGET_CP_EVENTS_PROPERTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
org.keycloak.testsuite.services.clientpolicy.executor.TestRaiseExeptionExecutorFactory
|
|
@ -18,6 +18,7 @@
|
||||||
package org.keycloak.testsuite.client;
|
package org.keycloak.testsuite.client;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
@ -42,6 +43,7 @@ import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import javax.ws.rs.BadRequestException;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
|
@ -423,10 +425,10 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
||||||
|
|
||||||
// Client CRUD operation by Admin REST API primitives
|
// Client CRUD operation by Admin REST API primitives
|
||||||
|
|
||||||
protected String createClientByAdmin(String clientId, Consumer<ClientRepresentation> op) throws ClientPolicyException {
|
protected String createClientByAdmin(String clientName, Consumer<ClientRepresentation> op) throws ClientPolicyException {
|
||||||
ClientRepresentation clientRep = new ClientRepresentation();
|
ClientRepresentation clientRep = new ClientRepresentation();
|
||||||
clientRep.setClientId(clientId);
|
clientRep.setClientId(clientName);
|
||||||
clientRep.setName(clientId);
|
clientRep.setName(clientName);
|
||||||
clientRep.setProtocol("openid-connect");
|
clientRep.setProtocol("openid-connect");
|
||||||
clientRep.setBearerOnly(Boolean.FALSE);
|
clientRep.setBearerOnly(Boolean.FALSE);
|
||||||
clientRep.setPublicClient(Boolean.FALSE);
|
clientRep.setPublicClient(Boolean.FALSE);
|
||||||
|
@ -435,7 +437,14 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
||||||
op.accept(clientRep);
|
op.accept(clientRep);
|
||||||
Response resp = adminClient.realm(REALM_NAME).clients().create(clientRep);
|
Response resp = adminClient.realm(REALM_NAME).clients().create(clientRep);
|
||||||
if (resp.getStatus() == Response.Status.BAD_REQUEST.getStatusCode()) {
|
if (resp.getStatus() == Response.Status.BAD_REQUEST.getStatusCode()) {
|
||||||
throw new ClientPolicyException(Errors.INVALID_REGISTRATION, "registration error by admin");
|
String respBody = resp.readEntity(String.class);
|
||||||
|
Map<String, String> responseJson = null;
|
||||||
|
try {
|
||||||
|
responseJson = JsonSerialization.readValue(respBody, Map.class);
|
||||||
|
} catch (IOException e) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
throw new ClientPolicyException(responseJson.get(OAuth2Constants.ERROR), responseJson.get(OAuth2Constants.ERROR_DESCRIPTION));
|
||||||
}
|
}
|
||||||
resp.close();
|
resp.close();
|
||||||
assertEquals(Response.Status.CREATED.getStatusCode(), resp.getStatus());
|
assertEquals(Response.Status.CREATED.getStatusCode(), resp.getStatus());
|
||||||
|
@ -445,21 +454,55 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
||||||
return cId;
|
return cId;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ClientRepresentation getClientByAdmin(String cId) {
|
protected ClientRepresentation getClientByAdmin(String cId) throws ClientPolicyException {
|
||||||
ClientResource clientResource = adminClient.realm(REALM_NAME).clients().get(cId);
|
ClientResource clientResource = adminClient.realm(REALM_NAME).clients().get(cId);
|
||||||
return clientResource.toRepresentation();
|
try {
|
||||||
|
return clientResource.toRepresentation();
|
||||||
|
} catch (BadRequestException bre) {
|
||||||
|
processClientPolicyExceptionByAdmin(bre);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void updateClientByAdmin(String cId, Consumer<ClientRepresentation> op) {
|
protected ClientRepresentation getClientByAdminWithName(String clientName) {
|
||||||
|
return adminClient.realm(REALM_NAME).clients().findByClientId(clientName).get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updateClientByAdmin(String cId, Consumer<ClientRepresentation> op) throws ClientPolicyException {
|
||||||
ClientResource clientResource = adminClient.realm(REALM_NAME).clients().get(cId);
|
ClientResource clientResource = adminClient.realm(REALM_NAME).clients().get(cId);
|
||||||
ClientRepresentation clientRep = clientResource.toRepresentation();
|
ClientRepresentation clientRep = clientResource.toRepresentation();
|
||||||
op.accept(clientRep);
|
op.accept(clientRep);
|
||||||
clientResource.update(clientRep);
|
try {
|
||||||
|
clientResource.update(clientRep);
|
||||||
|
} catch (BadRequestException bre) {
|
||||||
|
processClientPolicyExceptionByAdmin(bre);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void deleteClientByAdmin(String cId) {
|
protected void deleteClientByAdmin(String cId) throws ClientPolicyException {
|
||||||
ClientResource clientResource = adminClient.realm(REALM_NAME).clients().get(cId);
|
ClientResource clientResource = adminClient.realm(REALM_NAME).clients().get(cId);
|
||||||
clientResource.remove();
|
try {
|
||||||
|
clientResource.remove();
|
||||||
|
} catch (BadRequestException bre) {
|
||||||
|
processClientPolicyExceptionByAdmin(bre);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processClientPolicyExceptionByAdmin(BadRequestException bre) throws ClientPolicyException {
|
||||||
|
Response resp = bre.getResponse();
|
||||||
|
if (resp.getStatus() != Response.Status.BAD_REQUEST.getStatusCode()) {
|
||||||
|
resp.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String respBody = resp.readEntity(String.class);
|
||||||
|
Map<String, String> responseJson = null;
|
||||||
|
try {
|
||||||
|
responseJson = JsonSerialization.readValue(respBody, Map.class);
|
||||||
|
} catch (IOException e) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
throw new ClientPolicyException(responseJson.get(OAuth2Constants.ERROR), responseJson.get(OAuth2Constants.ERROR_DESCRIPTION));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Registration/Initial Access Token acquisition for Dynamic Client Registration
|
// Registration/Initial Access Token acquisition for Dynamic Client Registration
|
||||||
|
|
|
@ -33,8 +33,7 @@ import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import javax.ws.rs.BadRequestException;
|
|
||||||
|
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
@ -58,6 +57,7 @@ import org.keycloak.events.EventType;
|
||||||
import org.keycloak.jose.jws.Algorithm;
|
import org.keycloak.jose.jws.Algorithm;
|
||||||
import org.keycloak.models.AdminRoles;
|
import org.keycloak.models.AdminRoles;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
|
import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
|
||||||
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
|
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||||
|
@ -72,6 +72,7 @@ import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.representations.idm.UserRepresentation;
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
import org.keycloak.representations.oidc.OIDCClientRepresentation;
|
import org.keycloak.representations.oidc.OIDCClientRepresentation;
|
||||||
import org.keycloak.representations.oidc.TokenMetadataRepresentation;
|
import org.keycloak.representations.oidc.TokenMetadataRepresentation;
|
||||||
|
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
||||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||||
import org.keycloak.services.clientpolicy.DefaultClientPolicyProviderFactory;
|
import org.keycloak.services.clientpolicy.DefaultClientPolicyProviderFactory;
|
||||||
import org.keycloak.services.clientpolicy.condition.AbstractClientPolicyConditionProviderFactory;
|
import org.keycloak.services.clientpolicy.condition.AbstractClientPolicyConditionProviderFactory;
|
||||||
|
@ -100,6 +101,7 @@ import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.A
|
||||||
import org.keycloak.testsuite.client.resources.TestApplicationResourceUrls;
|
import org.keycloak.testsuite.client.resources.TestApplicationResourceUrls;
|
||||||
import org.keycloak.testsuite.rest.resource.TestingOIDCEndpointsApplicationResource.AuthorizationEndpointRequestObject;
|
import org.keycloak.testsuite.rest.resource.TestingOIDCEndpointsApplicationResource.AuthorizationEndpointRequestObject;
|
||||||
import org.keycloak.testsuite.services.clientpolicy.condition.TestRaiseExeptionConditionFactory;
|
import org.keycloak.testsuite.services.clientpolicy.condition.TestRaiseExeptionConditionFactory;
|
||||||
|
import org.keycloak.testsuite.services.clientpolicy.executor.TestRaiseExeptionExecutorFactory;
|
||||||
import org.keycloak.testsuite.util.MutualTLSUtils;
|
import org.keycloak.testsuite.util.MutualTLSUtils;
|
||||||
import org.keycloak.testsuite.util.OAuthClient;
|
import org.keycloak.testsuite.util.OAuthClient;
|
||||||
|
|
||||||
|
@ -161,8 +163,8 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
clientRep.setClientAuthenticatorType(ClientIdAndSecretAuthenticator.PROVIDER_ID);
|
clientRep.setClientAuthenticatorType(ClientIdAndSecretAuthenticator.PROVIDER_ID);
|
||||||
});
|
});
|
||||||
fail();
|
fail();
|
||||||
} catch (ClientPolicyException e) {
|
} catch (ClientPolicyException cpe) {
|
||||||
assertEquals(Errors.INVALID_REGISTRATION, e.getMessage());
|
assertEquals(OAuthErrorException.INVALID_CLIENT_METADATA, cpe.getError());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,8 +183,8 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
try {
|
try {
|
||||||
createClientByAdmin(generateSuffixedName(CLIENT_NAME), (ClientRepresentation clientRep) -> {});
|
createClientByAdmin(generateSuffixedName(CLIENT_NAME), (ClientRepresentation clientRep) -> {});
|
||||||
fail();
|
fail();
|
||||||
} catch (ClientPolicyException e) {
|
} catch (ClientPolicyException cpe) {
|
||||||
assertEquals(Errors.INVALID_REGISTRATION, e.getMessage());
|
assertEquals(OAuthErrorException.INVALID_CLIENT_METADATA, cpe.getError());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,8 +200,8 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
clientRep.setClientAuthenticatorType(ClientIdAndSecretAuthenticator.PROVIDER_ID);
|
clientRep.setClientAuthenticatorType(ClientIdAndSecretAuthenticator.PROVIDER_ID);
|
||||||
});
|
});
|
||||||
fail();
|
fail();
|
||||||
} catch (BadRequestException bre) {
|
} catch (ClientPolicyException cpe) {
|
||||||
assertEquals("HTTP 400 Bad Request", bre.getMessage());
|
assertEquals(OAuthErrorException.INVALID_CLIENT_METADATA, cpe.getError());
|
||||||
}
|
}
|
||||||
assertEquals(JWTClientSecretAuthenticator.PROVIDER_ID, getClientByAdmin(cId).getClientAuthenticatorType());
|
assertEquals(JWTClientSecretAuthenticator.PROVIDER_ID, getClientByAdmin(cId).getClientAuthenticatorType());
|
||||||
}
|
}
|
||||||
|
@ -323,7 +325,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
|
|
||||||
String conditionName = ClientRolesCondition_NAME;
|
String conditionName = ClientRolesCondition_NAME;
|
||||||
createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList(SAMPLE_CLIENT_ROLE)));
|
setConditionClientRoles(provider, Arrays.asList(SAMPLE_CLIENT_ROLE));
|
||||||
});
|
});
|
||||||
registerCondition(conditionName, policyName);
|
registerCondition(conditionName, policyName);
|
||||||
logger.info("... Registered Condition : " + conditionName);
|
logger.info("... Registered Condition : " + conditionName);
|
||||||
|
@ -331,7 +333,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
failLoginByNotFollowingPKCE(clientId);
|
failLoginByNotFollowingPKCE(clientId);
|
||||||
|
|
||||||
updateCondition(conditionName, (ComponentRepresentation provider) -> {
|
updateCondition(conditionName, (ComponentRepresentation provider) -> {
|
||||||
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList("anothor-client-role")));
|
setConditionClientRoles(provider, Arrays.asList("anothor-client-role"));
|
||||||
});
|
});
|
||||||
|
|
||||||
successfulLoginAndLogout(clientId, clientSecret);
|
successfulLoginAndLogout(clientId, clientSecret);
|
||||||
|
@ -349,14 +351,14 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
|
|
||||||
String roleConditionName = ClientRolesCondition_NAME;
|
String roleConditionName = ClientRolesCondition_NAME;
|
||||||
createCondition(roleConditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
createCondition(roleConditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList(SAMPLE_CLIENT_ROLE)));
|
setConditionClientRoles(provider, Arrays.asList(SAMPLE_CLIENT_ROLE));
|
||||||
});
|
});
|
||||||
registerCondition(roleConditionName, policyName);
|
registerCondition(roleConditionName, policyName);
|
||||||
logger.info("... Registered Condition : " + roleConditionName);
|
logger.info("... Registered Condition : " + roleConditionName);
|
||||||
|
|
||||||
String updateConditionName = ClientUpdateContextCondition_NAME;
|
String updateConditionName = ClientUpdateContextCondition_NAME;
|
||||||
createCondition(updateConditionName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
createCondition(updateConditionName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
setConditionRegistrationMethods(provider, new ArrayList<>(Arrays.asList(ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER)));
|
setConditionRegistrationMethods(provider, Arrays.asList(ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER));
|
||||||
});
|
});
|
||||||
registerCondition(updateConditionName, policyName);
|
registerCondition(updateConditionName, policyName);
|
||||||
logger.info("... Registered Condition : " + updateConditionName);
|
logger.info("... Registered Condition : " + updateConditionName);
|
||||||
|
@ -431,21 +433,21 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
|
|
||||||
String roleConditionAlphaName = generateSuffixedName(ClientRolesCondition_NAME);
|
String roleConditionAlphaName = generateSuffixedName(ClientRolesCondition_NAME);
|
||||||
createCondition(roleConditionAlphaName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
createCondition(roleConditionAlphaName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList(roleAlphaName, roleZetaName)));
|
setConditionClientRoles(provider, Arrays.asList(roleAlphaName, roleZetaName));
|
||||||
});
|
});
|
||||||
registerCondition(roleConditionAlphaName, policyAlphaName);
|
registerCondition(roleConditionAlphaName, policyAlphaName);
|
||||||
logger.info("... Registered Condition : " + roleConditionAlphaName);
|
logger.info("... Registered Condition : " + roleConditionAlphaName);
|
||||||
|
|
||||||
String updateConditionAlphaName = generateSuffixedName(ClientUpdateContextCondition_NAME);
|
String updateConditionAlphaName = generateSuffixedName(ClientUpdateContextCondition_NAME);
|
||||||
createCondition(updateConditionAlphaName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
createCondition(updateConditionAlphaName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
setConditionRegistrationMethods(provider, new ArrayList<>(Arrays.asList(ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER)));
|
setConditionRegistrationMethods(provider, Arrays.asList(ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER));
|
||||||
});
|
});
|
||||||
registerCondition(updateConditionAlphaName, policyAlphaName);
|
registerCondition(updateConditionAlphaName, policyAlphaName);
|
||||||
logger.info("... Registered Condition : " + updateConditionAlphaName);
|
logger.info("... Registered Condition : " + updateConditionAlphaName);
|
||||||
|
|
||||||
String clientAuthExecutorAlphaName = generateSuffixedName(SecureClientAuthEnforceExecutor_NAME);
|
String clientAuthExecutorAlphaName = generateSuffixedName(SecureClientAuthEnforceExecutor_NAME);
|
||||||
createExecutor(clientAuthExecutorAlphaName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
createExecutor(clientAuthExecutorAlphaName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
setExecutorAcceptedClientAuthMethods(provider, new ArrayList<>(Arrays.asList(ClientIdAndSecretAuthenticator.PROVIDER_ID)));
|
setExecutorAcceptedClientAuthMethods(provider, Arrays.asList(ClientIdAndSecretAuthenticator.PROVIDER_ID));
|
||||||
setExecutorAugmentActivate(provider);
|
setExecutorAugmentActivate(provider);
|
||||||
setExecutorAugmentedClientAuthMethod(provider, ClientIdAndSecretAuthenticator.PROVIDER_ID);
|
setExecutorAugmentedClientAuthMethod(provider, ClientIdAndSecretAuthenticator.PROVIDER_ID);
|
||||||
});
|
});
|
||||||
|
@ -458,7 +460,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
|
|
||||||
String roleConditionBetaName = generateSuffixedName(ClientRolesCondition_NAME);
|
String roleConditionBetaName = generateSuffixedName(ClientRolesCondition_NAME);
|
||||||
createCondition(roleConditionBetaName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
createCondition(roleConditionBetaName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList(roleBetaName, roleZetaName)));
|
setConditionClientRoles(provider, Arrays.asList(roleBetaName, roleZetaName));
|
||||||
});
|
});
|
||||||
registerCondition(roleConditionBetaName, policyBetaName);
|
registerCondition(roleConditionBetaName, policyBetaName);
|
||||||
logger.info("... Registered Condition : " + roleConditionBetaName);
|
logger.info("... Registered Condition : " + roleConditionBetaName);
|
||||||
|
@ -507,8 +509,8 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
try {
|
try {
|
||||||
createClientByAdmin(generateSuffixedName(CLIENT_NAME), (ClientRepresentation clientRep) -> {});
|
createClientByAdmin(generateSuffixedName(CLIENT_NAME), (ClientRepresentation clientRep) -> {});
|
||||||
fail();
|
fail();
|
||||||
} catch (ClientPolicyException e) {
|
} catch (ClientPolicyException cpe) {
|
||||||
assertEquals(Errors.INVALID_REGISTRATION, e.getMessage());
|
assertEquals(OAuthErrorException.SERVER_ERROR, cpe.getError());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -611,15 +613,15 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
|
|
||||||
String conditionName = ClientUpdateSourceHostsCondition_NAME;
|
String conditionName = ClientUpdateSourceHostsCondition_NAME;
|
||||||
createCondition(conditionName, ClientUpdateSourceHostsConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
createCondition(conditionName, ClientUpdateSourceHostsConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
setConditionClientUpdateSourceHosts(provider, new ArrayList<>(Arrays.asList("localhost", "127.0.0.1")));
|
setConditionClientUpdateSourceHosts(provider, Arrays.asList("localhost", "127.0.0.1"));
|
||||||
});
|
});
|
||||||
registerCondition(conditionName, policyName);
|
registerCondition(conditionName, policyName);
|
||||||
logger.info("... Registered Condition : " + conditionName);
|
logger.info("... Registered Condition : " + conditionName);
|
||||||
|
|
||||||
String executorName = SecureClientAuthEnforceExecutor_NAME;
|
String executorName = SecureClientAuthEnforceExecutor_NAME;
|
||||||
createExecutor(executorName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
createExecutor(executorName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
setExecutorAcceptedClientAuthMethods(provider, new ArrayList<>(Arrays.asList(
|
setExecutorAcceptedClientAuthMethods(provider, Arrays.asList(
|
||||||
JWTClientAuthenticator.PROVIDER_ID, JWTClientSecretAuthenticator.PROVIDER_ID, X509ClientAuthenticator.PROVIDER_ID)));
|
JWTClientAuthenticator.PROVIDER_ID, JWTClientSecretAuthenticator.PROVIDER_ID, X509ClientAuthenticator.PROVIDER_ID));
|
||||||
});
|
});
|
||||||
registerExecutor(executorName, policyName);
|
registerExecutor(executorName, policyName);
|
||||||
logger.info("... Registered Executor : " + executorName);
|
logger.info("... Registered Executor : " + executorName);
|
||||||
|
@ -631,12 +633,12 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
clientRep.setSecret(clientSecret);
|
clientRep.setSecret(clientSecret);
|
||||||
});
|
});
|
||||||
fail();
|
fail();
|
||||||
} catch (ClientPolicyException e) {
|
} catch (ClientPolicyException cpe) {
|
||||||
assertEquals(Errors.INVALID_REGISTRATION, e.getMessage());
|
assertEquals(OAuthErrorException.INVALID_CLIENT_METADATA, cpe.getError());
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCondition(conditionName, (ComponentRepresentation provider) -> {
|
updateCondition(conditionName, (ComponentRepresentation provider) -> {
|
||||||
setConditionClientUpdateSourceHosts(provider, new ArrayList<>(Arrays.asList("example.com")));
|
setConditionClientUpdateSourceHosts(provider, Arrays.asList("example.com"));
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
createClientByAdmin(clientId, (ClientRepresentation clientRep) -> {
|
createClientByAdmin(clientId, (ClientRepresentation clientRep) -> {
|
||||||
|
@ -655,14 +657,14 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
|
|
||||||
String conditionName = ClientUpdateSourceGroupsCondition_NAME;
|
String conditionName = ClientUpdateSourceGroupsCondition_NAME;
|
||||||
createCondition(conditionName, ClientUpdateSourceGroupsConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
createCondition(conditionName, ClientUpdateSourceGroupsConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
setConditionClientUpdateSourceGroups(provider, new ArrayList<>(Arrays.asList("topGroup")));
|
setConditionClientUpdateSourceGroups(provider, Arrays.asList("topGroup"));
|
||||||
});
|
});
|
||||||
registerCondition(conditionName, policyName);
|
registerCondition(conditionName, policyName);
|
||||||
logger.info("... Registered Condition : " + conditionName);
|
logger.info("... Registered Condition : " + conditionName);
|
||||||
|
|
||||||
String executorName = SecureClientAuthEnforceExecutor_NAME;
|
String executorName = SecureClientAuthEnforceExecutor_NAME;
|
||||||
createExecutor(executorName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
createExecutor(executorName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
setExecutorAcceptedClientAuthMethods(provider, new ArrayList<>(Arrays.asList(JWTClientAuthenticator.PROVIDER_ID)));
|
setExecutorAcceptedClientAuthMethods(provider,Arrays.asList(JWTClientAuthenticator.PROVIDER_ID));
|
||||||
});
|
});
|
||||||
registerExecutor(executorName, policyName);
|
registerExecutor(executorName, policyName);
|
||||||
logger.info("... Registered Executor : " + executorName);
|
logger.info("... Registered Executor : " + executorName);
|
||||||
|
@ -690,14 +692,14 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
|
|
||||||
String conditionName = ClientUpdateSourceRolesCondition_NAME;
|
String conditionName = ClientUpdateSourceRolesCondition_NAME;
|
||||||
createCondition(conditionName, ClientUpdateSourceRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
createCondition(conditionName, ClientUpdateSourceRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
setConditionUpdatingClientSourceRoles(provider, new ArrayList<>(Arrays.asList(AdminRoles.CREATE_CLIENT)));
|
setConditionUpdatingClientSourceRoles(provider, Arrays.asList(AdminRoles.CREATE_CLIENT));
|
||||||
});
|
});
|
||||||
registerCondition(conditionName, policyName);
|
registerCondition(conditionName, policyName);
|
||||||
logger.info("... Registered Condition : " + conditionName);
|
logger.info("... Registered Condition : " + conditionName);
|
||||||
|
|
||||||
String executorName = SecureClientAuthEnforceExecutor_NAME;
|
String executorName = SecureClientAuthEnforceExecutor_NAME;
|
||||||
createExecutor(executorName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
createExecutor(executorName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
setExecutorAcceptedClientAuthMethods(provider, new ArrayList<>(Arrays.asList(JWTClientAuthenticator.PROVIDER_ID)));
|
setExecutorAcceptedClientAuthMethods(provider, Arrays.asList(JWTClientAuthenticator.PROVIDER_ID));
|
||||||
});
|
});
|
||||||
registerExecutor(executorName, policyName);
|
registerExecutor(executorName, policyName);
|
||||||
logger.info("... Registered Executor : " + executorName);
|
logger.info("... Registered Executor : " + executorName);
|
||||||
|
@ -725,7 +727,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
|
|
||||||
String conditionName = ClientScopesCondition_NAME;
|
String conditionName = ClientScopesCondition_NAME;
|
||||||
createCondition(conditionName, ClientScopesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
createCondition(conditionName, ClientScopesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
setConditionClientScopes(provider, new ArrayList<>(Arrays.asList("offline_access", "microprofile-jwt")));
|
setConditionClientScopes(provider, Arrays.asList("offline_access", "microprofile-jwt"));
|
||||||
});
|
});
|
||||||
registerCondition(conditionName, policyName);
|
registerCondition(conditionName, policyName);
|
||||||
logger.info("... Registered Condition : " + conditionName);
|
logger.info("... Registered Condition : " + conditionName);
|
||||||
|
@ -759,7 +761,6 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testClientAccessTypeCondition() throws ClientRegistrationException, ClientPolicyException {
|
public void testClientAccessTypeCondition() throws ClientRegistrationException, ClientPolicyException {
|
||||||
String policyName = POLICY_NAME;
|
String policyName = POLICY_NAME;
|
||||||
|
@ -768,7 +769,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
|
|
||||||
String conditionName = ClientAccessTypeCondition_NAME;
|
String conditionName = ClientAccessTypeCondition_NAME;
|
||||||
createCondition(conditionName, ClientAccessTypeConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
createCondition(conditionName, ClientAccessTypeConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
setConditionClientAccessType(provider, new ArrayList<>(Arrays.asList(ClientAccessTypeConditionFactory.TYPE_CONFIDENTIAL)));
|
setConditionClientAccessType(provider, Arrays.asList(ClientAccessTypeConditionFactory.TYPE_CONFIDENTIAL));
|
||||||
});
|
});
|
||||||
registerCondition(conditionName, policyName);
|
registerCondition(conditionName, policyName);
|
||||||
logger.info("... Registered Condition : " + conditionName);
|
logger.info("... Registered Condition : " + conditionName);
|
||||||
|
@ -805,7 +806,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
|
|
||||||
String conditionName = ClientRolesCondition_NAME;
|
String conditionName = ClientRolesCondition_NAME;
|
||||||
createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList(SAMPLE_CLIENT_ROLE)));
|
setConditionClientRoles(provider, Arrays.asList(SAMPLE_CLIENT_ROLE));
|
||||||
});
|
});
|
||||||
registerCondition(conditionName, policyName);
|
registerCondition(conditionName, policyName);
|
||||||
logger.info("... Registered Condition : " + conditionName);
|
logger.info("... Registered Condition : " + conditionName);
|
||||||
|
@ -869,7 +870,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
|
|
||||||
String conditionName = ClientRolesCondition_NAME;
|
String conditionName = ClientRolesCondition_NAME;
|
||||||
createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList(SAMPLE_CLIENT_ROLE)));
|
setConditionClientRoles(provider, Arrays.asList(SAMPLE_CLIENT_ROLE));
|
||||||
});
|
});
|
||||||
registerCondition(conditionName, policyName);
|
registerCondition(conditionName, policyName);
|
||||||
logger.info("... Registered Condition : " + conditionName);
|
logger.info("... Registered Condition : " + conditionName);
|
||||||
|
@ -972,7 +973,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
String roleBetaName = "sample-client-role-beta";
|
String roleBetaName = "sample-client-role-beta";
|
||||||
String conditionName = ClientRolesCondition_NAME;
|
String conditionName = ClientRolesCondition_NAME;
|
||||||
createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList(roleBetaName)));
|
setConditionClientRoles(provider, Arrays.asList(roleBetaName));
|
||||||
});
|
});
|
||||||
registerCondition(conditionName, policyName);
|
registerCondition(conditionName, policyName);
|
||||||
logger.info("... Registered Condition : " + conditionName);
|
logger.info("... Registered Condition : " + conditionName);
|
||||||
|
@ -1023,10 +1024,10 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
|
|
||||||
String conditionName = ClientUpdateContextCondition_NAME;
|
String conditionName = ClientUpdateContextCondition_NAME;
|
||||||
createCondition(conditionName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
createCondition(conditionName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
setConditionRegistrationMethods(provider, new ArrayList<>(Arrays.asList(
|
setConditionRegistrationMethods(provider, Arrays.asList(
|
||||||
ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER,
|
ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER,
|
||||||
ClientUpdateContextConditionFactory.BY_INITIAL_ACCESS_TOKEN,
|
ClientUpdateContextConditionFactory.BY_INITIAL_ACCESS_TOKEN,
|
||||||
ClientUpdateContextConditionFactory.BY_REGISTRATION_ACCESS_TOKEN)));
|
ClientUpdateContextConditionFactory.BY_REGISTRATION_ACCESS_TOKEN));
|
||||||
});
|
});
|
||||||
registerCondition(conditionName, policyName);
|
registerCondition(conditionName, policyName);
|
||||||
logger.info("... Registered Condition : " + conditionName);
|
logger.info("... Registered Condition : " + conditionName);
|
||||||
|
@ -1044,8 +1045,8 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
clientRep.getAttributes().put(OIDCConfigAttributes.USER_INFO_RESPONSE_SIGNATURE_ALG, Algorithm.none.name());
|
clientRep.getAttributes().put(OIDCConfigAttributes.USER_INFO_RESPONSE_SIGNATURE_ALG, Algorithm.none.name());
|
||||||
});
|
});
|
||||||
fail();
|
fail();
|
||||||
} catch (ClientPolicyException e) {
|
} catch (ClientPolicyException cpe) {
|
||||||
assertEquals(Errors.INVALID_REGISTRATION, e.getMessage());
|
assertEquals(OAuthErrorException.INVALID_REQUEST, cpe.getError());
|
||||||
}
|
}
|
||||||
|
|
||||||
// create by Admin REST API - success
|
// create by Admin REST API - success
|
||||||
|
@ -1062,32 +1063,32 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
try {
|
try {
|
||||||
updateClientByAdmin(cAppAdminId, (ClientRepresentation clientRep) -> {
|
updateClientByAdmin(cAppAdminId, (ClientRepresentation clientRep) -> {
|
||||||
clientRep.setAttributes(new HashMap<>());
|
clientRep.setAttributes(new HashMap<>());
|
||||||
clientRep.getAttributes().put(OIDCConfigAttributes.ACCESS_TOKEN_SIGNED_RESPONSE_ALG, Algorithm.RS512.name());
|
clientRep.getAttributes().put(OIDCConfigAttributes.ACCESS_TOKEN_SIGNED_RESPONSE_ALG, org.keycloak.crypto.Algorithm.RS512);
|
||||||
});
|
});
|
||||||
} catch (BadRequestException bre) {
|
} catch (ClientPolicyException cpe) {
|
||||||
assertEquals("HTTP 400 Bad Request", bre.getMessage());
|
assertEquals(Errors.INVALID_REQUEST, cpe.getError());
|
||||||
}
|
}
|
||||||
ClientRepresentation cRep = getClientByAdmin(cAppAdminId);
|
ClientRepresentation cRep = getClientByAdmin(cAppAdminId);
|
||||||
assertEquals(Algorithm.ES256.name(), cRep.getAttributes().get(OIDCConfigAttributes.ACCESS_TOKEN_SIGNED_RESPONSE_ALG));
|
assertEquals(org.keycloak.crypto.Algorithm.ES256, cRep.getAttributes().get(OIDCConfigAttributes.ACCESS_TOKEN_SIGNED_RESPONSE_ALG));
|
||||||
|
|
||||||
// update by Admin REST API - success
|
// update by Admin REST API - success
|
||||||
updateClientByAdmin(cAppAdminId, (ClientRepresentation clientRep) -> {
|
updateClientByAdmin(cAppAdminId, (ClientRepresentation clientRep) -> {
|
||||||
clientRep.setAttributes(new HashMap<>());
|
clientRep.setAttributes(new HashMap<>());
|
||||||
clientRep.getAttributes().put(OIDCConfigAttributes.ACCESS_TOKEN_SIGNED_RESPONSE_ALG, Algorithm.PS384.name());
|
clientRep.getAttributes().put(OIDCConfigAttributes.ACCESS_TOKEN_SIGNED_RESPONSE_ALG, org.keycloak.crypto.Algorithm.PS384);
|
||||||
});
|
});
|
||||||
cRep = getClientByAdmin(cAppAdminId);
|
cRep = getClientByAdmin(cAppAdminId);
|
||||||
assertEquals(Algorithm.PS384.name(), cRep.getAttributes().get(OIDCConfigAttributes.ACCESS_TOKEN_SIGNED_RESPONSE_ALG));
|
assertEquals(org.keycloak.crypto.Algorithm.PS384, cRep.getAttributes().get(OIDCConfigAttributes.ACCESS_TOKEN_SIGNED_RESPONSE_ALG));
|
||||||
|
|
||||||
// create dynamically - fail
|
// create dynamically - fail
|
||||||
try {
|
try {
|
||||||
createClientByAdmin(generateSuffixedName("App-in-Dynamic"), (ClientRepresentation clientRep) -> {
|
createClientByAdmin(generateSuffixedName("App-in-Dynamic"), (ClientRepresentation clientRep) -> {
|
||||||
clientRep.setSecret("secret");
|
clientRep.setSecret("secret");
|
||||||
clientRep.setAttributes(new HashMap<>());
|
clientRep.setAttributes(new HashMap<>());
|
||||||
clientRep.getAttributes().put(OIDCConfigAttributes.USER_INFO_RESPONSE_SIGNATURE_ALG, Algorithm.RS384.name());
|
clientRep.getAttributes().put(OIDCConfigAttributes.USER_INFO_RESPONSE_SIGNATURE_ALG, org.keycloak.crypto.Algorithm.RS384);
|
||||||
});
|
});
|
||||||
fail();
|
fail();
|
||||||
} catch (ClientPolicyException e) {
|
} catch (ClientPolicyException cpe) {
|
||||||
assertEquals(Errors.INVALID_REGISTRATION, e.getMessage());
|
assertEquals(OAuthErrorException.INVALID_REQUEST, cpe.getError());
|
||||||
}
|
}
|
||||||
|
|
||||||
// create dynamically - success
|
// create dynamically - success
|
||||||
|
@ -1103,7 +1104,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
// update dynamically - fail
|
// update dynamically - fail
|
||||||
try {
|
try {
|
||||||
updateClientDynamically(cAppDynamicClientId, (OIDCClientRepresentation clientRep) -> {
|
updateClientDynamically(cAppDynamicClientId, (OIDCClientRepresentation clientRep) -> {
|
||||||
clientRep.setIdTokenSignedResponseAlg(Algorithm.RS256.name());
|
clientRep.setIdTokenSignedResponseAlg(org.keycloak.crypto.Algorithm.RS256);
|
||||||
});
|
});
|
||||||
fail();
|
fail();
|
||||||
} catch (ClientRegistrationException e) {
|
} catch (ClientRegistrationException e) {
|
||||||
|
@ -1126,10 +1127,10 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
|
|
||||||
String conditionName = ClientUpdateContextCondition_NAME;
|
String conditionName = ClientUpdateContextCondition_NAME;
|
||||||
createCondition(conditionName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
createCondition(conditionName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
setConditionRegistrationMethods(provider, new ArrayList<>(Arrays.asList(
|
setConditionRegistrationMethods(provider, Arrays.asList(
|
||||||
ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER,
|
ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER,
|
||||||
ClientUpdateContextConditionFactory.BY_INITIAL_ACCESS_TOKEN,
|
ClientUpdateContextConditionFactory.BY_INITIAL_ACCESS_TOKEN,
|
||||||
ClientUpdateContextConditionFactory.BY_REGISTRATION_ACCESS_TOKEN)));
|
ClientUpdateContextConditionFactory.BY_REGISTRATION_ACCESS_TOKEN));
|
||||||
});
|
});
|
||||||
registerCondition(conditionName, policyName);
|
registerCondition(conditionName, policyName);
|
||||||
logger.info("... Registered Condition : " + conditionName);
|
logger.info("... Registered Condition : " + conditionName);
|
||||||
|
@ -1148,9 +1149,9 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
assertEquals(ERR_MSG_CLIENT_REG_FAIL, e.getMessage());
|
assertEquals(ERR_MSG_CLIENT_REG_FAIL, e.getMessage());
|
||||||
}
|
}
|
||||||
updateCondition(conditionName, (ComponentRepresentation provider) -> {
|
updateCondition(conditionName, (ComponentRepresentation provider) -> {
|
||||||
setConditionRegistrationMethods(provider, new ArrayList<>(Arrays.asList(
|
setConditionRegistrationMethods(provider, Arrays.asList(
|
||||||
ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER,
|
ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER,
|
||||||
ClientUpdateContextConditionFactory.BY_REGISTRATION_ACCESS_TOKEN)));
|
ClientUpdateContextConditionFactory.BY_REGISTRATION_ACCESS_TOKEN));
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
createClientDynamically(generateSuffixedName(CLIENT_NAME), (OIDCClientRepresentation clientRep) -> {});
|
createClientDynamically(generateSuffixedName(CLIENT_NAME), (OIDCClientRepresentation clientRep) -> {});
|
||||||
|
@ -1172,7 +1173,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
|
|
||||||
String conditionName = ClientRolesCondition_NAME;
|
String conditionName = ClientRolesCondition_NAME;
|
||||||
createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList(roleAlphaName, roleZetaName)));
|
setConditionClientRoles(provider, Arrays.asList(roleAlphaName, roleZetaName));
|
||||||
});
|
});
|
||||||
registerCondition(conditionName, policyName);
|
registerCondition(conditionName, policyName);
|
||||||
logger.info("... Registered Condition : " + conditionName);
|
logger.info("... Registered Condition : " + conditionName);
|
||||||
|
@ -1317,6 +1318,73 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExtendedClientPolicyIntefacesForClientRegistrationPolicyMigration() throws ClientRegistrationException, ClientPolicyException {
|
||||||
|
String policyName = "MyPolicy";
|
||||||
|
String clientName = "ByAdmin-App" + KeycloakModelUtils.generateId().substring(0, 7);
|
||||||
|
String executorName = "TestRaiseExeptionExecutor";
|
||||||
|
|
||||||
|
createPolicy(policyName, DefaultClientPolicyProviderFactory.PROVIDER_ID, null, null, null);
|
||||||
|
logger.info("... Created Policy : " + policyName);
|
||||||
|
|
||||||
|
createCondition("AnyClientConditionFactory", AnyClientConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
|
});
|
||||||
|
registerCondition("AnyClientConditionFactory", policyName);
|
||||||
|
logger.info("... Registered Condition : AnyClientConditionFactory");
|
||||||
|
|
||||||
|
createExecutor(executorName, TestRaiseExeptionExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
|
provider.getConfig().put(TestRaiseExeptionExecutorFactory.TARGET_CP_EVENTS, Arrays.asList(ClientPolicyEvent.REGISTERED.toString()));
|
||||||
|
});
|
||||||
|
registerExecutor(executorName, policyName);
|
||||||
|
logger.info("... Registered Executor : " + executorName);
|
||||||
|
|
||||||
|
String clientId = null;
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
createClientByAdmin(clientName, (ClientRepresentation clientRep) -> {
|
||||||
|
});
|
||||||
|
fail();
|
||||||
|
} catch (ClientPolicyException cpe) {
|
||||||
|
assertEquals(ClientPolicyEvent.REGISTERED.toString(), cpe.getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTargetCPEvents(executorName, Arrays.asList(ClientPolicyEvent.UPDATED));
|
||||||
|
|
||||||
|
clientId = getClientByAdminWithName(clientName).getId();
|
||||||
|
assertEquals(true, getClientByAdmin(clientId).isEnabled());
|
||||||
|
try {
|
||||||
|
updateClientByAdmin(clientId, (ClientRepresentation clientRep) -> {
|
||||||
|
clientRep.setEnabled(false);
|
||||||
|
});
|
||||||
|
fail();
|
||||||
|
} catch (ClientPolicyException cpe) {
|
||||||
|
assertEquals(ClientPolicyEvent.UPDATED.toString(), cpe.getError());
|
||||||
|
}
|
||||||
|
assertEquals(false, getClientByAdmin(clientId).isEnabled());
|
||||||
|
|
||||||
|
updateTargetCPEvents(executorName, Arrays.asList(ClientPolicyEvent.VIEW));
|
||||||
|
try {
|
||||||
|
getClientByAdmin(clientId);
|
||||||
|
} catch (ClientPolicyException cpe) {
|
||||||
|
assertEquals(ClientPolicyEvent.VIEW.toString(), cpe.getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTargetCPEvents(executorName, Arrays.asList(ClientPolicyEvent.UNREGISTER));
|
||||||
|
try {
|
||||||
|
deleteClientByAdmin(clientId);
|
||||||
|
} catch (ClientPolicyException cpe) {
|
||||||
|
assertEquals(ClientPolicyEvent.UNREGISTER.toString(), cpe.getError());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
updateExecutor(executorName, (ComponentRepresentation provider) -> {
|
||||||
|
provider.getConfig().put(TestRaiseExeptionExecutorFactory.TARGET_CP_EVENTS, Collections.singletonList((String)null));
|
||||||
|
});
|
||||||
|
deleteClientByAdmin(clientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO : For dynamic client registration, the existing test scheme can not distinguish when the exception happens on which event so that the migrated client policy executors test them afterwards.
|
||||||
|
}
|
||||||
|
|
||||||
private void checkMtlsFlow() throws IOException {
|
private void checkMtlsFlow() throws IOException {
|
||||||
// Check login.
|
// Check login.
|
||||||
OAuthClient.AuthorizationEndpointResponse loginResponse = oauth.doLogin(TEST_USER_NAME, TEST_USER_PASSWORD);
|
OAuthClient.AuthorizationEndpointResponse loginResponse = oauth.doLogin(TEST_USER_NAME, TEST_USER_PASSWORD);
|
||||||
|
@ -1438,18 +1506,20 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
createPolicy(policyName, DefaultClientPolicyProviderFactory.PROVIDER_ID, null, null, null);
|
createPolicy(policyName, DefaultClientPolicyProviderFactory.PROVIDER_ID, null, null, null);
|
||||||
logger.info("... Created Policy : " + policyName);
|
logger.info("... Created Policy : " + policyName);
|
||||||
|
|
||||||
createCondition(ClientUpdateContextCondition_NAME, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
String conditionName = ClientUpdateContextCondition_NAME;
|
||||||
setConditionRegistrationMethods(provider, new ArrayList<>(Arrays.asList(ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER)));
|
createCondition(conditionName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
|
setConditionRegistrationMethods(provider, Arrays.asList(ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER));
|
||||||
});
|
});
|
||||||
registerCondition(ClientUpdateContextCondition_NAME, policyName);
|
registerCondition(conditionName, policyName);
|
||||||
logger.info("... Registered Condition : " + ClientUpdateContextCondition_NAME);
|
logger.info("... Registered Condition : " + conditionName);
|
||||||
|
|
||||||
createExecutor(SecureClientAuthEnforceExecutor_NAME, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
String executorName = SecureClientAuthEnforceExecutor_NAME;
|
||||||
setExecutorAcceptedClientAuthMethods(provider, new ArrayList<>(Arrays.asList(
|
createExecutor(executorName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
JWTClientAuthenticator.PROVIDER_ID, JWTClientSecretAuthenticator.PROVIDER_ID, X509ClientAuthenticator.PROVIDER_ID)));
|
setExecutorAcceptedClientAuthMethods(provider, Arrays.asList(
|
||||||
|
JWTClientAuthenticator.PROVIDER_ID, JWTClientSecretAuthenticator.PROVIDER_ID, X509ClientAuthenticator.PROVIDER_ID));
|
||||||
});
|
});
|
||||||
registerExecutor(SecureClientAuthEnforceExecutor_NAME, policyName);
|
registerExecutor(executorName, policyName);
|
||||||
logger.info("... Registered Executor : " + SecureClientAuthEnforceExecutor_NAME);
|
logger.info("... Registered Executor : " + executorName);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1458,31 +1528,35 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
createPolicy(policyName, DefaultClientPolicyProviderFactory.PROVIDER_ID, null, null, null);
|
createPolicy(policyName, DefaultClientPolicyProviderFactory.PROVIDER_ID, null, null, null);
|
||||||
logger.info("... Created Policy : " + policyName);
|
logger.info("... Created Policy : " + policyName);
|
||||||
|
|
||||||
createCondition(ClientUpdateContextCondition_NAME, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
String conditionName = ClientUpdateContextCondition_NAME;
|
||||||
setConditionRegistrationMethods(provider, new ArrayList<>(Arrays.asList(ClientUpdateContextConditionFactory.BY_INITIAL_ACCESS_TOKEN)));
|
createCondition(conditionName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
|
setConditionRegistrationMethods(provider, Arrays.asList(ClientUpdateContextConditionFactory.BY_INITIAL_ACCESS_TOKEN));
|
||||||
});
|
});
|
||||||
registerCondition(ClientUpdateContextCondition_NAME, policyName);
|
registerCondition(conditionName, policyName);
|
||||||
logger.info("... Registered Condition : " + ClientUpdateContextCondition_NAME);
|
logger.info("... Registered Condition : " + conditionName);
|
||||||
|
|
||||||
createCondition(ClientRolesCondition_NAME, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
conditionName = ClientRolesCondition_NAME;
|
||||||
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList(SAMPLE_CLIENT_ROLE)));
|
createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
|
setConditionClientRoles(provider, Arrays.asList(SAMPLE_CLIENT_ROLE));
|
||||||
});
|
});
|
||||||
registerCondition(ClientRolesCondition_NAME, policyName);
|
registerCondition(conditionName, policyName);
|
||||||
logger.info("... Registered Condition : " + ClientRolesCondition_NAME);
|
logger.info("... Registered Condition : " + conditionName);
|
||||||
|
|
||||||
createExecutor(SecureClientAuthEnforceExecutor_NAME, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
String executorName = SecureClientAuthEnforceExecutor_NAME;
|
||||||
setExecutorAcceptedClientAuthMethods(provider, new ArrayList<>(Arrays.asList(ClientIdAndSecretAuthenticator.PROVIDER_ID, JWTClientAuthenticator.PROVIDER_ID)));
|
createExecutor(executorName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
|
setExecutorAcceptedClientAuthMethods(provider, Arrays.asList(ClientIdAndSecretAuthenticator.PROVIDER_ID, JWTClientAuthenticator.PROVIDER_ID));
|
||||||
setExecutorAugmentedClientAuthMethod(provider, ClientIdAndSecretAuthenticator.PROVIDER_ID);
|
setExecutorAugmentedClientAuthMethod(provider, ClientIdAndSecretAuthenticator.PROVIDER_ID);
|
||||||
setExecutorAugmentActivate(provider);
|
setExecutorAugmentActivate(provider);
|
||||||
});
|
});
|
||||||
registerExecutor(SecureClientAuthEnforceExecutor_NAME, policyName);
|
registerExecutor(executorName, policyName);
|
||||||
logger.info("... Registered Executor : " + SecureClientAuthEnforceExecutor_NAME);
|
logger.info("... Registered Executor : " + executorName);
|
||||||
|
|
||||||
createExecutor(PKCEEnforceExecutor_NAME, PKCEEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
executorName = PKCEEnforceExecutor_NAME;
|
||||||
|
createExecutor(executorName, PKCEEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
|
||||||
setExecutorAugmentActivate(provider);
|
setExecutorAugmentActivate(provider);
|
||||||
});
|
});
|
||||||
registerExecutor(PKCEEnforceExecutor_NAME, policyName);
|
registerExecutor(executorName, policyName);
|
||||||
logger.info("... Registered Executor : " + PKCEEnforceExecutor_NAME);
|
logger.info("... Registered Executor : " + executorName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void successfulLoginAndLogout(String clientId, String clientSecret) {
|
private void successfulLoginAndLogout(String clientId, String clientSecret) {
|
||||||
|
@ -1587,4 +1661,9 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
||||||
assertEquals(ERR_MSG_MISSING_NONCE, oauth.getCurrentQuery().get(OAuth2Constants.ERROR_DESCRIPTION));
|
assertEquals(ERR_MSG_MISSING_NONCE, oauth.getCurrentQuery().get(OAuth2Constants.ERROR_DESCRIPTION));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateTargetCPEvents(String executorName, List<ClientPolicyEvent> events) {
|
||||||
|
updateExecutor(executorName, (ComponentRepresentation provider) -> {
|
||||||
|
provider.getConfig().put(TestRaiseExeptionExecutorFactory.TARGET_CP_EVENTS, events.stream().map(i->i.toString()).collect(Collectors.toList()));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue