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:
Takashi Norimatsu 2021-01-18 08:42:17 +09:00 committed by Marek Posolda
parent b83064b142
commit 882f5ffea4
51 changed files with 971 additions and 301 deletions

View file

@ -20,7 +20,11 @@ package org.keycloak.services.clientpolicy;
public enum ClientPolicyEvent {
REGISTER,
REGISTERED,
UPDATE,
UPDATED,
VIEW,
UNREGISTER,
AUTHORIZATION_REQUEST,
TOKEN_REQUEST,
TOKEN_REFRESH,

View file

@ -44,10 +44,10 @@ import org.keycloak.protocol.oidc.utils.RedirectUtils;
import org.keycloak.services.ErrorPageException;
import org.keycloak.services.ServicesLogger;
import org.keycloak.services.Urls;
import org.keycloak.services.clientpolicy.AuthorizationRequestContext;
import org.keycloak.services.clientpolicy.ClientPolicyContext;
import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.DefaultClientPolicyManager;
import org.keycloak.services.clientpolicy.context.AuthorizationRequestContext;
import org.keycloak.services.messages.Messages;
import org.keycloak.services.resources.LoginActionsService;
import org.keycloak.services.util.CacheControlUtil;

View file

@ -46,7 +46,7 @@ import org.keycloak.representations.RefreshToken;
import org.keycloak.services.ErrorPage;
import org.keycloak.services.ErrorResponseException;
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.UserSessionManager;
import org.keycloak.services.messages.Messages;

View file

@ -85,8 +85,8 @@ import org.keycloak.services.CorsErrorResponseException;
import org.keycloak.services.ServicesLogger;
import org.keycloak.services.Urls;
import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.TokenRefreshContext;
import org.keycloak.services.clientpolicy.TokenRequestContext;
import org.keycloak.services.clientpolicy.context.TokenRefreshContext;
import org.keycloak.services.clientpolicy.context.TokenRequestContext;
import org.keycloak.services.managers.AppAuthManager;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.AuthenticationSessionManager;

View file

@ -33,7 +33,7 @@ import org.keycloak.services.CorsErrorResponseException;
import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.clientpolicy.ClientPolicyException;
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.core.Context;

View file

@ -48,7 +48,7 @@ import org.keycloak.protocol.oidc.utils.AuthorizeClientUtil;
import org.keycloak.representations.AccessToken;
import org.keycloak.services.CorsErrorResponseException;
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.UserSessionManager;
import org.keycloak.services.resources.Cors;

View file

@ -49,7 +49,7 @@ import org.keycloak.representations.AccessToken;
import org.keycloak.services.CorsErrorResponseException;
import org.keycloak.services.Urls;
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.AuthenticationManager;
import org.keycloak.services.managers.UserSessionCrossDCManager;

View file

@ -17,7 +17,10 @@
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 org.jboss.logging.Logger;

View file

@ -30,12 +30,12 @@ import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
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.ClientPolicyException;
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
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 {

View file

@ -28,7 +28,7 @@ import org.keycloak.services.clientpolicy.ClientPolicyContext;
import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
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.util.TokenUtil;
@ -45,7 +45,7 @@ public class ClientUpdateContextCondition extends AbstractClientPolicyConditionP
switch (context.getEvent()) {
case REGISTER:
case UPDATE:
if (isAuthMethodMatched((ClientUpdateContext)context)) return ClientPolicyVote.YES;
if (isAuthMethodMatched((ClientCRUDContext)context)) return ClientPolicyVote.YES;
return ClientPolicyVote.NO;
default:
return ClientPolicyVote.ABSTAIN;
@ -72,7 +72,7 @@ public class ClientUpdateContextCondition extends AbstractClientPolicyConditionP
return isMatched;
}
private boolean isAuthMethodMatched(ClientUpdateContext context) {
private boolean isAuthMethodMatched(ClientCRUDContext context) {
String authMethod = null;
if (context.getToken() == null) {

View file

@ -29,15 +29,15 @@ import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.UserModel;
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.ClientPolicyException;
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
import org.keycloak.services.clientpolicy.ClientPolicyVote;
import org.keycloak.services.clientpolicy.ClientUpdateContext;
import org.keycloak.services.clientpolicy.DynamicClientRegisterContext;
import org.keycloak.services.clientpolicy.DynamicClientUpdateContext;
import org.keycloak.services.clientpolicy.context.AdminClientRegisterContext;
import org.keycloak.services.clientpolicy.context.AdminClientUpdateContext;
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 {
@ -52,17 +52,17 @@ public class ClientUpdateSourceGroupsCondition extends AbstractClientPolicyCondi
switch (context.getEvent()) {
case REGISTER:
if (context instanceof AdminClientRegisterContext) {
return getVoteForGroupsMatched(((ClientUpdateContext)context).getAuthenticatedUser());
return getVoteForGroupsMatched(((ClientCRUDContext)context).getAuthenticatedUser());
} else if (context instanceof DynamicClientRegisterContext) {
return getVoteForGroupsMatched(((ClientUpdateContext)context).getToken());
return getVoteForGroupsMatched(((ClientCRUDContext)context).getToken());
} else {
throw new ClientPolicyException(OAuthErrorException.SERVER_ERROR, "unexpected context type.");
}
case UPDATE:
if (context instanceof AdminClientUpdateContext) {
return getVoteForGroupsMatched(((ClientUpdateContext)context).getAuthenticatedUser());
return getVoteForGroupsMatched(((ClientCRUDContext)context).getAuthenticatedUser());
} else if (context instanceof DynamicClientUpdateContext) {
return getVoteForGroupsMatched(((ClientUpdateContext)context).getToken());
return getVoteForGroupsMatched(((ClientCRUDContext)context).getToken());
} else {
throw new ClientPolicyException(OAuthErrorException.SERVER_ERROR, "unexpected context type.");
}

View file

@ -30,15 +30,15 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
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.ClientPolicyException;
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
import org.keycloak.services.clientpolicy.ClientPolicyVote;
import org.keycloak.services.clientpolicy.ClientUpdateContext;
import org.keycloak.services.clientpolicy.DynamicClientRegisterContext;
import org.keycloak.services.clientpolicy.DynamicClientUpdateContext;
import org.keycloak.services.clientpolicy.context.AdminClientRegisterContext;
import org.keycloak.services.clientpolicy.context.AdminClientUpdateContext;
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 {
@ -53,17 +53,17 @@ public class ClientUpdateSourceRolesCondition extends AbstractClientPolicyCondit
switch (context.getEvent()) {
case REGISTER:
if (context instanceof AdminClientRegisterContext) {
return getVoteForRolesMatched(((ClientUpdateContext)context).getAuthenticatedUser());
return getVoteForRolesMatched(((ClientCRUDContext)context).getAuthenticatedUser());
} else if (context instanceof DynamicClientRegisterContext) {
return getVoteForRolesMatched(((ClientUpdateContext)context).getToken());
return getVoteForRolesMatched(((ClientCRUDContext)context).getToken());
} else {
throw new ClientPolicyException(OAuthErrorException.SERVER_ERROR, "unexpected context type.");
}
case UPDATE:
if (context instanceof AdminClientUpdateContext) {
return getVoteForRolesMatched(((ClientUpdateContext)context).getAuthenticatedUser());
return getVoteForRolesMatched(((ClientCRUDContext)context).getAuthenticatedUser());
} else if (context instanceof DynamicClientUpdateContext) {
return getVoteForRolesMatched(((ClientUpdateContext)context).getToken());
return getVoteForRolesMatched(((ClientCRUDContext)context).getToken());
} else {
throw new ClientPolicyException(OAuthErrorException.SERVER_ERROR, "unexpected context type.");
}

View file

@ -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.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -15,36 +15,21 @@
* limitations under the License.
*/
package org.keycloak.services.clientpolicy;
package org.keycloak.services.clientpolicy.context;
import org.keycloak.models.ClientModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.JsonWebToken;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
import org.keycloak.services.resources.admin.AdminAuth;
public class AdminClientRegisterContext implements ClientUpdateContext {
abstract class AbstractAdminClientCRUDContext implements ClientCRUDContext {
private final ClientRepresentation clientRepresentation;
private final AdminAuth adminAuth;
protected final AdminAuth adminAuth;
public AdminClientRegisterContext(ClientRepresentation clientRepresentation,
AdminAuth adminAuth) {
this.clientRepresentation = clientRepresentation;
public AbstractAdminClientCRUDContext(AdminAuth adminAuth) {
this.adminAuth = adminAuth;
}
@Override
public ClientPolicyEvent getEvent() {
return ClientPolicyEvent.REGISTER;
}
@Override
public ClientRepresentation getProposedClientRepresentation() {
return clientRepresentation;
}
@Override
public ClientModel getAuthenticatedClient() {
return adminAuth.getClient();

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -15,26 +15,22 @@
* limitations under the License.
*/
package org.keycloak.services.clientpolicy;
package org.keycloak.services.clientpolicy.context;
import org.keycloak.models.ClientModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.JsonWebToken;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
import org.keycloak.services.resources.admin.AdminAuth;
public class AdminClientUpdateContext implements ClientUpdateContext {
public class AdminClientUpdateContext extends AbstractAdminClientCRUDContext {
private final ClientRepresentation clientRepresentation;
private final AdminAuth adminAuth;
private final ClientModel client;
private final ClientRepresentation proposedClientRepresentation;
private final ClientModel targetClient;
public AdminClientUpdateContext(ClientRepresentation clientRepresentation,
AdminAuth adminAuth, ClientModel client) {
this.clientRepresentation = clientRepresentation;
this.adminAuth = adminAuth;
this.client = client;
public AdminClientUpdateContext(ClientRepresentation proposedClientRepresentation, ClientModel targetClient, AdminAuth adminAuth) {
super(adminAuth);
this.proposedClientRepresentation = proposedClientRepresentation;
this.targetClient = targetClient;
}
@Override
@ -44,26 +40,11 @@ public class AdminClientUpdateContext implements ClientUpdateContext {
@Override
public ClientRepresentation getProposedClientRepresentation() {
return clientRepresentation;
return proposedClientRepresentation;
}
@Override
public ClientModel getClientToBeUpdated() {
return client;
}
@Override
public ClientModel getAuthenticatedClient() {
return adminAuth.getClient();
}
@Override
public UserModel getAuthenticatedUser() {
return adminAuth.getUser();
}
@Override
public JsonWebToken getToken() {
return adminAuth.getToken();
public ClientModel getTargetClient() {
return targetClient;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.keycloak.services.clientpolicy;
package org.keycloak.services.clientpolicy.context;
import javax.ws.rs.core.MultivaluedMap;

View file

@ -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.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -15,31 +15,35 @@
* limitations under the License.
*/
package org.keycloak.services.clientpolicy;
package org.keycloak.services.clientpolicy.context;
import org.keycloak.models.ClientModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.JsonWebToken;
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}
*/
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}
*/
default ClientModel getClientToBeUpdated() {
default ClientModel getTargetClient() {
return null;
}
@ -48,19 +52,25 @@ public interface ClientUpdateContext extends ClientPolicyContext {
*
* @return {@link UserModel}
*/
UserModel getAuthenticatedUser();
default UserModel getAuthenticatedUser() {
return null;
}
/**
* returns {@link UserModel} of the authenticated client.
*
* @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}
*/
JsonWebToken getToken();
default JsonWebToken getToken() {
return null;
}
}

View file

@ -15,35 +15,21 @@
* 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.UserModel;
import org.keycloak.representations.JsonWebToken;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
import org.keycloak.services.clientregistration.ClientRegistrationContext;
public class DynamicClientRegisterContext implements ClientUpdateContext {
public class DynamicClientRegisterContext extends AbstractDynamicClientCRUDContext {
private final ClientRegistrationContext context;
private JsonWebToken token;
private UserModel user;
private ClientModel client;
private final ClientRepresentation proposedClientRepresentation;
public DynamicClientRegisterContext(ClientRegistrationContext context,
JsonWebToken token, RealmModel realm) {
this.context = context;
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());
}
}
public DynamicClientRegisterContext(ClientRegistrationContext context, JsonWebToken token, RealmModel realm) {
super(context.getSession(), token, realm);
this.proposedClientRepresentation = context.getClient();
}
@Override
@ -53,21 +39,6 @@ public class DynamicClientRegisterContext implements ClientUpdateContext {
@Override
public ClientRepresentation getProposedClientRepresentation() {
return context.getClient();
}
@Override
public ClientModel getAuthenticatedClient() {
return client;
}
@Override
public UserModel getAuthenticatedUser() {
return user;
}
@Override
public JsonWebToken getToken() {
return token;
return proposedClientRepresentation;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -15,37 +15,24 @@
* 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.UserModel;
import org.keycloak.representations.JsonWebToken;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
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 JsonWebToken token;
private UserModel user;
private ClientModel client;
private final ClientRepresentation proposedClientRepresentation;
public DynamicClientUpdateContext(ClientRegistrationContext context,
ClientModel client, JsonWebToken token, RealmModel realm) {
this.context = context;
this.clientToBeUpdated = client;
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());
}
}
public DynamicClientUpdateContext(ClientRegistrationContext context, ClientModel proposedClientRepresentation, JsonWebToken token, RealmModel realm) {
super(context.getSession(), token, realm);
this.clientToBeUpdated = proposedClientRepresentation;
this.proposedClientRepresentation = context.getClient();
}
@Override
@ -55,26 +42,11 @@ public class DynamicClientUpdateContext implements ClientUpdateContext {
@Override
public ClientRepresentation getProposedClientRepresentation() {
return context.getClient();
return proposedClientRepresentation;
}
@Override
public ClientModel getClientToBeUpdated() {
public ClientModel getTargetClient() {
return clientToBeUpdated;
}
@Override
public ClientModel getAuthenticatedClient() {
return client;
}
@Override
public UserModel getAuthenticatedUser() {
return user;
}
@Override
public JsonWebToken getToken() {
return token;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.keycloak.services.clientpolicy;
package org.keycloak.services.clientpolicy.context;
import javax.ws.rs.core.MultivaluedMap;

View file

@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.keycloak.services.clientpolicy;
package org.keycloak.services.clientpolicy.context;
import javax.ws.rs.core.MultivaluedMap;

View file

@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.keycloak.services.clientpolicy;
package org.keycloak.services.clientpolicy.context;
import javax.ws.rs.core.MultivaluedMap;

View file

@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.keycloak.services.clientpolicy;
package org.keycloak.services.clientpolicy.context;
import javax.ws.rs.core.MultivaluedMap;

View file

@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.keycloak.services.clientpolicy;
package org.keycloak.services.clientpolicy.context;
import javax.ws.rs.core.MultivaluedMap;

View file

@ -15,7 +15,7 @@
* 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.ClientPolicyEvent;

View file

@ -23,7 +23,7 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.services.clientpolicy.ClientPolicyContext;
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;
public abstract class AbstractAugumentingClientRegistrationPolicyExecutor implements ClientPolicyExecutorProvider {
@ -46,7 +46,7 @@ public abstract class AbstractAugumentingClientRegistrationPolicyExecutor implem
switch (context.getEvent()) {
case REGISTER:
case UPDATE:
ClientUpdateContext clientUpdateContext = (ClientUpdateContext)context;
ClientCRUDContext clientUpdateContext = (ClientCRUDContext)context;
augment(clientUpdateContext.getProposedClientRepresentation());
validate(clientUpdateContext.getProposedClientRepresentation());
break;

View file

@ -27,7 +27,12 @@ import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.RefreshToken;
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 javax.ws.rs.core.MultivaluedMap;
@ -75,29 +80,26 @@ public class HolderOfKeyEnforceExecutor extends AbstractAugumentingClientRegistr
HttpRequest request = session.getContext().getContextObject(HttpRequest.class);
switch (context.getEvent()) {
case TOKEN_REQUEST:
AccessToken.CertConf certConf = MtlsHoKTokenUtil.bindTokenWithClientCertificate(request, session);
if (certConf == null) {
throw new ClientPolicyException(OAuthErrorException.INVALID_REQUEST, "Client Certification missing for MTLS HoK Token Binding");
}
break;
case TOKEN_REFRESH:
checkTokenRefresh((TokenRefreshContext) context, request);
break;
case TOKEN_REVOKE:
checkTokenRevoke((TokenRevokeContext) context, request);
break;
case USERINFO_REQUEST:
checkUserInfo((UserInfoRequestContext) context, request);
break;
case LOGOUT_REQUEST:
checkLogout((LogoutRequestContext) context, request);
break;
default:
return;
}
}

View file

@ -38,10 +38,10 @@ import org.keycloak.protocol.oidc.utils.OAuth2Code;
import org.keycloak.protocol.oidc.utils.OAuth2CodeParser;
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.services.clientpolicy.AuthorizationRequestContext;
import org.keycloak.services.clientpolicy.ClientPolicyContext;
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;
public class PKCEEnforceExecutor extends AbstractAugumentingClientRegistrationPolicyExecutor {

View file

@ -24,15 +24,15 @@ import org.jboss.logging.Logger;
import org.keycloak.OAuthErrorException;
import org.keycloak.component.ComponentModel;
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.ClientPolicyException;
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
import org.keycloak.services.clientpolicy.ClientUpdateContext;
import org.keycloak.services.clientpolicy.DynamicClientRegisterContext;
import org.keycloak.services.clientpolicy.DynamicClientUpdateContext;
import org.keycloak.services.clientpolicy.context.AdminClientRegisterContext;
import org.keycloak.services.clientpolicy.context.AdminClientUpdateContext;
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 {
@ -61,14 +61,14 @@ public class SecureRedirectUriEnforceExecutor implements ClientPolicyExecutorPro
switch (context.getEvent()) {
case REGISTER:
if (context instanceof AdminClientRegisterContext || context instanceof DynamicClientRegisterContext) {
confirmSecureRedirectUris(((ClientUpdateContext)context).getProposedClientRepresentation().getRedirectUris());
confirmSecureRedirectUris(((ClientCRUDContext)context).getProposedClientRepresentation().getRedirectUris());
} else {
throw new ClientPolicyException(OAuthErrorException.INVALID_REQUEST, "not allowed input format.");
}
return;
case UPDATE:
if (context instanceof AdminClientUpdateContext || context instanceof DynamicClientUpdateContext) {
confirmSecureRedirectUris(((ClientUpdateContext)context).getProposedClientRepresentation().getRedirectUris());
confirmSecureRedirectUris(((ClientCRUDContext)context).getProposedClientRepresentation().getRedirectUris());
} else {
throw new ClientPolicyException(OAuthErrorException.INVALID_REQUEST, "not allowed input format.");
}

View file

@ -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.utils.OIDCResponseType;
import org.keycloak.services.Urls;
import org.keycloak.services.clientpolicy.AuthorizationRequestContext;
import org.keycloak.services.clientpolicy.ClientPolicyContext;
import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
import org.keycloak.services.clientpolicy.context.AuthorizationRequestContext;
import com.fasterxml.jackson.databind.JsonNode;

View file

@ -23,10 +23,10 @@ import org.keycloak.component.ComponentModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequest;
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
import org.keycloak.services.clientpolicy.AuthorizationRequestContext;
import org.keycloak.services.clientpolicy.ClientPolicyContext;
import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
import org.keycloak.services.clientpolicy.context.AuthorizationRequestContext;
public class SecureResponseTypeExecutor implements ClientPolicyExecutorProvider {

View file

@ -23,10 +23,10 @@ import org.keycloak.component.ComponentModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequest;
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
import org.keycloak.services.clientpolicy.AuthorizationRequestContext;
import org.keycloak.services.clientpolicy.ClientPolicyContext;
import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
import org.keycloak.services.clientpolicy.context.AuthorizationRequestContext;
import org.keycloak.util.TokenUtil;
public class SecureSessionEnforceExecutor implements ClientPolicyExecutorProvider {

View file

@ -28,13 +28,13 @@ import org.keycloak.crypto.Algorithm;
import org.keycloak.models.KeycloakSession;
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
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.ClientPolicyException;
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
import org.keycloak.services.clientpolicy.DynamicClientRegisterContext;
import org.keycloak.services.clientpolicy.DynamicClientUpdateContext;
import org.keycloak.services.clientpolicy.context.AdminClientRegisterContext;
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 {

View file

@ -30,6 +30,9 @@ import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.oidc.OIDCClientRepresentation;
import org.keycloak.services.ErrorResponseException;
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.RegistrationAuth;
import org.keycloak.services.managers.ClientManager;
@ -70,6 +73,7 @@ public abstract class AbstractClientRegistrationProvider implements ClientRegist
RepresentationToModel.createResourceServer(clientModel, session, true);
}
session.clientPolicy().triggerOnEvent(new DynamicClientRegisteredContext(context, clientModel, auth.getJwt(), realm));
ClientRegistrationPolicyManager.triggerAfterRegister(context, registrationAuth, clientModel);
client = ModelToRepresentation.toRepresentation(clientModel, session);
@ -90,6 +94,8 @@ public abstract class AbstractClientRegistrationProvider implements ClientRegist
return client;
} catch (ModelDuplicateException e) {
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);
}
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);
event.client(client.getClientId()).success();

View file

@ -37,8 +37,10 @@ import org.keycloak.protocol.oidc.utils.AuthorizeClientUtil;
import org.keycloak.representations.JsonWebToken;
import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.DynamicClientRegisterContext;
import org.keycloak.services.clientpolicy.DynamicClientUpdateContext;
import org.keycloak.services.clientpolicy.context.DynamicClientRegisterContext;
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.ClientRegistrationPolicyManager;
import org.keycloak.services.clientregistration.policy.RegistrationAuth;
@ -199,8 +201,9 @@ public class ClientRegistrationAuth {
if (authenticated) {
try {
session.clientPolicy().triggerOnEvent(new DynamicClientViewContext(session, client, jwt, realm));
ClientRegistrationPolicyManager.triggerBeforeView(session, provider, authType, client);
} catch (ClientRegistrationPolicyException crpe) {
} catch (ClientRegistrationPolicyException | ClientPolicyException crpe) {
throw forbidden(crpe.getMessage());
}
} else {
@ -230,8 +233,9 @@ public class ClientRegistrationAuth {
RegistrationAuth chainType = requireUpdateAuth(client);
try {
session.clientPolicy().triggerOnEvent(new DynamicClientUnregisterContext(session, client, jwt, realm));
ClientRegistrationPolicyManager.triggerBeforeRemove(session, provider, chainType, client);
} catch (ClientRegistrationPolicyException crpe) {
} catch (ClientRegistrationPolicyException | ClientPolicyException crpe) {
throw forbidden(crpe.getMessage());
}
}

View file

@ -50,8 +50,11 @@ import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.idm.UserSessionRepresentation;
import org.keycloak.services.ErrorResponse;
import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.clientpolicy.AdminClientUpdateContext;
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.policy.RegistrationAuth;
import org.keycloak.services.managers.ClientManager;
@ -130,12 +133,8 @@ public class ClientResource {
auth.clients().requireConfigure(client);
try {
session.clientPolicy().triggerOnEvent(new AdminClientUpdateContext(rep, auth.adminAuth(), client));
} catch (ClientPolicyException cpe) {
throw new ErrorResponseException(cpe.getError(), cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
}
session.clientPolicy().triggerOnEvent(new AdminClientUpdateContext(rep, client, auth.adminAuth()));
try {
updateClientFromRep(rep, client, session);
ValidationUtil.validateClient(session, client, false, r -> {
@ -146,10 +145,14 @@ public class ClientResource {
Response.Status.BAD_REQUEST);
});
session.clientPolicy().triggerOnEvent(new AdminClientUpdatedContext(rep, client, auth.adminAuth()));
adminEvent.operation(OperationType.UPDATE).resourcePath(session.getContext().getUri()).representation(rep).success();
return Response.noContent().build();
} catch (ModelDuplicateException e) {
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
@Produces(MediaType.APPLICATION_JSON)
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);
ClientRepresentation representation = ModelToRepresentation.toRepresentation(client, session);
@ -206,6 +215,12 @@ public class ClientResource {
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);
adminEvent.operation(OperationType.DELETE).resourcePath(session.getContext().getUri()).success();
}

View file

@ -34,8 +34,9 @@ import org.keycloak.representations.idm.authorization.ResourceServerRepresentati
import org.keycloak.services.ErrorResponse;
import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.ForbiddenException;
import org.keycloak.services.clientpolicy.AdminClientRegisterContext;
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.RealmManager;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
@ -163,11 +164,7 @@ public class ClientsResource {
try {
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);
if (TRUE.equals(rep.isServiceAccountsEnabled())) {
@ -200,9 +197,13 @@ public class ClientsResource {
Response.Status.BAD_REQUEST);
});
session.clientPolicy().triggerOnEvent(new AdminClientRegisteredContext(clientModel, auth.adminAuth()));
return Response.created(session.getContext().getUri().getAbsolutePathBuilder().path(clientModel.getId()).build()).build();
} catch (ModelDuplicateException e) {
return ErrorResponse.exists("Client " + rep.getClientId() + " already exists");
} catch (ClientPolicyException cpe) {
throw new ErrorResponseException(cpe.getError(), cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
}
}

View file

@ -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()));
}
}

View file

@ -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);
}
}

View file

@ -18,6 +18,7 @@
package org.keycloak.testsuite.client;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.net.URI;
@ -42,6 +43,7 @@ import java.util.Map;
import java.util.UUID;
import java.util.function.Consumer;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.core.Response;
import org.apache.http.HttpResponse;
@ -423,10 +425,10 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
// 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();
clientRep.setClientId(clientId);
clientRep.setName(clientId);
clientRep.setClientId(clientName);
clientRep.setName(clientName);
clientRep.setProtocol("openid-connect");
clientRep.setBearerOnly(Boolean.FALSE);
clientRep.setPublicClient(Boolean.FALSE);
@ -435,7 +437,14 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
op.accept(clientRep);
Response resp = adminClient.realm(REALM_NAME).clients().create(clientRep);
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();
assertEquals(Response.Status.CREATED.getStatusCode(), resp.getStatus());
@ -445,21 +454,55 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
return cId;
}
protected ClientRepresentation getClientByAdmin(String cId) {
protected ClientRepresentation getClientByAdmin(String cId) throws ClientPolicyException {
ClientResource clientResource = adminClient.realm(REALM_NAME).clients().get(cId);
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);
ClientRepresentation clientRep = clientResource.toRepresentation();
op.accept(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);
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

View file

@ -33,8 +33,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import javax.ws.rs.BadRequestException;
import java.util.stream.Collectors;
import org.apache.http.HttpResponse;
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.models.AdminRoles;
import org.keycloak.models.Constants;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
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.oidc.OIDCClientRepresentation;
import org.keycloak.representations.oidc.TokenMetadataRepresentation;
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.DefaultClientPolicyProviderFactory;
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.rest.resource.TestingOIDCEndpointsApplicationResource.AuthorizationEndpointRequestObject;
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.OAuthClient;
@ -161,8 +163,8 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
clientRep.setClientAuthenticatorType(ClientIdAndSecretAuthenticator.PROVIDER_ID);
});
fail();
} catch (ClientPolicyException e) {
assertEquals(Errors.INVALID_REGISTRATION, e.getMessage());
} catch (ClientPolicyException cpe) {
assertEquals(OAuthErrorException.INVALID_CLIENT_METADATA, cpe.getError());
}
}
@ -181,8 +183,8 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
try {
createClientByAdmin(generateSuffixedName(CLIENT_NAME), (ClientRepresentation clientRep) -> {});
fail();
} catch (ClientPolicyException e) {
assertEquals(Errors.INVALID_REGISTRATION, e.getMessage());
} catch (ClientPolicyException cpe) {
assertEquals(OAuthErrorException.INVALID_CLIENT_METADATA, cpe.getError());
}
}
@ -198,8 +200,8 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
clientRep.setClientAuthenticatorType(ClientIdAndSecretAuthenticator.PROVIDER_ID);
});
fail();
} catch (BadRequestException bre) {
assertEquals("HTTP 400 Bad Request", bre.getMessage());
} catch (ClientPolicyException cpe) {
assertEquals(OAuthErrorException.INVALID_CLIENT_METADATA, cpe.getError());
}
assertEquals(JWTClientSecretAuthenticator.PROVIDER_ID, getClientByAdmin(cId).getClientAuthenticatorType());
}
@ -323,7 +325,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String conditionName = ClientRolesCondition_NAME;
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);
logger.info("... Registered Condition : " + conditionName);
@ -331,7 +333,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
failLoginByNotFollowingPKCE(clientId);
updateCondition(conditionName, (ComponentRepresentation provider) -> {
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList("anothor-client-role")));
setConditionClientRoles(provider, Arrays.asList("anothor-client-role"));
});
successfulLoginAndLogout(clientId, clientSecret);
@ -349,14 +351,14 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String roleConditionName = ClientRolesCondition_NAME;
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);
logger.info("... Registered Condition : " + roleConditionName);
String updateConditionName = ClientUpdateContextCondition_NAME;
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);
logger.info("... Registered Condition : " + updateConditionName);
@ -431,21 +433,21 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String roleConditionAlphaName = generateSuffixedName(ClientRolesCondition_NAME);
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);
logger.info("... Registered Condition : " + roleConditionAlphaName);
String updateConditionAlphaName = generateSuffixedName(ClientUpdateContextCondition_NAME);
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);
logger.info("... Registered Condition : " + updateConditionAlphaName);
String clientAuthExecutorAlphaName = generateSuffixedName(SecureClientAuthEnforceExecutor_NAME);
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);
setExecutorAugmentedClientAuthMethod(provider, ClientIdAndSecretAuthenticator.PROVIDER_ID);
});
@ -458,7 +460,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String roleConditionBetaName = generateSuffixedName(ClientRolesCondition_NAME);
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);
logger.info("... Registered Condition : " + roleConditionBetaName);
@ -507,8 +509,8 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
try {
createClientByAdmin(generateSuffixedName(CLIENT_NAME), (ClientRepresentation clientRep) -> {});
fail();
} catch (ClientPolicyException e) {
assertEquals(Errors.INVALID_REGISTRATION, e.getMessage());
} catch (ClientPolicyException cpe) {
assertEquals(OAuthErrorException.SERVER_ERROR, cpe.getError());
}
}
@ -611,15 +613,15 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String conditionName = ClientUpdateSourceHostsCondition_NAME;
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);
logger.info("... Registered Condition : " + conditionName);
String executorName = SecureClientAuthEnforceExecutor_NAME;
createExecutor(executorName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setExecutorAcceptedClientAuthMethods(provider, new ArrayList<>(Arrays.asList(
JWTClientAuthenticator.PROVIDER_ID, JWTClientSecretAuthenticator.PROVIDER_ID, X509ClientAuthenticator.PROVIDER_ID)));
setExecutorAcceptedClientAuthMethods(provider, Arrays.asList(
JWTClientAuthenticator.PROVIDER_ID, JWTClientSecretAuthenticator.PROVIDER_ID, X509ClientAuthenticator.PROVIDER_ID));
});
registerExecutor(executorName, policyName);
logger.info("... Registered Executor : " + executorName);
@ -631,12 +633,12 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
clientRep.setSecret(clientSecret);
});
fail();
} catch (ClientPolicyException e) {
assertEquals(Errors.INVALID_REGISTRATION, e.getMessage());
} catch (ClientPolicyException cpe) {
assertEquals(OAuthErrorException.INVALID_CLIENT_METADATA, cpe.getError());
}
updateCondition(conditionName, (ComponentRepresentation provider) -> {
setConditionClientUpdateSourceHosts(provider, new ArrayList<>(Arrays.asList("example.com")));
setConditionClientUpdateSourceHosts(provider, Arrays.asList("example.com"));
});
try {
createClientByAdmin(clientId, (ClientRepresentation clientRep) -> {
@ -655,14 +657,14 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String conditionName = ClientUpdateSourceGroupsCondition_NAME;
createCondition(conditionName, ClientUpdateSourceGroupsConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionClientUpdateSourceGroups(provider, new ArrayList<>(Arrays.asList("topGroup")));
setConditionClientUpdateSourceGroups(provider, Arrays.asList("topGroup"));
});
registerCondition(conditionName, policyName);
logger.info("... Registered Condition : " + conditionName);
String executorName = SecureClientAuthEnforceExecutor_NAME;
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);
logger.info("... Registered Executor : " + executorName);
@ -690,14 +692,14 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String conditionName = ClientUpdateSourceRolesCondition_NAME;
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);
logger.info("... Registered Condition : " + conditionName);
String executorName = SecureClientAuthEnforceExecutor_NAME;
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);
logger.info("... Registered Executor : " + executorName);
@ -725,7 +727,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String conditionName = ClientScopesCondition_NAME;
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);
logger.info("... Registered Condition : " + conditionName);
@ -759,7 +761,6 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
}
}
@Test
public void testClientAccessTypeCondition() throws ClientRegistrationException, ClientPolicyException {
String policyName = POLICY_NAME;
@ -768,7 +769,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String conditionName = ClientAccessTypeCondition_NAME;
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);
logger.info("... Registered Condition : " + conditionName);
@ -805,7 +806,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String conditionName = ClientRolesCondition_NAME;
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);
logger.info("... Registered Condition : " + conditionName);
@ -869,7 +870,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String conditionName = ClientRolesCondition_NAME;
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);
logger.info("... Registered Condition : " + conditionName);
@ -972,7 +973,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String roleBetaName = "sample-client-role-beta";
String conditionName = ClientRolesCondition_NAME;
createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList(roleBetaName)));
setConditionClientRoles(provider, Arrays.asList(roleBetaName));
});
registerCondition(conditionName, policyName);
logger.info("... Registered Condition : " + conditionName);
@ -1023,10 +1024,10 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String conditionName = ClientUpdateContextCondition_NAME;
createCondition(conditionName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionRegistrationMethods(provider, new ArrayList<>(Arrays.asList(
setConditionRegistrationMethods(provider, Arrays.asList(
ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER,
ClientUpdateContextConditionFactory.BY_INITIAL_ACCESS_TOKEN,
ClientUpdateContextConditionFactory.BY_REGISTRATION_ACCESS_TOKEN)));
ClientUpdateContextConditionFactory.BY_REGISTRATION_ACCESS_TOKEN));
});
registerCondition(conditionName, policyName);
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());
});
fail();
} catch (ClientPolicyException e) {
assertEquals(Errors.INVALID_REGISTRATION, e.getMessage());
} catch (ClientPolicyException cpe) {
assertEquals(OAuthErrorException.INVALID_REQUEST, cpe.getError());
}
// create by Admin REST API - success
@ -1062,32 +1063,32 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
try {
updateClientByAdmin(cAppAdminId, (ClientRepresentation clientRep) -> {
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) {
assertEquals("HTTP 400 Bad Request", bre.getMessage());
} catch (ClientPolicyException cpe) {
assertEquals(Errors.INVALID_REQUEST, cpe.getError());
}
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
updateClientByAdmin(cAppAdminId, (ClientRepresentation clientRep) -> {
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);
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
try {
createClientByAdmin(generateSuffixedName("App-in-Dynamic"), (ClientRepresentation clientRep) -> {
clientRep.setSecret("secret");
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();
} catch (ClientPolicyException e) {
assertEquals(Errors.INVALID_REGISTRATION, e.getMessage());
} catch (ClientPolicyException cpe) {
assertEquals(OAuthErrorException.INVALID_REQUEST, cpe.getError());
}
// create dynamically - success
@ -1103,7 +1104,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
// update dynamically - fail
try {
updateClientDynamically(cAppDynamicClientId, (OIDCClientRepresentation clientRep) -> {
clientRep.setIdTokenSignedResponseAlg(Algorithm.RS256.name());
clientRep.setIdTokenSignedResponseAlg(org.keycloak.crypto.Algorithm.RS256);
});
fail();
} catch (ClientRegistrationException e) {
@ -1126,10 +1127,10 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String conditionName = ClientUpdateContextCondition_NAME;
createCondition(conditionName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionRegistrationMethods(provider, new ArrayList<>(Arrays.asList(
setConditionRegistrationMethods(provider, Arrays.asList(
ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER,
ClientUpdateContextConditionFactory.BY_INITIAL_ACCESS_TOKEN,
ClientUpdateContextConditionFactory.BY_REGISTRATION_ACCESS_TOKEN)));
ClientUpdateContextConditionFactory.BY_REGISTRATION_ACCESS_TOKEN));
});
registerCondition(conditionName, policyName);
logger.info("... Registered Condition : " + conditionName);
@ -1148,9 +1149,9 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
assertEquals(ERR_MSG_CLIENT_REG_FAIL, e.getMessage());
}
updateCondition(conditionName, (ComponentRepresentation provider) -> {
setConditionRegistrationMethods(provider, new ArrayList<>(Arrays.asList(
setConditionRegistrationMethods(provider, Arrays.asList(
ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER,
ClientUpdateContextConditionFactory.BY_REGISTRATION_ACCESS_TOKEN)));
ClientUpdateContextConditionFactory.BY_REGISTRATION_ACCESS_TOKEN));
});
try {
createClientDynamically(generateSuffixedName(CLIENT_NAME), (OIDCClientRepresentation clientRep) -> {});
@ -1172,7 +1173,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String conditionName = ClientRolesCondition_NAME;
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);
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 {
// Check login.
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);
logger.info("... Created Policy : " + policyName);
createCondition(ClientUpdateContextCondition_NAME, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionRegistrationMethods(provider, new ArrayList<>(Arrays.asList(ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER)));
String conditionName = ClientUpdateContextCondition_NAME;
createCondition(conditionName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionRegistrationMethods(provider, Arrays.asList(ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER));
});
registerCondition(ClientUpdateContextCondition_NAME, policyName);
logger.info("... Registered Condition : " + ClientUpdateContextCondition_NAME);
registerCondition(conditionName, policyName);
logger.info("... Registered Condition : " + conditionName);
createExecutor(SecureClientAuthEnforceExecutor_NAME, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setExecutorAcceptedClientAuthMethods(provider, new ArrayList<>(Arrays.asList(
JWTClientAuthenticator.PROVIDER_ID, JWTClientSecretAuthenticator.PROVIDER_ID, X509ClientAuthenticator.PROVIDER_ID)));
String executorName = SecureClientAuthEnforceExecutor_NAME;
createExecutor(executorName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setExecutorAcceptedClientAuthMethods(provider, Arrays.asList(
JWTClientAuthenticator.PROVIDER_ID, JWTClientSecretAuthenticator.PROVIDER_ID, X509ClientAuthenticator.PROVIDER_ID));
});
registerExecutor(SecureClientAuthEnforceExecutor_NAME, policyName);
logger.info("... Registered Executor : " + SecureClientAuthEnforceExecutor_NAME);
registerExecutor(executorName, policyName);
logger.info("... Registered Executor : " + executorName);
}
@ -1458,31 +1528,35 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
createPolicy(policyName, DefaultClientPolicyProviderFactory.PROVIDER_ID, null, null, null);
logger.info("... Created Policy : " + policyName);
createCondition(ClientUpdateContextCondition_NAME, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionRegistrationMethods(provider, new ArrayList<>(Arrays.asList(ClientUpdateContextConditionFactory.BY_INITIAL_ACCESS_TOKEN)));
String conditionName = ClientUpdateContextCondition_NAME;
createCondition(conditionName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionRegistrationMethods(provider, Arrays.asList(ClientUpdateContextConditionFactory.BY_INITIAL_ACCESS_TOKEN));
});
registerCondition(ClientUpdateContextCondition_NAME, policyName);
logger.info("... Registered Condition : " + ClientUpdateContextCondition_NAME);
registerCondition(conditionName, policyName);
logger.info("... Registered Condition : " + conditionName);
createCondition(ClientRolesCondition_NAME, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList(SAMPLE_CLIENT_ROLE)));
conditionName = ClientRolesCondition_NAME;
createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionClientRoles(provider, Arrays.asList(SAMPLE_CLIENT_ROLE));
});
registerCondition(ClientRolesCondition_NAME, policyName);
logger.info("... Registered Condition : " + ClientRolesCondition_NAME);
registerCondition(conditionName, policyName);
logger.info("... Registered Condition : " + conditionName);
createExecutor(SecureClientAuthEnforceExecutor_NAME, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setExecutorAcceptedClientAuthMethods(provider, new ArrayList<>(Arrays.asList(ClientIdAndSecretAuthenticator.PROVIDER_ID, JWTClientAuthenticator.PROVIDER_ID)));
String executorName = SecureClientAuthEnforceExecutor_NAME;
createExecutor(executorName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setExecutorAcceptedClientAuthMethods(provider, Arrays.asList(ClientIdAndSecretAuthenticator.PROVIDER_ID, JWTClientAuthenticator.PROVIDER_ID));
setExecutorAugmentedClientAuthMethod(provider, ClientIdAndSecretAuthenticator.PROVIDER_ID);
setExecutorAugmentActivate(provider);
});
registerExecutor(SecureClientAuthEnforceExecutor_NAME, policyName);
logger.info("... Registered Executor : " + SecureClientAuthEnforceExecutor_NAME);
registerExecutor(executorName, policyName);
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);
});
registerExecutor(PKCEEnforceExecutor_NAME, policyName);
logger.info("... Registered Executor : " + PKCEEnforceExecutor_NAME);
registerExecutor(executorName, policyName);
logger.info("... Registered Executor : " + executorName);
}
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));
}
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()));
});
}
}