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 { public enum ClientPolicyEvent {
REGISTER, REGISTER,
REGISTERED,
UPDATE, UPDATE,
UPDATED,
VIEW,
UNREGISTER,
AUTHORIZATION_REQUEST, AUTHORIZATION_REQUEST,
TOKEN_REQUEST, TOKEN_REQUEST,
TOKEN_REFRESH, TOKEN_REFRESH,

View file

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

View file

@ -46,7 +46,7 @@ import org.keycloak.representations.RefreshToken;
import org.keycloak.services.ErrorPage; import org.keycloak.services.ErrorPage;
import org.keycloak.services.ErrorResponseException; import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.clientpolicy.ClientPolicyException; import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.LogoutRequestContext; import org.keycloak.services.clientpolicy.context.LogoutRequestContext;
import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.UserSessionManager; import org.keycloak.services.managers.UserSessionManager;
import org.keycloak.services.messages.Messages; import org.keycloak.services.messages.Messages;

View file

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

View file

@ -33,7 +33,7 @@ import org.keycloak.services.CorsErrorResponseException;
import org.keycloak.services.ErrorResponseException; import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.clientpolicy.ClientPolicyException; import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.DefaultClientPolicyManager; import org.keycloak.services.clientpolicy.DefaultClientPolicyManager;
import org.keycloak.services.clientpolicy.TokenIntrospectContext; import org.keycloak.services.clientpolicy.context.TokenIntrospectContext;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;

View file

@ -48,7 +48,7 @@ import org.keycloak.protocol.oidc.utils.AuthorizeClientUtil;
import org.keycloak.representations.AccessToken; import org.keycloak.representations.AccessToken;
import org.keycloak.services.CorsErrorResponseException; import org.keycloak.services.CorsErrorResponseException;
import org.keycloak.services.clientpolicy.ClientPolicyException; import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.TokenRevokeContext; import org.keycloak.services.clientpolicy.context.TokenRevokeContext;
import org.keycloak.services.managers.UserSessionCrossDCManager; import org.keycloak.services.managers.UserSessionCrossDCManager;
import org.keycloak.services.managers.UserSessionManager; import org.keycloak.services.managers.UserSessionManager;
import org.keycloak.services.resources.Cors; import org.keycloak.services.resources.Cors;

View file

@ -49,7 +49,7 @@ import org.keycloak.representations.AccessToken;
import org.keycloak.services.CorsErrorResponseException; import org.keycloak.services.CorsErrorResponseException;
import org.keycloak.services.Urls; import org.keycloak.services.Urls;
import org.keycloak.services.clientpolicy.ClientPolicyException; import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.UserInfoRequestContext; import org.keycloak.services.clientpolicy.context.UserInfoRequestContext;
import org.keycloak.services.managers.AppAuthManager; import org.keycloak.services.managers.AppAuthManager;
import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.UserSessionCrossDCManager; import org.keycloak.services.managers.UserSessionCrossDCManager;

View file

@ -17,7 +17,10 @@
package org.keycloak.services.clientpolicy; package org.keycloak.services.clientpolicy;
import java.util.*; import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;

View file

@ -30,12 +30,12 @@ import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequest; import org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequest;
import org.keycloak.services.clientpolicy.AuthorizationRequestContext;
import org.keycloak.services.clientpolicy.ClientPolicyContext; import org.keycloak.services.clientpolicy.ClientPolicyContext;
import org.keycloak.services.clientpolicy.ClientPolicyException; import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.ClientPolicyLogger; import org.keycloak.services.clientpolicy.ClientPolicyLogger;
import org.keycloak.services.clientpolicy.ClientPolicyVote; import org.keycloak.services.clientpolicy.ClientPolicyVote;
import org.keycloak.services.clientpolicy.TokenRequestContext; import org.keycloak.services.clientpolicy.context.AuthorizationRequestContext;
import org.keycloak.services.clientpolicy.context.TokenRequestContext;
public class ClientScopesCondition extends AbstractClientPolicyConditionProvider { public class ClientScopesCondition extends AbstractClientPolicyConditionProvider {

View file

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

View file

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

View file

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

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

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

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. * limitations under the License.
*/ */
package org.keycloak.services.clientpolicy; package org.keycloak.services.clientpolicy.context;
import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.MultivaluedMap;

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. * and other contributors as indicated by the @author tags.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -15,31 +15,35 @@
* limitations under the License. * limitations under the License.
*/ */
package org.keycloak.services.clientpolicy; package org.keycloak.services.clientpolicy.context;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.representations.JsonWebToken; import org.keycloak.representations.JsonWebToken;
import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.services.clientpolicy.ClientPolicyContext;
/** /**
* Represents the context in the client registration/update by Dynamic Client Registration or Admin REST API. * Represents the context in the request to register/read/update/unregister client by Dynamic Client Registration or Admin REST API.
*/ */
public interface ClientUpdateContext extends ClientPolicyContext { public interface ClientCRUDContext extends ClientPolicyContext {
/** /**
* returns {@link ClientRepresentation} for creating or updating the current client. * returns {@link ClientRepresentation} for creating the new client or updating the existing client.
* *
* @return {@link ClientRepresentation} * @return {@link ClientRepresentation}
*/ */
ClientRepresentation getProposedClientRepresentation(); default ClientRepresentation getProposedClientRepresentation() {
return null;
}
/** /**
* returns {@link ClientModel} of the current client to be updated. * returns {@link ClientModel} of the existing client to be updated/read/updated/deleted.
* on REGISTER event, it returns null.
* *
* @return {@link ClientModel} * @return {@link ClientModel}
*/ */
default ClientModel getClientToBeUpdated() { default ClientModel getTargetClient() {
return null; return null;
} }
@ -48,19 +52,25 @@ public interface ClientUpdateContext extends ClientPolicyContext {
* *
* @return {@link UserModel} * @return {@link UserModel}
*/ */
UserModel getAuthenticatedUser(); default UserModel getAuthenticatedUser() {
return null;
}
/** /**
* returns {@link UserModel} of the authenticated client. * returns {@link UserModel} of the authenticated client.
* *
* @return {@link UserModel} * @return {@link UserModel}
*/ */
ClientModel getAuthenticatedClient(); default ClientModel getAuthenticatedClient() {
return null;
}
/** /**
* returns {@link JsonWebToken} of the token accompanied with registration/update client * returns {@link JsonWebToken} of the token accompanied with the request to register/read/update/unregister client
* *
* @return {@link JsonWebToken} * @return {@link JsonWebToken}
*/ */
JsonWebToken getToken(); default JsonWebToken getToken() {
return null;
}
} }

View file

@ -15,35 +15,21 @@
* limitations under the License. * limitations under the License.
*/ */
package org.keycloak.services.clientpolicy; package org.keycloak.services.clientpolicy.context;
import org.keycloak.models.ClientModel;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.JsonWebToken; import org.keycloak.representations.JsonWebToken;
import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.services.clientpolicy.ClientPolicyEvent; import org.keycloak.services.clientpolicy.ClientPolicyEvent;
import org.keycloak.services.clientregistration.ClientRegistrationContext; import org.keycloak.services.clientregistration.ClientRegistrationContext;
public class DynamicClientRegisterContext implements ClientUpdateContext { public class DynamicClientRegisterContext extends AbstractDynamicClientCRUDContext {
private final ClientRegistrationContext context; private final ClientRepresentation proposedClientRepresentation;
private JsonWebToken token;
private UserModel user;
private ClientModel client;
public DynamicClientRegisterContext(ClientRegistrationContext context, public DynamicClientRegisterContext(ClientRegistrationContext context, JsonWebToken token, RealmModel realm) {
JsonWebToken token, RealmModel realm) { super(context.getSession(), token, realm);
this.context = context; this.proposedClientRepresentation = context.getClient();
this.token = token;
if (token != null) {
if (token.getSubject() != null) {
this.user = context.getSession().users().getUserById(realm, token.getSubject());
}
if (token.getIssuedFor() != null) {
this.client = realm.getClientByClientId(token.getIssuedFor());
}
}
} }
@Override @Override
@ -53,21 +39,6 @@ public class DynamicClientRegisterContext implements ClientUpdateContext {
@Override @Override
public ClientRepresentation getProposedClientRepresentation() { public ClientRepresentation getProposedClientRepresentation() {
return context.getClient(); return proposedClientRepresentation;
}
@Override
public ClientModel getAuthenticatedClient() {
return client;
}
@Override
public UserModel getAuthenticatedUser() {
return user;
}
@Override
public JsonWebToken getToken() {
return token;
} }
} }

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. * limitations under the License.
*/ */
package org.keycloak.services.clientpolicy; package org.keycloak.services.clientpolicy.context;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.JsonWebToken; import org.keycloak.representations.JsonWebToken;
import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.services.clientpolicy.ClientPolicyEvent; import org.keycloak.services.clientpolicy.ClientPolicyEvent;
import org.keycloak.services.clientregistration.ClientRegistrationContext; import org.keycloak.services.clientregistration.ClientRegistrationContext;
public class DynamicClientUpdateContext implements ClientUpdateContext { public class DynamicClientUpdateContext extends AbstractDynamicClientCRUDContext {
private final ClientRegistrationContext context;
private final ClientModel clientToBeUpdated; private final ClientModel clientToBeUpdated;
private JsonWebToken token; private final ClientRepresentation proposedClientRepresentation;
private UserModel user;
private ClientModel client;
public DynamicClientUpdateContext(ClientRegistrationContext context, public DynamicClientUpdateContext(ClientRegistrationContext context, ClientModel proposedClientRepresentation, JsonWebToken token, RealmModel realm) {
ClientModel client, JsonWebToken token, RealmModel realm) { super(context.getSession(), token, realm);
this.context = context; this.clientToBeUpdated = proposedClientRepresentation;
this.clientToBeUpdated = client; this.proposedClientRepresentation = context.getClient();
this.token = token;
if (token != null) {
if (token.getSubject() != null) {
this.user = context.getSession().users().getUserById(realm, token.getSubject());
}
if (token.getIssuedFor() != null) {
this.client = realm.getClientByClientId(token.getIssuedFor());
}
}
} }
@Override @Override
@ -55,26 +42,11 @@ public class DynamicClientUpdateContext implements ClientUpdateContext {
@Override @Override
public ClientRepresentation getProposedClientRepresentation() { public ClientRepresentation getProposedClientRepresentation() {
return context.getClient(); return proposedClientRepresentation;
} }
@Override @Override
public ClientModel getClientToBeUpdated() { public ClientModel getTargetClient() {
return clientToBeUpdated; return clientToBeUpdated;
} }
@Override
public ClientModel getAuthenticatedClient() {
return client;
}
@Override
public UserModel getAuthenticatedUser() {
return user;
}
@Override
public JsonWebToken getToken() {
return token;
}
} }

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. * limitations under the License.
*/ */
package org.keycloak.services.clientpolicy; package org.keycloak.services.clientpolicy.context;
import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.MultivaluedMap;

View file

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

View file

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

View file

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

View file

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

View file

@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
package org.keycloak.services.clientpolicy; package org.keycloak.services.clientpolicy.context;
import org.keycloak.services.clientpolicy.ClientPolicyContext; import org.keycloak.services.clientpolicy.ClientPolicyContext;
import org.keycloak.services.clientpolicy.ClientPolicyEvent; import org.keycloak.services.clientpolicy.ClientPolicyEvent;

View file

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

View file

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

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.OAuth2CodeParser;
import org.keycloak.protocol.oidc.utils.OIDCResponseType; import org.keycloak.protocol.oidc.utils.OIDCResponseType;
import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.services.clientpolicy.AuthorizationRequestContext;
import org.keycloak.services.clientpolicy.ClientPolicyContext; import org.keycloak.services.clientpolicy.ClientPolicyContext;
import org.keycloak.services.clientpolicy.ClientPolicyException; import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.TokenRequestContext; import org.keycloak.services.clientpolicy.context.AuthorizationRequestContext;
import org.keycloak.services.clientpolicy.context.TokenRequestContext;
import org.keycloak.services.clientpolicy.executor.AbstractAugumentingClientRegistrationPolicyExecutor; import org.keycloak.services.clientpolicy.executor.AbstractAugumentingClientRegistrationPolicyExecutor;
public class PKCEEnforceExecutor extends AbstractAugumentingClientRegistrationPolicyExecutor { public class PKCEEnforceExecutor extends AbstractAugumentingClientRegistrationPolicyExecutor {

View file

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

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

View file

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

View file

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

View file

@ -28,13 +28,13 @@ import org.keycloak.crypto.Algorithm;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.protocol.oidc.OIDCConfigAttributes; import org.keycloak.protocol.oidc.OIDCConfigAttributes;
import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.services.clientpolicy.AdminClientRegisterContext;
import org.keycloak.services.clientpolicy.AdminClientUpdateContext;
import org.keycloak.services.clientpolicy.ClientPolicyContext; import org.keycloak.services.clientpolicy.ClientPolicyContext;
import org.keycloak.services.clientpolicy.ClientPolicyException; import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.ClientPolicyLogger; import org.keycloak.services.clientpolicy.ClientPolicyLogger;
import org.keycloak.services.clientpolicy.DynamicClientRegisterContext; import org.keycloak.services.clientpolicy.context.AdminClientRegisterContext;
import org.keycloak.services.clientpolicy.DynamicClientUpdateContext; import org.keycloak.services.clientpolicy.context.AdminClientUpdateContext;
import org.keycloak.services.clientpolicy.context.DynamicClientRegisterContext;
import org.keycloak.services.clientpolicy.context.DynamicClientUpdateContext;
public class SecureSigningAlgorithmEnforceExecutor implements ClientPolicyExecutorProvider { public class SecureSigningAlgorithmEnforceExecutor implements ClientPolicyExecutorProvider {

View file

@ -30,6 +30,9 @@ import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.oidc.OIDCClientRepresentation; import org.keycloak.representations.oidc.OIDCClientRepresentation;
import org.keycloak.services.ErrorResponseException; import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.ForbiddenException; import org.keycloak.services.ForbiddenException;
import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.context.DynamicClientRegisteredContext;
import org.keycloak.services.clientpolicy.context.DynamicClientUpdatedContext;
import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyManager; import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyManager;
import org.keycloak.services.clientregistration.policy.RegistrationAuth; import org.keycloak.services.clientregistration.policy.RegistrationAuth;
import org.keycloak.services.managers.ClientManager; import org.keycloak.services.managers.ClientManager;
@ -70,6 +73,7 @@ public abstract class AbstractClientRegistrationProvider implements ClientRegist
RepresentationToModel.createResourceServer(clientModel, session, true); RepresentationToModel.createResourceServer(clientModel, session, true);
} }
session.clientPolicy().triggerOnEvent(new DynamicClientRegisteredContext(context, clientModel, auth.getJwt(), realm));
ClientRegistrationPolicyManager.triggerAfterRegister(context, registrationAuth, clientModel); ClientRegistrationPolicyManager.triggerAfterRegister(context, registrationAuth, clientModel);
client = ModelToRepresentation.toRepresentation(clientModel, session); client = ModelToRepresentation.toRepresentation(clientModel, session);
@ -90,6 +94,8 @@ public abstract class AbstractClientRegistrationProvider implements ClientRegist
return client; return client;
} catch (ModelDuplicateException e) { } catch (ModelDuplicateException e) {
throw new ErrorResponseException(ErrorCodes.INVALID_CLIENT_METADATA, "Client Identifier in use", Response.Status.BAD_REQUEST); throw new ErrorResponseException(ErrorCodes.INVALID_CLIENT_METADATA, "Client Identifier in use", Response.Status.BAD_REQUEST);
} catch (ClientPolicyException cpe) {
throw new ErrorResponseException(cpe.getError(), cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
} }
} }
@ -134,6 +140,11 @@ public abstract class AbstractClientRegistrationProvider implements ClientRegist
rep.setRegistrationAccessToken(registrationAccessToken); rep.setRegistrationAccessToken(registrationAccessToken);
} }
try {
session.clientPolicy().triggerOnEvent(new DynamicClientUpdatedContext(session, client, auth.getJwt(), client.getRealm()));
} catch (ClientPolicyException cpe) {
throw new ErrorResponseException(cpe.getError(), cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
}
ClientRegistrationPolicyManager.triggerAfterUpdate(context, registrationAuth, client); ClientRegistrationPolicyManager.triggerAfterUpdate(context, registrationAuth, client);
event.client(client.getClientId()).success(); event.client(client.getClientId()).success();

View file

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

View file

@ -50,8 +50,11 @@ import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.idm.UserSessionRepresentation; import org.keycloak.representations.idm.UserSessionRepresentation;
import org.keycloak.services.ErrorResponse; import org.keycloak.services.ErrorResponse;
import org.keycloak.services.ErrorResponseException; import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.clientpolicy.AdminClientUpdateContext;
import org.keycloak.services.clientpolicy.ClientPolicyException; import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.context.AdminClientUnregisterContext;
import org.keycloak.services.clientpolicy.context.AdminClientUpdateContext;
import org.keycloak.services.clientpolicy.context.AdminClientUpdatedContext;
import org.keycloak.services.clientpolicy.context.AdminClientViewContext;
import org.keycloak.services.clientregistration.ClientRegistrationTokenUtils; import org.keycloak.services.clientregistration.ClientRegistrationTokenUtils;
import org.keycloak.services.clientregistration.policy.RegistrationAuth; import org.keycloak.services.clientregistration.policy.RegistrationAuth;
import org.keycloak.services.managers.ClientManager; import org.keycloak.services.managers.ClientManager;
@ -130,12 +133,8 @@ public class ClientResource {
auth.clients().requireConfigure(client); auth.clients().requireConfigure(client);
try { try {
session.clientPolicy().triggerOnEvent(new AdminClientUpdateContext(rep, auth.adminAuth(), client)); session.clientPolicy().triggerOnEvent(new AdminClientUpdateContext(rep, client, auth.adminAuth()));
} catch (ClientPolicyException cpe) {
throw new ErrorResponseException(cpe.getError(), cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
}
try {
updateClientFromRep(rep, client, session); updateClientFromRep(rep, client, session);
ValidationUtil.validateClient(session, client, false, r -> { ValidationUtil.validateClient(session, client, false, r -> {
@ -146,10 +145,14 @@ public class ClientResource {
Response.Status.BAD_REQUEST); Response.Status.BAD_REQUEST);
}); });
session.clientPolicy().triggerOnEvent(new AdminClientUpdatedContext(rep, client, auth.adminAuth()));
adminEvent.operation(OperationType.UPDATE).resourcePath(session.getContext().getUri()).representation(rep).success(); adminEvent.operation(OperationType.UPDATE).resourcePath(session.getContext().getUri()).representation(rep).success();
return Response.noContent().build(); return Response.noContent().build();
} catch (ModelDuplicateException e) { } catch (ModelDuplicateException e) {
return ErrorResponse.exists("Client already exists"); return ErrorResponse.exists("Client already exists");
} catch (ClientPolicyException cpe) {
throw new ErrorResponseException(cpe.getError(), cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
} }
} }
@ -162,6 +165,12 @@ public class ClientResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public ClientRepresentation getClient() { public ClientRepresentation getClient() {
try {
session.clientPolicy().triggerOnEvent(new AdminClientViewContext(client, auth.adminAuth()));
} catch (ClientPolicyException cpe) {
throw new ErrorResponseException(cpe.getError(), cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
}
auth.clients().requireView(client); auth.clients().requireView(client);
ClientRepresentation representation = ModelToRepresentation.toRepresentation(client, session); ClientRepresentation representation = ModelToRepresentation.toRepresentation(client, session);
@ -206,6 +215,12 @@ public class ClientResource {
throw new NotFoundException("Could not find client"); throw new NotFoundException("Could not find client");
} }
try {
session.clientPolicy().triggerOnEvent(new AdminClientUnregisterContext(client, auth.adminAuth()));
} catch (ClientPolicyException cpe) {
throw new ErrorResponseException(cpe.getError(), cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
}
new ClientManager(new RealmManager(session)).removeClient(realm, client); new ClientManager(new RealmManager(session)).removeClient(realm, client);
adminEvent.operation(OperationType.DELETE).resourcePath(session.getContext().getUri()).success(); adminEvent.operation(OperationType.DELETE).resourcePath(session.getContext().getUri()).success();
} }

View file

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

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; package org.keycloak.testsuite.client;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
@ -42,6 +43,7 @@ import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.function.Consumer; import java.util.function.Consumer;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
@ -423,10 +425,10 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
// Client CRUD operation by Admin REST API primitives // Client CRUD operation by Admin REST API primitives
protected String createClientByAdmin(String clientId, Consumer<ClientRepresentation> op) throws ClientPolicyException { protected String createClientByAdmin(String clientName, Consumer<ClientRepresentation> op) throws ClientPolicyException {
ClientRepresentation clientRep = new ClientRepresentation(); ClientRepresentation clientRep = new ClientRepresentation();
clientRep.setClientId(clientId); clientRep.setClientId(clientName);
clientRep.setName(clientId); clientRep.setName(clientName);
clientRep.setProtocol("openid-connect"); clientRep.setProtocol("openid-connect");
clientRep.setBearerOnly(Boolean.FALSE); clientRep.setBearerOnly(Boolean.FALSE);
clientRep.setPublicClient(Boolean.FALSE); clientRep.setPublicClient(Boolean.FALSE);
@ -435,7 +437,14 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
op.accept(clientRep); op.accept(clientRep);
Response resp = adminClient.realm(REALM_NAME).clients().create(clientRep); Response resp = adminClient.realm(REALM_NAME).clients().create(clientRep);
if (resp.getStatus() == Response.Status.BAD_REQUEST.getStatusCode()) { if (resp.getStatus() == Response.Status.BAD_REQUEST.getStatusCode()) {
throw new ClientPolicyException(Errors.INVALID_REGISTRATION, "registration error by admin"); String respBody = resp.readEntity(String.class);
Map<String, String> responseJson = null;
try {
responseJson = JsonSerialization.readValue(respBody, Map.class);
} catch (IOException e) {
fail();
}
throw new ClientPolicyException(responseJson.get(OAuth2Constants.ERROR), responseJson.get(OAuth2Constants.ERROR_DESCRIPTION));
} }
resp.close(); resp.close();
assertEquals(Response.Status.CREATED.getStatusCode(), resp.getStatus()); assertEquals(Response.Status.CREATED.getStatusCode(), resp.getStatus());
@ -445,21 +454,55 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
return cId; return cId;
} }
protected ClientRepresentation getClientByAdmin(String cId) { protected ClientRepresentation getClientByAdmin(String cId) throws ClientPolicyException {
ClientResource clientResource = adminClient.realm(REALM_NAME).clients().get(cId); ClientResource clientResource = adminClient.realm(REALM_NAME).clients().get(cId);
try {
return clientResource.toRepresentation(); return clientResource.toRepresentation();
} catch (BadRequestException bre) {
processClientPolicyExceptionByAdmin(bre);
}
return null;
} }
protected void updateClientByAdmin(String cId, Consumer<ClientRepresentation> op) { protected ClientRepresentation getClientByAdminWithName(String clientName) {
return adminClient.realm(REALM_NAME).clients().findByClientId(clientName).get(0);
}
protected void updateClientByAdmin(String cId, Consumer<ClientRepresentation> op) throws ClientPolicyException {
ClientResource clientResource = adminClient.realm(REALM_NAME).clients().get(cId); ClientResource clientResource = adminClient.realm(REALM_NAME).clients().get(cId);
ClientRepresentation clientRep = clientResource.toRepresentation(); ClientRepresentation clientRep = clientResource.toRepresentation();
op.accept(clientRep); op.accept(clientRep);
try {
clientResource.update(clientRep); clientResource.update(clientRep);
} catch (BadRequestException bre) {
processClientPolicyExceptionByAdmin(bre);
}
} }
protected void deleteClientByAdmin(String cId) { protected void deleteClientByAdmin(String cId) throws ClientPolicyException {
ClientResource clientResource = adminClient.realm(REALM_NAME).clients().get(cId); ClientResource clientResource = adminClient.realm(REALM_NAME).clients().get(cId);
try {
clientResource.remove(); clientResource.remove();
} catch (BadRequestException bre) {
processClientPolicyExceptionByAdmin(bre);
}
}
private void processClientPolicyExceptionByAdmin(BadRequestException bre) throws ClientPolicyException {
Response resp = bre.getResponse();
if (resp.getStatus() != Response.Status.BAD_REQUEST.getStatusCode()) {
resp.close();
return;
}
String respBody = resp.readEntity(String.class);
Map<String, String> responseJson = null;
try {
responseJson = JsonSerialization.readValue(respBody, Map.class);
} catch (IOException e) {
fail();
}
throw new ClientPolicyException(responseJson.get(OAuth2Constants.ERROR), responseJson.get(OAuth2Constants.ERROR_DESCRIPTION));
} }
// Registration/Initial Access Token acquisition for Dynamic Client Registration // Registration/Initial Access Token acquisition for Dynamic Client Registration

View file

@ -33,8 +33,7 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import javax.ws.rs.BadRequestException;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
@ -58,6 +57,7 @@ import org.keycloak.events.EventType;
import org.keycloak.jose.jws.Algorithm; import org.keycloak.jose.jws.Algorithm;
import org.keycloak.models.AdminRoles; import org.keycloak.models.AdminRoles;
import org.keycloak.models.Constants; import org.keycloak.models.Constants;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper; import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
import org.keycloak.protocol.oidc.OIDCConfigAttributes; import org.keycloak.protocol.oidc.OIDCConfigAttributes;
import org.keycloak.protocol.oidc.OIDCLoginProtocol; import org.keycloak.protocol.oidc.OIDCLoginProtocol;
@ -72,6 +72,7 @@ import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.oidc.OIDCClientRepresentation; import org.keycloak.representations.oidc.OIDCClientRepresentation;
import org.keycloak.representations.oidc.TokenMetadataRepresentation; import org.keycloak.representations.oidc.TokenMetadataRepresentation;
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
import org.keycloak.services.clientpolicy.ClientPolicyException; import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.DefaultClientPolicyProviderFactory; import org.keycloak.services.clientpolicy.DefaultClientPolicyProviderFactory;
import org.keycloak.services.clientpolicy.condition.AbstractClientPolicyConditionProviderFactory; import org.keycloak.services.clientpolicy.condition.AbstractClientPolicyConditionProviderFactory;
@ -100,6 +101,7 @@ import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.A
import org.keycloak.testsuite.client.resources.TestApplicationResourceUrls; import org.keycloak.testsuite.client.resources.TestApplicationResourceUrls;
import org.keycloak.testsuite.rest.resource.TestingOIDCEndpointsApplicationResource.AuthorizationEndpointRequestObject; import org.keycloak.testsuite.rest.resource.TestingOIDCEndpointsApplicationResource.AuthorizationEndpointRequestObject;
import org.keycloak.testsuite.services.clientpolicy.condition.TestRaiseExeptionConditionFactory; import org.keycloak.testsuite.services.clientpolicy.condition.TestRaiseExeptionConditionFactory;
import org.keycloak.testsuite.services.clientpolicy.executor.TestRaiseExeptionExecutorFactory;
import org.keycloak.testsuite.util.MutualTLSUtils; import org.keycloak.testsuite.util.MutualTLSUtils;
import org.keycloak.testsuite.util.OAuthClient; import org.keycloak.testsuite.util.OAuthClient;
@ -161,8 +163,8 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
clientRep.setClientAuthenticatorType(ClientIdAndSecretAuthenticator.PROVIDER_ID); clientRep.setClientAuthenticatorType(ClientIdAndSecretAuthenticator.PROVIDER_ID);
}); });
fail(); fail();
} catch (ClientPolicyException e) { } catch (ClientPolicyException cpe) {
assertEquals(Errors.INVALID_REGISTRATION, e.getMessage()); assertEquals(OAuthErrorException.INVALID_CLIENT_METADATA, cpe.getError());
} }
} }
@ -181,8 +183,8 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
try { try {
createClientByAdmin(generateSuffixedName(CLIENT_NAME), (ClientRepresentation clientRep) -> {}); createClientByAdmin(generateSuffixedName(CLIENT_NAME), (ClientRepresentation clientRep) -> {});
fail(); fail();
} catch (ClientPolicyException e) { } catch (ClientPolicyException cpe) {
assertEquals(Errors.INVALID_REGISTRATION, e.getMessage()); assertEquals(OAuthErrorException.INVALID_CLIENT_METADATA, cpe.getError());
} }
} }
@ -198,8 +200,8 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
clientRep.setClientAuthenticatorType(ClientIdAndSecretAuthenticator.PROVIDER_ID); clientRep.setClientAuthenticatorType(ClientIdAndSecretAuthenticator.PROVIDER_ID);
}); });
fail(); fail();
} catch (BadRequestException bre) { } catch (ClientPolicyException cpe) {
assertEquals("HTTP 400 Bad Request", bre.getMessage()); assertEquals(OAuthErrorException.INVALID_CLIENT_METADATA, cpe.getError());
} }
assertEquals(JWTClientSecretAuthenticator.PROVIDER_ID, getClientByAdmin(cId).getClientAuthenticatorType()); assertEquals(JWTClientSecretAuthenticator.PROVIDER_ID, getClientByAdmin(cId).getClientAuthenticatorType());
} }
@ -323,7 +325,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String conditionName = ClientRolesCondition_NAME; String conditionName = ClientRolesCondition_NAME;
createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList(SAMPLE_CLIENT_ROLE))); setConditionClientRoles(provider, Arrays.asList(SAMPLE_CLIENT_ROLE));
}); });
registerCondition(conditionName, policyName); registerCondition(conditionName, policyName);
logger.info("... Registered Condition : " + conditionName); logger.info("... Registered Condition : " + conditionName);
@ -331,7 +333,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
failLoginByNotFollowingPKCE(clientId); failLoginByNotFollowingPKCE(clientId);
updateCondition(conditionName, (ComponentRepresentation provider) -> { updateCondition(conditionName, (ComponentRepresentation provider) -> {
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList("anothor-client-role"))); setConditionClientRoles(provider, Arrays.asList("anothor-client-role"));
}); });
successfulLoginAndLogout(clientId, clientSecret); successfulLoginAndLogout(clientId, clientSecret);
@ -349,14 +351,14 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String roleConditionName = ClientRolesCondition_NAME; String roleConditionName = ClientRolesCondition_NAME;
createCondition(roleConditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { createCondition(roleConditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList(SAMPLE_CLIENT_ROLE))); setConditionClientRoles(provider, Arrays.asList(SAMPLE_CLIENT_ROLE));
}); });
registerCondition(roleConditionName, policyName); registerCondition(roleConditionName, policyName);
logger.info("... Registered Condition : " + roleConditionName); logger.info("... Registered Condition : " + roleConditionName);
String updateConditionName = ClientUpdateContextCondition_NAME; String updateConditionName = ClientUpdateContextCondition_NAME;
createCondition(updateConditionName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { createCondition(updateConditionName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionRegistrationMethods(provider, new ArrayList<>(Arrays.asList(ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER))); setConditionRegistrationMethods(provider, Arrays.asList(ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER));
}); });
registerCondition(updateConditionName, policyName); registerCondition(updateConditionName, policyName);
logger.info("... Registered Condition : " + updateConditionName); logger.info("... Registered Condition : " + updateConditionName);
@ -431,21 +433,21 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String roleConditionAlphaName = generateSuffixedName(ClientRolesCondition_NAME); String roleConditionAlphaName = generateSuffixedName(ClientRolesCondition_NAME);
createCondition(roleConditionAlphaName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { createCondition(roleConditionAlphaName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList(roleAlphaName, roleZetaName))); setConditionClientRoles(provider, Arrays.asList(roleAlphaName, roleZetaName));
}); });
registerCondition(roleConditionAlphaName, policyAlphaName); registerCondition(roleConditionAlphaName, policyAlphaName);
logger.info("... Registered Condition : " + roleConditionAlphaName); logger.info("... Registered Condition : " + roleConditionAlphaName);
String updateConditionAlphaName = generateSuffixedName(ClientUpdateContextCondition_NAME); String updateConditionAlphaName = generateSuffixedName(ClientUpdateContextCondition_NAME);
createCondition(updateConditionAlphaName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { createCondition(updateConditionAlphaName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionRegistrationMethods(provider, new ArrayList<>(Arrays.asList(ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER))); setConditionRegistrationMethods(provider, Arrays.asList(ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER));
}); });
registerCondition(updateConditionAlphaName, policyAlphaName); registerCondition(updateConditionAlphaName, policyAlphaName);
logger.info("... Registered Condition : " + updateConditionAlphaName); logger.info("... Registered Condition : " + updateConditionAlphaName);
String clientAuthExecutorAlphaName = generateSuffixedName(SecureClientAuthEnforceExecutor_NAME); String clientAuthExecutorAlphaName = generateSuffixedName(SecureClientAuthEnforceExecutor_NAME);
createExecutor(clientAuthExecutorAlphaName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { createExecutor(clientAuthExecutorAlphaName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setExecutorAcceptedClientAuthMethods(provider, new ArrayList<>(Arrays.asList(ClientIdAndSecretAuthenticator.PROVIDER_ID))); setExecutorAcceptedClientAuthMethods(provider, Arrays.asList(ClientIdAndSecretAuthenticator.PROVIDER_ID));
setExecutorAugmentActivate(provider); setExecutorAugmentActivate(provider);
setExecutorAugmentedClientAuthMethod(provider, ClientIdAndSecretAuthenticator.PROVIDER_ID); setExecutorAugmentedClientAuthMethod(provider, ClientIdAndSecretAuthenticator.PROVIDER_ID);
}); });
@ -458,7 +460,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String roleConditionBetaName = generateSuffixedName(ClientRolesCondition_NAME); String roleConditionBetaName = generateSuffixedName(ClientRolesCondition_NAME);
createCondition(roleConditionBetaName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { createCondition(roleConditionBetaName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList(roleBetaName, roleZetaName))); setConditionClientRoles(provider, Arrays.asList(roleBetaName, roleZetaName));
}); });
registerCondition(roleConditionBetaName, policyBetaName); registerCondition(roleConditionBetaName, policyBetaName);
logger.info("... Registered Condition : " + roleConditionBetaName); logger.info("... Registered Condition : " + roleConditionBetaName);
@ -507,8 +509,8 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
try { try {
createClientByAdmin(generateSuffixedName(CLIENT_NAME), (ClientRepresentation clientRep) -> {}); createClientByAdmin(generateSuffixedName(CLIENT_NAME), (ClientRepresentation clientRep) -> {});
fail(); fail();
} catch (ClientPolicyException e) { } catch (ClientPolicyException cpe) {
assertEquals(Errors.INVALID_REGISTRATION, e.getMessage()); assertEquals(OAuthErrorException.SERVER_ERROR, cpe.getError());
} }
} }
@ -611,15 +613,15 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String conditionName = ClientUpdateSourceHostsCondition_NAME; String conditionName = ClientUpdateSourceHostsCondition_NAME;
createCondition(conditionName, ClientUpdateSourceHostsConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { createCondition(conditionName, ClientUpdateSourceHostsConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionClientUpdateSourceHosts(provider, new ArrayList<>(Arrays.asList("localhost", "127.0.0.1"))); setConditionClientUpdateSourceHosts(provider, Arrays.asList("localhost", "127.0.0.1"));
}); });
registerCondition(conditionName, policyName); registerCondition(conditionName, policyName);
logger.info("... Registered Condition : " + conditionName); logger.info("... Registered Condition : " + conditionName);
String executorName = SecureClientAuthEnforceExecutor_NAME; String executorName = SecureClientAuthEnforceExecutor_NAME;
createExecutor(executorName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { createExecutor(executorName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setExecutorAcceptedClientAuthMethods(provider, new ArrayList<>(Arrays.asList( setExecutorAcceptedClientAuthMethods(provider, Arrays.asList(
JWTClientAuthenticator.PROVIDER_ID, JWTClientSecretAuthenticator.PROVIDER_ID, X509ClientAuthenticator.PROVIDER_ID))); JWTClientAuthenticator.PROVIDER_ID, JWTClientSecretAuthenticator.PROVIDER_ID, X509ClientAuthenticator.PROVIDER_ID));
}); });
registerExecutor(executorName, policyName); registerExecutor(executorName, policyName);
logger.info("... Registered Executor : " + executorName); logger.info("... Registered Executor : " + executorName);
@ -631,12 +633,12 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
clientRep.setSecret(clientSecret); clientRep.setSecret(clientSecret);
}); });
fail(); fail();
} catch (ClientPolicyException e) { } catch (ClientPolicyException cpe) {
assertEquals(Errors.INVALID_REGISTRATION, e.getMessage()); assertEquals(OAuthErrorException.INVALID_CLIENT_METADATA, cpe.getError());
} }
updateCondition(conditionName, (ComponentRepresentation provider) -> { updateCondition(conditionName, (ComponentRepresentation provider) -> {
setConditionClientUpdateSourceHosts(provider, new ArrayList<>(Arrays.asList("example.com"))); setConditionClientUpdateSourceHosts(provider, Arrays.asList("example.com"));
}); });
try { try {
createClientByAdmin(clientId, (ClientRepresentation clientRep) -> { createClientByAdmin(clientId, (ClientRepresentation clientRep) -> {
@ -655,14 +657,14 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String conditionName = ClientUpdateSourceGroupsCondition_NAME; String conditionName = ClientUpdateSourceGroupsCondition_NAME;
createCondition(conditionName, ClientUpdateSourceGroupsConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { createCondition(conditionName, ClientUpdateSourceGroupsConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionClientUpdateSourceGroups(provider, new ArrayList<>(Arrays.asList("topGroup"))); setConditionClientUpdateSourceGroups(provider, Arrays.asList("topGroup"));
}); });
registerCondition(conditionName, policyName); registerCondition(conditionName, policyName);
logger.info("... Registered Condition : " + conditionName); logger.info("... Registered Condition : " + conditionName);
String executorName = SecureClientAuthEnforceExecutor_NAME; String executorName = SecureClientAuthEnforceExecutor_NAME;
createExecutor(executorName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { createExecutor(executorName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setExecutorAcceptedClientAuthMethods(provider, new ArrayList<>(Arrays.asList(JWTClientAuthenticator.PROVIDER_ID))); setExecutorAcceptedClientAuthMethods(provider,Arrays.asList(JWTClientAuthenticator.PROVIDER_ID));
}); });
registerExecutor(executorName, policyName); registerExecutor(executorName, policyName);
logger.info("... Registered Executor : " + executorName); logger.info("... Registered Executor : " + executorName);
@ -690,14 +692,14 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String conditionName = ClientUpdateSourceRolesCondition_NAME; String conditionName = ClientUpdateSourceRolesCondition_NAME;
createCondition(conditionName, ClientUpdateSourceRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { createCondition(conditionName, ClientUpdateSourceRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionUpdatingClientSourceRoles(provider, new ArrayList<>(Arrays.asList(AdminRoles.CREATE_CLIENT))); setConditionUpdatingClientSourceRoles(provider, Arrays.asList(AdminRoles.CREATE_CLIENT));
}); });
registerCondition(conditionName, policyName); registerCondition(conditionName, policyName);
logger.info("... Registered Condition : " + conditionName); logger.info("... Registered Condition : " + conditionName);
String executorName = SecureClientAuthEnforceExecutor_NAME; String executorName = SecureClientAuthEnforceExecutor_NAME;
createExecutor(executorName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { createExecutor(executorName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setExecutorAcceptedClientAuthMethods(provider, new ArrayList<>(Arrays.asList(JWTClientAuthenticator.PROVIDER_ID))); setExecutorAcceptedClientAuthMethods(provider, Arrays.asList(JWTClientAuthenticator.PROVIDER_ID));
}); });
registerExecutor(executorName, policyName); registerExecutor(executorName, policyName);
logger.info("... Registered Executor : " + executorName); logger.info("... Registered Executor : " + executorName);
@ -725,7 +727,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String conditionName = ClientScopesCondition_NAME; String conditionName = ClientScopesCondition_NAME;
createCondition(conditionName, ClientScopesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { createCondition(conditionName, ClientScopesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionClientScopes(provider, new ArrayList<>(Arrays.asList("offline_access", "microprofile-jwt"))); setConditionClientScopes(provider, Arrays.asList("offline_access", "microprofile-jwt"));
}); });
registerCondition(conditionName, policyName); registerCondition(conditionName, policyName);
logger.info("... Registered Condition : " + conditionName); logger.info("... Registered Condition : " + conditionName);
@ -759,7 +761,6 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
} }
} }
@Test @Test
public void testClientAccessTypeCondition() throws ClientRegistrationException, ClientPolicyException { public void testClientAccessTypeCondition() throws ClientRegistrationException, ClientPolicyException {
String policyName = POLICY_NAME; String policyName = POLICY_NAME;
@ -768,7 +769,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String conditionName = ClientAccessTypeCondition_NAME; String conditionName = ClientAccessTypeCondition_NAME;
createCondition(conditionName, ClientAccessTypeConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { createCondition(conditionName, ClientAccessTypeConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionClientAccessType(provider, new ArrayList<>(Arrays.asList(ClientAccessTypeConditionFactory.TYPE_CONFIDENTIAL))); setConditionClientAccessType(provider, Arrays.asList(ClientAccessTypeConditionFactory.TYPE_CONFIDENTIAL));
}); });
registerCondition(conditionName, policyName); registerCondition(conditionName, policyName);
logger.info("... Registered Condition : " + conditionName); logger.info("... Registered Condition : " + conditionName);
@ -805,7 +806,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String conditionName = ClientRolesCondition_NAME; String conditionName = ClientRolesCondition_NAME;
createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList(SAMPLE_CLIENT_ROLE))); setConditionClientRoles(provider, Arrays.asList(SAMPLE_CLIENT_ROLE));
}); });
registerCondition(conditionName, policyName); registerCondition(conditionName, policyName);
logger.info("... Registered Condition : " + conditionName); logger.info("... Registered Condition : " + conditionName);
@ -869,7 +870,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String conditionName = ClientRolesCondition_NAME; String conditionName = ClientRolesCondition_NAME;
createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList(SAMPLE_CLIENT_ROLE))); setConditionClientRoles(provider, Arrays.asList(SAMPLE_CLIENT_ROLE));
}); });
registerCondition(conditionName, policyName); registerCondition(conditionName, policyName);
logger.info("... Registered Condition : " + conditionName); logger.info("... Registered Condition : " + conditionName);
@ -972,7 +973,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String roleBetaName = "sample-client-role-beta"; String roleBetaName = "sample-client-role-beta";
String conditionName = ClientRolesCondition_NAME; String conditionName = ClientRolesCondition_NAME;
createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList(roleBetaName))); setConditionClientRoles(provider, Arrays.asList(roleBetaName));
}); });
registerCondition(conditionName, policyName); registerCondition(conditionName, policyName);
logger.info("... Registered Condition : " + conditionName); logger.info("... Registered Condition : " + conditionName);
@ -1023,10 +1024,10 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String conditionName = ClientUpdateContextCondition_NAME; String conditionName = ClientUpdateContextCondition_NAME;
createCondition(conditionName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { createCondition(conditionName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionRegistrationMethods(provider, new ArrayList<>(Arrays.asList( setConditionRegistrationMethods(provider, Arrays.asList(
ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER, ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER,
ClientUpdateContextConditionFactory.BY_INITIAL_ACCESS_TOKEN, ClientUpdateContextConditionFactory.BY_INITIAL_ACCESS_TOKEN,
ClientUpdateContextConditionFactory.BY_REGISTRATION_ACCESS_TOKEN))); ClientUpdateContextConditionFactory.BY_REGISTRATION_ACCESS_TOKEN));
}); });
registerCondition(conditionName, policyName); registerCondition(conditionName, policyName);
logger.info("... Registered Condition : " + conditionName); logger.info("... Registered Condition : " + conditionName);
@ -1044,8 +1045,8 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
clientRep.getAttributes().put(OIDCConfigAttributes.USER_INFO_RESPONSE_SIGNATURE_ALG, Algorithm.none.name()); clientRep.getAttributes().put(OIDCConfigAttributes.USER_INFO_RESPONSE_SIGNATURE_ALG, Algorithm.none.name());
}); });
fail(); fail();
} catch (ClientPolicyException e) { } catch (ClientPolicyException cpe) {
assertEquals(Errors.INVALID_REGISTRATION, e.getMessage()); assertEquals(OAuthErrorException.INVALID_REQUEST, cpe.getError());
} }
// create by Admin REST API - success // create by Admin REST API - success
@ -1062,32 +1063,32 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
try { try {
updateClientByAdmin(cAppAdminId, (ClientRepresentation clientRep) -> { updateClientByAdmin(cAppAdminId, (ClientRepresentation clientRep) -> {
clientRep.setAttributes(new HashMap<>()); clientRep.setAttributes(new HashMap<>());
clientRep.getAttributes().put(OIDCConfigAttributes.ACCESS_TOKEN_SIGNED_RESPONSE_ALG, Algorithm.RS512.name()); clientRep.getAttributes().put(OIDCConfigAttributes.ACCESS_TOKEN_SIGNED_RESPONSE_ALG, org.keycloak.crypto.Algorithm.RS512);
}); });
} catch (BadRequestException bre) { } catch (ClientPolicyException cpe) {
assertEquals("HTTP 400 Bad Request", bre.getMessage()); assertEquals(Errors.INVALID_REQUEST, cpe.getError());
} }
ClientRepresentation cRep = getClientByAdmin(cAppAdminId); ClientRepresentation cRep = getClientByAdmin(cAppAdminId);
assertEquals(Algorithm.ES256.name(), cRep.getAttributes().get(OIDCConfigAttributes.ACCESS_TOKEN_SIGNED_RESPONSE_ALG)); assertEquals(org.keycloak.crypto.Algorithm.ES256, cRep.getAttributes().get(OIDCConfigAttributes.ACCESS_TOKEN_SIGNED_RESPONSE_ALG));
// update by Admin REST API - success // update by Admin REST API - success
updateClientByAdmin(cAppAdminId, (ClientRepresentation clientRep) -> { updateClientByAdmin(cAppAdminId, (ClientRepresentation clientRep) -> {
clientRep.setAttributes(new HashMap<>()); clientRep.setAttributes(new HashMap<>());
clientRep.getAttributes().put(OIDCConfigAttributes.ACCESS_TOKEN_SIGNED_RESPONSE_ALG, Algorithm.PS384.name()); clientRep.getAttributes().put(OIDCConfigAttributes.ACCESS_TOKEN_SIGNED_RESPONSE_ALG, org.keycloak.crypto.Algorithm.PS384);
}); });
cRep = getClientByAdmin(cAppAdminId); cRep = getClientByAdmin(cAppAdminId);
assertEquals(Algorithm.PS384.name(), cRep.getAttributes().get(OIDCConfigAttributes.ACCESS_TOKEN_SIGNED_RESPONSE_ALG)); assertEquals(org.keycloak.crypto.Algorithm.PS384, cRep.getAttributes().get(OIDCConfigAttributes.ACCESS_TOKEN_SIGNED_RESPONSE_ALG));
// create dynamically - fail // create dynamically - fail
try { try {
createClientByAdmin(generateSuffixedName("App-in-Dynamic"), (ClientRepresentation clientRep) -> { createClientByAdmin(generateSuffixedName("App-in-Dynamic"), (ClientRepresentation clientRep) -> {
clientRep.setSecret("secret"); clientRep.setSecret("secret");
clientRep.setAttributes(new HashMap<>()); clientRep.setAttributes(new HashMap<>());
clientRep.getAttributes().put(OIDCConfigAttributes.USER_INFO_RESPONSE_SIGNATURE_ALG, Algorithm.RS384.name()); clientRep.getAttributes().put(OIDCConfigAttributes.USER_INFO_RESPONSE_SIGNATURE_ALG, org.keycloak.crypto.Algorithm.RS384);
}); });
fail(); fail();
} catch (ClientPolicyException e) { } catch (ClientPolicyException cpe) {
assertEquals(Errors.INVALID_REGISTRATION, e.getMessage()); assertEquals(OAuthErrorException.INVALID_REQUEST, cpe.getError());
} }
// create dynamically - success // create dynamically - success
@ -1103,7 +1104,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
// update dynamically - fail // update dynamically - fail
try { try {
updateClientDynamically(cAppDynamicClientId, (OIDCClientRepresentation clientRep) -> { updateClientDynamically(cAppDynamicClientId, (OIDCClientRepresentation clientRep) -> {
clientRep.setIdTokenSignedResponseAlg(Algorithm.RS256.name()); clientRep.setIdTokenSignedResponseAlg(org.keycloak.crypto.Algorithm.RS256);
}); });
fail(); fail();
} catch (ClientRegistrationException e) { } catch (ClientRegistrationException e) {
@ -1126,10 +1127,10 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String conditionName = ClientUpdateContextCondition_NAME; String conditionName = ClientUpdateContextCondition_NAME;
createCondition(conditionName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { createCondition(conditionName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionRegistrationMethods(provider, new ArrayList<>(Arrays.asList( setConditionRegistrationMethods(provider, Arrays.asList(
ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER, ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER,
ClientUpdateContextConditionFactory.BY_INITIAL_ACCESS_TOKEN, ClientUpdateContextConditionFactory.BY_INITIAL_ACCESS_TOKEN,
ClientUpdateContextConditionFactory.BY_REGISTRATION_ACCESS_TOKEN))); ClientUpdateContextConditionFactory.BY_REGISTRATION_ACCESS_TOKEN));
}); });
registerCondition(conditionName, policyName); registerCondition(conditionName, policyName);
logger.info("... Registered Condition : " + conditionName); logger.info("... Registered Condition : " + conditionName);
@ -1148,9 +1149,9 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
assertEquals(ERR_MSG_CLIENT_REG_FAIL, e.getMessage()); assertEquals(ERR_MSG_CLIENT_REG_FAIL, e.getMessage());
} }
updateCondition(conditionName, (ComponentRepresentation provider) -> { updateCondition(conditionName, (ComponentRepresentation provider) -> {
setConditionRegistrationMethods(provider, new ArrayList<>(Arrays.asList( setConditionRegistrationMethods(provider, Arrays.asList(
ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER, ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER,
ClientUpdateContextConditionFactory.BY_REGISTRATION_ACCESS_TOKEN))); ClientUpdateContextConditionFactory.BY_REGISTRATION_ACCESS_TOKEN));
}); });
try { try {
createClientDynamically(generateSuffixedName(CLIENT_NAME), (OIDCClientRepresentation clientRep) -> {}); createClientDynamically(generateSuffixedName(CLIENT_NAME), (OIDCClientRepresentation clientRep) -> {});
@ -1172,7 +1173,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
String conditionName = ClientRolesCondition_NAME; String conditionName = ClientRolesCondition_NAME;
createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList(roleAlphaName, roleZetaName))); setConditionClientRoles(provider, Arrays.asList(roleAlphaName, roleZetaName));
}); });
registerCondition(conditionName, policyName); registerCondition(conditionName, policyName);
logger.info("... Registered Condition : " + conditionName); logger.info("... Registered Condition : " + conditionName);
@ -1317,6 +1318,73 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
} }
} }
@Test
public void testExtendedClientPolicyIntefacesForClientRegistrationPolicyMigration() throws ClientRegistrationException, ClientPolicyException {
String policyName = "MyPolicy";
String clientName = "ByAdmin-App" + KeycloakModelUtils.generateId().substring(0, 7);
String executorName = "TestRaiseExeptionExecutor";
createPolicy(policyName, DefaultClientPolicyProviderFactory.PROVIDER_ID, null, null, null);
logger.info("... Created Policy : " + policyName);
createCondition("AnyClientConditionFactory", AnyClientConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
});
registerCondition("AnyClientConditionFactory", policyName);
logger.info("... Registered Condition : AnyClientConditionFactory");
createExecutor(executorName, TestRaiseExeptionExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
provider.getConfig().put(TestRaiseExeptionExecutorFactory.TARGET_CP_EVENTS, Arrays.asList(ClientPolicyEvent.REGISTERED.toString()));
});
registerExecutor(executorName, policyName);
logger.info("... Registered Executor : " + executorName);
String clientId = null;
try {
try {
createClientByAdmin(clientName, (ClientRepresentation clientRep) -> {
});
fail();
} catch (ClientPolicyException cpe) {
assertEquals(ClientPolicyEvent.REGISTERED.toString(), cpe.getError());
}
updateTargetCPEvents(executorName, Arrays.asList(ClientPolicyEvent.UPDATED));
clientId = getClientByAdminWithName(clientName).getId();
assertEquals(true, getClientByAdmin(clientId).isEnabled());
try {
updateClientByAdmin(clientId, (ClientRepresentation clientRep) -> {
clientRep.setEnabled(false);
});
fail();
} catch (ClientPolicyException cpe) {
assertEquals(ClientPolicyEvent.UPDATED.toString(), cpe.getError());
}
assertEquals(false, getClientByAdmin(clientId).isEnabled());
updateTargetCPEvents(executorName, Arrays.asList(ClientPolicyEvent.VIEW));
try {
getClientByAdmin(clientId);
} catch (ClientPolicyException cpe) {
assertEquals(ClientPolicyEvent.VIEW.toString(), cpe.getError());
}
updateTargetCPEvents(executorName, Arrays.asList(ClientPolicyEvent.UNREGISTER));
try {
deleteClientByAdmin(clientId);
} catch (ClientPolicyException cpe) {
assertEquals(ClientPolicyEvent.UNREGISTER.toString(), cpe.getError());
}
} finally {
updateExecutor(executorName, (ComponentRepresentation provider) -> {
provider.getConfig().put(TestRaiseExeptionExecutorFactory.TARGET_CP_EVENTS, Collections.singletonList((String)null));
});
deleteClientByAdmin(clientId);
}
// TODO : For dynamic client registration, the existing test scheme can not distinguish when the exception happens on which event so that the migrated client policy executors test them afterwards.
}
private void checkMtlsFlow() throws IOException { private void checkMtlsFlow() throws IOException {
// Check login. // Check login.
OAuthClient.AuthorizationEndpointResponse loginResponse = oauth.doLogin(TEST_USER_NAME, TEST_USER_PASSWORD); OAuthClient.AuthorizationEndpointResponse loginResponse = oauth.doLogin(TEST_USER_NAME, TEST_USER_PASSWORD);
@ -1438,18 +1506,20 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
createPolicy(policyName, DefaultClientPolicyProviderFactory.PROVIDER_ID, null, null, null); createPolicy(policyName, DefaultClientPolicyProviderFactory.PROVIDER_ID, null, null, null);
logger.info("... Created Policy : " + policyName); logger.info("... Created Policy : " + policyName);
createCondition(ClientUpdateContextCondition_NAME, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { String conditionName = ClientUpdateContextCondition_NAME;
setConditionRegistrationMethods(provider, new ArrayList<>(Arrays.asList(ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER))); createCondition(conditionName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionRegistrationMethods(provider, Arrays.asList(ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER));
}); });
registerCondition(ClientUpdateContextCondition_NAME, policyName); registerCondition(conditionName, policyName);
logger.info("... Registered Condition : " + ClientUpdateContextCondition_NAME); logger.info("... Registered Condition : " + conditionName);
createExecutor(SecureClientAuthEnforceExecutor_NAME, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { String executorName = SecureClientAuthEnforceExecutor_NAME;
setExecutorAcceptedClientAuthMethods(provider, new ArrayList<>(Arrays.asList( createExecutor(executorName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
JWTClientAuthenticator.PROVIDER_ID, JWTClientSecretAuthenticator.PROVIDER_ID, X509ClientAuthenticator.PROVIDER_ID))); setExecutorAcceptedClientAuthMethods(provider, Arrays.asList(
JWTClientAuthenticator.PROVIDER_ID, JWTClientSecretAuthenticator.PROVIDER_ID, X509ClientAuthenticator.PROVIDER_ID));
}); });
registerExecutor(SecureClientAuthEnforceExecutor_NAME, policyName); registerExecutor(executorName, policyName);
logger.info("... Registered Executor : " + SecureClientAuthEnforceExecutor_NAME); logger.info("... Registered Executor : " + executorName);
} }
@ -1458,31 +1528,35 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
createPolicy(policyName, DefaultClientPolicyProviderFactory.PROVIDER_ID, null, null, null); createPolicy(policyName, DefaultClientPolicyProviderFactory.PROVIDER_ID, null, null, null);
logger.info("... Created Policy : " + policyName); logger.info("... Created Policy : " + policyName);
createCondition(ClientUpdateContextCondition_NAME, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { String conditionName = ClientUpdateContextCondition_NAME;
setConditionRegistrationMethods(provider, new ArrayList<>(Arrays.asList(ClientUpdateContextConditionFactory.BY_INITIAL_ACCESS_TOKEN))); createCondition(conditionName, ClientUpdateContextConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionRegistrationMethods(provider, Arrays.asList(ClientUpdateContextConditionFactory.BY_INITIAL_ACCESS_TOKEN));
}); });
registerCondition(ClientUpdateContextCondition_NAME, policyName); registerCondition(conditionName, policyName);
logger.info("... Registered Condition : " + ClientUpdateContextCondition_NAME); logger.info("... Registered Condition : " + conditionName);
createCondition(ClientRolesCondition_NAME, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { conditionName = ClientRolesCondition_NAME;
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList(SAMPLE_CLIENT_ROLE))); createCondition(conditionName, ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionClientRoles(provider, Arrays.asList(SAMPLE_CLIENT_ROLE));
}); });
registerCondition(ClientRolesCondition_NAME, policyName); registerCondition(conditionName, policyName);
logger.info("... Registered Condition : " + ClientRolesCondition_NAME); logger.info("... Registered Condition : " + conditionName);
createExecutor(SecureClientAuthEnforceExecutor_NAME, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { String executorName = SecureClientAuthEnforceExecutor_NAME;
setExecutorAcceptedClientAuthMethods(provider, new ArrayList<>(Arrays.asList(ClientIdAndSecretAuthenticator.PROVIDER_ID, JWTClientAuthenticator.PROVIDER_ID))); createExecutor(executorName, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setExecutorAcceptedClientAuthMethods(provider, Arrays.asList(ClientIdAndSecretAuthenticator.PROVIDER_ID, JWTClientAuthenticator.PROVIDER_ID));
setExecutorAugmentedClientAuthMethod(provider, ClientIdAndSecretAuthenticator.PROVIDER_ID); setExecutorAugmentedClientAuthMethod(provider, ClientIdAndSecretAuthenticator.PROVIDER_ID);
setExecutorAugmentActivate(provider); setExecutorAugmentActivate(provider);
}); });
registerExecutor(SecureClientAuthEnforceExecutor_NAME, policyName); registerExecutor(executorName, policyName);
logger.info("... Registered Executor : " + SecureClientAuthEnforceExecutor_NAME); logger.info("... Registered Executor : " + executorName);
createExecutor(PKCEEnforceExecutor_NAME, PKCEEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> { executorName = PKCEEnforceExecutor_NAME;
createExecutor(executorName, PKCEEnforceExecutorFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setExecutorAugmentActivate(provider); setExecutorAugmentActivate(provider);
}); });
registerExecutor(PKCEEnforceExecutor_NAME, policyName); registerExecutor(executorName, policyName);
logger.info("... Registered Executor : " + PKCEEnforceExecutor_NAME); logger.info("... Registered Executor : " + executorName);
} }
private void successfulLoginAndLogout(String clientId, String clientSecret) { private void successfulLoginAndLogout(String clientId, String clientSecret) {
@ -1587,4 +1661,9 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
assertEquals(ERR_MSG_MISSING_NONCE, oauth.getCurrentQuery().get(OAuth2Constants.ERROR_DESCRIPTION)); assertEquals(ERR_MSG_MISSING_NONCE, oauth.getCurrentQuery().get(OAuth2Constants.ERROR_DESCRIPTION));
} }
private void updateTargetCPEvents(String executorName, List<ClientPolicyEvent> events) {
updateExecutor(executorName, (ComponentRepresentation provider) -> {
provider.getConfig().put(TestRaiseExeptionExecutorFactory.TARGET_CP_EVENTS, events.stream().map(i->i.toString()).collect(Collectors.toList()));
});
}
} }