KEYCLOAK-14209 Client policies admin console support. Changing of format of JSON for client policies and profiles. Remove support for default policies (#7969)
* KEYCLOAK-14209 KEYCLOAK-17988 Client policies admin console support. Changing of format of JSON for client policies and profiles. Refactoring based on feedback and remove builtin policies
This commit is contained in:
parent
f37a24dd91
commit
a6d4316084
99 changed files with 3267 additions and 1993 deletions
|
@ -17,18 +17,19 @@
|
|||
|
||||
package org.keycloak.representations.idm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
* Client Policies' (the set of all Client Policy) external representation class
|
||||
*
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ClientPoliciesRepresentation {
|
||||
protected List<ClientPolicyRepresentation> policies;
|
||||
protected List<ClientPolicyRepresentation> policies = new ArrayList<>();
|
||||
|
||||
public List<ClientPolicyRepresentation> getPolicies() {
|
||||
return policies;
|
||||
|
@ -38,4 +39,17 @@ public class ClientPoliciesRepresentation {
|
|||
this.policies = policies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return JsonSerialization.mapper.convertValue(this, JsonNode.class).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof ClientPoliciesRepresentation)) return false;
|
||||
JsonNode jsonNode = JsonSerialization.mapper.convertValue(this, JsonNode.class);
|
||||
JsonNode jsonNodeThat = JsonSerialization.mapper.convertValue(obj, JsonNode.class);
|
||||
return jsonNode.equals(jsonNodeThat);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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.representations.idm;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAnyGetter;
|
||||
import com.fasterxml.jackson.annotation.JsonAnySetter;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Just adds some type-safety to the ClientPolicyConditionConfiguration
|
||||
*
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public class ClientPolicyConditionConfigurationRepresentation {
|
||||
|
||||
private Map<String, Object> configAsMap = new HashMap<>();
|
||||
|
||||
@JsonProperty("is-negative-logic")
|
||||
private Boolean negativeLogic;
|
||||
|
||||
public Boolean isNegativeLogic() {
|
||||
return negativeLogic;
|
||||
}
|
||||
|
||||
public void setNegativeLogic(Boolean negativeLogic) {
|
||||
this.negativeLogic = negativeLogic;
|
||||
}
|
||||
|
||||
@JsonAnyGetter
|
||||
public Map<String, Object> getConfigAsMap() {
|
||||
return configAsMap;
|
||||
}
|
||||
|
||||
@JsonAnySetter
|
||||
public void setConfigAsMap(String name, Object value) {
|
||||
this.configAsMap.put(name, value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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.representations.idm;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ClientPolicyConditionRepresentation {
|
||||
|
||||
@JsonProperty("condition")
|
||||
private String conditionProviderId;
|
||||
|
||||
private ClientPolicyConditionConfigurationRepresentation configuration;
|
||||
|
||||
public ClientPolicyConditionRepresentation() {
|
||||
}
|
||||
|
||||
public ClientPolicyConditionRepresentation(String conditionProviderId, ClientPolicyConditionConfigurationRepresentation configuration) {
|
||||
this.conditionProviderId = conditionProviderId;
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
public String getConditionProviderId() {
|
||||
return conditionProviderId;
|
||||
}
|
||||
|
||||
public void setConditionProviderId(String conditionProviderId) {
|
||||
this.conditionProviderId = conditionProviderId;
|
||||
}
|
||||
|
||||
public ClientPolicyConditionConfigurationRepresentation getConfiguration() {
|
||||
return configuration;
|
||||
}
|
||||
|
||||
public void setConfiguration(ClientPolicyConditionConfigurationRepresentation configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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.representations.idm;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAnyGetter;
|
||||
import com.fasterxml.jackson.annotation.JsonAnySetter;
|
||||
|
||||
/**
|
||||
* Just adds some type-safety to the ClientPolicyExecutorConfiguration
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ClientPolicyExecutorConfigurationRepresentation {
|
||||
|
||||
private Map<String, Object> configAsMap = new HashMap<>();
|
||||
|
||||
@JsonAnyGetter
|
||||
public Map<String, Object> getConfigAsMap() {
|
||||
return configAsMap;
|
||||
}
|
||||
|
||||
@JsonAnySetter
|
||||
public void setConfigAsMap(String name, Object value) {
|
||||
this.configAsMap.put(name, value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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.representations.idm;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ClientPolicyExecutorRepresentation {
|
||||
|
||||
@JsonProperty("executor")
|
||||
private String executorProviderId;
|
||||
|
||||
private ClientPolicyExecutorConfigurationRepresentation configuration;
|
||||
|
||||
public ClientPolicyExecutorRepresentation() {
|
||||
}
|
||||
|
||||
public ClientPolicyExecutorRepresentation(String executorProviderId, ClientPolicyExecutorConfigurationRepresentation configuration) {
|
||||
this.executorProviderId = executorProviderId;
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
public String getExecutorProviderId() {
|
||||
return executorProviderId;
|
||||
}
|
||||
|
||||
public void setExecutorProviderId(String providerId) {
|
||||
this.executorProviderId = providerId;
|
||||
}
|
||||
|
||||
public ClientPolicyExecutorConfigurationRepresentation getConfiguration() {
|
||||
return configuration;
|
||||
}
|
||||
|
||||
public void setConfiguration(ClientPolicyExecutorConfigurationRepresentation configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
}
|
|
@ -19,21 +19,17 @@ package org.keycloak.representations.idm;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
/**
|
||||
* Client Policy's external representation class
|
||||
*
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ClientPolicyRepresentation {
|
||||
|
||||
protected String name;
|
||||
protected String description;
|
||||
protected Boolean builtin;
|
||||
protected Boolean enable;
|
||||
protected List<Object> conditions;
|
||||
protected Boolean enabled;
|
||||
protected List<ClientPolicyConditionRepresentation> conditions;
|
||||
protected List<String> profiles;
|
||||
|
||||
public String getName() {
|
||||
|
@ -52,27 +48,19 @@ public class ClientPolicyRepresentation {
|
|||
this.description = description;
|
||||
}
|
||||
|
||||
public Boolean isBuiltin() {
|
||||
return builtin;
|
||||
public Boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setBuiltin(Boolean builtin) {
|
||||
this.builtin = builtin;
|
||||
public void setEnabled(Boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public Boolean isEnable() {
|
||||
return enable;
|
||||
}
|
||||
|
||||
public void setEnable(Boolean enable) {
|
||||
this.enable = enable;
|
||||
}
|
||||
|
||||
public List<Object> getConditions() {
|
||||
public List<ClientPolicyConditionRepresentation> getConditions() {
|
||||
return conditions;
|
||||
}
|
||||
|
||||
public void setConditions(List<Object> conditions) {
|
||||
public void setConditions(List<ClientPolicyConditionRepresentation> conditions) {
|
||||
this.conditions = conditions;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,20 +19,16 @@ package org.keycloak.representations.idm;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
/**
|
||||
* Client Profile's external representation class
|
||||
*
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ClientProfileRepresentation {
|
||||
|
||||
protected String name;
|
||||
protected String description;
|
||||
protected Boolean builtin;
|
||||
protected List<Object> executors;
|
||||
protected List<ClientPolicyExecutorRepresentation> executors;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
|
@ -50,19 +46,11 @@ public class ClientProfileRepresentation {
|
|||
this.description = description;
|
||||
}
|
||||
|
||||
public Boolean isBuiltin() {
|
||||
return builtin;
|
||||
}
|
||||
|
||||
public void setBuiltin(Boolean builtin) {
|
||||
this.builtin = builtin;
|
||||
}
|
||||
|
||||
public List<Object> getExecutors() {
|
||||
public List<ClientPolicyExecutorRepresentation> getExecutors() {
|
||||
return executors;
|
||||
}
|
||||
|
||||
public void setExecutors(List<Object> executors) {
|
||||
public void setExecutors(List<ClientPolicyExecutorRepresentation> executors) {
|
||||
this.executors = executors;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,18 +17,25 @@
|
|||
|
||||
package org.keycloak.representations.idm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
* Client Profiles' (the set of all Client Profile) external representation class
|
||||
*
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ClientProfilesRepresentation {
|
||||
protected List<ClientProfileRepresentation> profiles;
|
||||
|
||||
private List<ClientProfileRepresentation> profiles = new ArrayList<>();
|
||||
|
||||
// Global profiles, which are builtin in Keycloak.
|
||||
@JsonProperty("globalProfiles")
|
||||
private List<ClientProfileRepresentation> globalProfiles;
|
||||
|
||||
public List<ClientProfileRepresentation> getProfiles() {
|
||||
return profiles;
|
||||
|
@ -38,4 +45,24 @@ public class ClientProfilesRepresentation {
|
|||
this.profiles = profiles;
|
||||
}
|
||||
|
||||
public List<ClientProfileRepresentation> getGlobalProfiles() {
|
||||
return globalProfiles;
|
||||
}
|
||||
|
||||
public void setGlobalProfiles(List<ClientProfileRepresentation> globalProfiles) {
|
||||
this.globalProfiles = globalProfiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return JsonSerialization.mapper.convertValue(this, JsonNode.class).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof ClientProfilesRepresentation)) return false;
|
||||
JsonNode jsonNode = JsonSerialization.mapper.convertValue(this, JsonNode.class);
|
||||
JsonNode jsonNodeThat = JsonSerialization.mapper.convertValue(obj, JsonNode.class);
|
||||
return jsonNode.equals(jsonNodeThat);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@ import javax.ws.rs.GET;
|
|||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.keycloak.representations.idm.ClientPoliciesRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
|
@ -17,10 +17,10 @@ public interface ClientPoliciesPoliciesResource {
|
|||
@GET
|
||||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
String getPolicies();
|
||||
ClientPoliciesRepresentation getPolicies();
|
||||
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
Response updatePolicies(final String json);
|
||||
void updatePolicies(final ClientPoliciesRepresentation clientPolicies);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,10 +4,11 @@ import javax.ws.rs.Consumes;
|
|||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.keycloak.representations.idm.ClientProfilesRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
|
@ -17,9 +18,14 @@ public interface ClientPoliciesProfilesResource {
|
|||
@GET
|
||||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
String getProfiles();
|
||||
ClientProfilesRepresentation getProfiles(@QueryParam("include-global-profiles") Boolean includeGlobalProfiles);
|
||||
|
||||
/**
|
||||
* Update client profiles in the realm. The "globalProfiles" field of clientProfiles is ignored as it is not possible to update global profiles
|
||||
*
|
||||
* @param clientProfiles
|
||||
*/
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
Response updateProfiles(final String json);
|
||||
void updateProfiles(final ClientProfilesRepresentation clientProfiles);
|
||||
}
|
||||
|
|
|
@ -50,7 +50,6 @@ public class QuarkusKeycloakApplication extends KeycloakApplication {
|
|||
QuarkusKeycloakSessionFactory instance = QuarkusKeycloakSessionFactory.getInstance();
|
||||
sessionFactory = instance;
|
||||
instance.init();
|
||||
instance.create().clientPolicy().setupClientPoliciesOnKeycloakApp("/keycloak-default-client-profiles.json", "/keycloak-default-client-policies.json");
|
||||
sessionFactory.publish(new PostMigrationEvent());
|
||||
}
|
||||
|
||||
|
|
|
@ -120,4 +120,8 @@ public final class Constants {
|
|||
*/
|
||||
public static final String STORAGE_BATCH_SIZE = "org.keycloak.storage.batch_size";
|
||||
|
||||
// Client Polices Realm Attributes Keys
|
||||
public static final String CLIENT_PROFILES = "client-policies.profiles";
|
||||
public static final String CLIENT_POLICIES = "client-policies.policies";
|
||||
|
||||
}
|
||||
|
|
|
@ -95,8 +95,8 @@ public class ModelToRepresentation {
|
|||
REALM_EXCLUDED_ATTRIBUTES.add("webAuthnPolicyAvoidSameAuthenticatorRegisterPasswordless");
|
||||
REALM_EXCLUDED_ATTRIBUTES.add("webAuthnPolicyAcceptableAaguidsPasswordless");
|
||||
|
||||
REALM_EXCLUDED_ATTRIBUTES.add("client-policies.profiles");
|
||||
REALM_EXCLUDED_ATTRIBUTES.add("client-policies.policies");
|
||||
REALM_EXCLUDED_ATTRIBUTES.add(Constants.CLIENT_POLICIES);
|
||||
REALM_EXCLUDED_ATTRIBUTES.add(Constants.CLIENT_PROFILES);
|
||||
}
|
||||
|
||||
|
||||
|
@ -295,7 +295,7 @@ public class ModelToRepresentation {
|
|||
return rep;
|
||||
}
|
||||
|
||||
public static RealmRepresentation toRepresentation(RealmModel realm, boolean internal) {
|
||||
public static RealmRepresentation toRepresentation(KeycloakSession session, RealmModel realm, boolean internal) {
|
||||
RealmRepresentation rep = new RealmRepresentation();
|
||||
rep.setId(realm.getId());
|
||||
rep.setRealm(realm.getName());
|
||||
|
@ -447,6 +447,8 @@ public class ModelToRepresentation {
|
|||
exportGroups(realm, rep);
|
||||
}
|
||||
|
||||
session.clientPolicy().updateRealmRepresentationFromModel(realm, rep);
|
||||
|
||||
rep.setAttributes(stripRealmAttributesIncludedAsFields(realm.getAttributes()));
|
||||
|
||||
if (!internal) {
|
||||
|
|
|
@ -1181,6 +1181,7 @@ public class RepresentationToModel {
|
|||
realm.setWebAuthnPolicyPasswordless(webAuthnPolicy);
|
||||
|
||||
updateCibaSettings(rep, realm);
|
||||
session.clientPolicy().updateRealmModelFromRepresentation(realm, rep);
|
||||
|
||||
if (rep.getSmtpServer() != null) {
|
||||
Map<String, String> config = new HashMap(rep.getSmtpServer());
|
||||
|
|
|
@ -1,762 +0,0 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.representations.idm.ClientPoliciesRepresentation;
|
||||
import org.keycloak.representations.idm.ClientPolicyRepresentation;
|
||||
import org.keycloak.representations.idm.ClientProfileRepresentation;
|
||||
import org.keycloak.representations.idm.ClientProfilesRepresentation;
|
||||
import org.keycloak.services.clientpolicy.condition.ClientPolicyConditionConfiguration;
|
||||
import org.keycloak.services.clientpolicy.condition.ClientPolicyConditionProvider;
|
||||
import org.keycloak.services.clientpolicy.executor.ClientPolicyExecutorConfiguration;
|
||||
import org.keycloak.services.clientpolicy.executor.ClientPolicyExecutorProvider;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* Utilities for treating client policies/profiles
|
||||
*
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public class ClientPoliciesUtil {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ClientPoliciesUtil.class);
|
||||
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
/**
|
||||
* gets existing client profiles in a realm as representation.
|
||||
* not return null.
|
||||
*/
|
||||
public static ClientProfilesRepresentation getClientProfilesRepresentation(KeycloakSession session, RealmModel realm) throws ClientPolicyException {
|
||||
ClientProfilesRepresentation profilesRep = null;
|
||||
String profilesJson = null;
|
||||
|
||||
// get existing profiles json
|
||||
if (realm != null) {
|
||||
profilesJson = session.clientPolicy().getClientProfilesJsonString(realm);
|
||||
} else {
|
||||
// if realm not specified, use builtin profiles set in keycloak's binary.
|
||||
profilesJson = session.clientPolicy().getClientProfilesOnKeycloakApp();
|
||||
}
|
||||
|
||||
// deserialize existing profiles (json -> representation)
|
||||
if (profilesJson == null) {
|
||||
return new ClientProfilesRepresentation();
|
||||
}
|
||||
profilesRep = convertClientProfilesJsonToRepresentation(profilesJson);
|
||||
if (profilesRep == null) {
|
||||
return new ClientProfilesRepresentation();
|
||||
}
|
||||
|
||||
return profilesRep;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets existing client profiles in a realm as model.
|
||||
* not return null.
|
||||
*/
|
||||
public static Map<String, ClientProfileModel> getClientProfilesModel(KeycloakSession session, RealmModel realm) {
|
||||
// get existing profiles as json
|
||||
String profilesJson = session.clientPolicy().getClientProfilesJsonString(realm);
|
||||
if (profilesJson == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
// deserialize existing profiles (json -> representation)
|
||||
ClientProfilesRepresentation profilesRep = null;
|
||||
try {
|
||||
profilesRep = convertClientProfilesJsonToRepresentation(profilesJson);
|
||||
} catch (ClientPolicyException e) {
|
||||
logger.warnv("Failed to serialize client profiles json string. err={0}, errDetail={1}", e.getError(), e.getErrorDetail());
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
if (profilesRep == null || profilesRep.getProfiles() == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
// constructing existing profiles (representation -> model)
|
||||
Map<String, ClientProfileModel> profileMap = new HashMap<>();
|
||||
for (ClientProfileRepresentation profileRep : profilesRep.getProfiles()) {
|
||||
// ignore profile without name
|
||||
if (profileRep.getName() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ClientProfileModel profileModel = new ClientProfileModel();
|
||||
profileModel.setName(profileRep.getName());
|
||||
profileModel.setDescription(profileRep.getDescription());
|
||||
if (profileRep.isBuiltin() != null) {
|
||||
profileModel.setBuiltin(profileRep.isBuiltin().booleanValue());
|
||||
} else {
|
||||
profileModel.setBuiltin(false);
|
||||
}
|
||||
|
||||
if (profileRep.getExecutors() == null) {
|
||||
profileModel.setExecutors(new ArrayList<>());
|
||||
profileMap.put(profileRep.getName(), profileModel);
|
||||
continue;
|
||||
}
|
||||
|
||||
List<Object> executors = new ArrayList<>();
|
||||
if (profileRep.getExecutors() != null) {
|
||||
profileRep.getExecutors().stream().forEach(obj->{
|
||||
JsonNode node = objectMapper.convertValue(obj, JsonNode.class);
|
||||
node.fields().forEachRemaining(executor->{
|
||||
ClientPolicyExecutorProvider provider = session.getProvider(ClientPolicyExecutorProvider.class, executor.getKey());
|
||||
if (provider == null) {
|
||||
// executor's provider not found. just skip it.
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ClientPolicyExecutorConfiguration configuration = (ClientPolicyExecutorConfiguration) JsonSerialization.mapper.convertValue(executor.getValue(), provider.getExecutorConfigurationClass());
|
||||
provider.setupConfiguration(configuration);
|
||||
executors.add(provider);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
logger.warnv("failed for Configuration Setup :: error = {0}", iae.getMessage());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
profileModel.setExecutors(executors);
|
||||
|
||||
profileMap.put(profileRep.getName(), profileModel);
|
||||
}
|
||||
|
||||
return profileMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* get validated and modified builtin client profiles set on keycloak app as representation.
|
||||
* it is loaded from json file enclosed in keycloak's binary.
|
||||
* not return null.
|
||||
*/
|
||||
public static ClientProfilesRepresentation getValidatedBuiltinClientProfilesRepresentation(KeycloakSession session, InputStream is) throws ClientPolicyException {
|
||||
// load builtin client profiles representation
|
||||
ClientProfilesRepresentation proposedProfilesRep = null;
|
||||
try {
|
||||
proposedProfilesRep = JsonSerialization.readValue(is, ClientProfilesRepresentation.class);
|
||||
} catch (Exception e) {
|
||||
throw new ClientPolicyException("failed to deserialize builtin proposed client profiles json string.", e.getMessage());
|
||||
}
|
||||
if (proposedProfilesRep == null) {
|
||||
return new ClientProfilesRepresentation();
|
||||
}
|
||||
|
||||
// no profile contained (it is valid)
|
||||
List<ClientProfileRepresentation> proposedProfileRepList = proposedProfilesRep.getProfiles();
|
||||
if (proposedProfileRepList == null || proposedProfileRepList.isEmpty()) {
|
||||
return new ClientProfilesRepresentation();
|
||||
}
|
||||
|
||||
// duplicated profile name is not allowed.
|
||||
if (proposedProfileRepList.size() != proposedProfileRepList.stream().map(i->i.getName()).distinct().count()) {
|
||||
throw new ClientPolicyException("proposed builtin client profile name duplicated.");
|
||||
}
|
||||
|
||||
// construct validated and modified profiles from builtin profiles in JSON file enclosed in keycloak binary.
|
||||
ClientProfilesRepresentation updatingProfilesRep = new ClientProfilesRepresentation();
|
||||
updatingProfilesRep.setProfiles(new ArrayList<>());
|
||||
List<ClientProfileRepresentation> updatingProfileList = updatingProfilesRep.getProfiles();
|
||||
|
||||
for (ClientProfileRepresentation proposedProfileRep : proposedProfilesRep.getProfiles()) {
|
||||
if (proposedProfileRep.getName() == null) {
|
||||
throw new ClientPolicyException("client profile without its name not allowed.");
|
||||
}
|
||||
|
||||
// ignore proposed ordinal profile because builtin profile can only be added.
|
||||
if (proposedProfileRep.isBuiltin() == null || !proposedProfileRep.isBuiltin()) {
|
||||
throw new ClientPolicyException("ordinal client profile not allowed.");
|
||||
}
|
||||
|
||||
ClientProfileRepresentation profileRep = new ClientProfileRepresentation();
|
||||
profileRep.setName(proposedProfileRep.getName());
|
||||
profileRep.setDescription(proposedProfileRep.getDescription());
|
||||
profileRep.setBuiltin(Boolean.TRUE);
|
||||
|
||||
profileRep.setExecutors(new ArrayList<>()); // to prevent returning null
|
||||
if (proposedProfileRep.getExecutors() != null) {
|
||||
for (Object executor : proposedProfileRep.getExecutors()) {
|
||||
if (isValidExecutor(session, executor) == false) {
|
||||
throw new ClientPolicyException("proposed client profile contains the executor with its invalid configuration.");
|
||||
}
|
||||
profileRep.getExecutors().add(executor);
|
||||
}
|
||||
}
|
||||
|
||||
updatingProfileList.add(profileRep);
|
||||
}
|
||||
|
||||
return updatingProfilesRep;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert client profiles as representation to json.
|
||||
* can return null.
|
||||
*/
|
||||
public static String convertClientProfilesRepresentationToJson(ClientProfilesRepresentation reps) throws ClientPolicyException {
|
||||
return convertRepresentationToJson(reps);
|
||||
}
|
||||
|
||||
/**
|
||||
* convert client profiles as json to representation.
|
||||
* not return null.
|
||||
*/
|
||||
private static ClientProfilesRepresentation convertClientProfilesJsonToRepresentation(String json) throws ClientPolicyException {
|
||||
return convertJsonToRepresentation(json, ClientProfilesRepresentation.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* get validated and modified client profiles as json.
|
||||
* it can be constructed by merging proposed client profiles with existing client profiles.
|
||||
* can return null.
|
||||
*/
|
||||
public static String getValidatedClientProfilesJson(KeycloakSession session, RealmModel realm, ClientProfilesRepresentation proposedProfilesRep) throws ClientPolicyException {
|
||||
return convertClientProfilesRepresentationToJson(getValidatedClientProfilesRepresentation(session, realm, proposedProfilesRep));
|
||||
}
|
||||
|
||||
/**
|
||||
* get validated and modified client profiles as representation.
|
||||
* it can be constructed by merging proposed client profiles with existing client profiles.
|
||||
* not return null.
|
||||
*/
|
||||
private static ClientProfilesRepresentation getValidatedClientProfilesRepresentation(KeycloakSession session, RealmModel realm, ClientProfilesRepresentation proposedProfilesRep) throws ClientPolicyException {
|
||||
if (proposedProfilesRep == null) {
|
||||
proposedProfilesRep = new ClientProfilesRepresentation();
|
||||
}
|
||||
if (realm == null) {
|
||||
throw new ClientPolicyException("realm not specified.");
|
||||
}
|
||||
|
||||
// deserialize existing profiles (json -> representation)
|
||||
ClientProfilesRepresentation existingProfilesRep = null;
|
||||
String existingProfilesJson = session.clientPolicy().getClientProfilesJsonString(realm);
|
||||
if (existingProfilesJson != null) {
|
||||
existingProfilesRep = convertClientProfilesJsonToRepresentation(existingProfilesJson);
|
||||
if (existingProfilesRep == null) {
|
||||
existingProfilesRep = new ClientProfilesRepresentation();
|
||||
}
|
||||
} else {
|
||||
existingProfilesRep = new ClientProfilesRepresentation();
|
||||
}
|
||||
|
||||
// no profile contained (it is valid)
|
||||
// back to initial builtin profiles
|
||||
List<ClientProfileRepresentation> proposedProfileRepList = proposedProfilesRep.getProfiles();
|
||||
if (proposedProfileRepList == null || proposedProfileRepList.isEmpty()) {
|
||||
proposedProfileRepList = new ArrayList<>();
|
||||
proposedProfilesRep.setProfiles(new ArrayList<>());
|
||||
}
|
||||
|
||||
// duplicated profile name is not allowed.
|
||||
if (proposedProfileRepList.size() != proposedProfileRepList.stream().map(i->i.getName()).distinct().count()) {
|
||||
throw new ClientPolicyException("proposed client profile name duplicated.");
|
||||
}
|
||||
|
||||
// construct updating profiles from existing profiles and proposed profiles
|
||||
ClientProfilesRepresentation updatingProfilesRep = new ClientProfilesRepresentation();
|
||||
updatingProfilesRep.setProfiles(new ArrayList<>());
|
||||
List<ClientProfileRepresentation> updatingProfileList = updatingProfilesRep.getProfiles();
|
||||
|
||||
// add existing builtin profiles to updating profiles
|
||||
List<ClientProfileRepresentation> existingProfileList = existingProfilesRep.getProfiles();
|
||||
if (existingProfileList != null && !existingProfileList.isEmpty()) {
|
||||
existingProfileList.stream().filter(i->i.isBuiltin()).forEach(i->updatingProfileList.add(i));
|
||||
}
|
||||
|
||||
for (ClientProfileRepresentation proposedProfileRep : proposedProfilesRep.getProfiles()) {
|
||||
if (proposedProfileRep.getName() == null) {
|
||||
throw new ClientPolicyException("client profile without its name not allowed.");
|
||||
}
|
||||
|
||||
// newly proposed builtin profile not allowed because builtin profile cannot added/deleted/modified.
|
||||
if (proposedProfileRep.isBuiltin() != null && proposedProfileRep.isBuiltin()) {
|
||||
throw new ClientPolicyException("newly builtin proposed client profile not allowed.");
|
||||
}
|
||||
|
||||
// not allow to overwrite builtin profiles
|
||||
if (updatingProfileList.stream().anyMatch(i->proposedProfileRep.getName().equals(i.getName()))) {
|
||||
throw new ClientPolicyException("proposed client profile name is the same one of the builtin profile.");
|
||||
}
|
||||
|
||||
// basically, proposed profile totally overrides existing profile
|
||||
ClientProfileRepresentation profileRep = new ClientProfileRepresentation();
|
||||
profileRep.setName(proposedProfileRep.getName());
|
||||
profileRep.setDescription(proposedProfileRep.getDescription());
|
||||
profileRep.setBuiltin(Boolean.FALSE);
|
||||
profileRep.setExecutors(new ArrayList<>());
|
||||
if (proposedProfileRep.getExecutors() != null) {
|
||||
for (Object executor : proposedProfileRep.getExecutors()) {
|
||||
if (isValidExecutor(session, executor) == false) {
|
||||
throw new ClientPolicyException("proposed client profile contains the executor with its invalid configuration.");
|
||||
}
|
||||
profileRep.getExecutors().add(executor);
|
||||
}
|
||||
}
|
||||
|
||||
updatingProfileList.add(profileRep);
|
||||
}
|
||||
|
||||
return updatingProfilesRep;
|
||||
}
|
||||
|
||||
/**
|
||||
* get validated and modified builtin client profiles in a realm as representation.
|
||||
* it can be constructed by merging proposed client profiles with existing client profiles.
|
||||
* not return null.
|
||||
*/
|
||||
public static ClientProfilesRepresentation getValidatedClientProfilesRepresentation(KeycloakSession session, RealmModel realm, String profilesJson) throws ClientPolicyException {
|
||||
if (profilesJson == null) {
|
||||
throw new ClientPolicyException("no client profiles json.");
|
||||
}
|
||||
|
||||
// deserialize existing profiles (json -> representation)
|
||||
ClientProfilesRepresentation proposedProfilesRep = convertClientProfilesJsonToRepresentation(profilesJson);
|
||||
|
||||
return getValidatedClientProfilesRepresentation(session, realm, proposedProfilesRep);
|
||||
}
|
||||
|
||||
/**
|
||||
* check whether the proposed executor's provider can be found in keycloak's ClientPolicyExecutorProvider list.
|
||||
* not return null.
|
||||
*/
|
||||
private static boolean isValidExecutor(KeycloakSession session, Object executor) {
|
||||
return isValidComponent(session, executor, "executor", (String providerId) -> {
|
||||
Set<String> providerSet = session.listProviderIds(ClientPolicyExecutorProvider.class);
|
||||
if (providerSet != null && providerSet.contains(providerId)) {
|
||||
return true;
|
||||
}
|
||||
logger.warnv("no executor provider found. providerId = {0}", providerId);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get existing client policies in a realm as representation.
|
||||
* not return null.
|
||||
*/
|
||||
public static ClientPoliciesRepresentation getClientPoliciesRepresentation(KeycloakSession session, RealmModel realm) throws ClientPolicyException {
|
||||
ClientPoliciesRepresentation policiesRep = null;
|
||||
String policiesJson = null;
|
||||
|
||||
// get existing policies json
|
||||
if (realm != null) {
|
||||
policiesJson = session.clientPolicy().getClientPoliciesJsonString(realm);
|
||||
} else {
|
||||
// if realm not specified, use builtin policies set in keycloak's binary.
|
||||
policiesJson = session.clientPolicy().getClientPoliciesOnKeycloakApp();
|
||||
}
|
||||
|
||||
// deserialize existing policies (json -> representation)
|
||||
if (policiesJson == null) {
|
||||
return new ClientPoliciesRepresentation();
|
||||
}
|
||||
policiesRep = convertClientPoliciesJsonToRepresentation(policiesJson);
|
||||
if (policiesRep == null) {
|
||||
return new ClientPoliciesRepresentation();
|
||||
}
|
||||
|
||||
return policiesRep;
|
||||
}
|
||||
|
||||
/**
|
||||
* get existing enabled client policies in a realm as model.
|
||||
* not return null.
|
||||
*/
|
||||
public static List<ClientPolicyModel> getEnabledClientProfilesModel(KeycloakSession session, RealmModel realm) {
|
||||
// get existing profiles as json
|
||||
String policiesJson = session.clientPolicy().getClientPoliciesJsonString(realm);
|
||||
if (policiesJson == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// deserialize existing policies (json -> representation)
|
||||
ClientPoliciesRepresentation policiesRep = null;
|
||||
try {
|
||||
policiesRep = convertClientPoliciesJsonToRepresentation(policiesJson);
|
||||
} catch (ClientPolicyException e) {
|
||||
logger.warnv("Failed to serialize client policies json string. err={0}, errDetail={1}", e.getError(), e.getErrorDetail());
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (policiesRep == null || policiesRep.getPolicies() == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// constructing existing policies (representation -> model)
|
||||
List<ClientPolicyModel> policyList = new ArrayList<>();
|
||||
for (ClientPolicyRepresentation policyRep: policiesRep.getPolicies()) {
|
||||
// ignore policy without name
|
||||
if (policyRep.getName() == null) {
|
||||
continue;
|
||||
}
|
||||
// pick up only enabled policy
|
||||
if (policyRep.isEnable() == null || policyRep.isEnable() == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ClientPolicyModel policyModel = new ClientPolicyModel();
|
||||
policyModel.setName(policyRep.getName());
|
||||
policyModel.setDescription(policyRep.getDescription());
|
||||
policyModel.setEnable(true);
|
||||
if (policyRep.isBuiltin() != null) {
|
||||
policyModel.setBuiltin(policyRep.isBuiltin().booleanValue());
|
||||
} else {
|
||||
policyModel.setBuiltin(false);
|
||||
}
|
||||
|
||||
List<Object> conditions = new ArrayList<>();
|
||||
if (policyRep.getConditions() != null) {
|
||||
policyRep.getConditions().stream().forEach(obj->{
|
||||
JsonNode node = objectMapper.convertValue(obj, JsonNode.class);
|
||||
node.fields().forEachRemaining(condition->{
|
||||
ClientPolicyConditionProvider provider = session.getProvider(ClientPolicyConditionProvider.class, condition.getKey());
|
||||
if (provider == null) {
|
||||
// condition's provider not found. just skip it.
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ClientPolicyConditionConfiguration configuration = (ClientPolicyConditionConfiguration) JsonSerialization.mapper.convertValue(condition.getValue(), provider.getConditionConfigurationClass());
|
||||
provider.setupConfiguration(configuration);
|
||||
conditions.add(provider);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
logger.warnv("failed for Configuration Setup :: error = {0}", iae.getMessage());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
policyModel.setConditions(conditions);
|
||||
|
||||
if (policyRep.getProfiles() != null) {
|
||||
policyModel.setProfiles(policyRep.getProfiles().stream().collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
policyList.add(policyModel);
|
||||
}
|
||||
|
||||
return policyList;
|
||||
}
|
||||
|
||||
/**
|
||||
* get validated and modified builtin client policies set on keycloak app as representation.
|
||||
* it is loaded from json file enclosed in keycloak's binary.
|
||||
* not return null.
|
||||
*/
|
||||
public static ClientPoliciesRepresentation getValidatedBuiltinClientPoliciesRepresentation(KeycloakSession session, InputStream is) throws ClientPolicyException {
|
||||
// load builtin client policies representation
|
||||
ClientPoliciesRepresentation proposedPoliciesRep = null;
|
||||
try {
|
||||
proposedPoliciesRep = JsonSerialization.readValue(is, ClientPoliciesRepresentation.class);
|
||||
} catch (Exception e) {
|
||||
throw new ClientPolicyException("failed to deserialize builtin proposed client policies json string.", e.getMessage());
|
||||
}
|
||||
if (proposedPoliciesRep == null) {
|
||||
proposedPoliciesRep = new ClientPoliciesRepresentation();
|
||||
}
|
||||
|
||||
// no policy contained (it is valid)
|
||||
List<ClientPolicyRepresentation> proposedPolicyRepList = proposedPoliciesRep.getPolicies();
|
||||
if (proposedPolicyRepList == null || proposedPolicyRepList.isEmpty()) {
|
||||
return new ClientPoliciesRepresentation();
|
||||
}
|
||||
|
||||
// duplicated policy name is not allowed.
|
||||
if (proposedPolicyRepList.size() != proposedPolicyRepList.stream().map(i->i.getName()).distinct().count()) {
|
||||
throw new ClientPolicyException("proposed builtin client policy name duplicated.");
|
||||
}
|
||||
|
||||
// construct validated and modified policies from builtin profiles in JSON file enclosed in keycloak binary.
|
||||
ClientPoliciesRepresentation updatingPoliciesRep = new ClientPoliciesRepresentation();
|
||||
updatingPoliciesRep.setPolicies(new ArrayList<>());
|
||||
List<ClientPolicyRepresentation> updatingPoliciesList = updatingPoliciesRep.getPolicies();
|
||||
|
||||
for (ClientPolicyRepresentation proposedPolicyRep : proposedPoliciesRep.getPolicies()) {
|
||||
if (proposedPolicyRep.getName() == null) {
|
||||
throw new ClientPolicyException("proposed client policy name missing.");
|
||||
}
|
||||
|
||||
// ignore proposed ordinal policy because builtin policy can only be added.
|
||||
if (proposedPolicyRep.isBuiltin() == null || !proposedPolicyRep.isBuiltin()) {
|
||||
throw new ClientPolicyException("ordinal client policy not allowed.");
|
||||
}
|
||||
|
||||
ClientPolicyRepresentation policyRep = new ClientPolicyRepresentation();
|
||||
policyRep.setName(proposedPolicyRep.getName());
|
||||
policyRep.setDescription(proposedPolicyRep.getDescription());
|
||||
policyRep.setBuiltin(Boolean.TRUE);
|
||||
Boolean enabled = (proposedPolicyRep.isEnable() != null) ? proposedPolicyRep.isEnable() : Boolean.FALSE;
|
||||
policyRep.setEnable(enabled);
|
||||
|
||||
policyRep.setConditions(new ArrayList<>());
|
||||
if (proposedPolicyRep.getConditions() != null) {
|
||||
for (Object condition : proposedPolicyRep.getConditions()) {
|
||||
if (isValidCondition(session, condition) == false) {
|
||||
throw new ClientPolicyException("the proposed client policy contains the condition with its invalid configuration.");
|
||||
}
|
||||
policyRep.getConditions().add(condition);
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> existingProfileNames = new HashSet<>();
|
||||
ClientProfilesRepresentation reps = getClientProfilesRepresentation(session, null);
|
||||
reps.getProfiles().stream().map(profile->profile.getName()).forEach(profileName->existingProfileNames.add(profileName));
|
||||
policyRep.setProfiles(new ArrayList<>());
|
||||
if (proposedPolicyRep.getProfiles() != null) {
|
||||
for (String profileName : proposedPolicyRep.getProfiles()) {
|
||||
if (existingProfileNames.contains(profileName) == false) {
|
||||
throw new ClientPolicyException("referring not existing client profile not allowed.");
|
||||
}
|
||||
}
|
||||
proposedPolicyRep.getProfiles().stream().distinct().forEach(profileName->policyRep.getProfiles().add(profileName));
|
||||
}
|
||||
|
||||
updatingPoliciesList.add(policyRep);
|
||||
}
|
||||
|
||||
return updatingPoliciesRep;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert client policies as representation to json.
|
||||
* can return null.
|
||||
*/
|
||||
public static String convertClientPoliciesRepresentationToJson(ClientPoliciesRepresentation reps) throws ClientPolicyException {
|
||||
return convertRepresentationToJson(reps);
|
||||
}
|
||||
|
||||
/**
|
||||
* convert client policies as json to representation.
|
||||
* not return null.
|
||||
*/
|
||||
private static ClientPoliciesRepresentation convertClientPoliciesJsonToRepresentation(String json) throws ClientPolicyException {
|
||||
return convertJsonToRepresentation(json, ClientPoliciesRepresentation.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* get validated and modified client policies as json.
|
||||
* it can be constructed by merging proposed client policies with existing client policies.
|
||||
* can return null.
|
||||
*/
|
||||
public static String getValidatedClientPoliciesJson(KeycloakSession session, RealmModel realm, ClientPoliciesRepresentation proposedPoliciesRep) throws ClientPolicyException {
|
||||
return convertClientPoliciesRepresentationToJson(getValidatedClientPoliciesRepresentation(session, realm, proposedPoliciesRep));
|
||||
}
|
||||
|
||||
/**
|
||||
* get validated and modified client policies as representation.
|
||||
* it can be constructed by merging proposed client policies with existing client policies.
|
||||
* not return null.
|
||||
*/
|
||||
private static ClientPoliciesRepresentation getValidatedClientPoliciesRepresentation(KeycloakSession session, RealmModel realm, ClientPoliciesRepresentation proposedPoliciesRep) throws ClientPolicyException {
|
||||
if (proposedPoliciesRep == null) {
|
||||
proposedPoliciesRep = new ClientPoliciesRepresentation();
|
||||
}
|
||||
if (realm == null) {
|
||||
throw new ClientPolicyException("realm not specified.");
|
||||
}
|
||||
|
||||
// deserialize existing profiles (json -> represetation)
|
||||
ClientPoliciesRepresentation existingPoliciesRep = null;
|
||||
String existingPoliciesJson = session.clientPolicy().getClientPoliciesJsonString(realm);
|
||||
if (existingPoliciesJson != null) {
|
||||
existingPoliciesRep = convertClientPoliciesJsonToRepresentation(existingPoliciesJson);
|
||||
if (existingPoliciesRep == null) {
|
||||
existingPoliciesRep = new ClientPoliciesRepresentation();
|
||||
}
|
||||
} else {
|
||||
existingPoliciesRep = new ClientPoliciesRepresentation();
|
||||
}
|
||||
|
||||
// no policy contained (it is valid)
|
||||
// back to initial builtin policies
|
||||
List<ClientPolicyRepresentation> proposedPolicyRepList = proposedPoliciesRep.getPolicies();
|
||||
if (proposedPolicyRepList == null || proposedPolicyRepList.isEmpty()) {
|
||||
proposedPolicyRepList = new ArrayList<>();
|
||||
proposedPoliciesRep.setPolicies(new ArrayList<>());
|
||||
}
|
||||
|
||||
// duplicated policy name is not allowed.
|
||||
if (proposedPolicyRepList.size() != proposedPolicyRepList.stream().map(i->i.getName()).distinct().count()) {
|
||||
throw new ClientPolicyException("proposed client policy name duplicated.");
|
||||
}
|
||||
|
||||
// construct updating policies from existing policies and proposed policies
|
||||
ClientPoliciesRepresentation updatingPoliciesRep = new ClientPoliciesRepresentation();
|
||||
updatingPoliciesRep.setPolicies(new ArrayList<>());
|
||||
List<ClientPolicyRepresentation> updatingPoliciesList = updatingPoliciesRep.getPolicies();
|
||||
|
||||
// add existing builtin policies to updating policies
|
||||
List<ClientPolicyRepresentation> existingPoliciesList = existingPoliciesRep.getPolicies();
|
||||
if (existingPoliciesList != null && !existingPoliciesList.isEmpty()) {
|
||||
existingPoliciesList.stream().filter(i->i.isBuiltin()).forEach(i->updatingPoliciesList.add(i));
|
||||
}
|
||||
|
||||
for (ClientPolicyRepresentation proposedPolicyRep : proposedPoliciesRep.getPolicies()) {
|
||||
if (proposedPolicyRep.getName() == null) {
|
||||
throw new ClientPolicyException("proposed client policy name missing.");
|
||||
}
|
||||
|
||||
// newly proposed builtin policy not allowed because builtin policy cannot added/deleted/modified.
|
||||
Boolean enabled = (proposedPolicyRep.isEnable() != null) ? proposedPolicyRep.isEnable() : Boolean.FALSE;
|
||||
if (proposedPolicyRep.isBuiltin() != null && proposedPolicyRep.isBuiltin()) {
|
||||
// only enable field of the existing builtin policy can be overridden.
|
||||
if (updatingPoliciesList.stream().anyMatch(i->i.getName().equals(proposedPolicyRep.getName()))) {
|
||||
updatingPoliciesList.stream().filter(i->i.getName().equals(proposedPolicyRep.getName())).forEach(i->i.setEnable(enabled));
|
||||
continue;
|
||||
}
|
||||
throw new ClientPolicyException("newly builtin proposed client policy not allowed.");
|
||||
}
|
||||
|
||||
// basically, proposed policy totally overrides existing policy except for enabled field..
|
||||
ClientPolicyRepresentation policyRep = new ClientPolicyRepresentation();
|
||||
policyRep.setName(proposedPolicyRep.getName());
|
||||
policyRep.setDescription(proposedPolicyRep.getDescription());
|
||||
policyRep.setBuiltin(Boolean.FALSE);
|
||||
policyRep.setEnable(enabled);
|
||||
|
||||
policyRep.setConditions(new ArrayList<>());
|
||||
if (proposedPolicyRep.getConditions() != null) {
|
||||
for (Object condition : proposedPolicyRep.getConditions()) {
|
||||
if (isValidCondition(session, condition) == false) {
|
||||
throw new ClientPolicyException("the proposed client policy contains the condition with its invalid configuration.");
|
||||
}
|
||||
policyRep.getConditions().add(condition);
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> existingProfileNames = new HashSet<>();
|
||||
ClientProfilesRepresentation reps = getClientProfilesRepresentation(session, realm);
|
||||
if (reps.getProfiles() != null) {
|
||||
reps.getProfiles().stream().map(profile->profile.getName()).forEach(profileName->existingProfileNames.add(profileName));
|
||||
}
|
||||
policyRep.setProfiles(new ArrayList<>());
|
||||
if (proposedPolicyRep.getProfiles() != null) {
|
||||
for (String profileName : proposedPolicyRep.getProfiles()) {
|
||||
if (existingProfileNames.contains(profileName) == false) {
|
||||
throw new ClientPolicyException("referring not existing client profile not allowed.");
|
||||
}
|
||||
}
|
||||
proposedPolicyRep.getProfiles().stream().distinct().forEach(profileName->policyRep.getProfiles().add(profileName));
|
||||
}
|
||||
|
||||
updatingPoliciesList.add(policyRep);
|
||||
}
|
||||
|
||||
return updatingPoliciesRep;
|
||||
}
|
||||
|
||||
/**
|
||||
* get validated and modified builtin client policies in a realm as representation.
|
||||
* it can be constructed by merging proposed client policies with existing client policies.
|
||||
* not return null.
|
||||
*/
|
||||
public static ClientPoliciesRepresentation getValidatedClientPoliciesRepresentation(KeycloakSession session, RealmModel realm, String policiesJson) throws ClientPolicyException {
|
||||
if (policiesJson == null) {
|
||||
throw new ClientPolicyException("no client policies json.");
|
||||
}
|
||||
// deserialize existing policies (json -> representation)
|
||||
ClientPoliciesRepresentation proposedPoliciesRep = convertClientPoliciesJsonToRepresentation(policiesJson);
|
||||
return getValidatedClientPoliciesRepresentation(session, realm, proposedPoliciesRep);
|
||||
}
|
||||
|
||||
/**
|
||||
* check whether the proposed condition's provider can be found in keycloak's ClientPolicyConditionProvider list.
|
||||
* not return null.
|
||||
*/
|
||||
private static boolean isValidCondition(KeycloakSession session, Object condition) {
|
||||
return isValidComponent(session, condition, "condition", (String providerId) -> {
|
||||
Set<String> providerSet = session.listProviderIds(ClientPolicyConditionProvider.class);
|
||||
if (providerSet != null && providerSet.contains(providerId)) {
|
||||
return true;
|
||||
}
|
||||
logger.warnv("no executor provider found. providerId = {0}", providerId);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private static boolean isValidComponent(KeycloakSession session, Object obj, String type, Predicate<String> f) {
|
||||
JsonNode node = null;
|
||||
|
||||
try {
|
||||
node = objectMapper.convertValue(obj, JsonNode.class);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
logger.warnv("invalid json string representating {0}. err={1}", type, iae.getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
Iterator<Entry<String, JsonNode>> it = node.fields();
|
||||
while (it.hasNext()) {
|
||||
Entry<String, JsonNode> entry = it.next();
|
||||
// whether find provider
|
||||
if(!f.test(entry.getKey())) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static String convertRepresentationToJson(Object reps) throws ClientPolicyException {
|
||||
if (reps == null) return null;
|
||||
|
||||
String json = null;
|
||||
try {
|
||||
json = objectMapper.writeValueAsString(reps);
|
||||
} catch (JsonProcessingException jpe) {
|
||||
throw new ClientPolicyException(jpe.getMessage());
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
private static <T> T convertJsonToRepresentation(String json, Class<T> type) throws ClientPolicyException {
|
||||
if (json == null) {
|
||||
throw new ClientPolicyException("no json.");
|
||||
}
|
||||
|
||||
T rep = null;
|
||||
try {
|
||||
rep = JsonSerialization.readValue(json, type);
|
||||
} catch (IOException ioe) {
|
||||
throw new ClientPolicyException("failed to deserialize.", ioe.getMessage());
|
||||
}
|
||||
|
||||
return rep;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2020 Red Hat, Inc. and/or its affiliates
|
||||
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -16,15 +16,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
package org.keycloak.services.clientpolicy.executor;
|
||||
package org.keycloak.services.clientpolicy;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
/**
|
||||
* Just adds some type-safety to the ClientPolicyExecutorConfiguration
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ClientPolicyExecutorConfiguration {
|
||||
public interface ClientPolicyManagerFactory extends ProviderFactory<ClientPolicyManager> {
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ClientPolicyManagerSpi implements Spi {
|
||||
|
||||
@Override
|
||||
public boolean isInternal() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "client-policy-manager";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Provider> getProviderClass() {
|
||||
return ClientPolicyManager.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||
return ClientPolicyManagerFactory.class;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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.condition;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.representations.idm.ClientPolicyConditionConfigurationRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public abstract class AbstractClientPolicyConditionProvider<CONFIG extends ClientPolicyConditionConfigurationRepresentation> implements ClientPolicyConditionProvider<CONFIG> {
|
||||
|
||||
protected final KeycloakSession session;
|
||||
protected CONFIG configuration;
|
||||
|
||||
public AbstractClientPolicyConditionProvider(KeycloakSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupConfiguration(CONFIG config) {
|
||||
if (config == null) {
|
||||
// Fallback for the case that null configuration is passed as an argument
|
||||
this.configuration = JsonSerialization.mapper.convertValue(new ClientPolicyConditionConfigurationRepresentation(), getConditionConfigurationClass());
|
||||
} else {
|
||||
this.configuration = config;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isNegativeLogic() throws ClientPolicyException {
|
||||
if (configuration == null) {
|
||||
throw new ClientPolicyException("Not allowed to call this when configuration is not set");
|
||||
}
|
||||
return Optional.ofNullable(this.configuration.isNegativeLogic()).orElse(Boolean.FALSE).booleanValue();
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* 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.condition;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
/**
|
||||
* Just adds some type-safety to the ClientPolicyConditionConfiguration
|
||||
*
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ClientPolicyConditionConfiguration {
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
package org.keycloak.services.clientpolicy.condition;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.representations.idm.ClientPolicyConditionConfigurationRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
|
@ -31,7 +32,7 @@ import org.keycloak.services.clientpolicy.ClientPolicyVote;
|
|||
*
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public interface ClientPolicyConditionProvider<CONFIG extends ClientPolicyConditionConfiguration> extends Provider {
|
||||
public interface ClientPolicyConditionProvider<CONFIG extends ClientPolicyConditionConfigurationRepresentation> extends Provider {
|
||||
|
||||
@Override
|
||||
default void close() {
|
||||
|
@ -42,14 +43,13 @@ public interface ClientPolicyConditionProvider<CONFIG extends ClientPolicyCondit
|
|||
*
|
||||
* @param config
|
||||
*/
|
||||
default void setupConfiguration(CONFIG config) {
|
||||
}
|
||||
void setupConfiguration(CONFIG config);
|
||||
|
||||
/**
|
||||
* @return Class, which should match the "config" argument of the {@link #setupConfiguration(ClientPolicyConditionConfiguration)}
|
||||
* @return Class, which should match the "config" argument of the {@link #setupConfiguration(ClientPolicyConditionConfigurationRepresentation)}
|
||||
*/
|
||||
default Class<CONFIG> getConditionConfigurationClass() {
|
||||
return (Class<CONFIG>) ClientPolicyConditionConfiguration.class;
|
||||
return (Class<CONFIG>) ClientPolicyConditionConfigurationRepresentation.class;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,9 +73,7 @@ public interface ClientPolicyConditionProvider<CONFIG extends ClientPolicyCondit
|
|||
*
|
||||
* @return true if the result of applyPolicy method is inverted.
|
||||
*/
|
||||
default boolean isNegativeLogic() {
|
||||
return false;
|
||||
}
|
||||
boolean isNegativeLogic() throws ClientPolicyException;
|
||||
|
||||
default String getName() {
|
||||
return getClass().toString();
|
||||
|
|
|
@ -17,11 +17,18 @@
|
|||
|
||||
package org.keycloak.services.clientpolicy.condition;
|
||||
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.provider.ConfiguredProvider;
|
||||
import org.keycloak.provider.EnvironmentDependentProviderFactory;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public interface ClientPolicyConditionProviderFactory extends ProviderFactory<ClientPolicyConditionProvider>, ConfiguredProvider {
|
||||
public interface ClientPolicyConditionProviderFactory extends ProviderFactory<ClientPolicyConditionProvider>, ConfiguredProvider, EnvironmentDependentProviderFactory {
|
||||
|
||||
@Override
|
||||
default boolean isSupported() {
|
||||
return Profile.isFeatureEnabled(Profile.Feature.CLIENT_POLICIES);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package org.keycloak.services.clientpolicy.executor;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.representations.idm.ClientPolicyExecutorConfigurationRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
||||
|
@ -30,7 +31,7 @@ import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
|||
*
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public interface ClientPolicyExecutorProvider<CONFIG extends ClientPolicyExecutorConfiguration> extends Provider {
|
||||
public interface ClientPolicyExecutorProvider<CONFIG extends ClientPolicyExecutorConfigurationRepresentation> extends Provider {
|
||||
|
||||
@Override
|
||||
default void close() {
|
||||
|
@ -45,10 +46,10 @@ public interface ClientPolicyExecutorProvider<CONFIG extends ClientPolicyExecuto
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Class, which should match the "config" argument of the {@link #setupConfiguration(ClientPolicyExecutorConfiguration)}
|
||||
* @return Class, which should match the "config" argument of the {@link #setupConfiguration(ClientPolicyExecutorConfigurationRepresentation)}
|
||||
*/
|
||||
default Class<CONFIG> getExecutorConfigurationClass() {
|
||||
return (Class<CONFIG>) ClientPolicyExecutorConfiguration.class;
|
||||
return (Class<CONFIG>) ClientPolicyExecutorConfigurationRepresentation.class;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,11 +17,18 @@
|
|||
|
||||
package org.keycloak.services.clientpolicy.executor;
|
||||
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.provider.ConfiguredProvider;
|
||||
import org.keycloak.provider.EnvironmentDependentProviderFactory;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public interface ClientPolicyExecutorProviderFactory extends ProviderFactory<ClientPolicyExecutorProvider>, ConfiguredProvider {
|
||||
public interface ClientPolicyExecutorProviderFactory extends ProviderFactory<ClientPolicyExecutorProvider>, ConfiguredProvider, EnvironmentDependentProviderFactory {
|
||||
|
||||
@Override
|
||||
default boolean isSupported() {
|
||||
return Profile.isFeatureEnabled(Profile.Feature.CLIENT_POLICIES);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,4 +97,5 @@ org.keycloak.validation.ClientValidationSPI
|
|||
org.keycloak.headers.SecurityHeadersSpi
|
||||
org.keycloak.services.clientpolicy.condition.ClientPolicyConditionSpi
|
||||
org.keycloak.services.clientpolicy.executor.ClientPolicyExecutorSpi
|
||||
org.keycloak.services.clientpolicy.ClientPolicyManagerSpi
|
||||
org.keycloak.userprofile.UserProfileSpi
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
package org.keycloak.services.clientpolicy;
|
||||
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.representations.idm.ClientPoliciesRepresentation;
|
||||
import org.keycloak.representations.idm.ClientProfilesRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
|
||||
/**
|
||||
|
@ -26,7 +29,7 @@ import org.keycloak.representations.idm.RealmRepresentation;
|
|||
*
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public interface ClientPolicyManager {
|
||||
public interface ClientPolicyManager extends Provider {
|
||||
|
||||
/**
|
||||
* execute a method for handling an event defined in {@link ClientPolicyEvent}.
|
||||
|
@ -37,64 +40,54 @@ public interface ClientPolicyManager {
|
|||
void triggerOnEvent(ClientPolicyContext context) throws ClientPolicyException;
|
||||
|
||||
/**
|
||||
* when booting keycloak, reads json representations of the builtin client profiles and policies from files
|
||||
* enclosed in keycloak-services jar file and put them onto the keycloak application.
|
||||
* when creating a realm, adds the default client policies, which should be available on the realm and put them onto the realm as its attribute.
|
||||
* if these operation fails, put null.
|
||||
*
|
||||
* @param profilesFilePath - the file path for the builtin client profiles
|
||||
* @param policiesFilePath - the file path for the builtin client policies
|
||||
*/
|
||||
void setupClientPoliciesOnKeycloakApp(String profilesFilePath, String policiesFilePath);
|
||||
|
||||
/**
|
||||
* when creating a realm, reads the builtin client profiles and policies
|
||||
* that have already been set on keycloak application on booting keycloak and put them onto the realm as its attribute.
|
||||
* if these operation fails, put null.
|
||||
*
|
||||
*
|
||||
* @param realm - the newly created realm
|
||||
*/
|
||||
void setupClientPoliciesOnCreatedRealm(RealmModel realm);
|
||||
|
||||
/**
|
||||
* when importing a realm, reads the builtin client profiles and policies
|
||||
* that have already been set on keycloak application on booting keycloak and override them
|
||||
* with ones loaded from the imported realm json file.
|
||||
* if these operation fails, rolls them back to the builtin client profiles and policies set on keycloak application.
|
||||
*
|
||||
* when importing a realm, or updating a realm, update model from the representation object
|
||||
*
|
||||
* @param realm - the newly created realm to be overriden by imported realm's representation
|
||||
* @param rep - imported realm's representation
|
||||
*/
|
||||
void setupClientPoliciesOnImportedRealm(RealmModel realm, RealmRepresentation rep);
|
||||
void updateRealmModelFromRepresentation(RealmModel realm, RealmRepresentation rep);
|
||||
|
||||
/**
|
||||
* when updating client profiles via Admin REST API, reads the json representation of the client profiles
|
||||
* and overrides the existing client profiles set on the realm with them.
|
||||
* if these operation fails, rolls them back to the existing client profiles and throw an exception.
|
||||
*
|
||||
* If the "clientProfiles" parameter contains the global client profiles, they won't be updated on the realm at all
|
||||
*
|
||||
* @param realm - the realm whose client profiles is to be overriden by the new client profiles
|
||||
* @param json - the json representation of the new client profiles that overrides the existing client profiles set on the realm
|
||||
* @param clientProfiles - the json representation of the new client profiles that overrides the existing client profiles set on the realm. With
|
||||
* the exception of global profiles, which are not overriden as mentioned above.
|
||||
* @throws {@link ClientPolicyException}
|
||||
*/
|
||||
void updateClientProfiles(RealmModel realm, String json) throws ClientPolicyException;
|
||||
void updateClientProfiles(RealmModel realm, ClientProfilesRepresentation clientProfiles) throws ClientPolicyException;
|
||||
|
||||
/**
|
||||
* when getting client profiles via Admin REST API, returns the existing client profiles set on the realm.
|
||||
*
|
||||
* @param realm - the realm whose client profiles is to be returned
|
||||
* @param includeGlobalProfiles - If true, method will return realm profiles and global profiles as well. If false, then "globalProfiles" field would be null
|
||||
* @return the json representation of the client profiles set on the realm
|
||||
*/
|
||||
String getClientProfiles(RealmModel realm);
|
||||
ClientProfilesRepresentation getClientProfiles(RealmModel realm, boolean includeGlobalProfiles) throws ClientPolicyException;
|
||||
|
||||
/**
|
||||
* when updating client policies via Admin REST API, reads the json representation of the client policies
|
||||
* and overrides the existing client policies set on the realm with them.
|
||||
* if these operation fails, rolls them back to the existing client policies and throw an exception.
|
||||
*
|
||||
*
|
||||
* @param realm - the realm whose client policies is to be overriden by the new client policies
|
||||
* @param json - the json representation of the new client policies that overrides the existing client policies set on the realm
|
||||
* @param clientPolicies - the json representation of the new client policies that overrides the existing client policies set on the realm
|
||||
* @throws {@link ClientPolicyException}
|
||||
*/
|
||||
void updateClientPolicies(RealmModel realm, String json) throws ClientPolicyException;
|
||||
void updateClientPolicies(RealmModel realm, ClientPoliciesRepresentation clientPolicies) throws ClientPolicyException;
|
||||
|
||||
/**
|
||||
* when getting client policies via Admin REST API, returns the existing client policies set on the realm.
|
||||
|
@ -102,45 +95,15 @@ public interface ClientPolicyManager {
|
|||
* @param realm - the realm whose client policies is to be returned
|
||||
* @return the json representation of the client policies set on the realm
|
||||
*/
|
||||
String getClientPolicies(RealmModel realm);
|
||||
ClientPoliciesRepresentation getClientPolicies(RealmModel realm) throws ClientPolicyException;
|
||||
|
||||
/**
|
||||
* when exporting realm the realm, prepares the exported representation of the client profiles and policies.
|
||||
* E.g. the builtin client profiles and policies are filtered out and not exported.
|
||||
*
|
||||
* when exporting realm, or retrieve the realm for admin REST API, prepares the exported representation of the client profiles and policies.
|
||||
* Global client profiles and policies are filtered out and not exported.
|
||||
*
|
||||
* @param realm - the realm to be exported
|
||||
* @param rep - the realm's representation to be exported actually
|
||||
*/
|
||||
void setupClientPoliciesOnExportingRealm(RealmModel realm, RealmRepresentation rep);
|
||||
|
||||
/**
|
||||
* returns the json representation of the builtin client profiles set on keycloak application.
|
||||
*
|
||||
* @return the json representation of the builtin client profiles set on keycloak application
|
||||
*/
|
||||
String getClientProfilesOnKeycloakApp();
|
||||
|
||||
/**
|
||||
* returns the json representation of the builtin client policies set on keycloak application.
|
||||
*
|
||||
* @return the json representation of the builtin client policies set on keycloak application
|
||||
*/
|
||||
String getClientPoliciesOnKeycloakApp();
|
||||
|
||||
/**
|
||||
* returns the json representation of the client profiles set on the realm.
|
||||
*
|
||||
* @param realm - the realm whose client profiles is to be returned
|
||||
* @return the json representation of the client profiles set on the realm
|
||||
*/
|
||||
String getClientProfilesJsonString(RealmModel realm);
|
||||
|
||||
/**
|
||||
* returns the json representation of the client policies set on the realm.
|
||||
*
|
||||
* @param realm - the realm whose client policies is to be returned
|
||||
* @return the json representation of the client policies set on the realm
|
||||
*/
|
||||
String getClientPoliciesJsonString(RealmModel realm);
|
||||
void updateRealmRepresentationFromModel(RealmModel realm, RealmRepresentation rep);
|
||||
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ public class ExportUtils {
|
|||
}
|
||||
|
||||
public static RealmRepresentation exportRealm(KeycloakSession session, RealmModel realm, ExportOptions options, boolean internal) {
|
||||
RealmRepresentation rep = ModelToRepresentation.toRepresentation(realm, internal);
|
||||
RealmRepresentation rep = ModelToRepresentation.toRepresentation(session, realm, internal);
|
||||
ModelToRepresentation.exportAuthenticationFlows(realm, rep);
|
||||
ModelToRepresentation.exportRequiredActions(realm, rep);
|
||||
|
||||
|
@ -260,9 +260,6 @@ public class ExportUtils {
|
|||
MultivaluedHashMap<String, ComponentExportRepresentation> components = exportComponents(realm, realm.getId());
|
||||
rep.setComponents(components);
|
||||
|
||||
// client policies
|
||||
session.clientPolicy().setupClientPoliciesOnExportingRealm(realm, rep);
|
||||
|
||||
return rep;
|
||||
}
|
||||
|
||||
|
|
|
@ -499,7 +499,7 @@ public class DefaultKeycloakSession implements KeycloakSession {
|
|||
@Override
|
||||
public ClientPolicyManager clientPolicy() {
|
||||
if (clientPolicyManager == null) {
|
||||
clientPolicyManager = new DefaultClientPolicyManager(this);
|
||||
clientPolicyManager = getProvider(ClientPolicyManager.class);
|
||||
}
|
||||
return clientPolicyManager;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,514 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.representations.idm.ClientPoliciesRepresentation;
|
||||
import org.keycloak.representations.idm.ClientPolicyConditionRepresentation;
|
||||
import org.keycloak.representations.idm.ClientPolicyExecutorRepresentation;
|
||||
import org.keycloak.representations.idm.ClientPolicyRepresentation;
|
||||
import org.keycloak.representations.idm.ClientProfileRepresentation;
|
||||
import org.keycloak.representations.idm.ClientProfilesRepresentation;
|
||||
import org.keycloak.representations.idm.ClientPolicyConditionConfigurationRepresentation;
|
||||
import org.keycloak.services.clientpolicy.condition.ClientPolicyConditionProvider;
|
||||
import org.keycloak.representations.idm.ClientPolicyExecutorConfigurationRepresentation;
|
||||
import org.keycloak.services.clientpolicy.executor.ClientPolicyExecutorProvider;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
* Utilities for treating client policies/profiles
|
||||
*
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public class ClientPoliciesUtil {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ClientPoliciesUtil.class);
|
||||
|
||||
/**
|
||||
* gets existing client profiles in a realm as representation.
|
||||
* not return null.
|
||||
*/
|
||||
static ClientProfilesRepresentation getClientProfilesRepresentation(KeycloakSession session, RealmModel realm) throws ClientPolicyException {
|
||||
String profilesJson = getClientProfilesJsonString(realm);
|
||||
|
||||
// deserialize existing profiles (json -> representation)
|
||||
if (profilesJson == null) {
|
||||
return new ClientProfilesRepresentation();
|
||||
}
|
||||
return convertClientProfilesJsonToRepresentation(profilesJson);
|
||||
}
|
||||
|
||||
/**
|
||||
* gets existing client profiles in a realm as model.
|
||||
* not return null.
|
||||
*/
|
||||
static Map<String, ClientProfileModel> getClientProfilesModel(KeycloakSession session, RealmModel realm, List<ClientProfileRepresentation> globalClientProfiles) {
|
||||
// get existing profiles as json
|
||||
String profilesJson = getClientProfilesJsonString(realm);
|
||||
if (profilesJson == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
// deserialize existing profiles (json -> representation)
|
||||
ClientProfilesRepresentation profilesRep = null;
|
||||
try {
|
||||
profilesRep = convertClientProfilesJsonToRepresentation(profilesJson);
|
||||
} catch (ClientPolicyException e) {
|
||||
logger.warnv("Failed to serialize client profiles json string. err={0}, errDetail={1}", e.getError(), e.getErrorDetail());
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
if (profilesRep == null || profilesRep.getProfiles() == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
List<ClientProfileRepresentation> profiles = profilesRep.getProfiles();
|
||||
|
||||
// Add global profiles as well
|
||||
profiles.addAll(globalClientProfiles);
|
||||
|
||||
// constructing existing profiles (representation -> model)
|
||||
Map<String, ClientProfileModel> profileMap = new HashMap<>();
|
||||
for (ClientProfileRepresentation profileRep : profilesRep.getProfiles()) {
|
||||
// ignore profile without name
|
||||
if (profileRep.getName() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ClientProfileModel profileModel = new ClientProfileModel();
|
||||
profileModel.setName(profileRep.getName());
|
||||
profileModel.setDescription(profileRep.getDescription());
|
||||
|
||||
if (profileRep.getExecutors() == null) {
|
||||
profileModel.setExecutors(new ArrayList<>());
|
||||
profileMap.put(profileRep.getName(), profileModel);
|
||||
continue;
|
||||
}
|
||||
|
||||
List<ClientPolicyExecutorProvider> executors = new ArrayList<>();
|
||||
if (profileRep.getExecutors() != null) {
|
||||
for (ClientPolicyExecutorRepresentation executorRep : profileRep.getExecutors()) {
|
||||
ClientPolicyExecutorProvider provider = session.getProvider(ClientPolicyExecutorProvider.class, executorRep.getExecutorProviderId());
|
||||
if (provider == null) {
|
||||
// executor's provider not found. just skip it.
|
||||
logger.warnf("Executor with provider ID %s not found", executorRep.getExecutorProviderId());
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
ClientPolicyExecutorConfigurationRepresentation configuration = (ClientPolicyExecutorConfigurationRepresentation) JsonSerialization.mapper.convertValue(executorRep.getConfiguration(), provider.getExecutorConfigurationClass());
|
||||
provider.setupConfiguration(configuration);
|
||||
executors.add(provider);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
logger.warnv("failed for Configuration Setup during setup provider {0} :: error = {1}", executorRep.getExecutorProviderId(), iae.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
profileModel.setExecutors(executors);
|
||||
|
||||
profileMap.put(profileRep.getName(), profileModel);
|
||||
}
|
||||
|
||||
return profileMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* get validated and modified global (built-in) client profiles set on keycloak app as representation.
|
||||
* it is loaded from json file enclosed in keycloak's binary.
|
||||
* not return null.
|
||||
*/
|
||||
static List<ClientProfileRepresentation> getValidatedGlobalClientProfilesRepresentation(KeycloakSession session, InputStream is) throws ClientPolicyException {
|
||||
// load builtin client profiles representation
|
||||
ClientProfilesRepresentation proposedProfilesRep = null;
|
||||
try {
|
||||
proposedProfilesRep = JsonSerialization.readValue(is, ClientProfilesRepresentation.class);
|
||||
} catch (Exception e) {
|
||||
throw new ClientPolicyException("failed to deserialize global proposed client profiles json string.", e.getMessage());
|
||||
}
|
||||
if (proposedProfilesRep == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// no profile contained (it is valid)
|
||||
List<ClientProfileRepresentation> proposedProfileRepList = proposedProfilesRep.getProfiles();
|
||||
if (proposedProfileRepList == null || proposedProfileRepList.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// duplicated profile name is not allowed.
|
||||
if (proposedProfileRepList.size() != proposedProfileRepList.stream().map(i->i.getName()).distinct().count()) {
|
||||
throw new ClientPolicyException("proposed global client profile name duplicated.");
|
||||
}
|
||||
|
||||
// construct validated and modified profiles from builtin profiles in JSON file enclosed in keycloak binary.
|
||||
List<ClientProfileRepresentation> updatingProfileList = new LinkedList<>();
|
||||
|
||||
for (ClientProfileRepresentation proposedProfileRep : proposedProfilesRep.getProfiles()) {
|
||||
if (proposedProfileRep.getName() == null) {
|
||||
throw new ClientPolicyException("client profile without its name not allowed.");
|
||||
}
|
||||
|
||||
ClientProfileRepresentation profileRep = new ClientProfileRepresentation();
|
||||
profileRep.setName(proposedProfileRep.getName());
|
||||
profileRep.setDescription(proposedProfileRep.getDescription());
|
||||
|
||||
profileRep.setExecutors(new ArrayList<>()); // to prevent returning null
|
||||
if (proposedProfileRep.getExecutors() != null) {
|
||||
for (ClientPolicyExecutorRepresentation executorRep : proposedProfileRep.getExecutors()) {
|
||||
// Skip the check if feature is disabled as then the executor implementations are disabled
|
||||
if (Profile.isFeatureEnabled(Profile.Feature.CLIENT_POLICIES) && !isValidExecutor(session, executorRep.getExecutorProviderId())) {
|
||||
throw new ClientPolicyException("proposed client profile contains the executor with its invalid configuration.");
|
||||
}
|
||||
profileRep.getExecutors().add(executorRep);
|
||||
}
|
||||
}
|
||||
|
||||
updatingProfileList.add(profileRep);
|
||||
}
|
||||
|
||||
return updatingProfileList;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert client profiles as representation to json.
|
||||
* can return null.
|
||||
*/
|
||||
public static String convertClientProfilesRepresentationToJson(ClientProfilesRepresentation reps) throws ClientPolicyException {
|
||||
try {
|
||||
return JsonSerialization.writeValueAsString(reps);
|
||||
} catch (IOException ioe) {
|
||||
throw new ClientPolicyException(ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* convert client profiles as json to representation.
|
||||
* not return null.
|
||||
*/
|
||||
private static ClientProfilesRepresentation convertClientProfilesJsonToRepresentation(String json) throws ClientPolicyException {
|
||||
try {
|
||||
return JsonSerialization.readValue(json, ClientProfilesRepresentation.class);
|
||||
} catch (IOException ioe) {
|
||||
throw new ClientPolicyException(ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get validated and modified client profiles as representation.
|
||||
* it can be constructed by merging proposed client profiles with existing client profiles.
|
||||
* not return null.
|
||||
*/
|
||||
static ClientProfilesRepresentation getValidatedClientProfilesForUpdate(KeycloakSession session, RealmModel realm,
|
||||
ClientProfilesRepresentation proposedProfilesRep, List<ClientProfileRepresentation> globalClientProfiles) throws ClientPolicyException {
|
||||
if (realm == null) {
|
||||
throw new ClientPolicyException("realm not specified.");
|
||||
}
|
||||
|
||||
// no profile contained (it is valid)
|
||||
List<ClientProfileRepresentation> proposedProfileRepList = proposedProfilesRep.getProfiles();
|
||||
if (proposedProfileRepList == null || proposedProfileRepList.isEmpty()) {
|
||||
proposedProfileRepList = new ArrayList<>();
|
||||
proposedProfilesRep.setProfiles(new ArrayList<>());
|
||||
}
|
||||
|
||||
// Profile without name not allowed
|
||||
if (proposedProfileRepList.stream().anyMatch(clientProfile -> clientProfile.getName() == null || clientProfile.getName().isEmpty())) {
|
||||
throw new ClientPolicyException("client profile without its name not allowed.");
|
||||
}
|
||||
|
||||
// duplicated profile name is not allowed.
|
||||
if (proposedProfileRepList.size() != proposedProfileRepList.stream().map(i->i.getName()).distinct().count()) {
|
||||
throw new ClientPolicyException("proposed client profile name duplicated.");
|
||||
}
|
||||
|
||||
// Conflict with any global profile is not allowed
|
||||
Set<String> globalProfileNames = globalClientProfiles.stream().map(ClientProfileRepresentation::getName).collect(Collectors.toSet());
|
||||
for (ClientProfileRepresentation clientProfile : proposedProfileRepList) {
|
||||
if (globalProfileNames.contains(clientProfile.getName())) {
|
||||
throw new ClientPolicyException("Proposed profile name duplicated as the name of some global profile");
|
||||
}
|
||||
}
|
||||
|
||||
// Validate executor
|
||||
for (ClientProfileRepresentation proposedProfileRep : proposedProfilesRep.getProfiles()) {
|
||||
if (proposedProfileRep.getExecutors() != null) {
|
||||
for (ClientPolicyExecutorRepresentation executorRep : proposedProfileRep.getExecutors()) {
|
||||
if (!isValidExecutor(session, executorRep.getExecutorProviderId())) {
|
||||
throw new ClientPolicyException("proposed client profile contains the executor, which does not have valid provider, or has invalid configuration.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure to not save built-in inside realm attribute
|
||||
proposedProfilesRep.setGlobalProfiles(null);
|
||||
|
||||
return proposedProfilesRep;
|
||||
}
|
||||
|
||||
/**
|
||||
* check whether the proposed executor's provider can be found in keycloak's ClientPolicyExecutorProvider list.
|
||||
* not return null.
|
||||
*/
|
||||
private static boolean isValidExecutor(KeycloakSession session, String executorProviderId) {
|
||||
Set<String> providerSet = session.listProviderIds(ClientPolicyExecutorProvider.class);
|
||||
if (providerSet != null && providerSet.contains(executorProviderId)) {
|
||||
return true;
|
||||
}
|
||||
logger.warnv("no executor provider found. providerId = {0}", executorProviderId);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get existing client policies in a realm as representation.
|
||||
* not return null.
|
||||
*/
|
||||
static ClientPoliciesRepresentation getClientPoliciesRepresentation(KeycloakSession session, RealmModel realm) throws ClientPolicyException {
|
||||
// get existing policies json
|
||||
String policiesJson = getClientPoliciesJsonString(realm);
|
||||
|
||||
// deserialize existing policies (json -> representation)
|
||||
if (policiesJson == null) {
|
||||
return new ClientPoliciesRepresentation();
|
||||
}
|
||||
return convertClientPoliciesJsonToRepresentation(policiesJson);
|
||||
}
|
||||
|
||||
/**
|
||||
* get existing enabled client policies in a realm as model.
|
||||
* not return null.
|
||||
*/
|
||||
static List<ClientPolicyModel> getEnabledClientPoliciesModel(KeycloakSession session, RealmModel realm) {
|
||||
// get existing profiles as json
|
||||
String policiesJson = getClientPoliciesJsonString(realm);
|
||||
if (policiesJson == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// deserialize existing policies (json -> representation)
|
||||
ClientPoliciesRepresentation policiesRep = null;
|
||||
try {
|
||||
policiesRep = convertClientPoliciesJsonToRepresentation(policiesJson);
|
||||
} catch (ClientPolicyException e) {
|
||||
logger.warnv("Failed to serialize client policies json string. err={0}, errDetail={1}", e.getError(), e.getErrorDetail());
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (policiesRep == null || policiesRep.getPolicies() == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// constructing existing policies (representation -> model)
|
||||
List<ClientPolicyModel> policyList = new ArrayList<>();
|
||||
for (ClientPolicyRepresentation policyRep: policiesRep.getPolicies()) {
|
||||
// ignore policy without name
|
||||
if (policyRep.getName() == null) {
|
||||
logger.warnf("Ignored client policy without name in the realm %s", realm.getName());
|
||||
continue;
|
||||
}
|
||||
// pick up only enabled policy
|
||||
if (policyRep.isEnabled() == null || policyRep.isEnabled() == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ClientPolicyModel policyModel = new ClientPolicyModel();
|
||||
policyModel.setName(policyRep.getName());
|
||||
policyModel.setDescription(policyRep.getDescription());
|
||||
policyModel.setEnable(true);
|
||||
|
||||
List<ClientPolicyConditionProvider> conditions = new ArrayList<>();
|
||||
if (policyRep.getConditions() != null) {
|
||||
for (ClientPolicyConditionRepresentation conditionRep : policyRep.getConditions()) {
|
||||
ClientPolicyConditionProvider provider = session.getProvider(ClientPolicyConditionProvider.class, conditionRep.getConditionProviderId());
|
||||
if (provider == null) {
|
||||
// condition's provider not found. just skip it.
|
||||
logger.warnf("Condition with provider ID %s not found", conditionRep.getConditionProviderId());
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
ClientPolicyConditionConfigurationRepresentation configuration = (ClientPolicyConditionConfigurationRepresentation) JsonSerialization.mapper.convertValue(conditionRep.getConfiguration(), provider.getConditionConfigurationClass());
|
||||
provider.setupConfiguration(configuration);
|
||||
conditions.add(provider);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
logger.warnv("failed for Configuration Setup :: error = {0}", iae.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
policyModel.setConditions(conditions);
|
||||
|
||||
if (policyRep.getProfiles() != null) {
|
||||
policyModel.setProfiles(policyRep.getProfiles().stream().collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
policyList.add(policyModel);
|
||||
}
|
||||
|
||||
return policyList;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert client policies as representation to json.
|
||||
* can return null.
|
||||
*/
|
||||
public static String convertClientPoliciesRepresentationToJson(ClientPoliciesRepresentation reps) throws ClientPolicyException {
|
||||
try {
|
||||
return JsonSerialization.writeValueAsString(reps);
|
||||
} catch (IOException ioe) {
|
||||
throw new ClientPolicyException(ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* convert client policies as json to representation.
|
||||
* not return null.
|
||||
*/
|
||||
private static ClientPoliciesRepresentation convertClientPoliciesJsonToRepresentation(String json) throws ClientPolicyException {
|
||||
try {
|
||||
return JsonSerialization.readValue(json, ClientPoliciesRepresentation.class);
|
||||
} catch (IOException ioe) {
|
||||
throw new ClientPolicyException(ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get validated and modified client policies as representation.
|
||||
* it can be constructed by merging proposed client policies with existing client policies.
|
||||
* not return null.
|
||||
*
|
||||
* @param session
|
||||
* @param realm
|
||||
* @param proposedPoliciesRep
|
||||
*/
|
||||
static ClientPoliciesRepresentation getValidatedClientPoliciesForUpdate(KeycloakSession session, RealmModel realm,
|
||||
ClientPoliciesRepresentation proposedPoliciesRep, List<ClientProfileRepresentation> existingGlobalProfiles) throws ClientPolicyException {
|
||||
if (realm == null) {
|
||||
throw new ClientPolicyException("realm not specified.");
|
||||
}
|
||||
|
||||
// no policy contained (it is valid)
|
||||
List<ClientPolicyRepresentation> proposedPolicyRepList = proposedPoliciesRep.getPolicies();
|
||||
if (proposedPolicyRepList == null || proposedPolicyRepList.isEmpty()) {
|
||||
proposedPolicyRepList = new ArrayList<>();
|
||||
proposedPoliciesRep.setPolicies(new ArrayList<>());
|
||||
}
|
||||
|
||||
// Policy without name not allowed
|
||||
if (proposedPolicyRepList.stream().anyMatch(clientPolicy -> clientPolicy.getName() == null || clientPolicy.getName().isEmpty())) {
|
||||
throw new ClientPolicyException("proposed client policy name missing.");
|
||||
}
|
||||
|
||||
// duplicated policy name is not allowed.
|
||||
if (proposedPolicyRepList.size() != proposedPolicyRepList.stream().map(i->i.getName()).distinct().count()) {
|
||||
throw new ClientPolicyException("proposed client policy name duplicated.");
|
||||
}
|
||||
|
||||
// construct updating policies from existing policies and proposed policies
|
||||
ClientPoliciesRepresentation updatingPoliciesRep = new ClientPoliciesRepresentation();
|
||||
updatingPoliciesRep.setPolicies(new ArrayList<>());
|
||||
List<ClientPolicyRepresentation> updatingPoliciesList = updatingPoliciesRep.getPolicies();
|
||||
|
||||
for (ClientPolicyRepresentation proposedPolicyRep : proposedPoliciesRep.getPolicies()) {
|
||||
// newly proposed builtin policy not allowed because builtin policy cannot added/deleted/modified.
|
||||
Boolean enabled = (proposedPolicyRep.isEnabled() != null) ? proposedPolicyRep.isEnabled() : Boolean.FALSE;
|
||||
|
||||
// basically, proposed policy totally overrides existing policy except for enabled field..
|
||||
ClientPolicyRepresentation policyRep = new ClientPolicyRepresentation();
|
||||
policyRep.setName(proposedPolicyRep.getName());
|
||||
policyRep.setDescription(proposedPolicyRep.getDescription());
|
||||
policyRep.setEnabled(enabled);
|
||||
|
||||
policyRep.setConditions(new ArrayList<>());
|
||||
if (proposedPolicyRep.getConditions() != null) {
|
||||
for (ClientPolicyConditionRepresentation conditionRep : proposedPolicyRep.getConditions()) {
|
||||
if (!isValidCondition(session, conditionRep.getConditionProviderId())) {
|
||||
throw new ClientPolicyException("the proposed client policy contains the condition with its invalid configuration.");
|
||||
}
|
||||
policyRep.getConditions().add(conditionRep);
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> existingProfileNames = existingGlobalProfiles.stream().map(ClientProfileRepresentation::getName).collect(Collectors.toSet());
|
||||
ClientProfilesRepresentation reps = getClientProfilesRepresentation(session, realm);
|
||||
policyRep.setProfiles(new ArrayList<>());
|
||||
if (reps.getProfiles() != null) {
|
||||
existingProfileNames.addAll(reps.getProfiles().stream()
|
||||
.map(ClientProfileRepresentation::getName)
|
||||
.collect(Collectors.toSet()));
|
||||
}
|
||||
if (proposedPolicyRep.getProfiles() != null) {
|
||||
for (String profileName : proposedPolicyRep.getProfiles()) {
|
||||
if (!existingProfileNames.contains(profileName)) {
|
||||
logger.warnf("Client policy %s referred not existing profile %s");
|
||||
throw new ClientPolicyException("referring not existing client profile not allowed.");
|
||||
}
|
||||
}
|
||||
proposedPolicyRep.getProfiles().stream().distinct().forEach(profileName->policyRep.getProfiles().add(profileName));
|
||||
}
|
||||
|
||||
updatingPoliciesList.add(policyRep);
|
||||
}
|
||||
|
||||
return updatingPoliciesRep;
|
||||
}
|
||||
|
||||
/**
|
||||
* check whether the proposed condition's provider can be found in keycloak's ClientPolicyConditionProvider list.
|
||||
* not return null.
|
||||
*/
|
||||
private static boolean isValidCondition(KeycloakSession session, String conditionProviderId) {
|
||||
Set<String> providerSet = session.listProviderIds(ClientPolicyConditionProvider.class);
|
||||
if (providerSet != null && providerSet.contains(conditionProviderId)) {
|
||||
return true;
|
||||
}
|
||||
logger.warnv("no condition provider found. providerId = {0}", conditionProviderId);
|
||||
return false;
|
||||
}
|
||||
|
||||
static String getClientProfilesJsonString(RealmModel realm) {
|
||||
return realm.getAttribute(Constants.CLIENT_PROFILES);
|
||||
}
|
||||
|
||||
static String getClientPoliciesJsonString(RealmModel realm) {
|
||||
return realm.getAttribute(Constants.CLIENT_POLICIES);
|
||||
}
|
||||
|
||||
static void setClientProfilesJsonString(RealmModel realm, String json) {
|
||||
realm.setAttribute(Constants.CLIENT_PROFILES, json);
|
||||
}
|
||||
|
||||
static void setClientPoliciesJsonString(RealmModel realm, String json) {
|
||||
realm.setAttribute(Constants.CLIENT_POLICIES, json);
|
||||
}
|
||||
|
||||
}
|
|
@ -20,6 +20,8 @@ package org.keycloak.services.clientpolicy;
|
|||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import org.keycloak.services.clientpolicy.condition.ClientPolicyConditionProvider;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
|
@ -27,9 +29,8 @@ public class ClientPolicyModel implements Serializable {
|
|||
|
||||
protected String name;
|
||||
protected String description;
|
||||
protected boolean builtin;
|
||||
protected boolean enable;
|
||||
protected List<Object> conditions; // ClientPolicyConditionProvider is not visible so that use Object.
|
||||
protected List<ClientPolicyConditionProvider> conditions;
|
||||
protected List<String> profiles;
|
||||
|
||||
public String getName() {
|
||||
|
@ -48,14 +49,6 @@ public class ClientPolicyModel implements Serializable {
|
|||
this.description = description;
|
||||
}
|
||||
|
||||
public boolean isBuiltin() {
|
||||
return builtin;
|
||||
}
|
||||
|
||||
public void setBuiltin(boolean builtin) {
|
||||
this.builtin = builtin;
|
||||
}
|
||||
|
||||
public boolean isEnable() {
|
||||
return enable;
|
||||
}
|
||||
|
@ -64,11 +57,11 @@ public class ClientPolicyModel implements Serializable {
|
|||
this.enable = enable;
|
||||
}
|
||||
|
||||
public List<Object> getConditions() {
|
||||
public List<ClientPolicyConditionProvider> getConditions() {
|
||||
return conditions;
|
||||
}
|
||||
|
||||
public void setConditions(List<Object> conditions) {
|
||||
public void setConditions(List<ClientPolicyConditionProvider> conditions) {
|
||||
this.conditions = conditions;
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
* 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;
|
||||
|
@ -20,6 +21,8 @@ package org.keycloak.services.clientpolicy;
|
|||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import org.keycloak.services.clientpolicy.executor.ClientPolicyExecutorProvider;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
|
@ -27,8 +30,7 @@ public class ClientProfileModel implements Serializable {
|
|||
|
||||
protected String name;
|
||||
protected String description;
|
||||
protected boolean builtin;
|
||||
protected List<Object> executors; // ClientPolicyExecutorProvider is not visible so that use Object.
|
||||
protected List<ClientPolicyExecutorProvider> executors;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
|
@ -46,19 +48,11 @@ public class ClientProfileModel implements Serializable {
|
|||
this.description = description;
|
||||
}
|
||||
|
||||
public boolean isBuiltin() {
|
||||
return builtin;
|
||||
}
|
||||
|
||||
public void setBuiltin(boolean builtin) {
|
||||
this.builtin = builtin;
|
||||
}
|
||||
|
||||
public List<Object> getExecutors() {
|
||||
public List<ClientPolicyExecutorProvider> getExecutors() {
|
||||
return executors;
|
||||
}
|
||||
|
||||
public void setExecutors(List<Object> executors) {
|
||||
public void setExecutors(List<ClientPolicyExecutorProvider> executors) {
|
||||
this.executors = executors;
|
||||
}
|
||||
}
|
|
@ -17,8 +17,11 @@
|
|||
|
||||
package org.keycloak.services.clientpolicy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
@ -31,6 +34,7 @@ import org.keycloak.representations.idm.ClientProfilesRepresentation;
|
|||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.services.clientpolicy.condition.ClientPolicyConditionProvider;
|
||||
import org.keycloak.services.clientpolicy.executor.ClientPolicyExecutorProvider;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
|
@ -40,9 +44,11 @@ public class DefaultClientPolicyManager implements ClientPolicyManager {
|
|||
private static final Logger logger = Logger.getLogger(DefaultClientPolicyManager.class);
|
||||
|
||||
private final KeycloakSession session;
|
||||
private final Supplier<List<ClientProfileRepresentation>> globalClientProfilesSupplier;
|
||||
|
||||
public DefaultClientPolicyManager(KeycloakSession session) {
|
||||
public DefaultClientPolicyManager(KeycloakSession session, Supplier<List<ClientProfileRepresentation>> globalClientProfilesSupplier) {
|
||||
this.session = session;
|
||||
this.globalClientProfilesSupplier = globalClientProfilesSupplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -62,8 +68,8 @@ public class DefaultClientPolicyManager implements ClientPolicyManager {
|
|||
}
|
||||
|
||||
private void doPolicyOperation(ClientConditionOperation condition, ClientExecutorOperation executor, RealmModel realm) throws ClientPolicyException {
|
||||
Map<String, ClientProfileModel> map = ClientPoliciesUtil.getClientProfilesModel(session, realm);
|
||||
List<ClientPolicyModel> list = ClientPoliciesUtil.getEnabledClientProfilesModel(session, realm).stream().collect(Collectors.toList());
|
||||
Map<String, ClientProfileModel> map = ClientPoliciesUtil.getClientProfilesModel(session, realm, globalClientProfilesSupplier.get());
|
||||
List<ClientPolicyModel> list = ClientPoliciesUtil.getEnabledClientPoliciesModel(session, realm).stream().collect(Collectors.toList());
|
||||
|
||||
if (list == null || list.isEmpty()) {
|
||||
logger.trace("POLICY OPERATION :: No enabled policy.");
|
||||
|
@ -71,13 +77,13 @@ public class DefaultClientPolicyManager implements ClientPolicyManager {
|
|||
}
|
||||
|
||||
for (ClientPolicyModel policy: list) {
|
||||
logger.tracev("POLICY OPERATION :: policy name = {0}, isBuiltin = {1}", policy.getName(), policy.isBuiltin());
|
||||
logger.tracev("POLICY OPERATION :: policy name = {0}", policy.getName());
|
||||
if (!isSatisfied(policy, condition)) {
|
||||
logger.tracev("POLICY UNSATISFIED :: policy name = {0}, isBuiltin = {1}", policy.getName(), policy.isBuiltin());
|
||||
logger.tracev("POLICY UNSATISFIED :: policy name = {0}", policy.getName());
|
||||
continue;
|
||||
}
|
||||
|
||||
logger.tracev("POLICY APPLIED :: policy name = {0}, isBuiltin = {1}", policy.getName(), policy.isBuiltin());
|
||||
logger.tracev("POLICY APPLIED :: policy name = {0}", policy.getName());
|
||||
execute(policy, executor, map);
|
||||
}
|
||||
}
|
||||
|
@ -92,8 +98,7 @@ public class DefaultClientPolicyManager implements ClientPolicyManager {
|
|||
}
|
||||
|
||||
boolean ret = false;
|
||||
for (Object obj : policy.getConditions()) {
|
||||
ClientPolicyConditionProvider condition = (ClientPolicyConditionProvider)obj;
|
||||
for (ClientPolicyConditionProvider condition : policy.getConditions()) {
|
||||
logger.tracev("CONDITION OPERATION :: policy name = {0}, condition name = {1}, provider id = {2}", policy.getName(), condition.getName(), condition.getProviderId());
|
||||
try {
|
||||
ClientPolicyVote vote = op.run(condition);
|
||||
|
@ -148,8 +153,7 @@ public class DefaultClientPolicyManager implements ClientPolicyManager {
|
|||
continue;
|
||||
}
|
||||
|
||||
for (Object obj : profile.getExecutors()) {
|
||||
ClientPolicyExecutorProvider executor = (ClientPolicyExecutorProvider)obj;
|
||||
for (ClientPolicyExecutorProvider executor : profile.getExecutors()) {
|
||||
logger.tracev("EXECUTION :: policy name = {0}, profile name = {1}, executor name = {2}, provider id = {3}", policy.getName(), profileName, executor.getName(), executor.getProviderId());
|
||||
try {
|
||||
op.run(executor);
|
||||
|
@ -170,236 +174,121 @@ public class DefaultClientPolicyManager implements ClientPolicyManager {
|
|||
void run(ClientPolicyExecutorProvider executor) throws ClientPolicyException;
|
||||
}
|
||||
|
||||
|
||||
// Client Polices Realm Attributes Keys
|
||||
public static final String CLIENT_PROFILES = "client-policies.profiles";
|
||||
public static final String CLIENT_POLICIES = "client-policies.policies";
|
||||
|
||||
// builtin profiles and policies are loaded on booting keycloak at once.
|
||||
// therefore, their representations are kept and remain unchanged.
|
||||
// these are shared among all realms.
|
||||
|
||||
// those can be null to show that no profile/policy exist
|
||||
private static String builtinClientProfilesJson;
|
||||
private static String builtinClientPoliciesJson;
|
||||
|
||||
@Override
|
||||
public void setupClientPoliciesOnKeycloakApp(String profilesFilePath, String policiesFilePath) {
|
||||
logger.trace("LOAD BUILTIN PROFILE POLICIES ON KEYCLOAK");
|
||||
|
||||
// client profile can be referred from client policy so that client profile needs to be loaded at first.
|
||||
// load builtin profiles on keycloak app
|
||||
ClientProfilesRepresentation validatedProfilesRep = null;
|
||||
try {
|
||||
validatedProfilesRep = ClientPoliciesUtil.getValidatedBuiltinClientProfilesRepresentation(session, getClass().getResourceAsStream(profilesFilePath));
|
||||
} catch (ClientPolicyException cpe) {
|
||||
logger.warnv("LOAD BUILTIN PROFILES ON KEYCLOAK FAILED :: error = {0}, error detail = {1}", cpe.getError(), cpe.getErrorDetail());
|
||||
return;
|
||||
}
|
||||
|
||||
String validatedJson = null;
|
||||
try {
|
||||
validatedJson = ClientPoliciesUtil.convertClientProfilesRepresentationToJson(validatedProfilesRep);
|
||||
} catch (ClientPolicyException cpe) {
|
||||
logger.warnv("VALIDATE SERIALIZE BUILTIN PROFILES ON KEYCLOAK FAILED :: error = {0}, error detail = {1}", cpe.getError(), cpe.getErrorDetail());
|
||||
return;
|
||||
}
|
||||
|
||||
builtinClientProfilesJson = validatedJson;
|
||||
|
||||
// load builtin policies on keycloak app
|
||||
ClientPoliciesRepresentation validatedPoliciesRep = null;
|
||||
try {
|
||||
validatedPoliciesRep = ClientPoliciesUtil.getValidatedBuiltinClientPoliciesRepresentation(session, getClass().getResourceAsStream(policiesFilePath));
|
||||
} catch (ClientPolicyException cpe) {
|
||||
logger.warnv("LOAD BUILTIN POLICIES ON KEYCLOAK FAILED :: error = {0}, error detail = {1}", cpe.getError(), cpe.getErrorDetail());
|
||||
builtinClientProfilesJson = null;
|
||||
return;
|
||||
}
|
||||
|
||||
validatedJson = null;
|
||||
try {
|
||||
validatedJson = ClientPoliciesUtil.convertClientPoliciesRepresentationToJson(validatedPoliciesRep);
|
||||
} catch (ClientPolicyException cpe) {
|
||||
logger.warnv("VALIDATE SERIALIZE BUILTIN POLICIES ON KEYCLOAK FAILED :: error = {0}, error detail = {1}", cpe.getError(), cpe.getErrorDetail());
|
||||
builtinClientProfilesJson = null;
|
||||
return;
|
||||
}
|
||||
|
||||
builtinClientPoliciesJson = validatedJson;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupClientPoliciesOnCreatedRealm(RealmModel realm) {
|
||||
logger.tracev("LOAD BUILTIN PROFILE POLICIES ON CREATED REALM :: realm = {0}", realm.getName());
|
||||
|
||||
// put already loaded builtin profiles/policies on keycloak app to newly created realm
|
||||
setClientProfilesJsonString(realm, builtinClientProfilesJson);
|
||||
setClientPoliciesJsonString(realm, builtinClientPoliciesJson);
|
||||
// For now, not create any create policies on the new realms. Administrator is supposed to add the policies if needed
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupClientPoliciesOnImportedRealm(RealmModel realm, RealmRepresentation rep) {
|
||||
public void updateRealmModelFromRepresentation(RealmModel realm, RealmRepresentation rep) {
|
||||
logger.tracev("LOAD PROFILE POLICIES ON IMPORTED REALM :: realm = {0}", realm.getName());
|
||||
|
||||
// put already loaded builtin profiles/policies on keycloak app to newly created realm
|
||||
setClientProfilesJsonString(realm, builtinClientProfilesJson);
|
||||
setClientPoliciesJsonString(realm, builtinClientPoliciesJson);
|
||||
|
||||
// merge imported polices/profiles with builtin policies/profiles
|
||||
String validatedJson = null;
|
||||
try {
|
||||
validatedJson = ClientPoliciesUtil.getValidatedClientProfilesJson(session, realm, rep.getClientProfiles());
|
||||
} catch (ClientPolicyException e) {
|
||||
logger.warnv("VALIDATE SERIALIZE IMPORTED REALM PROFILES FAILED :: error = {0}, error detail = {1}", e.getError(), e.getErrorDetail());
|
||||
// revert to builtin profiles
|
||||
validatedJson = builtinClientProfilesJson;
|
||||
if (rep.getClientProfiles() != null) {
|
||||
try {
|
||||
updateClientProfiles(realm, rep.getClientProfiles());
|
||||
} catch (ClientPolicyException e) {
|
||||
logger.warnv("VALIDATE SERIALIZE IMPORTED REALM PROFILES FAILED :: error = {0}, error detail = {1}", e.getError(), e.getErrorDetail());
|
||||
throw new RuntimeException("Failed to update client profiles", e);
|
||||
}
|
||||
}
|
||||
setClientProfilesJsonString(realm, validatedJson);
|
||||
|
||||
try {
|
||||
validatedJson = ClientPoliciesUtil.getValidatedClientPoliciesJson(session, realm, rep.getClientPolicies());
|
||||
} catch (ClientPolicyException e) {
|
||||
logger.warnv("VALIDATE SERIALIZE IMPORTED REALM POLICIES FAILED :: error = {0}, error detail = {1}", e.getError(), e.getErrorDetail());
|
||||
// revert to builtin profiles
|
||||
validatedJson = builtinClientPoliciesJson;
|
||||
if (rep.getClientPolicies() != null) {
|
||||
try {
|
||||
updateClientPolicies(realm, rep.getClientPolicies());
|
||||
} catch (ClientPolicyException e) {
|
||||
logger.warnv("VALIDATE SERIALIZE IMPORTED REALM POLICIES FAILED :: error = {0}, error detail = {1}", e.getError(), e.getErrorDetail());
|
||||
throw new RuntimeException("Failed to update client policies", e);
|
||||
}
|
||||
} else {
|
||||
setupClientPoliciesOnCreatedRealm(realm);
|
||||
}
|
||||
setClientPoliciesJsonString(realm, validatedJson);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateClientProfiles(RealmModel realm, String json) throws ClientPolicyException {
|
||||
logger.tracev("UPDATE PROFILES :: realm = {0}, PUT = {1}", realm.getName(), json);
|
||||
String validatedJsonString = null;
|
||||
public void updateClientProfiles(RealmModel realm, ClientProfilesRepresentation clientProfiles) throws ClientPolicyException {
|
||||
try {
|
||||
validatedJsonString = getValidatedClientProfilesJson(realm, json);
|
||||
if (clientProfiles == null) {
|
||||
throw new ClientPolicyException("Passing null clientProfiles not allowed");
|
||||
}
|
||||
ClientProfilesRepresentation validatedProfilesRep = ClientPoliciesUtil.getValidatedClientProfilesForUpdate(session, realm, clientProfiles, globalClientProfilesSupplier.get());
|
||||
String validatedJsonString = ClientPoliciesUtil.convertClientProfilesRepresentationToJson(validatedProfilesRep);
|
||||
ClientPoliciesUtil.setClientProfilesJsonString(realm, validatedJsonString);
|
||||
logger.tracev("UPDATE PROFILES :: realm = {0}, validated and modified PUT = {1}", realm.getName(), validatedJsonString);
|
||||
} catch (ClientPolicyException e) {
|
||||
logger.warnv("VALIDATE SERIALIZE PROFILES FAILED :: error = {0}, error detail = {1}", e.getError(), e.getErrorDetail());
|
||||
throw e;
|
||||
}
|
||||
setClientProfilesJsonString(realm, validatedJsonString);
|
||||
logger.tracev("UPDATE PROFILES :: realm = {0}, validated and modified PUT = {1}", realm.getName(), validatedJsonString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientProfiles(RealmModel realm) {
|
||||
String json = getClientProfilesJsonString(realm);
|
||||
logger.tracev("GET PROFILES :: realm = {0}, GET = {1}", realm.getName(), json);
|
||||
return json;
|
||||
public ClientProfilesRepresentation getClientProfiles(RealmModel realm, boolean includeGlobalProfiles) throws ClientPolicyException {
|
||||
try {
|
||||
ClientProfilesRepresentation clientProfiles = ClientPoliciesUtil.getClientProfilesRepresentation(session, realm);
|
||||
if (includeGlobalProfiles) {
|
||||
clientProfiles.setGlobalProfiles(new LinkedList<>(globalClientProfilesSupplier.get()));
|
||||
}
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.tracev("GET PROFILES :: realm = {0}, GET = {1}", realm.getName(), JsonSerialization.writeValueAsString(clientProfiles));
|
||||
}
|
||||
|
||||
return clientProfiles;
|
||||
} catch (ClientPolicyException e) {
|
||||
logger.warnv("GET CLIENT PROFILES FAILED :: error = {0}, error detail = {1}", e.getError(), e.getErrorDetail());
|
||||
throw e;
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException("Unexpected exception when converting JSON to String", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateClientPolicies(RealmModel realm, String json) throws ClientPolicyException {
|
||||
logger.tracev("UPDATE POLICIES :: realm = {0}, PUT = {1}", realm.getName(), json);
|
||||
public void updateClientPolicies(RealmModel realm, ClientPoliciesRepresentation clientPolicies) throws ClientPolicyException {
|
||||
String validatedJsonString = null;
|
||||
try {
|
||||
validatedJsonString = getValidatedClientPoliciesJson(realm, json);
|
||||
if (clientPolicies == null) {
|
||||
throw new ClientPolicyException("Passing null clientPolicies not allowed");
|
||||
}
|
||||
ClientPoliciesRepresentation clientPoliciesRep = ClientPoliciesUtil.getValidatedClientPoliciesForUpdate(session, realm, clientPolicies, globalClientProfilesSupplier.get());
|
||||
validatedJsonString = ClientPoliciesUtil.convertClientPoliciesRepresentationToJson(clientPoliciesRep);
|
||||
} catch (ClientPolicyException e) {
|
||||
logger.warnv("VALIDATE SERIALIZE POLICIES FAILED :: error = {0}, error detail = {1}", e.getError(), e.getErrorDetail());
|
||||
throw e;
|
||||
}
|
||||
setClientPoliciesJsonString(realm, validatedJsonString);
|
||||
ClientPoliciesUtil.setClientPoliciesJsonString(realm, validatedJsonString);
|
||||
logger.tracev("UPDATE POLICIES :: realm = {0}, validated and modified PUT = {1}", realm.getName(), validatedJsonString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupClientPoliciesOnExportingRealm(RealmModel realm, RealmRepresentation rep) {
|
||||
// client profiles that filter out builtin profiles..
|
||||
ClientProfilesRepresentation filteredOutProfiles = null;
|
||||
public ClientPoliciesRepresentation getClientPolicies(RealmModel realm) throws ClientPolicyException {
|
||||
try {
|
||||
filteredOutProfiles = getClientProfilesForExport(realm);
|
||||
} catch (ClientPolicyException e) {
|
||||
// set as null
|
||||
}
|
||||
rep.setClientProfiles(filteredOutProfiles);
|
||||
|
||||
// client policies that filter out builtin and policies.
|
||||
ClientPoliciesRepresentation filteredOutPolicies = null;
|
||||
try {
|
||||
filteredOutPolicies = getClientPoliciesForExport(realm);
|
||||
} catch (ClientPolicyException e) {
|
||||
// set as null
|
||||
}
|
||||
rep.setClientPolicies(filteredOutPolicies);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientPolicies(RealmModel realm) {
|
||||
String json = getClientPoliciesJsonString(realm);
|
||||
logger.tracev("GET POLICIES :: realm = {0}, GET = {1}", realm.getName(), json);
|
||||
return json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientProfilesOnKeycloakApp() {
|
||||
return builtinClientProfilesJson;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientPoliciesOnKeycloakApp() {
|
||||
return builtinClientPoliciesJson;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientProfilesJsonString(RealmModel realm) {
|
||||
return realm.getAttribute(CLIENT_PROFILES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientPoliciesJsonString(RealmModel realm) {
|
||||
return realm.getAttribute(CLIENT_POLICIES);
|
||||
}
|
||||
|
||||
private void setClientProfilesJsonString(RealmModel realm, String json) {
|
||||
realm.setAttribute(CLIENT_PROFILES, json);
|
||||
}
|
||||
|
||||
private void setClientPoliciesJsonString(RealmModel realm, String json) {
|
||||
realm.setAttribute(CLIENT_POLICIES, json);
|
||||
}
|
||||
|
||||
private String getValidatedClientProfilesJson(RealmModel realm, String profilesJson) throws ClientPolicyException {
|
||||
ClientProfilesRepresentation validatedProfilesRep = ClientPoliciesUtil.getValidatedClientProfilesRepresentation(session, realm, profilesJson);
|
||||
return ClientPoliciesUtil.convertClientProfilesRepresentationToJson(validatedProfilesRep);
|
||||
}
|
||||
|
||||
private String getValidatedClientPoliciesJson(RealmModel realm, String policiesJson) throws ClientPolicyException {
|
||||
ClientPoliciesRepresentation validatedPoliciesRep = ClientPoliciesUtil.getValidatedClientPoliciesRepresentation(session, realm, policiesJson);
|
||||
return ClientPoliciesUtil.convertClientPoliciesRepresentationToJson(validatedPoliciesRep);
|
||||
}
|
||||
|
||||
/**
|
||||
* not return null
|
||||
*/
|
||||
private ClientProfilesRepresentation getClientProfilesForExport(RealmModel realm) throws ClientPolicyException {
|
||||
ClientProfilesRepresentation profilesRep = ClientPoliciesUtil.getClientProfilesRepresentation(session, realm);
|
||||
if (profilesRep == null || profilesRep.getProfiles() == null) {
|
||||
return new ClientProfilesRepresentation();
|
||||
}
|
||||
|
||||
// not export builtin profiles
|
||||
List<ClientProfileRepresentation> filteredProfileRepList = profilesRep.getProfiles().stream().filter(profileRep->!profileRep.isBuiltin()).collect(Collectors.toList());
|
||||
profilesRep.setProfiles(filteredProfileRepList);
|
||||
return profilesRep;
|
||||
}
|
||||
|
||||
/**
|
||||
* not return null
|
||||
*/
|
||||
private ClientPoliciesRepresentation getClientPoliciesForExport(RealmModel realm) throws ClientPolicyException {
|
||||
ClientPoliciesRepresentation policiesRep = ClientPoliciesUtil.getClientPoliciesRepresentation(session, realm);
|
||||
if (policiesRep == null || policiesRep.getPolicies() == null) {
|
||||
return new ClientPoliciesRepresentation();
|
||||
}
|
||||
|
||||
policiesRep.getPolicies().stream().forEach(policyRep->{
|
||||
if (policyRep.isBuiltin()) {
|
||||
// only keeps name, builtin and enabled fields.
|
||||
policyRep.setDescription(null);
|
||||
policyRep.setConditions(null);
|
||||
policyRep.setProfiles(null);
|
||||
ClientPoliciesRepresentation clientPolicies = ClientPoliciesUtil.getClientPoliciesRepresentation(session, realm);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.tracev("GET POLICIES :: realm = {0}, GET = {1}", realm.getName(), JsonSerialization.writeValueAsString(clientPolicies));
|
||||
}
|
||||
});
|
||||
return policiesRep;
|
||||
return clientPolicies;
|
||||
} catch (ClientPolicyException e) {
|
||||
logger.warnv("GET CLIENT POLICIES FAILED :: error = {0}, error detail = {1}", e.getError(), e.getErrorDetail());
|
||||
throw e;
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException("Unexpected exception when converting JSON to String", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRealmRepresentationFromModel(RealmModel realm, RealmRepresentation rep) {
|
||||
try {
|
||||
// client profiles that filter out global profiles..
|
||||
ClientProfilesRepresentation filteredOutProfiles = getClientProfiles(realm, false);
|
||||
rep.setClientProfiles(filteredOutProfiles);
|
||||
|
||||
ClientPoliciesRepresentation filteredOutPolicies = getClientPolicies(realm);
|
||||
rep.setClientPolicies(filteredOutPolicies);
|
||||
} catch (ClientPolicyException cpe) {
|
||||
throw new IllegalStateException("Exception during export client profiles or client policies", cpe);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.representations.idm.ClientProfileRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class DefaultClientPolicyManagerFactory implements ClientPolicyManagerFactory {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DefaultClientPolicyManagerFactory.class);
|
||||
|
||||
// Global (builtin) profiles are loaded on booting keycloak at once.
|
||||
// therefore, their representations are kept and remain unchanged.
|
||||
// these are shared among all realms.
|
||||
private volatile List<ClientProfileRepresentation> globalClientProfiles;
|
||||
|
||||
@Override
|
||||
public ClientPolicyManager create(KeycloakSession session) {
|
||||
return new DefaultClientPolicyManager(session, () -> getGlobalClientProfiles(session));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInit(KeycloakSessionFactory factory) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "default";
|
||||
}
|
||||
|
||||
/**
|
||||
* When this method is called, assumption is that CLIENT_POLICIES feature is enabled
|
||||
*/
|
||||
protected List<ClientProfileRepresentation> getGlobalClientProfiles(KeycloakSession session) {
|
||||
if (globalClientProfiles == null) {
|
||||
synchronized (this) {
|
||||
if (globalClientProfiles == null) {
|
||||
logger.trace("LOAD GLOBAL CLIENT PROFILES ON KEYCLOAK");
|
||||
|
||||
// load builtin profiles from keycloak-services
|
||||
try {
|
||||
this.globalClientProfiles = ClientPoliciesUtil.getValidatedGlobalClientProfilesRepresentation(session, getClass().getResourceAsStream("/keycloak-default-client-profiles.json"));
|
||||
} catch (ClientPolicyException cpe) {
|
||||
logger.warnv("LOAD GLOBAL PROFILES ON KEYCLOAK FAILED :: error = {0}, error detail = {1}", cpe.getError(), cpe.getErrorDetail());
|
||||
throw new IllegalStateException(cpe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return globalClientProfiles;
|
||||
}
|
||||
}
|
|
@ -17,54 +17,24 @@
|
|||
|
||||
package org.keycloak.services.clientpolicy.condition;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.representations.idm.ClientPolicyConditionConfigurationRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyVote;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public class AnyClientCondition implements ClientPolicyConditionProvider<AnyClientCondition.Configuration> {
|
||||
|
||||
// to avoid null configuration, use vacant new instance to indicate that there is no configuration set up.
|
||||
private Configuration configuration = new Configuration();
|
||||
public class AnyClientCondition extends AbstractClientPolicyConditionProvider<ClientPolicyConditionConfigurationRepresentation> {
|
||||
|
||||
public AnyClientCondition(KeycloakSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupConfiguration(Configuration config) {
|
||||
this.configuration = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Configuration> getConditionConfigurationClass() {
|
||||
return Configuration.class;
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Configuration extends ClientPolicyConditionConfiguration {
|
||||
@JsonProperty("is-negative-logic")
|
||||
protected Boolean negativeLogic;
|
||||
|
||||
public Boolean isNegativeLogic() {
|
||||
return negativeLogic;
|
||||
}
|
||||
|
||||
public void setNegativeLogic(Boolean negativeLogic) {
|
||||
this.negativeLogic = negativeLogic;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNegativeLogic() {
|
||||
return Optional.ofNullable(this.configuration.isNegativeLogic()).orElse(Boolean.FALSE).booleanValue();
|
||||
public Class<ClientPolicyConditionConfigurationRepresentation> getConditionConfigurationClass() {
|
||||
return ClientPolicyConditionConfigurationRepresentation.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -24,31 +24,20 @@ import java.util.Optional;
|
|||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.representations.idm.ClientPolicyConditionConfigurationRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyVote;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public class ClientAccessTypeCondition implements ClientPolicyConditionProvider<ClientAccessTypeCondition.Configuration> {
|
||||
public class ClientAccessTypeCondition extends AbstractClientPolicyConditionProvider<ClientAccessTypeCondition.Configuration> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ClientAccessTypeCondition.class);
|
||||
|
||||
// to avoid null configuration, use vacant new instance to indicate that there is no configuration set up.
|
||||
private Configuration configuration = new Configuration();
|
||||
private final KeycloakSession session;
|
||||
|
||||
public ClientAccessTypeCondition(KeycloakSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupConfiguration(Configuration config) {
|
||||
this.configuration = config;
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -56,18 +45,7 @@ public class ClientAccessTypeCondition implements ClientPolicyConditionProvider<
|
|||
return Configuration.class;
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Configuration extends ClientPolicyConditionConfiguration {
|
||||
@JsonProperty("is-negative-logic")
|
||||
protected Boolean negativeLogic;
|
||||
|
||||
public Boolean isNegativeLogic() {
|
||||
return negativeLogic;
|
||||
}
|
||||
|
||||
public void setNegativeLogic(Boolean negativeLogic) {
|
||||
this.negativeLogic = negativeLogic;
|
||||
}
|
||||
public static class Configuration extends ClientPolicyConditionConfigurationRepresentation {
|
||||
|
||||
protected List<String> type;
|
||||
|
||||
|
@ -80,11 +58,6 @@ public class ClientAccessTypeCondition implements ClientPolicyConditionProvider<
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNegativeLogic() {
|
||||
return Optional.ofNullable(this.configuration.isNegativeLogic()).orElse(Boolean.FALSE).booleanValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProviderId() {
|
||||
return ClientAccessTypeConditionFactory.PROVIDER_ID;
|
||||
|
|
|
@ -73,7 +73,7 @@ public class ClientAccessTypeConditionFactory implements ClientPolicyConditionPr
|
|||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "It uses the client's access type (confidential, public, bearer-only) to determine whether the policy is applied.";
|
||||
return "It uses the client's access type (confidential, public, bearer-only) to determine whether the policy is applied. Condition is checked during most of OpenID Connect requests (Authorization request, token requests, introspection endpoint request etc).";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,7 +19,6 @@ package org.keycloak.services.clientpolicy.condition;
|
|||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -27,31 +26,20 @@ import org.jboss.logging.Logger;
|
|||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.representations.idm.ClientPolicyConditionConfigurationRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyVote;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public class ClientRolesCondition implements ClientPolicyConditionProvider<ClientRolesCondition.Configuration> {
|
||||
public class ClientRolesCondition extends AbstractClientPolicyConditionProvider<ClientRolesCondition.Configuration> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ClientRolesCondition.class);
|
||||
|
||||
// to avoid null configuration, use vacant new instance to indicate that there is no configuration set up.
|
||||
private Configuration configuration = new Configuration();
|
||||
private final KeycloakSession session;
|
||||
|
||||
public ClientRolesCondition(KeycloakSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupConfiguration(Configuration config) {
|
||||
this.configuration = config;
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -59,18 +47,7 @@ public class ClientRolesCondition implements ClientPolicyConditionProvider<Clien
|
|||
return Configuration.class;
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Configuration extends ClientPolicyConditionConfiguration {
|
||||
@JsonProperty("is-negative-logic")
|
||||
protected Boolean negativeLogic;
|
||||
|
||||
public Boolean isNegativeLogic() {
|
||||
return negativeLogic;
|
||||
}
|
||||
|
||||
public void setNegativeLogic(Boolean negativeLogic) {
|
||||
this.negativeLogic = negativeLogic;
|
||||
}
|
||||
public static class Configuration extends ClientPolicyConditionConfigurationRepresentation {
|
||||
|
||||
protected List<String> roles;
|
||||
|
||||
|
@ -83,11 +60,6 @@ public class ClientRolesCondition implements ClientPolicyConditionProvider<Clien
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNegativeLogic() {
|
||||
return Optional.ofNullable(this.configuration.isNegativeLogic()).orElse(Boolean.FALSE).booleanValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProviderId() {
|
||||
return ClientRolesConditionFactory.PROVIDER_ID;
|
||||
|
|
|
@ -66,7 +66,7 @@ public class ClientRolesConditionFactory implements ClientPolicyConditionProvide
|
|||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "The condition checks whether one of the specified client roles is applied to the client to determine whether the policy is applied.";
|
||||
return "The condition checks whether one of the specified client roles exists on the client to determine whether the policy is applied. This effectively allows client administrator to create client role of specified name on the client to make sure that particular client policy will be applied on requests of this client. Condition is checked during most of OpenID Connect requests (Authorization request, token requests, introspection endpoint request etc).";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -21,7 +21,6 @@ import java.util.Arrays;
|
|||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
@ -30,33 +29,22 @@ import org.keycloak.models.AuthenticatedClientSessionModel;
|
|||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequest;
|
||||
import org.keycloak.representations.idm.ClientPolicyConditionConfigurationRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyVote;
|
||||
import org.keycloak.services.clientpolicy.context.AuthorizationRequestContext;
|
||||
import org.keycloak.services.clientpolicy.context.TokenRequestContext;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public class ClientScopesCondition implements ClientPolicyConditionProvider<ClientScopesCondition.Configuration> {
|
||||
public class ClientScopesCondition extends AbstractClientPolicyConditionProvider<ClientScopesCondition.Configuration> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ClientScopesCondition.class);
|
||||
|
||||
// to avoid null configuration, use vacant new instance to indicate that there is no configuration set up.
|
||||
private Configuration configuration = new Configuration();
|
||||
private final KeycloakSession session;
|
||||
|
||||
public ClientScopesCondition(KeycloakSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupConfiguration(Configuration config) {
|
||||
this.configuration = config;
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -64,18 +52,7 @@ public class ClientScopesCondition implements ClientPolicyConditionProvider<Clie
|
|||
return Configuration.class;
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Configuration extends ClientPolicyConditionConfiguration {
|
||||
@JsonProperty("is-negative-logic")
|
||||
protected Boolean negativeLogic;
|
||||
|
||||
public Boolean isNegativeLogic() {
|
||||
return negativeLogic;
|
||||
}
|
||||
|
||||
public void setNegativeLogic(Boolean negativeLogic) {
|
||||
this.negativeLogic = negativeLogic;
|
||||
}
|
||||
public static class Configuration extends ClientPolicyConditionConfigurationRepresentation {
|
||||
|
||||
protected String type;
|
||||
protected List<String> scope;
|
||||
|
@ -97,11 +74,6 @@ public class ClientScopesCondition implements ClientPolicyConditionProvider<Clie
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNegativeLogic() {
|
||||
return Optional.ofNullable(this.configuration.isNegativeLogic()).orElse(Boolean.FALSE).booleanValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProviderId() {
|
||||
return ClientScopesConditionFactory.PROVIDER_ID;
|
||||
|
|
|
@ -18,9 +18,11 @@
|
|||
package org.keycloak.services.clientpolicy.condition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.keycloak.Config.Scope;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
|
@ -40,10 +42,13 @@ public class ClientScopesConditionFactory implements ClientPolicyConditionProvid
|
|||
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||
|
||||
static {
|
||||
ProviderConfigProperty property;
|
||||
property = new ProviderConfigProperty(SCOPES, PROVIDER_ID + ".label", PROVIDER_ID + ".tooltip", ProviderConfigProperty.MULTIVALUED_STRING_TYPE, "offline_access");
|
||||
ProviderConfigProperty property = new ProviderConfigProperty(SCOPES, PROVIDER_ID + ".label", PROVIDER_ID + ".tooltip", ProviderConfigProperty.MULTIVALUED_STRING_TYPE, OAuth2Constants.OFFLINE_ACCESS);
|
||||
configProperties.add(property);
|
||||
property = new ProviderConfigProperty(TYPE, "Scope Type", "Default or Optional", ProviderConfigProperty.LIST_TYPE, OPTIONAL);
|
||||
property = new ProviderConfigProperty(TYPE, "Scope Type",
|
||||
"If set to 'Default', condition evaluates to true if client has some default scopes of the values specified by the 'Expected Scopes' property. " +
|
||||
"If set to 'Optional', condition evaluates to true if client has some optional scopes of the values specified by the 'Expected Scopes' property and at the same time, the scope were used as a value of 'scope' parameter in the request",
|
||||
ProviderConfigProperty.LIST_TYPE, OPTIONAL);
|
||||
property.setOptions(Arrays.asList(DEFAULT, OPTIONAL));
|
||||
configProperties.add(property);
|
||||
}
|
||||
|
||||
|
@ -71,7 +76,7 @@ public class ClientScopesConditionFactory implements ClientPolicyConditionProvid
|
|||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "It uses the scopes requested or assigned in advance to the client to determine whether the policy is applied to this client.";
|
||||
return "It uses the scopes requested or assigned in advance to the client to determine whether the policy is applied to this client. Condition is evaluated during OpenID Connect authorization request and/or token request.";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,11 +19,11 @@ package org.keycloak.services.clientpolicy.condition;
|
|||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.representations.JsonWebToken;
|
||||
import org.keycloak.representations.idm.ClientPolicyConditionConfigurationRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyVote;
|
||||
|
@ -31,27 +31,17 @@ import org.keycloak.services.clientpolicy.context.ClientCRUDContext;
|
|||
import org.keycloak.services.clientregistration.ClientRegistrationTokenUtils;
|
||||
import org.keycloak.util.TokenUtil;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public class ClientUpdateContextCondition implements ClientPolicyConditionProvider<ClientUpdateContextCondition.Configuration> {
|
||||
public class ClientUpdateContextCondition extends AbstractClientPolicyConditionProvider<ClientUpdateContextCondition.Configuration> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ClientUpdateContextCondition.class);
|
||||
|
||||
// to avoid null configuration, use vacant new instance to indicate that there is no configuration set up.
|
||||
private Configuration configuration = new Configuration();
|
||||
private final KeycloakSession session;
|
||||
|
||||
public ClientUpdateContextCondition(KeycloakSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupConfiguration(Configuration config) {
|
||||
this.configuration = config;
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -59,18 +49,7 @@ public class ClientUpdateContextCondition implements ClientPolicyConditionProvid
|
|||
return Configuration.class;
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Configuration extends ClientPolicyConditionConfiguration {
|
||||
@JsonProperty("is-negative-logic")
|
||||
protected Boolean negativeLogic;
|
||||
|
||||
public Boolean isNegativeLogic() {
|
||||
return negativeLogic;
|
||||
}
|
||||
|
||||
public void setNegativeLogic(Boolean negativeLogic) {
|
||||
this.negativeLogic = negativeLogic;
|
||||
}
|
||||
public static class Configuration extends ClientPolicyConditionConfigurationRepresentation {
|
||||
|
||||
@JsonProperty("update-client-source")
|
||||
protected List<String> updateClientSource;
|
||||
|
@ -84,11 +63,6 @@ public class ClientUpdateContextCondition implements ClientPolicyConditionProvid
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNegativeLogic() {
|
||||
return Optional.ofNullable(this.configuration.isNegativeLogic()).orElse(Boolean.FALSE).booleanValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProviderId() {
|
||||
return ClientUpdateContextConditionFactory.PROVIDER_ID;
|
||||
|
|
|
@ -44,7 +44,11 @@ public class ClientUpdateContextConditionFactory implements ClientPolicyConditio
|
|||
|
||||
static {
|
||||
ProviderConfigProperty property;
|
||||
property = new ProviderConfigProperty(UPDATE_CLIENT_SOURCE, null, null, ProviderConfigProperty.MULTIVALUED_LIST_TYPE, BY_AUTHENTICATED_USER);
|
||||
property = new ProviderConfigProperty(UPDATE_CLIENT_SOURCE, "Update Client Context", "Specifies the context how is client created or updated. " +
|
||||
"ByInitialAccessToken is usually OpenID Connect client registration with the initial access token. " +
|
||||
"ByRegistrationAccessToken is usually OpenID Connect client update request with the registration access token. " +
|
||||
"ByAuthenticatedUser is usually Admin REST request with the token on behalf of authenticated user or client (service account). ByAnonymous is usually anonymous OpenID Client registration request.",
|
||||
ProviderConfigProperty.MULTIVALUED_LIST_TYPE, BY_AUTHENTICATED_USER);
|
||||
List<String> updateProfileValues = Arrays.asList(BY_AUTHENTICATED_USER, BY_ANONYMOUS, BY_INITIAL_ACCESS_TOKEN, BY_REGISTRATION_ACCESS_TOKEN);
|
||||
property.setOptions(updateProfileValues);
|
||||
configProperties.add(property);
|
||||
|
|
|
@ -19,7 +19,6 @@ package org.keycloak.services.clientpolicy.condition;
|
|||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -29,6 +28,7 @@ import org.keycloak.models.GroupModel;
|
|||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.JsonWebToken;
|
||||
import org.keycloak.representations.idm.ClientPolicyConditionConfigurationRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyVote;
|
||||
|
@ -38,27 +38,15 @@ import org.keycloak.services.clientpolicy.context.ClientCRUDContext;
|
|||
import org.keycloak.services.clientpolicy.context.DynamicClientRegisterContext;
|
||||
import org.keycloak.services.clientpolicy.context.DynamicClientUpdateContext;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public class ClientUpdateSourceGroupsCondition implements ClientPolicyConditionProvider<ClientUpdateSourceGroupsCondition.Configuration> {
|
||||
public class ClientUpdateSourceGroupsCondition extends AbstractClientPolicyConditionProvider<ClientUpdateSourceGroupsCondition.Configuration> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ClientUpdateSourceGroupsCondition.class);
|
||||
|
||||
// to avoid null configuration, use vacant new instance to indicate that there is no configuration set up.
|
||||
private Configuration configuration = new Configuration();
|
||||
private final KeycloakSession session;
|
||||
|
||||
public ClientUpdateSourceGroupsCondition(KeycloakSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupConfiguration(Configuration config) {
|
||||
this.configuration = config;
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -66,18 +54,7 @@ public class ClientUpdateSourceGroupsCondition implements ClientPolicyConditionP
|
|||
return Configuration.class;
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Configuration extends ClientPolicyConditionConfiguration {
|
||||
@JsonProperty("is-negative-logic")
|
||||
protected Boolean negativeLogic;
|
||||
|
||||
public Boolean isNegativeLogic() {
|
||||
return negativeLogic;
|
||||
}
|
||||
|
||||
public void setNegativeLogic(Boolean negativeLogic) {
|
||||
this.negativeLogic = negativeLogic;
|
||||
}
|
||||
public static class Configuration extends ClientPolicyConditionConfigurationRepresentation {
|
||||
|
||||
protected List<String> groups;
|
||||
|
||||
|
@ -90,11 +67,6 @@ public class ClientUpdateSourceGroupsCondition implements ClientPolicyConditionP
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNegativeLogic() {
|
||||
return Optional.ofNullable(this.configuration.isNegativeLogic()).orElse(Boolean.FALSE).booleanValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProviderId() {
|
||||
return ClientUpdateSourceGroupsConditionFactory.PROVIDER_ID;
|
||||
|
|
|
@ -21,36 +21,26 @@ import java.net.InetAddress;
|
|||
import java.net.UnknownHostException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.representations.idm.ClientPolicyConditionConfigurationRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyVote;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public class ClientUpdateSourceHostsCondition implements ClientPolicyConditionProvider<ClientUpdateSourceHostsCondition.Configuration> {
|
||||
public class ClientUpdateSourceHostsCondition extends AbstractClientPolicyConditionProvider<ClientUpdateSourceHostsCondition.Configuration> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ClientUpdateSourceHostsCondition.class);
|
||||
|
||||
// to avoid null configuration, use vacant new instance to indicate that there is no configuration set up.
|
||||
private Configuration configuration = new Configuration();
|
||||
private final KeycloakSession session;
|
||||
|
||||
public ClientUpdateSourceHostsCondition(KeycloakSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupConfiguration(Configuration config) {
|
||||
this.configuration = config;
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -59,18 +49,7 @@ public class ClientUpdateSourceHostsCondition implements ClientPolicyConditionPr
|
|||
}
|
||||
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Configuration extends ClientPolicyConditionConfiguration {
|
||||
@JsonProperty("is-negative-logic")
|
||||
protected Boolean negativeLogic;
|
||||
|
||||
public Boolean isNegativeLogic() {
|
||||
return negativeLogic;
|
||||
}
|
||||
|
||||
public void setNegativeLogic(Boolean negativeLogic) {
|
||||
this.negativeLogic = negativeLogic;
|
||||
}
|
||||
public static class Configuration extends ClientPolicyConditionConfigurationRepresentation {
|
||||
|
||||
@JsonProperty("trusted-hosts")
|
||||
protected List<String> trustedHosts;
|
||||
|
@ -84,11 +63,6 @@ public class ClientUpdateSourceHostsCondition implements ClientPolicyConditionPr
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNegativeLogic() {
|
||||
return Optional.ofNullable(this.configuration.isNegativeLogic()).orElse(Boolean.FALSE).booleanValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProviderId() {
|
||||
return ClientUpdateSourceHostsConditionFactory.PROVIDER_ID;
|
||||
|
|
|
@ -19,7 +19,6 @@ package org.keycloak.services.clientpolicy.condition;
|
|||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -29,7 +28,9 @@ import org.keycloak.models.KeycloakSession;
|
|||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.representations.JsonWebToken;
|
||||
import org.keycloak.representations.idm.ClientPolicyConditionConfigurationRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyVote;
|
||||
|
@ -39,27 +40,16 @@ import org.keycloak.services.clientpolicy.context.ClientCRUDContext;
|
|||
import org.keycloak.services.clientpolicy.context.DynamicClientRegisterContext;
|
||||
import org.keycloak.services.clientpolicy.context.DynamicClientUpdateContext;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public class ClientUpdateSourceRolesCondition implements ClientPolicyConditionProvider<ClientUpdateSourceRolesCondition.Configuration> {
|
||||
public class ClientUpdateSourceRolesCondition extends AbstractClientPolicyConditionProvider<ClientUpdateSourceRolesCondition.Configuration> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ClientUpdateSourceRolesCondition.class);
|
||||
|
||||
// to avoid null configuration, use vacant new instance to indicate that there is no configuration set up.
|
||||
private Configuration configuration = new Configuration();
|
||||
private final KeycloakSession session;
|
||||
|
||||
public ClientUpdateSourceRolesCondition(KeycloakSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupConfiguration(Configuration config) {
|
||||
this.configuration = config;
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -67,18 +57,7 @@ public class ClientUpdateSourceRolesCondition implements ClientPolicyConditionPr
|
|||
return Configuration.class;
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Configuration extends ClientPolicyConditionConfiguration {
|
||||
@JsonProperty("is-negative-logic")
|
||||
protected Boolean negativeLogic;
|
||||
|
||||
public Boolean isNegativeLogic() {
|
||||
return negativeLogic;
|
||||
}
|
||||
|
||||
public void setNegativeLogic(Boolean negativeLogic) {
|
||||
this.negativeLogic = negativeLogic;
|
||||
}
|
||||
public static class Configuration extends ClientPolicyConditionConfigurationRepresentation {
|
||||
|
||||
protected List<String> roles;
|
||||
|
||||
|
@ -91,11 +70,6 @@ public class ClientUpdateSourceRolesCondition implements ClientPolicyConditionPr
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNegativeLogic() {
|
||||
return Optional.ofNullable(this.configuration.isNegativeLogic()).orElse(Boolean.FALSE).booleanValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProviderId() {
|
||||
return ClientUpdateSourceRolesConditionFactory.PROVIDER_ID;
|
||||
|
@ -147,28 +121,21 @@ public class ClientUpdateSourceRolesCondition implements ClientPolicyConditionPr
|
|||
Set<String> expectedRoles = instantiateRolesForMatching();
|
||||
if (expectedRoles == null) return false;
|
||||
|
||||
// user.getRoleMappingsStream() never returns null according to {@link UserModel.getRoleMappingsStream}
|
||||
Set<String> roles = user.getRoleMappingsStream().map(RoleModel::getName).collect(Collectors.toSet());
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
// user.getRoleMappingsStream() never returns null according to {@link UserModel.getRoleMappingsStream}
|
||||
Set<String> roles = user.getRoleMappingsStream().map(RoleModel::getName).collect(Collectors.toSet());
|
||||
|
||||
roles.forEach(i -> logger.tracev("user role = {0}", i));
|
||||
expectedRoles.forEach(i -> logger.tracev("roles expected = {0}", i));
|
||||
}
|
||||
|
||||
RealmModel realm = session.getContext().getRealm();
|
||||
boolean isMatched = expectedRoles.stream().anyMatch(i->{
|
||||
if (realm.getRole(i) != null && user.hasRole(realm.getRole(i))) {
|
||||
return true;
|
||||
}
|
||||
return realm.getClientsStream().anyMatch(j->{
|
||||
if (j.getRole(i) != null && user.hasRole(j.getRole(i))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
return isMatched;
|
||||
for (String roleName : expectedRoles) {
|
||||
RoleModel role = KeycloakModelUtils.getRoleFromString(realm, roleName);
|
||||
if (role == null) continue;
|
||||
if (user.hasRole(role)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Set<String> instantiateRolesForMatching() {
|
||||
|
|
|
@ -20,15 +20,14 @@ package org.keycloak.services.clientpolicy.executor;
|
|||
import org.keycloak.OAuthErrorException;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.representations.idm.ClientPolicyExecutorConfigurationRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public class ConfidentialClientAcceptExecutor implements ClientPolicyExecutorProvider<ClientPolicyExecutorConfiguration> {
|
||||
public class ConfidentialClientAcceptExecutor implements ClientPolicyExecutorProvider<ClientPolicyExecutorConfigurationRepresentation> {
|
||||
|
||||
protected final KeycloakSession session;
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.keycloak.services.clientpolicy.executor;
|
|||
|
||||
import org.keycloak.events.Errors;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.representations.idm.ClientPolicyExecutorConfigurationRepresentation;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
|
@ -27,7 +28,7 @@ import org.keycloak.services.clientpolicy.context.ClientCRUDContext;
|
|||
/**
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public class ConsentRequiredExecutor implements ClientPolicyExecutorProvider<ClientPolicyExecutorConfiguration> {
|
||||
public class ConsentRequiredExecutor implements ClientPolicyExecutorProvider<ClientPolicyExecutorConfigurationRepresentation> {
|
||||
|
||||
@Override
|
||||
public void executeOnEvent(ClientPolicyContext context) throws ClientPolicyException {
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.keycloak.models.KeycloakSession;
|
|||
import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.RefreshToken;
|
||||
import org.keycloak.representations.idm.ClientPolicyExecutorConfigurationRepresentation;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
|
@ -36,7 +37,6 @@ import org.keycloak.services.clientpolicy.context.TokenRevokeContext;
|
|||
import org.keycloak.services.clientpolicy.context.UserInfoRequestContext;
|
||||
import org.keycloak.services.util.MtlsHoKTokenUtil;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
|
@ -61,8 +61,7 @@ public class HolderOfKeyEnforceExecutor implements ClientPolicyExecutorProvider<
|
|||
return Configuration.class;
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Configuration extends ClientPolicyExecutorConfiguration {
|
||||
public static class Configuration extends ClientPolicyExecutorConfigurationRepresentation {
|
||||
@JsonProperty("is-augment")
|
||||
protected Boolean augment;
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ public class HolderOfKeyEnforceExecutorFactory implements ClientPolicyExecutorPr
|
|||
public static final String IS_AUGMENT = "is-augment";
|
||||
|
||||
private static final ProviderConfigProperty IS_AUGMENT_PROPERTY = new ProviderConfigProperty(
|
||||
IS_AUGMENT, null, null, ProviderConfigProperty.BOOLEAN_TYPE, false);
|
||||
IS_AUGMENT, "Augment Configuration", "If On, then the during client creation or update, the configuration of the client will be augmented to use MTLS HoK token", ProviderConfigProperty.BOOLEAN_TYPE, false);
|
||||
|
||||
@Override
|
||||
public ClientPolicyExecutorProvider create(KeycloakSession session) {
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequest
|
|||
import org.keycloak.protocol.oidc.utils.OAuth2Code;
|
||||
import org.keycloak.protocol.oidc.utils.OAuth2CodeParser;
|
||||
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
|
||||
import org.keycloak.representations.idm.ClientPolicyExecutorConfigurationRepresentation;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
|
@ -42,7 +43,6 @@ import org.keycloak.services.clientpolicy.context.AuthorizationRequestContext;
|
|||
import org.keycloak.services.clientpolicy.context.ClientCRUDContext;
|
||||
import org.keycloak.services.clientpolicy.context.TokenRequestContext;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
|
@ -70,8 +70,7 @@ public class PKCEEnforceExecutor implements ClientPolicyExecutorProvider<PKCEEnf
|
|||
return Configuration.class;
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Configuration extends ClientPolicyExecutorConfiguration {
|
||||
public static class Configuration extends ClientPolicyExecutorConfigurationRepresentation {
|
||||
@JsonProperty("is-augment")
|
||||
protected Boolean augment;
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ public class PKCEEnforceExecutorFactory implements ClientPolicyExecutorProviderF
|
|||
public static final String IS_AUGMENT = "is-augment";
|
||||
|
||||
private static final ProviderConfigProperty IS_AUGMENT_PROPERTY = new ProviderConfigProperty(
|
||||
IS_AUGMENT, null, null, ProviderConfigProperty.BOOLEAN_TYPE, false);
|
||||
IS_AUGMENT, "Augment Configuration", "If On, then the during client creation or update, the configuration of the client will be augmented to enforce usage of PKCE", ProviderConfigProperty.BOOLEAN_TYPE, false);
|
||||
|
||||
@Override
|
||||
public ClientPolicyExecutorProvider create(KeycloakSession session) {
|
||||
|
|
|
@ -21,12 +21,12 @@ import java.util.List;
|
|||
|
||||
import org.keycloak.OAuthErrorException;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.representations.idm.ClientPolicyExecutorConfigurationRepresentation;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
import org.keycloak.services.clientpolicy.context.ClientCRUDContext;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
|
@ -51,8 +51,7 @@ public class SecureClientAuthEnforceExecutor implements ClientPolicyExecutorProv
|
|||
return Configuration.class;
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Configuration extends ClientPolicyExecutorConfiguration {
|
||||
public static class Configuration extends ClientPolicyExecutorConfigurationRepresentation {
|
||||
@JsonProperty("client-authns")
|
||||
protected List<String> clientAuthns;
|
||||
@JsonProperty("client-authns-augment")
|
||||
|
|
|
@ -20,12 +20,15 @@ package org.keycloak.services.clientpolicy.executor;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.keycloak.Config.Scope;
|
||||
import org.keycloak.authentication.ClientAuthenticator;
|
||||
import org.keycloak.authentication.authenticators.client.JWTClientAuthenticator;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
|
@ -38,12 +41,7 @@ public class SecureClientAuthEnforceExecutorFactory implements ClientPolicyExecu
|
|||
public static final String CLIENT_AUTHNS = "client-authns";
|
||||
public static final String CLIENT_AUTHNS_AUGMENT = "client-authns-augment";
|
||||
|
||||
private static final ProviderConfigProperty IS_AUGMENT_PROPERTY = new ProviderConfigProperty(
|
||||
IS_AUGMENT, null, null, ProviderConfigProperty.BOOLEAN_TYPE, false);
|
||||
private static final ProviderConfigProperty CLIENTAUTHNS_PROPERTY = new ProviderConfigProperty(
|
||||
CLIENT_AUTHNS, null, null, ProviderConfigProperty.MULTIVALUED_STRING_TYPE, null);
|
||||
private static final ProviderConfigProperty CLIENTAUTHNS_AUGMENT = new ProviderConfigProperty(
|
||||
CLIENT_AUTHNS_AUGMENT, null, null, ProviderConfigProperty.STRING_TYPE, JWTClientAuthenticator.PROVIDER_ID);
|
||||
private List<ProviderConfigProperty> configProperties = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public ClientPolicyExecutorProvider create(KeycloakSession session) {
|
||||
|
@ -56,6 +54,25 @@ public class SecureClientAuthEnforceExecutorFactory implements ClientPolicyExecu
|
|||
|
||||
@Override
|
||||
public void postInit(KeycloakSessionFactory factory) {
|
||||
ProviderConfigProperty isAugmentProperty = new ProviderConfigProperty(
|
||||
IS_AUGMENT, "Augment Configuration", "If On, then the during client creation or update, the configuration of the client will be augmented to enforce the authentication method to new clients",
|
||||
ProviderConfigProperty.BOOLEAN_TYPE, false);
|
||||
|
||||
List<String> clientAuthProviders = factory.getProviderFactoriesStream(ClientAuthenticator.class)
|
||||
.map(ProviderFactory::getId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
ProviderConfigProperty clientAuthnsProperty = new ProviderConfigProperty(
|
||||
CLIENT_AUTHNS, "Client Authentication Methods", "List of available client authentication methods, which are allowed for clients to use. Other client authentication methods will not be allowed.",
|
||||
ProviderConfigProperty.MULTIVALUED_LIST_TYPE, null);
|
||||
clientAuthnsProperty.setOptions(clientAuthProviders);
|
||||
|
||||
ProviderConfigProperty clientAuthnsAugment = new ProviderConfigProperty(
|
||||
CLIENT_AUTHNS_AUGMENT, "Augment Client Authentication Method", "If 'Augment Configuration' is ON, then this client authentication method will be set as the authentication method to new clients",
|
||||
ProviderConfigProperty.LIST_TYPE, JWTClientAuthenticator.PROVIDER_ID);
|
||||
clientAuthnsAugment.setOptions(clientAuthProviders);
|
||||
|
||||
configProperties = Arrays.asList(isAugmentProperty, clientAuthnsProperty, clientAuthnsAugment);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -74,7 +91,7 @@ public class SecureClientAuthEnforceExecutorFactory implements ClientPolicyExecu
|
|||
|
||||
@Override
|
||||
public List<ProviderConfigProperty> getConfigProperties() {
|
||||
return new ArrayList<>(Arrays.asList(IS_AUGMENT_PROPERTY, CLIENTAUTHNS_PROPERTY, CLIENTAUTHNS_AUGMENT));
|
||||
return configProperties;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.keycloak.models.Constants;
|
|||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.ClientPolicyExecutorConfigurationRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
import org.keycloak.services.clientpolicy.context.AdminClientRegisterContext;
|
||||
|
@ -40,7 +41,7 @@ import org.keycloak.services.clientpolicy.context.DynamicClientUpdateContext;
|
|||
/**
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public class SecureClientRegisteringUriEnforceExecutor implements ClientPolicyExecutorProvider<ClientPolicyExecutorConfiguration> {
|
||||
public class SecureClientRegisteringUriEnforceExecutor implements ClientPolicyExecutorProvider<ClientPolicyExecutorConfigurationRepresentation> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SecureClientRegisteringUriEnforceExecutor.class);
|
||||
|
||||
|
|
|
@ -31,13 +31,12 @@ import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
|||
import org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequest;
|
||||
import org.keycloak.protocol.oidc.endpoints.request.AuthzEndpointRequestParser;
|
||||
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
|
||||
import org.keycloak.representations.idm.ClientPolicyExecutorConfigurationRepresentation;
|
||||
import org.keycloak.services.Urls;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
import org.keycloak.services.clientpolicy.context.AuthorizationRequestContext;
|
||||
import org.keycloak.services.clientpolicy.executor.PKCEEnforceExecutor.Configuration;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
|
@ -80,8 +79,7 @@ public class SecureRequestObjectExecutor implements ClientPolicyExecutorProvider
|
|||
return Configuration.class;
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Configuration extends ClientPolicyExecutorConfiguration {
|
||||
public static class Configuration extends ClientPolicyExecutorConfigurationRepresentation {
|
||||
@JsonProperty("available-period")
|
||||
protected Integer availablePeriod;
|
||||
@JsonProperty("verify-nbf")
|
||||
|
|
|
@ -37,7 +37,14 @@ public class SecureRequestObjectExecutorFactory implements ClientPolicyExecutorP
|
|||
public static final String VERIFY_NBF = "verify-nbf";
|
||||
|
||||
private static final ProviderConfigProperty VERIFY_NBF_PROPERTY = new ProviderConfigProperty(
|
||||
VERIFY_NBF, null, null, ProviderConfigProperty.BOOLEAN_TYPE, true);
|
||||
VERIFY_NBF, "Verify Not-Before", "If ON, then it will be verified if 'request' object used in OIDC authorization request contains not-before " +
|
||||
"claim and this claim will be validated", ProviderConfigProperty.BOOLEAN_TYPE, true);
|
||||
|
||||
public static final String AVAILABLE_PERIOD = "available-period";
|
||||
|
||||
private static final ProviderConfigProperty AVAILABLE_PERIOD_PROPERTY = new ProviderConfigProperty(
|
||||
AVAILABLE_PERIOD, "Available Period", "The maximum period in seconds for which the 'request' object used in OIDC authorization request is considered valid. " +
|
||||
"It is used if 'Verify Not-Before' is ON.", ProviderConfigProperty.STRING_TYPE, "3600");
|
||||
|
||||
@Override
|
||||
public ClientPolicyExecutorProvider create(KeycloakSession session) {
|
||||
|
@ -68,7 +75,7 @@ public class SecureRequestObjectExecutorFactory implements ClientPolicyExecutorP
|
|||
|
||||
@Override
|
||||
public List<ProviderConfigProperty> getConfigProperties() {
|
||||
return new ArrayList<>(Arrays.asList(VERIFY_NBF_PROPERTY));
|
||||
return new ArrayList<>(Arrays.asList(VERIFY_NBF_PROPERTY, AVAILABLE_PERIOD_PROPERTY));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.keycloak.OAuthErrorException;
|
|||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequest;
|
||||
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
|
||||
import org.keycloak.representations.idm.ClientPolicyExecutorConfigurationRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
import org.keycloak.services.clientpolicy.context.AuthorizationRequestContext;
|
||||
|
@ -29,7 +30,7 @@ import org.keycloak.services.clientpolicy.context.AuthorizationRequestContext;
|
|||
/**
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public class SecureResponseTypeExecutor implements ClientPolicyExecutorProvider<ClientPolicyExecutorConfiguration> {
|
||||
public class SecureResponseTypeExecutor implements ClientPolicyExecutorProvider<ClientPolicyExecutorConfigurationRepresentation> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SecureResponseTypeExecutor.class);
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.keycloak.OAuthErrorException;
|
|||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequest;
|
||||
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
|
||||
import org.keycloak.representations.idm.ClientPolicyExecutorConfigurationRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
import org.keycloak.services.clientpolicy.context.AuthorizationRequestContext;
|
||||
|
@ -30,7 +31,7 @@ import org.keycloak.util.TokenUtil;
|
|||
/**
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public class SecureSessionEnforceExecutor implements ClientPolicyExecutorProvider<ClientPolicyExecutorConfiguration> {
|
||||
public class SecureSessionEnforceExecutor implements ClientPolicyExecutorProvider<ClientPolicyExecutorConfigurationRepresentation> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SecureSessionEnforceExecutor.class);
|
||||
|
||||
|
|
|
@ -19,9 +19,11 @@ package org.keycloak.services.clientpolicy.executor;
|
|||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
|
@ -29,6 +31,7 @@ import org.keycloak.OAuthErrorException;
|
|||
import org.keycloak.crypto.Algorithm;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
|
||||
import org.keycloak.representations.idm.ClientPolicyExecutorConfigurationRepresentation;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
|
@ -37,7 +40,6 @@ import org.keycloak.services.clientpolicy.context.AdminClientUpdateContext;
|
|||
import org.keycloak.services.clientpolicy.context.DynamicClientRegisterContext;
|
||||
import org.keycloak.services.clientpolicy.context.DynamicClientUpdateContext;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
|
@ -61,6 +63,15 @@ public class SecureSigningAlgorithmEnforceExecutor implements ClientPolicyExecut
|
|||
|
||||
private static final String DEFAULT_ALGORITHM_VALUE = Algorithm.PS256;
|
||||
|
||||
static final Set<String> ALLOWED_ALGORITHMS = new LinkedHashSet<>(Arrays.asList(
|
||||
Algorithm.PS256,
|
||||
Algorithm.PS384,
|
||||
Algorithm.PS512,
|
||||
Algorithm.ES256,
|
||||
Algorithm.ES384,
|
||||
Algorithm.ES512
|
||||
));
|
||||
|
||||
public SecureSigningAlgorithmEnforceExecutor(KeycloakSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
@ -81,8 +92,7 @@ public class SecureSigningAlgorithmEnforceExecutor implements ClientPolicyExecut
|
|||
return Configuration.class;
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Configuration extends ClientPolicyExecutorConfiguration {
|
||||
public static class Configuration extends ClientPolicyExecutorConfigurationRepresentation {
|
||||
@JsonProperty("default-algorithm")
|
||||
protected String defaultAlgorithm;
|
||||
|
||||
|
@ -165,16 +175,7 @@ public class SecureSigningAlgorithmEnforceExecutor implements ClientPolicyExecut
|
|||
}
|
||||
|
||||
private static boolean isSecureAlgorithm(String sigAlg) {
|
||||
switch (sigAlg) {
|
||||
case Algorithm.PS256:
|
||||
case Algorithm.PS384:
|
||||
case Algorithm.PS512:
|
||||
case Algorithm.ES256:
|
||||
case Algorithm.ES384:
|
||||
case Algorithm.ES512:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return ALLOWED_ALGORITHMS.contains(sigAlg);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.keycloak.services.clientpolicy.executor;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.keycloak.Config.Scope;
|
||||
|
@ -37,7 +38,8 @@ public class SecureSigningAlgorithmEnforceExecutorFactory implements ClientPolic
|
|||
public static final String DEFAULT_ALGORITHM = "default-algorithm";
|
||||
|
||||
private static final ProviderConfigProperty DEFAULT_ALGORITHM_PROPERTY = new ProviderConfigProperty(
|
||||
DEFAULT_ALGORITHM, null, null, ProviderConfigProperty.STRING_TYPE, Algorithm.PS256);
|
||||
DEFAULT_ALGORITHM, "Default Algorithm", "Default signature algorithm, which will be set to clients during client registration/update in case that client does not specify any algorithm",
|
||||
ProviderConfigProperty.LIST_TYPE, Algorithm.PS256, new LinkedList<>(SecureSigningAlgorithmEnforceExecutor.ALLOWED_ALGORITHMS).toArray(new String[] {}));
|
||||
|
||||
@Override
|
||||
public ClientPolicyExecutorProvider create(KeycloakSession session) {
|
||||
|
@ -63,7 +65,7 @@ public class SecureSigningAlgorithmEnforceExecutorFactory implements ClientPolic
|
|||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "It refuses the client whose signature algorithms are considered not to be secure. It accepts ES256, ES384, ES512, PS256, PS384 and PS512.";
|
||||
return "It refuses the client whose signature algorithms are considered not to be secure. This is applied by server for signing ID Token, UserInfo and Access Token. Also it is used by client for Token Endpoint Authentication signature algorithm (for JWT client authenticators) and OIDC Request object. It accepts ES256, ES384, ES512, PS256, PS384 and PS512.";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -23,16 +23,15 @@ import org.jboss.logging.Logger;
|
|||
import org.jboss.resteasy.spi.HttpRequest;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.OAuthErrorException;
|
||||
import org.keycloak.authentication.authenticators.client.JWTClientAuthenticator;
|
||||
import org.keycloak.common.util.ObjectUtil;
|
||||
import org.keycloak.crypto.Algorithm;
|
||||
import org.keycloak.jose.jws.JWSInput;
|
||||
import org.keycloak.jose.jws.JWSInputException;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.representations.idm.ClientPolicyExecutorConfigurationRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class SecureSigningAlgorithmForSignedJwtEnforceExecutor implements ClientPolicyExecutorProvider<SecureSigningAlgorithmForSignedJwtEnforceExecutor.Configuration> {
|
||||
|
@ -61,8 +60,7 @@ public class SecureSigningAlgorithmForSignedJwtEnforceExecutor implements Client
|
|||
return SecureSigningAlgorithmForSignedJwtEnforceExecutorFactory.PROVIDER_ID;
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Configuration extends ClientPolicyExecutorConfiguration {
|
||||
public static class Configuration extends ClientPolicyExecutorConfigurationRepresentation {
|
||||
@JsonProperty("require-client-assertion")
|
||||
protected Boolean requireClientAssertion;
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ public class SecureSigningAlgorithmForSignedJwtEnforceExecutorFactory implements
|
|||
public static final String REQUIRE_CLIENT_ASSERTION = "require-client-assertion";
|
||||
|
||||
private static final ProviderConfigProperty REQUIRE_CLIENT_ASSERTION_PROPERTY = new ProviderConfigProperty(
|
||||
REQUIRE_CLIENT_ASSERTION, null, null, ProviderConfigProperty.BOOLEAN_TYPE, false);
|
||||
REQUIRE_CLIENT_ASSERTION, "Require Client Assertion", "If this is ON, then parameter 'client_assertion' will be required and request will fail if it is not present. If false, then parameter 'client_assertion' is not required. When 'client_assertion' parameter is present, then the algorithm on the JWT from specified client assertion is always checked regardless of the value of this switch", ProviderConfigProperty.BOOLEAN_TYPE, false);
|
||||
|
||||
@Override
|
||||
public ClientPolicyExecutorProvider create(KeycloakSession session) {
|
||||
|
|
|
@ -124,7 +124,7 @@ public class RealmManager {
|
|||
createDefaultClientScopes(realm);
|
||||
setupAuthorizationServices(realm);
|
||||
setupClientRegistrations(realm);
|
||||
setupClientPolicies(realm);
|
||||
session.clientPolicy().setupClientPoliciesOnCreatedRealm(realm);
|
||||
|
||||
fireRealmPostCreate(realm);
|
||||
|
||||
|
@ -599,7 +599,7 @@ public class RealmManager {
|
|||
MigrationModelManager.migrateImport(session, realm, rep, skipUserDependent);
|
||||
}
|
||||
|
||||
setupClientPolicies(realm, rep);
|
||||
session.clientPolicy().updateRealmModelFromRepresentation(realm, rep);
|
||||
|
||||
fireRealmPostCreate(realm);
|
||||
|
||||
|
@ -714,14 +714,6 @@ public class RealmManager {
|
|||
DefaultClientRegistrationPolicies.addDefaultPolicies(realm);
|
||||
}
|
||||
|
||||
private void setupClientPolicies(RealmModel realm, RealmRepresentation rep) {
|
||||
session.clientPolicy().setupClientPoliciesOnImportedRealm(realm, rep);
|
||||
}
|
||||
|
||||
private void setupClientPolicies(RealmModel realm) {
|
||||
session.clientPolicy().setupClientPoliciesOnCreatedRealm(realm);
|
||||
}
|
||||
|
||||
private void fireRealmPostCreate(RealmModel realm) {
|
||||
session.getKeycloakSessionFactory().publish(new RealmModel.RealmPostCreateEvent() {
|
||||
@Override
|
||||
|
|
|
@ -172,8 +172,6 @@ public class KeycloakApplication extends Application {
|
|||
}
|
||||
// TODO up here ^^
|
||||
|
||||
session.clientPolicy().setupClientPoliciesOnKeycloakApp("/keycloak-default-client-profiles.json", "/keycloak-default-client-policies.json");
|
||||
|
||||
ApplianceBootstrap applianceBootstrap = new ApplianceBootstrap(session);
|
||||
exportImportManager[0] = new ExportImportManager(session);
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package org.keycloak.services.resources.admin;
|
||||
|
||||
import javax.ws.rs.BadRequestException;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.PUT;
|
||||
|
@ -32,6 +33,7 @@ import org.jboss.resteasy.spi.HttpRequest;
|
|||
import org.jboss.resteasy.spi.HttpResponse;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.representations.idm.ClientPoliciesRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
|
||||
|
@ -58,19 +60,23 @@ public class ClientPoliciesResource {
|
|||
@GET
|
||||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public String getPolicies() {
|
||||
public ClientPoliciesRepresentation getPolicies() {
|
||||
auth.realm().requireViewRealm();
|
||||
|
||||
return session.clientPolicy().getClientPolicies(realm);
|
||||
try {
|
||||
return session.clientPolicy().getClientPolicies(realm);
|
||||
} catch (ClientPolicyException e) {
|
||||
throw new BadRequestException(Response.status(Status.BAD_REQUEST).entity(e.getError()).build());
|
||||
}
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response updatePolicies(final String json) {
|
||||
public Response updatePolicies(final ClientPoliciesRepresentation clientPolicies) {
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
try {
|
||||
session.clientPolicy().updateClientPolicies(realm, json);
|
||||
session.clientPolicy().updateClientPolicies(realm, clientPolicies);
|
||||
} catch (ClientPolicyException e) {
|
||||
return Response.status(Status.BAD_REQUEST).entity(e.getError()).build();
|
||||
}
|
||||
|
|
|
@ -17,10 +17,12 @@
|
|||
|
||||
package org.keycloak.services.resources.admin;
|
||||
|
||||
import javax.ws.rs.BadRequestException;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
@ -32,6 +34,7 @@ import org.jboss.resteasy.spi.HttpRequest;
|
|||
import org.jboss.resteasy.spi.HttpResponse;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.representations.idm.ClientProfilesRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
|
||||
|
@ -58,19 +61,23 @@ public class ClientProfilesResource {
|
|||
@GET
|
||||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public String getProfiles() {
|
||||
public ClientProfilesRepresentation getProfiles(@QueryParam("include-global-profiles") boolean includeGlobalProfiles) {
|
||||
auth.realm().requireViewRealm();
|
||||
|
||||
return session.clientPolicy().getClientProfiles(realm);
|
||||
try {
|
||||
return session.clientPolicy().getClientProfiles(realm, includeGlobalProfiles);
|
||||
} catch (ClientPolicyException e) {
|
||||
throw new BadRequestException(Response.status(Status.BAD_REQUEST).entity(e.getError()).build());
|
||||
}
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response updateProfiles(final String json) {
|
||||
public Response updateProfiles(final ClientProfilesRepresentation clientProfiles) {
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
try {
|
||||
session.clientPolicy().updateClientProfiles(realm, json);
|
||||
session.clientPolicy().updateClientProfiles(realm, clientProfiles);
|
||||
} catch (ClientPolicyException e) {
|
||||
return Response.status(Status.BAD_REQUEST).entity(e.getError()).build();
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ import org.keycloak.KeyPairVerifier;
|
|||
import org.keycloak.authentication.CredentialRegistrator;
|
||||
import org.keycloak.authentication.RequiredActionProvider;
|
||||
import org.keycloak.common.ClientConnection;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.common.util.PemUtils;
|
||||
import org.keycloak.email.EmailTemplateProvider;
|
||||
|
@ -113,6 +114,7 @@ import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluato
|
|||
import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissions;
|
||||
import org.keycloak.representations.idm.LDAPCapabilityRepresentation;
|
||||
import org.keycloak.utils.ProfileHelper;
|
||||
import org.keycloak.utils.ReservedCharValidator;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
@ -371,7 +373,7 @@ public class RealmAdminResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public RealmRepresentation getRealm() {
|
||||
if (auth.realm().canViewRealm()) {
|
||||
return ModelToRepresentation.toRepresentation(realm, false);
|
||||
return ModelToRepresentation.toRepresentation(session, realm, false);
|
||||
} else {
|
||||
auth.realm().requireViewRealmNameList();
|
||||
|
||||
|
@ -379,7 +381,7 @@ public class RealmAdminResource {
|
|||
rep.setRealm(realm.getName());
|
||||
|
||||
if (auth.realm().canViewIdentityProviders()) {
|
||||
RealmRepresentation r = ModelToRepresentation.toRepresentation(realm, false);
|
||||
RealmRepresentation r = ModelToRepresentation.toRepresentation(session, realm, false);
|
||||
rep.setIdentityProviders(r.getIdentityProviders());
|
||||
rep.setIdentityProviderMappers(r.getIdentityProviderMappers());
|
||||
}
|
||||
|
@ -1209,6 +1211,7 @@ public class RealmAdminResource {
|
|||
|
||||
@Path("client-policies/policies")
|
||||
public ClientPoliciesResource getClientPoliciesResource() {
|
||||
ProfileHelper.requireFeature(Profile.Feature.CLIENT_POLICIES);
|
||||
ClientPoliciesResource resource = new ClientPoliciesResource(realm, auth);
|
||||
ResteasyProviderFactory.getInstance().injectProperties(resource);
|
||||
return resource;
|
||||
|
@ -1216,6 +1219,7 @@ public class RealmAdminResource {
|
|||
|
||||
@Path("client-policies/profiles")
|
||||
public ClientProfilesResource getClientProfilesResource() {
|
||||
ProfileHelper.requireFeature(Profile.Feature.CLIENT_POLICIES);
|
||||
ClientProfilesResource resource = new ClientProfilesResource(realm, auth);
|
||||
ResteasyProviderFactory.getInstance().injectProperties(resource);
|
||||
return resource;
|
||||
|
|
|
@ -102,7 +102,7 @@ public class RealmsAdminResource {
|
|||
|
||||
protected RealmRepresentation toRealmRep(RealmModel realm) {
|
||||
if (AdminPermissions.realms(session, auth).canView(realm)) {
|
||||
return ModelToRepresentation.toRepresentation(realm, false);
|
||||
return ModelToRepresentation.toRepresentation(session, realm, false);
|
||||
} else if (AdminPermissions.realms(session, auth).isAdmin(realm)) {
|
||||
RealmRepresentation rep = new RealmRepresentation();
|
||||
rep.setRealm(realm.getName());
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
org.keycloak.services.clientpolicy.DefaultClientPolicyManagerFactory
|
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"policies": [
|
||||
{
|
||||
"name": "builtin-default-policy",
|
||||
"description": "The built-in default policy applied to all clients.",
|
||||
"builtin": true,
|
||||
"enable": false,
|
||||
"conditions": [
|
||||
{
|
||||
"anyclient-condition": {}
|
||||
}
|
||||
],
|
||||
"profiles": [
|
||||
"builtin-default-profile"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"profiles": [
|
||||
{
|
||||
"name": "builtin-default-profile",
|
||||
"description": "The built-in default profile for enforcing basic security level to clients.",
|
||||
"builtin": true,
|
||||
"name": "global-default-profile",
|
||||
"description": "The global default profile for enforcing basic security level to clients.",
|
||||
"executors": [
|
||||
{
|
||||
"secure-session-enforce-executor": {}
|
||||
"executor": "secure-session-enforce-executor",
|
||||
"configuration": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ public class RunHelpers {
|
|||
|
||||
@Override
|
||||
public FetchOnServer getRunOnServer() {
|
||||
return (FetchOnServer) session -> ModelToRepresentation.toRepresentation(session.getContext().getRealm(), true);
|
||||
return (FetchOnServer) session -> ModelToRepresentation.toRepresentation(session, session.getContext().getRealm(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -22,23 +22,16 @@ import org.keycloak.models.KeycloakSession;
|
|||
import org.keycloak.services.clientpolicy.ClientPolicyContext;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyVote;
|
||||
import org.keycloak.services.clientpolicy.condition.ClientPolicyConditionConfiguration;
|
||||
import org.keycloak.services.clientpolicy.condition.ClientPolicyConditionProvider;
|
||||
import org.keycloak.services.clientpolicy.condition.AbstractClientPolicyConditionProvider;
|
||||
import org.keycloak.representations.idm.ClientPolicyConditionConfigurationRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public class TestRaiseExeptionCondition implements ClientPolicyConditionProvider<TestRaiseExeptionCondition.Configuration> {
|
||||
|
||||
// to avoid null configuration, use vacant new instance to indicate that there is no configuration set up.
|
||||
private Configuration configuration = new Configuration();
|
||||
public class TestRaiseExeptionCondition extends AbstractClientPolicyConditionProvider<TestRaiseExeptionCondition.Configuration> {
|
||||
|
||||
public TestRaiseExeptionCondition(KeycloakSession session) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupConfiguration(Configuration config) {
|
||||
this.configuration = config;
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -46,7 +39,7 @@ public class TestRaiseExeptionCondition implements ClientPolicyConditionProvider
|
|||
return Configuration.class;
|
||||
}
|
||||
|
||||
public static class Configuration extends ClientPolicyConditionConfiguration {
|
||||
public static class Configuration extends ClientPolicyConditionConfigurationRepresentation {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -66,4 +66,8 @@ public class TestRaiseExeptionConditionFactory implements ClientPolicyConditionP
|
|||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,10 +22,10 @@ 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.executor.ClientPolicyExecutorConfiguration;
|
||||
import org.keycloak.representations.idm.ClientPolicyExecutorConfigurationRepresentation;
|
||||
import org.keycloak.services.clientpolicy.executor.ClientPolicyExecutorProvider;
|
||||
|
||||
public class TestRaiseExeptionExecutor implements ClientPolicyExecutorProvider<ClientPolicyExecutorConfiguration> {
|
||||
public class TestRaiseExeptionExecutor implements ClientPolicyExecutorProvider<ClientPolicyExecutorConfigurationRepresentation> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(TestRaiseExeptionExecutor.class);
|
||||
|
||||
|
|
|
@ -63,4 +63,8 @@ public class TestRaiseExeptionExecutorFactory implements ClientPolicyExecutorPro
|
|||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package org.keycloak.testsuite.client;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
@ -38,6 +39,7 @@ import java.security.spec.PKCS8EncodedKeySpec;
|
|||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
|
@ -60,9 +62,11 @@ import org.apache.http.client.methods.HttpPost;
|
|||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.OAuthErrorException;
|
||||
|
@ -74,6 +78,7 @@ import org.keycloak.client.registration.ClientRegistration;
|
|||
import org.keycloak.client.registration.ClientRegistrationException;
|
||||
import org.keycloak.common.util.Base64;
|
||||
import org.keycloak.common.util.Base64Url;
|
||||
import org.keycloak.common.util.BouncyIntegration;
|
||||
import org.keycloak.common.util.KeyUtils;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
import org.keycloak.common.util.Time;
|
||||
|
@ -92,6 +97,10 @@ import org.keycloak.representations.JsonWebToken;
|
|||
import org.keycloak.representations.idm.ClientInitialAccessCreatePresentation;
|
||||
import org.keycloak.representations.idm.ClientInitialAccessPresentation;
|
||||
import org.keycloak.representations.idm.ClientPoliciesRepresentation;
|
||||
import org.keycloak.representations.idm.ClientPolicyConditionConfigurationRepresentation;
|
||||
import org.keycloak.representations.idm.ClientPolicyConditionRepresentation;
|
||||
import org.keycloak.representations.idm.ClientPolicyExecutorConfigurationRepresentation;
|
||||
import org.keycloak.representations.idm.ClientPolicyExecutorRepresentation;
|
||||
import org.keycloak.representations.idm.ClientPolicyRepresentation;
|
||||
import org.keycloak.representations.idm.ClientProfileRepresentation;
|
||||
import org.keycloak.representations.idm.ClientProfilesRepresentation;
|
||||
|
@ -100,7 +109,6 @@ import org.keycloak.representations.oidc.OIDCClientRepresentation;
|
|||
import org.keycloak.representations.oidc.TokenMetadataRepresentation;
|
||||
import org.keycloak.services.Urls;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
import org.keycloak.services.clientpolicy.condition.AnyClientCondition;
|
||||
import org.keycloak.services.clientpolicy.condition.AnyClientConditionFactory;
|
||||
import org.keycloak.services.clientpolicy.condition.ClientAccessTypeCondition;
|
||||
import org.keycloak.services.clientpolicy.condition.ClientAccessTypeConditionFactory;
|
||||
|
@ -132,6 +140,7 @@ import org.keycloak.services.clientpolicy.executor.SecureSigningAlgorithmEnforce
|
|||
import org.keycloak.services.clientpolicy.executor.SecureSigningAlgorithmForSignedJwtEnforceExecutor;
|
||||
import org.keycloak.services.clientpolicy.executor.SecureSigningAlgorithmForSignedJwtEnforceExecutorFactory;
|
||||
import org.keycloak.testsuite.AbstractKeycloakTest;
|
||||
import org.keycloak.testsuite.Assert;
|
||||
import org.keycloak.testsuite.AssertEvents;
|
||||
import org.keycloak.testsuite.admin.ApiUtil;
|
||||
import org.keycloak.testsuite.client.resources.TestApplicationResourceUrls;
|
||||
|
@ -170,6 +179,11 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClientPoliciesTest() {
|
||||
BouncyIntegration.init();
|
||||
}
|
||||
|
||||
@Rule
|
||||
public AssertEvents events = new AssertEvents(this);
|
||||
|
||||
|
@ -189,9 +203,9 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
revertToBuiltinPolicies();
|
||||
}
|
||||
|
||||
protected void loadValidProfilesAndPolicies() throws Exception {
|
||||
protected void setupValidProfilesAndPolicies() throws Exception {
|
||||
// load profiles
|
||||
ClientProfileRepresentation loadedProfileRep = (new ClientProfileBuilder()).createProfile("ordinal-test-profile", "The profile that can be loaded.", Boolean.FALSE, null)
|
||||
ClientProfileRepresentation loadedProfileRep = (new ClientProfileBuilder()).createProfile("ordinal-test-profile", "The profile that can be loaded.")
|
||||
.addExecutor(SecureClientAuthEnforceExecutorFactory.PROVIDER_ID,
|
||||
createSecureClientAuthEnforceExecutorConfig(
|
||||
Boolean.TRUE,
|
||||
|
@ -199,7 +213,7 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
JWTClientAuthenticator.PROVIDER_ID))
|
||||
.toRepresentation();
|
||||
|
||||
ClientProfileRepresentation loadedProfileRepWithoutBuiltinField = (new ClientProfileBuilder()).createProfile("lack-of-builtin-field-test-profile", "Without builtin field that is treated as builtin=false.", null, null)
|
||||
ClientProfileRepresentation loadedProfileRepWithoutBuiltinField = (new ClientProfileBuilder()).createProfile("lack-of-builtin-field-test-profile", "Without builtin field that is treated as builtin=false.")
|
||||
.addExecutor(SecureClientAuthEnforceExecutorFactory.PROVIDER_ID,
|
||||
createSecureClientAuthEnforceExecutorConfig(
|
||||
Boolean.TRUE,
|
||||
|
@ -226,34 +240,34 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
(new ClientPolicyBuilder()).createPolicy(
|
||||
"new-policy",
|
||||
"duplicated profiles are ignored.",
|
||||
Boolean.FALSE,
|
||||
Boolean.TRUE,
|
||||
null,
|
||||
Arrays.asList("builtin-default-profile", "ordinal-test-profile", "lack-of-builtin-field-test-profile", "ordinal-test-profile"))
|
||||
Boolean.TRUE)
|
||||
.addCondition(ClientAccessTypeConditionFactory.PROVIDER_ID,
|
||||
createClientAccessTypeConditionConfig(Arrays.asList(ClientAccessTypeConditionFactory.TYPE_PUBLIC, ClientAccessTypeConditionFactory.TYPE_BEARERONLY)))
|
||||
.addCondition(ClientRolesConditionFactory.PROVIDER_ID,
|
||||
createClientRolesConditionConfig(Arrays.asList(SAMPLE_CLIENT_ROLE)))
|
||||
.addCondition(ClientScopesConditionFactory.PROVIDER_ID,
|
||||
createClientScopesConditionConfig(ClientScopesConditionFactory.OPTIONAL, Arrays.asList(SAMPLE_CLIENT_ROLE)))
|
||||
.addProfile("global-default-profile")
|
||||
.addProfile("ordinal-test-profile")
|
||||
.addProfile("lack-of-builtin-field-test-profile")
|
||||
.addProfile("ordinal-test-profile")
|
||||
|
||||
.toRepresentation();
|
||||
|
||||
ClientPolicyRepresentation loadedPolicyRepWithoutBuiltinField =
|
||||
(new ClientPolicyBuilder()).createPolicy(
|
||||
"lack-of-builtin-field-test-policy",
|
||||
"Without builtin field that is treated as builtin=false.",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
Arrays.asList("lack-of-builtin-field-test-profile"))
|
||||
null)
|
||||
.addCondition(ClientUpdateContextConditionFactory.PROVIDER_ID,
|
||||
createClientUpdateContextConditionConfig(Arrays.asList(ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER)))
|
||||
.addCondition(ClientUpdateSourceGroupsConditionFactory.PROVIDER_ID,
|
||||
createClientUpdateSourceGroupsConditionConfig(Arrays.asList("topGroup")))
|
||||
.addCondition(ClientUpdateSourceHostsConditionFactory.PROVIDER_ID,
|
||||
.addCondition(ClientUpdateSourceHostsConditionFactory.PROVIDER_ID,
|
||||
createClientUpdateSourceHostsConditionConfig(Arrays.asList("localhost", "127.0.0.1")))
|
||||
.addCondition(ClientUpdateSourceRolesConditionFactory.PROVIDER_ID,
|
||||
createClientUpdateSourceRolesConditionConfig(Arrays.asList(AdminRoles.CREATE_CLIENT)))
|
||||
.addProfile("lack-of-builtin-field-test-profile")
|
||||
.toRepresentation();
|
||||
|
||||
json = (new ClientPoliciesBuilder())
|
||||
|
@ -268,21 +282,21 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
protected void assertExpectedLoadedProfiles(Consumer<ClientProfilesRepresentation> modifiedAssertion) {
|
||||
|
||||
// retrieve loaded builtin profiles
|
||||
ClientProfilesRepresentation actualProfilesRep = getProfiles();
|
||||
ClientProfilesRepresentation actualProfilesRep = getProfilesWithGlobals();
|
||||
|
||||
// same profiles
|
||||
assertExpectedProfiles(actualProfilesRep, Arrays.asList("builtin-default-profile", "ordinal-test-profile", "lack-of-builtin-field-test-profile"));
|
||||
assertExpectedProfiles(actualProfilesRep, Arrays.asList("global-default-profile"), Arrays.asList("ordinal-test-profile", "lack-of-builtin-field-test-profile"));
|
||||
|
||||
// each profile - builtin-default-profile
|
||||
ClientProfileRepresentation actualProfileRep = getProfileRepresentation(actualProfilesRep, "builtin-default-profile");
|
||||
assertExpectedProfile(actualProfileRep, "builtin-default-profile", "The built-in default profile for enforcing basic security level to clients.", true);
|
||||
// each profile - global-default-profile
|
||||
ClientProfileRepresentation actualProfileRep = getProfileRepresentation(actualProfilesRep, "global-default-profile", true);
|
||||
assertExpectedProfile(actualProfileRep, "global-default-profile", "The global default profile for enforcing basic security level to clients.");
|
||||
|
||||
// each executor
|
||||
assertExpectedExecutors(Arrays.asList(SecureSessionEnforceExecutorFactory.PROVIDER_ID), actualProfileRep);
|
||||
assertExpectedSecureSessionEnforceExecutor(actualProfileRep);
|
||||
|
||||
// each profile - ordinal-test-profile - updated
|
||||
actualProfileRep = getProfileRepresentation(actualProfilesRep, "ordinal-test-profile");
|
||||
actualProfileRep = getProfileRepresentation(actualProfilesRep, "ordinal-test-profile", false);
|
||||
modifiedAssertion.accept(actualProfilesRep);
|
||||
|
||||
// each executor
|
||||
|
@ -290,8 +304,8 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
assertExpectedSecureClientAuthEnforceExecutor(Arrays.asList(JWTClientAuthenticator.PROVIDER_ID), true, JWTClientAuthenticator.PROVIDER_ID, actualProfileRep);
|
||||
|
||||
// each profile - lack-of-builtin-field-test-profile
|
||||
actualProfileRep = getProfileRepresentation(actualProfilesRep, "lack-of-builtin-field-test-profile");
|
||||
assertExpectedProfile(actualProfileRep, "lack-of-builtin-field-test-profile", "Without builtin field that is treated as builtin=false.", false);
|
||||
actualProfileRep = getProfileRepresentation(actualProfilesRep, "lack-of-builtin-field-test-profile", false);
|
||||
assertExpectedProfile(actualProfileRep, "lack-of-builtin-field-test-profile", "Without builtin field that is treated as builtin=false.");
|
||||
|
||||
// each executor
|
||||
assertExpectedExecutors(Arrays.asList(
|
||||
|
@ -319,7 +333,7 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
ClientPoliciesRepresentation actualPoliciesRep = getPolicies();
|
||||
|
||||
// same policies
|
||||
assertExpectedPolicies(Arrays.asList("builtin-default-policy", "new-policy", "lack-of-builtin-field-test-policy"), actualPoliciesRep);
|
||||
assertExpectedPolicies(Arrays.asList("new-policy", "lack-of-builtin-field-test-policy"), actualPoliciesRep);
|
||||
|
||||
// each policy - new-policy - updated
|
||||
ClientPolicyRepresentation actualPolicyRep = getPolicyRepresentation(actualPoliciesRep, "new-policy");
|
||||
|
@ -333,13 +347,13 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
|
||||
// each policy - lack-of-builtin-field-test-policy
|
||||
actualPolicyRep = getPolicyRepresentation(actualPoliciesRep, "lack-of-builtin-field-test-policy");
|
||||
assertExpectedPolicy("lack-of-builtin-field-test-policy", "Without builtin field that is treated as builtin=false.", false, false, Arrays.asList("lack-of-builtin-field-test-profile"), actualPolicyRep);
|
||||
assertExpectedPolicy("lack-of-builtin-field-test-policy", "Without builtin field that is treated as builtin=false.", false, Arrays.asList("lack-of-builtin-field-test-profile"), actualPolicyRep);
|
||||
|
||||
// each condition
|
||||
assertExpectedConditions(Arrays.asList(ClientUpdateContextConditionFactory.PROVIDER_ID, ClientUpdateSourceGroupsConditionFactory.PROVIDER_ID, ClientUpdateSourceHostsConditionFactory.PROVIDER_ID, ClientUpdateSourceRolesConditionFactory.PROVIDER_ID), actualPolicyRep);
|
||||
assertExpectedClientUpdateContextCondition(Arrays.asList(ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER), actualPolicyRep);
|
||||
assertExpectedClientUpdateSourceGroupsCondition(Arrays.asList("topGroup"), actualPolicyRep);
|
||||
assertExpectedClientUpdateSourceHostsCondition(Arrays.asList("localhost", "127.0.0.1"), Arrays.asList(Boolean.TRUE, Boolean.TRUE), actualPolicyRep);
|
||||
assertExpectedClientUpdateSourceHostsCondition(Arrays.asList("localhost", "127.0.0.1"), actualPolicyRep);
|
||||
assertExpectedClientUpdateSourceRolesCondition(Arrays.asList(AdminRoles.CREATE_CLIENT), actualPolicyRep);
|
||||
}
|
||||
|
||||
|
@ -783,51 +797,23 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
profileRep = new ClientProfileRepresentation();
|
||||
}
|
||||
|
||||
public ClientProfileBuilder createProfile(String name, String description, Boolean isBuiltin, List<Object> executors) {
|
||||
public ClientProfileBuilder createProfile(String name, String description) {
|
||||
if (name != null) {
|
||||
profileRep.setName(name);
|
||||
}
|
||||
if (description != null) {
|
||||
profileRep.setDescription(description);
|
||||
}
|
||||
if (isBuiltin != null) {
|
||||
profileRep.setBuiltin(isBuiltin);
|
||||
} else {
|
||||
profileRep.setBuiltin(Boolean.FALSE);
|
||||
}
|
||||
if (executors != null) {
|
||||
profileRep.setExecutors(executors);
|
||||
} else {
|
||||
profileRep.setExecutors(new ArrayList<>());
|
||||
}
|
||||
profileRep.setExecutors(new ArrayList<>());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClientProfileBuilder addExecutor(String providerId, Object config) {
|
||||
String configString = null;
|
||||
public ClientProfileBuilder addExecutor(String providerId, ClientPolicyExecutorConfigurationRepresentation config) {
|
||||
if (config == null) {
|
||||
configString = "{}";
|
||||
} else {
|
||||
try {
|
||||
configString = objectMapper.writeValueAsString(config);
|
||||
} catch (JsonProcessingException e) {
|
||||
fail();
|
||||
}
|
||||
config = new ClientPolicyExecutorConfigurationRepresentation();
|
||||
}
|
||||
String executorJson = (new StringBuilder())
|
||||
.append("{\"")
|
||||
.append(providerId)
|
||||
.append("\":")
|
||||
.append(configString)
|
||||
.append("}")
|
||||
.toString();
|
||||
JsonNode node = null;
|
||||
try {
|
||||
node = objectMapper.readTree(executorJson);
|
||||
} catch (JsonProcessingException e) {
|
||||
fail();
|
||||
}
|
||||
profileRep.getExecutors().add(node);
|
||||
profileRep.getExecutors().add(new ClientPolicyExecutorRepresentation(providerId, config));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -849,19 +835,19 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
|
||||
// Client Profiles - Executor CRUD Operations
|
||||
|
||||
protected Object createHolderOfKeyEnforceExecutorConfig(Boolean isAugment) {
|
||||
protected HolderOfKeyEnforceExecutor.Configuration createHolderOfKeyEnforceExecutorConfig(Boolean isAugment) {
|
||||
HolderOfKeyEnforceExecutor.Configuration config = new HolderOfKeyEnforceExecutor.Configuration();
|
||||
config.setAugment(isAugment);
|
||||
return config;
|
||||
}
|
||||
|
||||
protected Object createPKCEEnforceExecutorConfig(Boolean isAugment) {
|
||||
protected PKCEEnforceExecutor.Configuration createPKCEEnforceExecutorConfig(Boolean isAugment) {
|
||||
PKCEEnforceExecutor.Configuration config = new PKCEEnforceExecutor.Configuration();
|
||||
config.setAugment(isAugment);
|
||||
return config;
|
||||
}
|
||||
|
||||
protected Object createSecureClientAuthEnforceExecutorConfig(Boolean isAugment, List<String> clientAuthns, String clientAuthnsAugment) {
|
||||
protected SecureClientAuthEnforceExecutor.Configuration createSecureClientAuthEnforceExecutorConfig(Boolean isAugment, List<String> clientAuthns, String clientAuthnsAugment) {
|
||||
SecureClientAuthEnforceExecutor.Configuration config = new SecureClientAuthEnforceExecutor.Configuration();
|
||||
config.setAugment(isAugment);
|
||||
config.setClientAuthns(clientAuthns);
|
||||
|
@ -869,20 +855,20 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
return config;
|
||||
}
|
||||
|
||||
protected Object createSecureRequestObjectExecutorConfig(Integer availablePeriod, Boolean verifyNbf) {
|
||||
protected SecureRequestObjectExecutor.Configuration createSecureRequestObjectExecutorConfig(Integer availablePeriod, Boolean verifyNbf) {
|
||||
SecureRequestObjectExecutor.Configuration config = new SecureRequestObjectExecutor.Configuration();
|
||||
if (availablePeriod != null) config.setAvailablePeriod(availablePeriod);
|
||||
if (verifyNbf != null) config.setVerifyNbf(verifyNbf);
|
||||
return config;
|
||||
}
|
||||
|
||||
protected Object createSecureSigningAlgorithmForSignedJwtEnforceExecutorConfig(Boolean requireClientAssertion) {
|
||||
protected SecureSigningAlgorithmForSignedJwtEnforceExecutor.Configuration createSecureSigningAlgorithmForSignedJwtEnforceExecutorConfig(Boolean requireClientAssertion) {
|
||||
SecureSigningAlgorithmForSignedJwtEnforceExecutor.Configuration config = new SecureSigningAlgorithmForSignedJwtEnforceExecutor.Configuration();
|
||||
config.setRequireClientAssertion(requireClientAssertion);
|
||||
return config;
|
||||
}
|
||||
|
||||
protected Object createSecureSigningAlgorithmEnforceExecutorConfig(String defaultAlgorithm) {
|
||||
protected SecureSigningAlgorithmEnforceExecutor.Configuration createSecureSigningAlgorithmEnforceExecutorConfig(String defaultAlgorithm) {
|
||||
SecureSigningAlgorithmEnforceExecutor.Configuration config = new SecureSigningAlgorithmEnforceExecutor.Configuration();
|
||||
config.setDefaultAlgorithm(defaultAlgorithm);
|
||||
return config;
|
||||
|
@ -927,59 +913,25 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
policyRep = new ClientPolicyRepresentation();
|
||||
}
|
||||
|
||||
public ClientPolicyBuilder createPolicy(String name, String description, Boolean isBuiltin, Boolean isEnabled, List<Object> conditions, List<String> profiles) {
|
||||
public ClientPolicyBuilder createPolicy(String name, String description, Boolean isEnabled) {
|
||||
policyRep.setName(name);
|
||||
if (description != null) {
|
||||
policyRep.setDescription(description);
|
||||
}
|
||||
if (isBuiltin != null) {
|
||||
policyRep.setBuiltin(isBuiltin);
|
||||
} else {
|
||||
policyRep.setBuiltin(Boolean.FALSE);
|
||||
}
|
||||
if (isEnabled != null) {
|
||||
policyRep.setEnable(isEnabled);
|
||||
policyRep.setEnabled(isEnabled);
|
||||
} else {
|
||||
policyRep.setEnable(Boolean.FALSE);
|
||||
}
|
||||
if (conditions != null) {
|
||||
policyRep.setConditions(conditions);
|
||||
} else {
|
||||
policyRep.setConditions(new ArrayList<>());
|
||||
}
|
||||
if (profiles != null) {
|
||||
policyRep.setProfiles(profiles);
|
||||
} else {
|
||||
policyRep.setProfiles(new ArrayList<>());
|
||||
policyRep.setEnabled(Boolean.FALSE);
|
||||
}
|
||||
|
||||
policyRep.setConditions(new ArrayList<>());
|
||||
policyRep.setProfiles(new ArrayList<>());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClientPolicyBuilder addCondition(String providerId, Object config) {
|
||||
String configString = null;
|
||||
if (config == null) {
|
||||
configString = "{}";
|
||||
} else {
|
||||
try {
|
||||
configString = objectMapper.writeValueAsString(config);
|
||||
} catch (JsonProcessingException e) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
String conditionJson = (new StringBuilder())
|
||||
.append("{\"")
|
||||
.append(providerId)
|
||||
.append("\":")
|
||||
.append(configString)
|
||||
.append("}")
|
||||
.toString();
|
||||
JsonNode node = null;
|
||||
try {
|
||||
node = objectMapper.readTree(conditionJson);
|
||||
} catch (JsonProcessingException e) {
|
||||
fail();
|
||||
}
|
||||
policyRep.getConditions().add(node);
|
||||
public ClientPolicyBuilder addCondition(String providerId, ClientPolicyConditionConfigurationRepresentation config) {
|
||||
policyRep.getConditions().add(new ClientPolicyConditionRepresentation(providerId, config));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -1005,58 +957,58 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
|
||||
// Client Policies - Condition CRUD Operations
|
||||
|
||||
protected Object createTestRaiseExeptionConditionConfig() {
|
||||
protected TestRaiseExeptionCondition.Configuration createTestRaiseExeptionConditionConfig() {
|
||||
return new TestRaiseExeptionCondition.Configuration();
|
||||
}
|
||||
|
||||
protected Object createAnyClientConditionConfig() {
|
||||
return new AnyClientCondition.Configuration();
|
||||
protected ClientPolicyConditionConfigurationRepresentation createAnyClientConditionConfig() {
|
||||
return new ClientPolicyConditionConfigurationRepresentation();
|
||||
}
|
||||
|
||||
protected Object createAnyClientConditionConfig(Boolean isNegativeLogic) {
|
||||
AnyClientCondition.Configuration config = new AnyClientCondition.Configuration();
|
||||
protected ClientPolicyConditionConfigurationRepresentation createAnyClientConditionConfig(Boolean isNegativeLogic) {
|
||||
ClientPolicyConditionConfigurationRepresentation config = new ClientPolicyConditionConfigurationRepresentation();
|
||||
config.setNegativeLogic(isNegativeLogic);
|
||||
return config;
|
||||
}
|
||||
|
||||
protected Object createClientAccessTypeConditionConfig(List<String> types) {
|
||||
protected ClientAccessTypeCondition.Configuration createClientAccessTypeConditionConfig(List<String> types) {
|
||||
ClientAccessTypeCondition.Configuration config = new ClientAccessTypeCondition.Configuration();
|
||||
config.setType(types);
|
||||
return config;
|
||||
}
|
||||
|
||||
protected Object createClientRolesConditionConfig(List<String> roles) {
|
||||
protected ClientRolesCondition.Configuration createClientRolesConditionConfig(List<String> roles) {
|
||||
ClientRolesCondition.Configuration config = new ClientRolesCondition.Configuration();
|
||||
config.setRoles(roles);
|
||||
return config;
|
||||
}
|
||||
|
||||
protected Object createClientScopesConditionConfig(String type, List<String> scopes) {
|
||||
protected ClientScopesCondition.Configuration createClientScopesConditionConfig(String type, List<String> scopes) {
|
||||
ClientScopesCondition.Configuration config = new ClientScopesCondition.Configuration();
|
||||
config.setType(type);
|
||||
config.setScope(scopes);
|
||||
return config;
|
||||
}
|
||||
|
||||
protected Object createClientUpdateContextConditionConfig(List<String> updateClientSource) {
|
||||
protected ClientUpdateContextCondition.Configuration createClientUpdateContextConditionConfig(List<String> updateClientSource) {
|
||||
ClientUpdateContextCondition.Configuration config = new ClientUpdateContextCondition.Configuration();
|
||||
config.setUpdateClientSource(updateClientSource);
|
||||
return config;
|
||||
}
|
||||
|
||||
protected Object createClientUpdateSourceGroupsConditionConfig(List<String> groups) {
|
||||
protected ClientUpdateSourceGroupsCondition.Configuration createClientUpdateSourceGroupsConditionConfig(List<String> groups) {
|
||||
ClientUpdateSourceGroupsCondition.Configuration config = new ClientUpdateSourceGroupsCondition.Configuration();
|
||||
config.setGroups(groups);
|
||||
return config;
|
||||
}
|
||||
|
||||
protected Object createClientUpdateSourceHostsConditionConfig(List<String> trustedHosts) {
|
||||
protected ClientUpdateSourceHostsCondition.Configuration createClientUpdateSourceHostsConditionConfig(List<String> trustedHosts) {
|
||||
ClientUpdateSourceHostsCondition.Configuration config = new ClientUpdateSourceHostsCondition.Configuration();
|
||||
config.setTrustedHosts(trustedHosts);
|
||||
return config;
|
||||
}
|
||||
|
||||
protected Object createClientUpdateSourceRolesConditionConfig(List<String> roles) {
|
||||
protected ClientUpdateSourceRolesCondition.Configuration createClientUpdateSourceRolesConditionConfig(List<String> roles) {
|
||||
ClientUpdateSourceRolesCondition.Configuration config = new ClientUpdateSourceRolesCondition.Configuration();
|
||||
config.setRoles(roles);
|
||||
return config;
|
||||
|
@ -1074,24 +1026,15 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
return json;
|
||||
}
|
||||
|
||||
protected ClientProfilesRepresentation convertToProfiles(String json) {
|
||||
ClientProfilesRepresentation reps = null;
|
||||
try {
|
||||
reps = JsonSerialization.readValue(json, ClientProfilesRepresentation.class);
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
return reps;
|
||||
}
|
||||
|
||||
protected String getProfilesJson() {
|
||||
return adminClient.realm(REALM_NAME).clientPoliciesProfilesResource().getProfiles();
|
||||
}
|
||||
|
||||
// TODO: Possibly change this to accept ClientProfilesRepresentation instead of String to have more type-safety.
|
||||
protected void updateProfiles(String json) throws ClientPolicyException {
|
||||
Response resp = adminClient.realm(REALM_NAME).clientPoliciesProfilesResource().updateProfiles(json);
|
||||
if (resp.getStatus() != 204) {
|
||||
throw new ClientPolicyException("update profiles failed", resp.getStatusInfo().toString());
|
||||
try {
|
||||
ClientProfilesRepresentation clientProfiles = JsonSerialization.readValue(json, ClientProfilesRepresentation.class);
|
||||
adminClient.realm(REALM_NAME).clientPoliciesProfilesResource().updateProfiles(clientProfiles);
|
||||
} catch (BadRequestException e) {
|
||||
throw new ClientPolicyException("update profiles failed", e.getResponse().getStatusInfo().toString());
|
||||
} catch (Exception e) {
|
||||
throw new ClientPolicyException("update profiles failed", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1103,16 +1046,12 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
updateProfiles("{}");
|
||||
}
|
||||
|
||||
protected ClientProfilesRepresentation getProfiles() {
|
||||
return convertToProfiles(getProfilesJson());
|
||||
protected ClientProfilesRepresentation getProfilesWithGlobals() {
|
||||
return adminClient.realm(REALM_NAME).clientPoliciesProfilesResource().getProfiles(true);
|
||||
}
|
||||
|
||||
protected ClientProfilesRepresentation getProfilesWithoutBuiltin() {
|
||||
ClientProfilesRepresentation reps = new ClientProfilesRepresentation();
|
||||
reps.setProfiles(new ArrayList<>());
|
||||
ClientProfilesRepresentation repsWithBuiltin = getProfiles();
|
||||
repsWithBuiltin.getProfiles().stream().filter(i->!i.isBuiltin()).forEach(j->reps.getProfiles().add(j));
|
||||
return reps;
|
||||
protected ClientProfilesRepresentation getProfilesWithoutGlobals() {
|
||||
return adminClient.realm(REALM_NAME).clientPoliciesProfilesResource().getProfiles(false);
|
||||
}
|
||||
|
||||
protected String convertToProfileJson(ClientProfileRepresentation rep) {
|
||||
|
@ -1138,7 +1077,7 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
protected ClientProfileRepresentation getProfile(String name) {
|
||||
if (name == null) return null;
|
||||
|
||||
ClientProfilesRepresentation reps = getProfiles();
|
||||
ClientProfilesRepresentation reps = getProfilesWithGlobals();
|
||||
if (reps == null || reps.getProfiles() == null) return null;
|
||||
|
||||
if (reps.getProfiles().stream().anyMatch(i->name.equals(i.getName()))) {
|
||||
|
@ -1153,7 +1092,7 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
}
|
||||
|
||||
protected void addProfile(ClientProfileRepresentation profileRep) throws ClientPolicyException {
|
||||
ClientProfilesRepresentation reps = getProfilesWithoutBuiltin();
|
||||
ClientProfilesRepresentation reps = getProfilesWithoutGlobals();
|
||||
if (reps == null || reps.getProfiles() == null) return;
|
||||
reps.getProfiles().add(profileRep);
|
||||
updateProfiles(convertToProfilesJson(reps));
|
||||
|
@ -1164,7 +1103,7 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
if (profileRep == null || profileRep.getName() == null) return;
|
||||
String profileName = profileRep.getName();
|
||||
|
||||
ClientProfilesRepresentation reps = getProfilesWithoutBuiltin();
|
||||
ClientProfilesRepresentation reps = getProfilesWithoutGlobals();
|
||||
|
||||
if (reps.getProfiles().stream().anyMatch(i->profileName.equals(i.getName()))) {
|
||||
ClientProfileRepresentation rep = reps.getProfiles().stream().filter(i->profileName.equals(i.getName())).collect(Collectors.toList()).get(0);
|
||||
|
@ -1179,7 +1118,7 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
protected void deleteProfile(String profileName) throws ClientPolicyException {
|
||||
if (profileName == null) return;
|
||||
|
||||
ClientProfilesRepresentation reps = getProfilesWithoutBuiltin();
|
||||
ClientProfilesRepresentation reps = getProfilesWithoutGlobals();
|
||||
|
||||
if (reps.getProfiles().stream().anyMatch(i->profileName.equals(i.getName()))) {
|
||||
ClientProfileRepresentation rep = reps.getProfiles().stream().filter(i->profileName.equals(i.getName())).collect(Collectors.toList()).get(0);
|
||||
|
@ -1202,45 +1141,24 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
return json;
|
||||
}
|
||||
|
||||
protected ClientPoliciesRepresentation convertToPolicies(String json) {
|
||||
ClientPoliciesRepresentation reps = null;
|
||||
try {
|
||||
reps = JsonSerialization.readValue(json, ClientPoliciesRepresentation.class);
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
return reps;
|
||||
}
|
||||
|
||||
protected String getPoliciesJson() {
|
||||
return adminClient.realm(REALM_NAME).clientPoliciesPoliciesResource().getPolicies();
|
||||
}
|
||||
|
||||
// TODO: Possibly change this to accept ClientPoliciesRepresentation instead of String to have more type-safety.
|
||||
protected void updatePolicies(String json) throws ClientPolicyException {
|
||||
Response resp = adminClient.realm(REALM_NAME).clientPoliciesPoliciesResource().updatePolicies(json);
|
||||
if (resp.getStatus() != 204) {
|
||||
throw new ClientPolicyException("update profiles failed", resp.getStatusInfo().toString());
|
||||
try {
|
||||
ClientPoliciesRepresentation clientPolicies = json==null ? null : JsonSerialization.readValue(json, ClientPoliciesRepresentation.class);
|
||||
adminClient.realm(REALM_NAME).clientPoliciesPoliciesResource().updatePolicies(clientPolicies);
|
||||
} catch (BadRequestException e) {
|
||||
throw new ClientPolicyException("update policies failed", e.getResponse().getStatusInfo().toString());
|
||||
} catch (IOException e) {
|
||||
throw new ClientPolicyException("update policies failed", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
protected void updatePolicies(ClientPoliciesRepresentation reps) throws ClientPolicyException {
|
||||
updatePolicies(convertToPoliciesJson(reps));
|
||||
}
|
||||
|
||||
protected void revertToBuiltinPolicies() throws ClientPolicyException {
|
||||
updatePolicies("{}");
|
||||
}
|
||||
|
||||
protected ClientPoliciesRepresentation getPolicies() {
|
||||
return convertToPolicies(getPoliciesJson());
|
||||
}
|
||||
|
||||
protected ClientPoliciesRepresentation getPoliciesWithoutBuiltin() {
|
||||
ClientPoliciesRepresentation reps = new ClientPoliciesRepresentation();
|
||||
reps.setPolicies(new ArrayList<>());
|
||||
ClientPoliciesRepresentation repsWithBuiltin = getPolicies();
|
||||
repsWithBuiltin.getPolicies().stream().filter(i->!i.isBuiltin()).forEach(j->reps.getPolicies().add(j));
|
||||
return reps;
|
||||
return adminClient.realm(REALM_NAME).clientPoliciesPoliciesResource().getPolicies();
|
||||
}
|
||||
|
||||
protected String convertToPolicyJson(ClientPolicyRepresentation rep) {
|
||||
|
@ -1281,7 +1199,7 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
}
|
||||
|
||||
protected void addPolicy(ClientPolicyRepresentation policyRep) throws ClientPolicyException {
|
||||
ClientPoliciesRepresentation reps = getPoliciesWithoutBuiltin();
|
||||
ClientPoliciesRepresentation reps = getPolicies();
|
||||
if (reps == null || reps.getPolicies() == null) return;
|
||||
reps.getPolicies().add(policyRep);
|
||||
updatePolicies(convertToPoliciesJson(reps));
|
||||
|
@ -1292,7 +1210,7 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
if (policyRep == null || policyRep.getName() == null) return;
|
||||
String policyName = policyRep.getName();
|
||||
|
||||
ClientPoliciesRepresentation reps = getPoliciesWithoutBuiltin();
|
||||
ClientPoliciesRepresentation reps = getPolicies();
|
||||
|
||||
if (reps.getPolicies().stream().anyMatch(i->policyName.equals(i.getName()))) {
|
||||
ClientPolicyRepresentation rep = reps.getPolicies().stream().filter(i->policyName.equals(i.getName())).collect(Collectors.toList()).get(0);
|
||||
|
@ -1307,7 +1225,7 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
protected void deletePolicy(String policyName) throws ClientPolicyException {
|
||||
if (policyName == null) return;
|
||||
|
||||
ClientPoliciesRepresentation reps = getPoliciesWithoutBuiltin();
|
||||
ClientPoliciesRepresentation reps = getPolicies();
|
||||
|
||||
if (reps.getPolicies().stream().anyMatch(i->policyName.equals(i.getName()))) {
|
||||
ClientPolicyRepresentation rep = reps.getPolicies().stream().filter(i->policyName.equals(i.getName())).collect(Collectors.toList()).get(0);
|
||||
|
@ -1328,24 +1246,28 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
|
||||
// profile
|
||||
|
||||
protected ClientProfileRepresentation getProfileRepresentation(ClientProfilesRepresentation profilesRep, String name) {
|
||||
return getCompoundRepresentation(profilesRep, name, (ClientProfilesRepresentation i)->i.getProfiles(), (ClientProfileRepresentation i)->i.getName());
|
||||
protected ClientProfileRepresentation getProfileRepresentation(ClientProfilesRepresentation profilesRep, String name, boolean global) {
|
||||
Function<ClientProfilesRepresentation, List<ClientProfileRepresentation>> profilesListGetter = global ? ClientProfilesRepresentation::getGlobalProfiles : ClientProfilesRepresentation::getProfiles;
|
||||
return getCompoundRepresentation(profilesRep, name, profilesListGetter, (ClientProfileRepresentation i)->i.getName());
|
||||
}
|
||||
|
||||
protected void assertExpectedProfiles(ClientProfilesRepresentation profilesRep, List<String> expectedProfiles) {
|
||||
assertExpetedCompounds(expectedProfiles, profilesRep, (ClientProfilesRepresentation i)->i.getProfiles(), (ClientProfileRepresentation i)->i.getName());
|
||||
protected void assertExpectedProfiles(ClientProfilesRepresentation profilesRep, List<String> expectedGlobalProfiles, List<String> expectedRealmProfiles) {
|
||||
assertExpectedCompounds(expectedGlobalProfiles, profilesRep, (ClientProfilesRepresentation i)->i.getGlobalProfiles(), (ClientProfileRepresentation i)->i.getName());
|
||||
assertExpectedCompounds(expectedRealmProfiles, profilesRep, (ClientProfilesRepresentation i)->i.getProfiles(), (ClientProfileRepresentation i)->i.getName());
|
||||
}
|
||||
|
||||
protected void assertExpectedProfile(ClientProfileRepresentation actualProfileRep, String name, String description, boolean isBuiltin) {
|
||||
protected void assertExpectedProfile(ClientProfileRepresentation actualProfileRep, String name, String description) {
|
||||
assertNotNull(actualProfileRep);
|
||||
assertEquals(description, actualProfileRep.getDescription());
|
||||
assertEquals(isBuiltin, actualProfileRep.isBuiltin());
|
||||
}
|
||||
|
||||
// executors
|
||||
|
||||
protected void assertExpectedExecutors(List<String> expectedExecutors, ClientProfileRepresentation profileRep) {
|
||||
assertExpetedElement(expectedExecutors, profileRep, (ClientProfileRepresentation i)->i.getExecutors());
|
||||
List<String> actualExecutorNames = profileRep.getExecutors().stream()
|
||||
.map(ClientPolicyExecutorRepresentation::getExecutorProviderId)
|
||||
.collect(Collectors.toList());
|
||||
assertThat(actualExecutorNames, Matchers.containsInAnyOrder(expectedExecutors.toArray()));
|
||||
}
|
||||
|
||||
protected void assertExpectedHolderOfKeyEnforceExecutor(boolean isAugment, ClientProfileRepresentation profileRep) {
|
||||
|
@ -1357,51 +1279,55 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
}
|
||||
|
||||
protected void assertExpectedSecureClientAuthEnforceExecutor(List<String> clientAuthns, boolean isAugment, String clientAuthnsAugment, ClientProfileRepresentation profileRep) {
|
||||
JsonNode actualExecutorConfig = assertExpectedAugmenedExecutor(isAugment, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, profileRep);
|
||||
assertExpectedAugmenedExecutor(isAugment, SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, profileRep);
|
||||
assertNotNull(profileRep);
|
||||
Map<String, Object> actualExecutorConfig = getConfigOfExecutor(SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, profileRep);
|
||||
assertNotNull(actualExecutorConfig);
|
||||
|
||||
Set<String> actualClientAuthns = new HashSet<>();
|
||||
if (actualExecutorConfig.findValue("client-authns") != null) actualExecutorConfig.findValue("client-authns").elements().forEachRemaining(i->actualClientAuthns.add(i.asText()));
|
||||
Set<String> actualClientAuthns = new HashSet<>((Collection<String>) actualExecutorConfig.get("client-authns"));
|
||||
assertEquals(new HashSet<>(clientAuthns), actualClientAuthns);
|
||||
|
||||
String actualClientAuthnAugment = null;
|
||||
if (actualExecutorConfig.findValue("client-authns-augment") != null) actualClientAuthnAugment = actualExecutorConfig.findValue("client-authns-augment").asText();
|
||||
String actualClientAuthnAugment = actualExecutorConfig.get("client-authns-augment").toString();
|
||||
assertEquals(clientAuthnsAugment, actualClientAuthnAugment);
|
||||
}
|
||||
|
||||
protected void assertExpectedSecureRedirectUriEnforceExecutor(ClientProfileRepresentation profileRep) {
|
||||
assertExpectedNoConfigElement(SecureClientRegisteringUriEnforceExecutorFactory.PROVIDER_ID, profileRep, (ClientProfileRepresentation i)->i.getExecutors());
|
||||
assertExpectedEmptyConfig(SecureClientRegisteringUriEnforceExecutorFactory.PROVIDER_ID, profileRep);
|
||||
}
|
||||
|
||||
protected void assertExpectedSecureRequestObjectExecutor(ClientProfileRepresentation profileRep) {
|
||||
assertExpectedNoConfigElement(SecureRequestObjectExecutorFactory.PROVIDER_ID, profileRep, (ClientProfileRepresentation i)->i.getExecutors());
|
||||
assertExpectedEmptyConfig(SecureRequestObjectExecutorFactory.PROVIDER_ID, profileRep);
|
||||
}
|
||||
|
||||
protected void assertExpectedSecureResponseTypeExecutor(ClientProfileRepresentation profileRep) {
|
||||
assertExpectedNoConfigElement(SecureResponseTypeExecutorFactory.PROVIDER_ID, profileRep, (ClientProfileRepresentation i)->i.getExecutors());
|
||||
assertExpectedEmptyConfig(SecureResponseTypeExecutorFactory.PROVIDER_ID, profileRep);
|
||||
}
|
||||
|
||||
protected void assertExpectedSecureSessionEnforceExecutor(ClientProfileRepresentation profileRep) {
|
||||
assertExpectedNoConfigElement(SecureSessionEnforceExecutorFactory.PROVIDER_ID, profileRep, (ClientProfileRepresentation i)->i.getExecutors());
|
||||
assertExpectedEmptyConfig(SecureSessionEnforceExecutorFactory.PROVIDER_ID, profileRep);
|
||||
}
|
||||
|
||||
protected void assertExpectedSecureSigningAlgorithmEnforceExecutor(ClientProfileRepresentation profileRep) {
|
||||
assertExpectedNoConfigElement(SecureSigningAlgorithmEnforceExecutorFactory.PROVIDER_ID, profileRep, (ClientProfileRepresentation i)->i.getExecutors());
|
||||
assertExpectedEmptyConfig(SecureSigningAlgorithmEnforceExecutorFactory.PROVIDER_ID, profileRep);
|
||||
}
|
||||
|
||||
protected void assertExpectedSecureSigningAlgorithmForSignedJwtEnforceExecutor(ClientProfileRepresentation profileRep) {
|
||||
assertExpectedNoConfigElement(SecureSigningAlgorithmForSignedJwtEnforceExecutorFactory.PROVIDER_ID, profileRep, (ClientProfileRepresentation i)->i.getExecutors());
|
||||
assertExpectedEmptyConfig(SecureSigningAlgorithmForSignedJwtEnforceExecutorFactory.PROVIDER_ID, profileRep);
|
||||
}
|
||||
|
||||
protected JsonNode assertExpectedAugmenedExecutor(boolean isAugment, String providerId, ClientProfileRepresentation profileRep) {
|
||||
protected void assertExpectedAugmenedExecutor(boolean isAugment, String providerId, ClientProfileRepresentation profileRep) {
|
||||
assertNotNull(profileRep);
|
||||
JsonNode actualExecutorConfig = getConfig(profileRep.getExecutors(), providerId);
|
||||
Map<String, Object> actualExecutorConfig = getConfigOfExecutor(providerId, profileRep);
|
||||
assertNotNull(actualExecutorConfig);
|
||||
|
||||
boolean actualIsAugment = false;
|
||||
if (actualExecutorConfig.findValue("is-augment") != null) actualIsAugment = actualExecutorConfig.findValue("is-augment").asBoolean();
|
||||
boolean actualIsAugment = actualExecutorConfig.get("is-augment") == null ? false : (Boolean) actualExecutorConfig.get("is-augment");
|
||||
assertEquals(isAugment, actualIsAugment);
|
||||
}
|
||||
|
||||
return actualExecutorConfig;
|
||||
private Map<String, Object> getConfigOfExecutor(String providerId, ClientProfileRepresentation profileRep) {
|
||||
ClientPolicyExecutorRepresentation executorRep = profileRep.getExecutors().stream()
|
||||
.filter(profileRepp -> providerId.equals(profileRepp.getExecutorProviderId()))
|
||||
.findFirst().orElse(null);
|
||||
return executorRep == null ? null : executorRep.getConfiguration().getConfigAsMap();
|
||||
}
|
||||
|
||||
// Assertions about policies
|
||||
|
@ -1429,94 +1355,69 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
assertEquals(new HashSet<>(expectedPolicies), actualPolicies);
|
||||
}
|
||||
|
||||
protected void assertExpectedPolicy(String name, String description, boolean isBuiltin, boolean isEnabled, List<String> profiles, ClientPolicyRepresentation actualPolicyRep) {
|
||||
protected void assertExpectedPolicy(String name, String description, boolean isEnabled, List<String> profiles, ClientPolicyRepresentation actualPolicyRep) {
|
||||
assertNotNull(actualPolicyRep);
|
||||
assertEquals(description, actualPolicyRep.getDescription());
|
||||
assertEquals(isBuiltin, actualPolicyRep.isBuiltin());
|
||||
assertEquals(isEnabled, actualPolicyRep.isEnable());
|
||||
assertEquals(isEnabled, actualPolicyRep.isEnabled());
|
||||
assertEquals(new HashSet<>(profiles), new HashSet<>(actualPolicyRep.getProfiles()));
|
||||
}
|
||||
|
||||
// conditions
|
||||
|
||||
protected void assertExpectedConditions(List<String> expectedConditions, ClientPolicyRepresentation policyRep) {
|
||||
assertExpetedElement(expectedConditions, policyRep, (ClientPolicyRepresentation i)->i.getConditions());
|
||||
List<String> actualConditionNames = policyRep.getConditions().stream()
|
||||
.map(ClientPolicyConditionRepresentation::getConditionProviderId)
|
||||
.collect(Collectors.toList());
|
||||
assertThat(actualConditionNames, Matchers.containsInAnyOrder(expectedConditions.toArray()));
|
||||
}
|
||||
|
||||
protected void assertExpectedAnyClientCondition(ClientPolicyRepresentation profileRep) {
|
||||
assertExpectedNoConfigElement(AnyClientConditionFactory.PROVIDER_ID, profileRep, (ClientPolicyRepresentation i)->i.getConditions());
|
||||
protected void assertExpectedAnyClientCondition(ClientPolicyRepresentation policyRep) {
|
||||
ClientPolicyConditionConfigurationRepresentation config = getConfigAsExpectedType(policyRep, AnyClientConditionFactory.PROVIDER_ID, ClientPolicyConditionConfigurationRepresentation.class);
|
||||
Assert.assertTrue("Expected empty configuration for provider " + AnyClientConditionFactory.PROVIDER_ID, config.getConfigAsMap().isEmpty());
|
||||
}
|
||||
|
||||
protected void assertExpectedClientAccessTypeCondition(List<String> type, ClientPolicyRepresentation policyRep) {
|
||||
JsonNode actualConditionConfig = getConfig(policyRep.getConditions(), ClientAccessTypeConditionFactory.PROVIDER_ID);
|
||||
|
||||
Set<String> actualTypes = new HashSet<>();
|
||||
if (actualConditionConfig.findValue("type") != null)
|
||||
actualConditionConfig.findValue("type").elements().forEachRemaining(i->actualTypes.add(i.asText()));
|
||||
assertEquals(new HashSet<>(type), actualTypes);
|
||||
ClientAccessTypeCondition.Configuration cfg = getConfigAsExpectedType(policyRep, ClientAccessTypeConditionFactory.PROVIDER_ID, ClientAccessTypeCondition.Configuration.class);
|
||||
Assert.assertEquals(cfg.getType(), type);
|
||||
}
|
||||
|
||||
protected void assertExpectedClientRolesCondition(List<String> roles, ClientPolicyRepresentation policyRep) {
|
||||
JsonNode actualConditionConfig = getConfig(policyRep.getConditions(), ClientRolesConditionFactory.PROVIDER_ID);
|
||||
|
||||
Set<String> actualRoles = new HashSet<>();
|
||||
if (actualConditionConfig.findValue("roles") != null)
|
||||
actualConditionConfig.findValue("roles").elements().forEachRemaining(i->actualRoles.add(i.asText()));
|
||||
assertEquals(new HashSet<>(roles), actualRoles);
|
||||
ClientRolesCondition.Configuration cfg = getConfigAsExpectedType(policyRep, ClientRolesConditionFactory.PROVIDER_ID, ClientRolesCondition.Configuration.class);
|
||||
Assert.assertEquals(cfg.getRoles(), roles);
|
||||
}
|
||||
|
||||
protected void assertExpectedClientScopesCondition(String type, List<String> scopes, ClientPolicyRepresentation policyRep) {
|
||||
JsonNode actualConditionConfig = getConfig(policyRep.getConditions(), ClientScopesConditionFactory.PROVIDER_ID);
|
||||
|
||||
String actualType = null;
|
||||
if (actualConditionConfig.findValue("type") != null) actualType = actualConditionConfig.findValue("type").asText();
|
||||
assertEquals(type, actualType);
|
||||
|
||||
Set<String> actualScopes = new HashSet<>();
|
||||
if (actualConditionConfig.findValue("scope") != null)
|
||||
actualConditionConfig.findValue("scope").elements().forEachRemaining(i->actualScopes.add(i.asText()));
|
||||
assertEquals(new HashSet<>(scopes), actualScopes);
|
||||
ClientScopesCondition.Configuration cfg = getConfigAsExpectedType(policyRep, ClientScopesConditionFactory.PROVIDER_ID, ClientScopesCondition.Configuration.class);
|
||||
Assert.assertEquals(cfg.getType(), type);
|
||||
Assert.assertEquals(cfg.getScope(), scopes);
|
||||
}
|
||||
|
||||
protected void assertExpectedClientUpdateContextCondition(List<String> updateClientSources, ClientPolicyRepresentation policyRep) {
|
||||
JsonNode actualConditionConfig = getConfig(policyRep.getConditions(), ClientUpdateContextConditionFactory.PROVIDER_ID);
|
||||
|
||||
Set<String> actualUpdateClientSources = new HashSet<>();
|
||||
if (actualConditionConfig.findValue("update-client-source") != null)
|
||||
actualConditionConfig.findValue("update-client-source").elements().forEachRemaining(i->actualUpdateClientSources.add(i.asText()));
|
||||
assertEquals(new HashSet<>(updateClientSources), actualUpdateClientSources);
|
||||
ClientUpdateContextCondition.Configuration cfg = getConfigAsExpectedType(policyRep, ClientUpdateContextConditionFactory.PROVIDER_ID, ClientUpdateContextCondition.Configuration.class);
|
||||
Assert.assertEquals(cfg.getUpdateClientSource(), updateClientSources);
|
||||
}
|
||||
|
||||
protected void assertExpectedClientUpdateSourceGroupsCondition(List<String> groups, ClientPolicyRepresentation policyRep) {
|
||||
JsonNode actualConditionConfig = getConfig(policyRep.getConditions(), ClientUpdateSourceGroupsConditionFactory.PROVIDER_ID);
|
||||
|
||||
Set<String> actualGroups = new HashSet<>();
|
||||
if (actualConditionConfig.findValue("groups") != null)
|
||||
actualConditionConfig.findValue("groups").elements().forEachRemaining(i->actualGroups.add(i.asText()));
|
||||
assertEquals(new HashSet<>(groups), actualGroups);
|
||||
ClientUpdateSourceGroupsCondition.Configuration cfg = getConfigAsExpectedType(policyRep, ClientUpdateSourceGroupsConditionFactory.PROVIDER_ID, ClientUpdateSourceGroupsCondition.Configuration.class);
|
||||
Assert.assertEquals(cfg.getGroups(), groups);
|
||||
}
|
||||
|
||||
protected void assertExpectedClientUpdateSourceHostsCondition(List<String> trustedHosts, List<Boolean> hostSendingRequestMustMatch, ClientPolicyRepresentation policyRep) {
|
||||
JsonNode actualConditionConfig = getConfig(policyRep.getConditions(), ClientUpdateSourceHostsConditionFactory.PROVIDER_ID);
|
||||
|
||||
List<String> actualTrustedHosts = new ArrayList<>();
|
||||
if (actualConditionConfig.findValue("trusted-hosts") != null)
|
||||
actualConditionConfig.findValue("trusted-hosts").elements().forEachRemaining(i->actualTrustedHosts.add(i.asText()));
|
||||
assertEquals(trustedHosts, actualTrustedHosts);
|
||||
|
||||
List<Boolean> actualHostSendingRequestMustMatch = new ArrayList<>();
|
||||
if (actualConditionConfig.findValue("host-sending-request-must-match") != null)
|
||||
actualConditionConfig.findValue("host-sending-request-must-match").elements().forEachRemaining(i->actualHostSendingRequestMustMatch.add(i.asBoolean()));
|
||||
assertEquals(trustedHosts, actualTrustedHosts);
|
||||
protected void assertExpectedClientUpdateSourceHostsCondition(List<String> trustedHosts, ClientPolicyRepresentation policyRep) {
|
||||
ClientUpdateSourceHostsCondition.Configuration cfg = getConfigAsExpectedType(policyRep, ClientUpdateSourceHostsConditionFactory.PROVIDER_ID, ClientUpdateSourceHostsCondition.Configuration.class);
|
||||
Assert.assertEquals(cfg.getTrustedHosts(), trustedHosts);
|
||||
}
|
||||
|
||||
protected void assertExpectedClientUpdateSourceRolesCondition(List<String> roles, ClientPolicyRepresentation policyRep) {
|
||||
JsonNode actualConditionConfig = getConfig(policyRep.getConditions(), ClientUpdateSourceRolesConditionFactory.PROVIDER_ID);
|
||||
ClientUpdateSourceRolesCondition.Configuration cfg = getConfigAsExpectedType(policyRep, ClientUpdateSourceRolesConditionFactory.PROVIDER_ID, ClientUpdateSourceRolesCondition.Configuration.class);
|
||||
Assert.assertEquals(cfg.getRoles(), roles);
|
||||
}
|
||||
|
||||
Set<String> actualRoles = new HashSet<>();
|
||||
if (actualConditionConfig.findValue("roles") != null)
|
||||
actualConditionConfig.findValue("roles").elements().forEachRemaining(i->actualRoles.add(i.asText()));
|
||||
assertEquals(new HashSet<>(roles), actualRoles);
|
||||
private <CFG extends ClientPolicyConditionConfigurationRepresentation> CFG getConfigAsExpectedType(ClientPolicyRepresentation policyRep, String conditionProviderId, Class<CFG> configClass) {
|
||||
ClientPolicyConditionRepresentation conditionRep = policyRep.getConditions().stream()
|
||||
.filter(condition -> conditionProviderId.equals(condition.getConditionProviderId()))
|
||||
.findFirst().orElseThrow(() -> new AssertionError("Expected to contain configuration for condition " + conditionProviderId));
|
||||
|
||||
return JsonSerialization.mapper.convertValue(conditionRep.getConfiguration(), configClass);
|
||||
}
|
||||
|
||||
// profiles/policies common (compounds)
|
||||
|
@ -1531,7 +1432,7 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
return rep;
|
||||
}
|
||||
|
||||
private <T, R> void assertExpetedCompounds(List<String> expected, R rep, Function<R, List<T>> f, Function<T, String> g) {
|
||||
private <T, R> void assertExpectedCompounds(List<String> expected, R rep, Function<R, List<T>> f, Function<T, String> g) {
|
||||
assertNotNull(rep);
|
||||
List<T> reps = f.apply(rep);
|
||||
if (reps == null) {
|
||||
|
@ -1553,33 +1454,9 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
|
|||
return reps.get(0);
|
||||
}
|
||||
|
||||
// condition/executor common (element)
|
||||
|
||||
private <T> void assertExpetedElement(List<String> expected, T rep, Function<T, List<Object>> f) {
|
||||
assertNotNull(rep);
|
||||
List<Object> objs = f.apply(rep);
|
||||
if (objs == null) {
|
||||
assertNull(expected);
|
||||
return;
|
||||
}
|
||||
Set<String> actual = objs.stream().map(i->{
|
||||
JsonNode node = objectMapper.convertValue(i, JsonNode.class);
|
||||
return node.fieldNames().next();
|
||||
}).collect(Collectors.toSet());
|
||||
assertEquals(new HashSet<>(expected), actual);
|
||||
}
|
||||
|
||||
private <T> void assertExpectedNoConfigElement(String providerId, T rep, Function<T, List<Object>> f) {
|
||||
assertNotNull(rep);
|
||||
JsonNode actualConfig = getConfig(f.apply(rep), providerId);
|
||||
assertEquals("", actualConfig.asText());
|
||||
}
|
||||
|
||||
private JsonNode getConfig(List<Object> objs, String providerId) {
|
||||
List<JsonNode> nodes = objs.stream().map(i->objectMapper.convertValue(i, JsonNode.class))
|
||||
.filter(j->j.fieldNames().next().equals(providerId)).collect(Collectors.toList());
|
||||
if (nodes == null || nodes.size() != 1) return null;
|
||||
return nodes.get(0);
|
||||
private void assertExpectedEmptyConfig(String executorProviderId, ClientProfileRepresentation profileRep) {
|
||||
Map<String, Object> config = getConfigOfExecutor(executorProviderId, profileRep);
|
||||
Assert.assertTrue("Expected empty configuration for provider " + executorProviderId, config.isEmpty());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ public class ClientPoliciesImportExportTest extends AbstractClientPoliciesTest {
|
|||
String targetFilePath = testingClient.testing().exportImport().getExportImportTestDirectory() + File.separator + "client-policies-exported-realm.json";
|
||||
testingClient.testing().exportImport().setFile(targetFilePath);
|
||||
|
||||
loadValidProfilesAndPolicies();
|
||||
setupValidProfilesAndPolicies();
|
||||
|
||||
testRealmExportImport();
|
||||
}
|
||||
|
@ -92,13 +92,13 @@ public class ClientPoliciesImportExportTest extends AbstractClientPoliciesTest {
|
|||
Assert.assertNames(adminClient.realms().findAll(), "master", "test");
|
||||
|
||||
assertExpectedLoadedProfiles((ClientProfilesRepresentation reps)->{
|
||||
ClientProfileRepresentation rep = getProfileRepresentation(reps, "ordinal-test-profile");
|
||||
assertExpectedProfile(rep, "ordinal-test-profile", "The profile that can be loaded.", false);
|
||||
ClientProfileRepresentation rep = getProfileRepresentation(reps, "ordinal-test-profile", false);
|
||||
assertExpectedProfile(rep, "ordinal-test-profile", "The profile that can be loaded.");
|
||||
});
|
||||
|
||||
assertExpectedLoadedPolicies((ClientPoliciesRepresentation reps)->{
|
||||
ClientPolicyRepresentation rep = getPolicyRepresentation(reps, "new-policy");
|
||||
assertExpectedPolicy("new-policy", "duplicated profiles are ignored.", false, true, Arrays.asList("builtin-default-profile", "ordinal-test-profile", "lack-of-builtin-field-test-profile"),
|
||||
assertExpectedPolicy("new-policy", "duplicated profiles are ignored.", true, Arrays.asList("global-default-profile", "ordinal-test-profile", "lack-of-builtin-field-test-profile"),
|
||||
rep);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -17,17 +17,23 @@
|
|||
|
||||
package org.keycloak.testsuite.client;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
|
||||
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.REMOTE;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.authentication.authenticators.client.ClientIdAndSecretAuthenticator;
|
||||
import org.keycloak.authentication.authenticators.client.JWTClientAuthenticator;
|
||||
import org.keycloak.authentication.authenticators.client.JWTClientSecretAuthenticator;
|
||||
import org.keycloak.authentication.authenticators.client.X509ClientAuthenticator;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.representations.idm.ClientPoliciesRepresentation;
|
||||
import org.keycloak.representations.idm.ClientPolicyRepresentation;
|
||||
|
@ -36,12 +42,12 @@ import org.keycloak.representations.idm.ClientProfilesRepresentation;
|
|||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
import org.keycloak.services.clientpolicy.ClientPoliciesUtil;
|
||||
import org.keycloak.services.clientpolicy.condition.AnyClientConditionFactory;
|
||||
import org.keycloak.services.clientpolicy.condition.ClientAccessTypeConditionFactory;
|
||||
import org.keycloak.services.clientpolicy.condition.ClientRolesConditionFactory;
|
||||
import org.keycloak.services.clientpolicy.executor.PKCEEnforceExecutorFactory;
|
||||
import org.keycloak.services.clientpolicy.executor.SecureClientAuthEnforceExecutorFactory;
|
||||
import org.keycloak.services.clientpolicy.executor.SecureSessionEnforceExecutorFactory;
|
||||
import org.keycloak.testsuite.Assert;
|
||||
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
|
||||
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
|
||||
|
||||
|
@ -67,53 +73,51 @@ public class ClientPoliciesLoadUpdateTest extends AbstractClientPoliciesTest {
|
|||
|
||||
@Test
|
||||
public void testLoadBuiltinProfilesAndPolicies() throws Exception {
|
||||
// retrieve loaded builtin profiles
|
||||
ClientProfilesRepresentation actualProfilesRep = getProfiles();
|
||||
// retrieve loaded global profiles
|
||||
ClientProfilesRepresentation actualProfilesRep = getProfilesWithGlobals();
|
||||
|
||||
// same profiles
|
||||
assertExpectedProfiles(actualProfilesRep, Arrays.asList("builtin-default-profile"));
|
||||
assertExpectedProfiles(actualProfilesRep, Arrays.asList("global-default-profile"), Collections.emptyList());
|
||||
|
||||
// each profile
|
||||
ClientProfileRepresentation actualProfileRep = getProfileRepresentation(actualProfilesRep, "builtin-default-profile");
|
||||
assertExpectedProfile(actualProfileRep, "builtin-default-profile", "The built-in default profile for enforcing basic security level to clients.", true);
|
||||
ClientProfileRepresentation actualProfileRep = getProfileRepresentation(actualProfilesRep, "global-default-profile", true);
|
||||
assertExpectedProfile(actualProfileRep, "global-default-profile", "The global default profile for enforcing basic security level to clients.");
|
||||
|
||||
// each executor
|
||||
assertExpectedExecutors(Arrays.asList(SecureSessionEnforceExecutorFactory.PROVIDER_ID), actualProfileRep);
|
||||
|
||||
// Check the "get" request without globals. Assert nothing loaded
|
||||
actualProfilesRep = getProfilesWithoutGlobals();
|
||||
assertExpectedProfiles(actualProfilesRep, null, Collections.emptyList());
|
||||
|
||||
// retrieve loaded builtin policies
|
||||
ClientPoliciesRepresentation actualPoliciesRep = getPolicies();
|
||||
|
||||
// same policies
|
||||
assertExpectedPolicies(Arrays.asList("builtin-default-policy"), actualPoliciesRep);
|
||||
|
||||
// each policy
|
||||
// No global policies expected
|
||||
assertExpectedPolicies(Collections.emptyList(), actualPoliciesRep);
|
||||
ClientPolicyRepresentation actualPolicyRep = getPolicyRepresentation(actualPoliciesRep, "builtin-default-policy");
|
||||
assertExpectedPolicy("builtin-default-policy", "The built-in default policy applied to all clients.", true, false, Arrays.asList("builtin-default-profile"), actualPolicyRep);
|
||||
|
||||
// each condition
|
||||
assertExpectedConditions(Arrays.asList(AnyClientConditionFactory.PROVIDER_ID), actualPolicyRep);
|
||||
|
||||
Assert.assertNull(actualPolicyRep);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateValidProfilesAndPolicies() throws Exception {
|
||||
loadValidProfilesAndPolicies();
|
||||
setupValidProfilesAndPolicies();
|
||||
|
||||
assertExpectedLoadedProfiles((ClientProfilesRepresentation reps)->{
|
||||
ClientProfileRepresentation rep = getProfileRepresentation(reps, "ordinal-test-profile");
|
||||
assertExpectedProfile(rep, "ordinal-test-profile", "The profile that can be loaded.", false);
|
||||
ClientProfileRepresentation rep = getProfileRepresentation(reps, "ordinal-test-profile", false);
|
||||
assertExpectedProfile(rep, "ordinal-test-profile", "The profile that can be loaded.");
|
||||
});
|
||||
|
||||
assertExpectedLoadedPolicies((ClientPoliciesRepresentation reps)->{
|
||||
ClientPolicyRepresentation rep = getPolicyRepresentation(reps, "new-policy");
|
||||
assertExpectedPolicy("new-policy", "duplicated profiles are ignored.", false, true, Arrays.asList("builtin-default-profile", "ordinal-test-profile", "lack-of-builtin-field-test-profile"),
|
||||
assertExpectedPolicy("new-policy", "duplicated profiles are ignored.", true, Arrays.asList("global-default-profile", "ordinal-test-profile", "lack-of-builtin-field-test-profile"),
|
||||
rep);
|
||||
});
|
||||
|
||||
// update existing profiles
|
||||
|
||||
String modifiedProfileDescription = "The profile has been updated.";
|
||||
ClientProfilesRepresentation actualProfilesRep = getProfilesWithoutBuiltin();
|
||||
ClientProfilesRepresentation actualProfilesRep = getProfilesWithoutGlobals();
|
||||
ClientProfilesBuilder profilesBuilder = new ClientProfilesBuilder();
|
||||
actualProfilesRep.getProfiles().stream().forEach(i->{
|
||||
if (i.getName().equals("ordinal-test-profile")) {
|
||||
|
@ -124,19 +128,19 @@ public class ClientPoliciesLoadUpdateTest extends AbstractClientPoliciesTest {
|
|||
updateProfiles(profilesBuilder.toString());
|
||||
|
||||
assertExpectedLoadedProfiles((ClientProfilesRepresentation reps)->{
|
||||
ClientProfileRepresentation rep = getProfileRepresentation(reps, "ordinal-test-profile");
|
||||
assertExpectedProfile(rep, "ordinal-test-profile", modifiedProfileDescription, false);
|
||||
ClientProfileRepresentation rep = getProfileRepresentation(reps, "ordinal-test-profile", false);
|
||||
assertExpectedProfile(rep, "ordinal-test-profile", modifiedProfileDescription);
|
||||
});
|
||||
|
||||
// update existing policies
|
||||
|
||||
String modifiedPolicyDescription = "The policy has also been updated.";
|
||||
ClientPoliciesRepresentation actualPoliciesRep = getPoliciesWithoutBuiltin();
|
||||
ClientPoliciesRepresentation actualPoliciesRep = getPolicies();
|
||||
ClientPoliciesBuilder policiesBuilder = new ClientPoliciesBuilder();
|
||||
actualPoliciesRep.getPolicies().stream().forEach(i->{
|
||||
if (i.getName().equals("new-policy")) {
|
||||
i.setDescription(modifiedPolicyDescription);
|
||||
i.setEnable(null);
|
||||
i.setEnabled(null);
|
||||
}
|
||||
policiesBuilder.addPolicy(i);
|
||||
});
|
||||
|
@ -144,7 +148,7 @@ public class ClientPoliciesLoadUpdateTest extends AbstractClientPoliciesTest {
|
|||
|
||||
assertExpectedLoadedPolicies((ClientPoliciesRepresentation reps)->{
|
||||
ClientPolicyRepresentation rep = getPolicyRepresentation(reps, "new-policy");
|
||||
assertExpectedPolicy("new-policy", modifiedPolicyDescription, false, false, Arrays.asList("builtin-default-profile", "ordinal-test-profile", "lack-of-builtin-field-test-profile"),
|
||||
assertExpectedPolicy("new-policy", modifiedPolicyDescription, false, Arrays.asList("global-default-profile", "ordinal-test-profile", "lack-of-builtin-field-test-profile"),
|
||||
rep);
|
||||
});
|
||||
|
||||
|
@ -152,10 +156,10 @@ public class ClientPoliciesLoadUpdateTest extends AbstractClientPoliciesTest {
|
|||
|
||||
@Test
|
||||
public void testDuplicatedProfiles() throws Exception {
|
||||
String beforeUpdateProfilesJson = ClientPoliciesUtil.convertClientProfilesRepresentationToJson(getProfiles());
|
||||
String beforeUpdateProfilesJson = ClientPoliciesUtil.convertClientProfilesRepresentationToJson(getProfilesWithGlobals());
|
||||
|
||||
// load profiles
|
||||
ClientProfileRepresentation duplicatedProfileRep = (new ClientProfileBuilder()).createProfile("builtin-basic-security", "Enforce basic security level", Boolean.TRUE, null)
|
||||
ClientProfileRepresentation duplicatedProfileRep = (new ClientProfileBuilder()).createProfile("builtin-basic-security", "Enforce basic security level")
|
||||
.addExecutor(SecureClientAuthEnforceExecutorFactory.PROVIDER_ID,
|
||||
createSecureClientAuthEnforceExecutorConfig(
|
||||
Boolean.FALSE,
|
||||
|
@ -167,7 +171,7 @@ public class ClientPoliciesLoadUpdateTest extends AbstractClientPoliciesTest {
|
|||
createPKCEEnforceExecutorConfig(Boolean.TRUE))
|
||||
.toRepresentation();
|
||||
|
||||
ClientProfileRepresentation loadedProfileRep = (new ClientProfileBuilder()).createProfile("ordinal-test-profile", "The profile that can be loaded.", Boolean.FALSE, null)
|
||||
ClientProfileRepresentation loadedProfileRep = (new ClientProfileBuilder()).createProfile("ordinal-test-profile", "The profile that can be loaded.")
|
||||
.addExecutor(SecureClientAuthEnforceExecutorFactory.PROVIDER_ID,
|
||||
createSecureClientAuthEnforceExecutorConfig(
|
||||
Boolean.TRUE,
|
||||
|
@ -182,25 +186,43 @@ public class ClientPoliciesLoadUpdateTest extends AbstractClientPoliciesTest {
|
|||
.toString();
|
||||
try {
|
||||
updateProfiles(json);
|
||||
fail();
|
||||
} catch (ClientPolicyException cpe) {
|
||||
assertEquals("Bad Request", cpe.getErrorDetail());
|
||||
String afterFailedUpdateProfilesJson = ClientPoliciesUtil.convertClientProfilesRepresentationToJson(getProfiles());
|
||||
String afterFailedUpdateProfilesJson = ClientPoliciesUtil.convertClientProfilesRepresentationToJson(getProfilesWithGlobals());
|
||||
assertEquals(beforeUpdateProfilesJson, afterFailedUpdateProfilesJson);
|
||||
return;
|
||||
}
|
||||
fail();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverwriteBuiltinProfileNotAllowed() throws Exception {
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile("global-default-profile", "Pershyy Profil")
|
||||
.addExecutor(SecureClientAuthEnforceExecutorFactory.PROVIDER_ID,
|
||||
createSecureClientAuthEnforceExecutorConfig(Boolean.TRUE,
|
||||
Arrays.asList(JWTClientAuthenticator.PROVIDER_ID, JWTClientSecretAuthenticator.PROVIDER_ID, X509ClientAuthenticator.PROVIDER_ID),
|
||||
X509ClientAuthenticator.PROVIDER_ID))
|
||||
.toRepresentation()
|
||||
).toString();
|
||||
try {
|
||||
updateProfiles(json);
|
||||
fail();
|
||||
} catch (ClientPolicyException cpe) {
|
||||
assertEquals("update profiles failed", cpe.getError());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullProfiles() throws Exception {
|
||||
String beforeUpdateProfilesJson = ClientPoliciesUtil.convertClientProfilesRepresentationToJson(getProfiles());
|
||||
String beforeUpdateProfilesJson = ClientPoliciesUtil.convertClientProfilesRepresentationToJson(getProfilesWithGlobals());
|
||||
|
||||
String json = null;
|
||||
try {
|
||||
updateProfiles(json);
|
||||
} catch (ClientPolicyException cpe) {
|
||||
assertEquals("Bad Request", cpe.getErrorDetail());
|
||||
String afterFailedUpdateProfilesJson = ClientPoliciesUtil.convertClientProfilesRepresentationToJson(getProfiles());
|
||||
assertEquals("argument \"content\" is null", cpe.getErrorDetail());
|
||||
String afterFailedUpdateProfilesJson = ClientPoliciesUtil.convertClientProfilesRepresentationToJson(getProfilesWithGlobals());
|
||||
assertEquals(beforeUpdateProfilesJson, afterFailedUpdateProfilesJson);
|
||||
return;
|
||||
}
|
||||
|
@ -209,7 +231,7 @@ public class ClientPoliciesLoadUpdateTest extends AbstractClientPoliciesTest {
|
|||
|
||||
@Test
|
||||
public void testInvalidFormattedJsonProfiles() throws Exception {
|
||||
String beforeUpdateProfilesJson = ClientPoliciesUtil.convertClientProfilesRepresentationToJson(getProfiles());
|
||||
String beforeUpdateProfilesJson = ClientPoliciesUtil.convertClientProfilesRepresentationToJson(getProfilesWithGlobals());
|
||||
|
||||
String json = "{\n"
|
||||
+ " \"profiles\": [\n"
|
||||
|
@ -232,8 +254,8 @@ public class ClientPoliciesLoadUpdateTest extends AbstractClientPoliciesTest {
|
|||
try {
|
||||
updateProfiles(json);
|
||||
} catch (ClientPolicyException cpe) {
|
||||
assertEquals("Bad Request", cpe.getErrorDetail());
|
||||
String afterFailedUpdateProfilesJson = ClientPoliciesUtil.convertClientProfilesRepresentationToJson(getProfiles());
|
||||
assertThat(cpe.getErrorDetail(), Matchers.startsWith("Unrecognized field"));
|
||||
String afterFailedUpdateProfilesJson = ClientPoliciesUtil.convertClientProfilesRepresentationToJson(getProfilesWithGlobals());
|
||||
assertEquals(beforeUpdateProfilesJson, afterFailedUpdateProfilesJson);
|
||||
return;
|
||||
}
|
||||
|
@ -242,7 +264,7 @@ public class ClientPoliciesLoadUpdateTest extends AbstractClientPoliciesTest {
|
|||
|
||||
@Test
|
||||
public void testInvalidFieldTypeJsonProfiles() throws Exception {
|
||||
String beforeUpdateProfilesJson = ClientPoliciesUtil.convertClientProfilesRepresentationToJson(getProfiles());
|
||||
String beforeUpdateProfilesJson = ClientPoliciesUtil.convertClientProfilesRepresentationToJson(getProfilesWithGlobals());
|
||||
|
||||
String json = "{\n"
|
||||
+ " \"profiles\": [\n"
|
||||
|
@ -250,14 +272,12 @@ public class ClientPoliciesLoadUpdateTest extends AbstractClientPoliciesTest {
|
|||
+ " \"name\" : \"ordinal-test-profile\",\n"
|
||||
+ " \"description\" : \"Not builtin profile that should be skipped.\",\n"
|
||||
+ " \"builtin\" : \"no\",\n"
|
||||
+ " \"executors\": [\n"
|
||||
+ " {\n"
|
||||
+ " \"executors\": {\n"
|
||||
+ " \"new-secure-client-authn-executor\": {\n"
|
||||
+ " \"client-authns\": [ \"private-key-jwt\" ],\n"
|
||||
+ " \"client-authns-augment\" : \"private-key-jwt\",\n"
|
||||
+ " \"is-augment\" : true\n"
|
||||
+ " }\n"
|
||||
+ " }\n"
|
||||
+ " ]\n"
|
||||
+ " }\n"
|
||||
+ " ]\n"
|
||||
|
@ -265,8 +285,8 @@ public class ClientPoliciesLoadUpdateTest extends AbstractClientPoliciesTest {
|
|||
try {
|
||||
updateProfiles(json);
|
||||
} catch (ClientPolicyException cpe) {
|
||||
assertEquals("Bad Request", cpe.getErrorDetail());
|
||||
String afterFailedUpdateProfilesJson = ClientPoliciesUtil.convertClientProfilesRepresentationToJson(getProfiles());
|
||||
assertThat(cpe.getErrorDetail(), Matchers.startsWith("Unrecognized field "));
|
||||
String afterFailedUpdateProfilesJson = ClientPoliciesUtil.convertClientProfilesRepresentationToJson(getProfilesWithGlobals());
|
||||
assertEquals(beforeUpdateProfilesJson, afterFailedUpdateProfilesJson);
|
||||
return;
|
||||
}
|
||||
|
@ -282,24 +302,21 @@ public class ClientPoliciesLoadUpdateTest extends AbstractClientPoliciesTest {
|
|||
(new ClientPolicyBuilder()).createPolicy(
|
||||
"builtin-duplicated-new-policy",
|
||||
"builtin duplicated new policy is ignored.",
|
||||
Boolean.FALSE,
|
||||
Boolean.TRUE,
|
||||
null,
|
||||
Arrays.asList("builtin-default-profile"))
|
||||
Boolean.TRUE)
|
||||
.addCondition(ClientRolesConditionFactory.PROVIDER_ID,
|
||||
createClientRolesConditionConfig(Arrays.asList(SAMPLE_CLIENT_ROLE)))
|
||||
.addProfile("global-default-profile")
|
||||
.toRepresentation();
|
||||
|
||||
ClientPolicyRepresentation loadedPolicyRep =
|
||||
(new ClientPolicyBuilder()).createPolicy(
|
||||
"new-policy",
|
||||
"duplicated profiles are ignored.",
|
||||
Boolean.FALSE,
|
||||
Boolean.TRUE,
|
||||
null,
|
||||
Arrays.asList("lack-of-builtin-field-test-profile", "ordinal-test-profile"))
|
||||
Boolean.TRUE)
|
||||
.addCondition(ClientAccessTypeConditionFactory.PROVIDER_ID,
|
||||
createClientAccessTypeConditionConfig(Arrays.asList(ClientAccessTypeConditionFactory.TYPE_PUBLIC, ClientAccessTypeConditionFactory.TYPE_BEARERONLY)))
|
||||
.addProfile("lack-of-builtin-field-test-profile")
|
||||
.addProfile("ordinal-test-profile")
|
||||
.toRepresentation();
|
||||
|
||||
String json = (new ClientPoliciesBuilder())
|
||||
|
@ -359,7 +376,7 @@ public class ClientPoliciesLoadUpdateTest extends AbstractClientPoliciesTest {
|
|||
try {
|
||||
updatePolicies(json);
|
||||
} catch (ClientPolicyException cpe) {
|
||||
assertEquals("Bad Request", cpe.getErrorDetail());
|
||||
assertThat(cpe.getErrorDetail(), Matchers.startsWith("Unrecognized field "));
|
||||
String afterFailedUpdatePoliciesJson = ClientPoliciesUtil.convertClientPoliciesRepresentationToJson(getPolicies());
|
||||
assertEquals(beforeUpdatePoliciesJson, afterFailedUpdatePoliciesJson);
|
||||
return;
|
||||
|
@ -386,11 +403,31 @@ public class ClientPoliciesLoadUpdateTest extends AbstractClientPoliciesTest {
|
|||
try {
|
||||
updatePolicies(json);
|
||||
} catch (ClientPolicyException cpe) {
|
||||
assertEquals("Bad Request", cpe.getErrorDetail());
|
||||
assertThat(cpe.getErrorDetail(), Matchers.startsWith("Unrecognized field "));
|
||||
String afterFailedUpdatePoliciesJson = ClientPoliciesUtil.convertClientPoliciesRepresentationToJson(getPolicies());
|
||||
assertEquals(beforeUpdatePoliciesJson, afterFailedUpdatePoliciesJson);
|
||||
return;
|
||||
}
|
||||
fail();
|
||||
}
|
||||
|
||||
// Test that regular CRUD of realm representation object through admin REST API does not remove
|
||||
@Test
|
||||
public void testCRUDRealmRepresentation() throws Exception {
|
||||
setupValidProfilesAndPolicies();
|
||||
|
||||
// Get the realm and assert that expected policies and profiles are present
|
||||
RealmResource testRealm = realmsResouce().realm("test");
|
||||
RealmRepresentation realmRep = testRealm.toRepresentation();
|
||||
assertExpectedProfiles(realmRep.getClientProfiles(), null, Arrays.asList("ordinal-test-profile", "lack-of-builtin-field-test-profile"));
|
||||
assertExpectedPolicies(Arrays.asList("new-policy", "lack-of-builtin-field-test-policy"), realmRep.getClientPolicies());
|
||||
|
||||
// Update the realm
|
||||
testRealm.update(realmRep);
|
||||
|
||||
// Test the realm again
|
||||
realmRep = testRealm.toRepresentation();
|
||||
assertExpectedProfiles(realmRep.getClientProfiles(), null, Arrays.asList("ordinal-test-profile", "lack-of-builtin-field-test-profile"));
|
||||
assertExpectedPolicies(Arrays.asList("new-policy", "lack-of-builtin-field-test-policy"), realmRep.getClientPolicies());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -249,7 +249,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
public void testAdminClientAugmentedAuthType() throws Exception {
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Pershyy Profil", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Pershyy Profil")
|
||||
.addExecutor(SecureClientAuthEnforceExecutorFactory.PROVIDER_ID,
|
||||
createSecureClientAuthEnforceExecutorConfig(Boolean.TRUE,
|
||||
Arrays.asList(JWTClientAuthenticator.PROVIDER_ID, JWTClientSecretAuthenticator.PROVIDER_ID, X509ClientAuthenticator.PROVIDER_ID),
|
||||
|
@ -260,7 +260,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// register policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Persha Polityka", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Persha Polityka", Boolean.TRUE)
|
||||
.addCondition(ClientUpdateContextConditionFactory.PROVIDER_ID,
|
||||
createClientUpdateContextConditionConfig(Arrays.asList(ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER)))
|
||||
.addProfile(PROFILE_NAME)
|
||||
|
@ -276,7 +276,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// update profiles
|
||||
json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Pershyy Profil", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Pershyy Profil")
|
||||
.addExecutor(SecureClientAuthEnforceExecutorFactory.PROVIDER_ID,
|
||||
createSecureClientAuthEnforceExecutorConfig(Boolean.TRUE,
|
||||
Arrays.asList(JWTClientAuthenticator.PROVIDER_ID, JWTClientSecretAuthenticator.PROVIDER_ID, X509ClientAuthenticator.PROVIDER_ID),
|
||||
|
@ -332,7 +332,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
public void testCreateUpdateDeleteConditionRuntime() throws Exception {
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Den Eichte profil", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Den Eichte profil")
|
||||
.addExecutor(PKCEEnforceExecutorFactory.PROVIDER_ID,
|
||||
createPKCEEnforceExecutorConfig(Boolean.TRUE))
|
||||
.toRepresentation()
|
||||
|
@ -350,7 +350,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// register policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Dei Eischt Politik", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Dei Eischt Politik", Boolean.TRUE)
|
||||
.addCondition(ClientRolesConditionFactory.PROVIDER_ID,
|
||||
createClientRolesConditionConfig(Arrays.asList(SAMPLE_CLIENT_ROLE)))
|
||||
.addProfile(PROFILE_NAME)
|
||||
|
@ -361,7 +361,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
failLoginByNotFollowingPKCE(clientId);
|
||||
|
||||
// update policies
|
||||
updatePolicy((new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Dei Aktualiseiert Eischt Politik", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
updatePolicy((new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Dei Aktualiseiert Eischt Politik", Boolean.TRUE)
|
||||
.addCondition(ClientRolesConditionFactory.PROVIDER_ID,
|
||||
createClientRolesConditionConfig(Arrays.asList("anothor-client-role")))
|
||||
.addProfile(PROFILE_NAME)
|
||||
|
@ -370,7 +370,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
successfulLoginAndLogout(clientId, clientSecret);
|
||||
|
||||
// update policies
|
||||
updatePolicy((new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Dei Aktualiseiert Eischt Politik", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
updatePolicy((new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Dei Aktualiseiert Eischt Politik", Boolean.TRUE)
|
||||
.addProfile(PROFILE_NAME)
|
||||
.toRepresentation());
|
||||
|
||||
|
@ -381,7 +381,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
public void testCreateUpdateDeleteExecutorRuntime() throws Exception {
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Purofairu Sono Ichi", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Purofairu Sono Ichi")
|
||||
.addExecutor(PKCEEnforceExecutorFactory.PROVIDER_ID,
|
||||
createPKCEEnforceExecutorConfig(Boolean.FALSE))
|
||||
.toRepresentation()
|
||||
|
@ -390,7 +390,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// register policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Porishii Sono Ichi", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Porishii Sono Ichi", Boolean.TRUE)
|
||||
.addCondition(ClientRolesConditionFactory.PROVIDER_ID,
|
||||
createClientRolesConditionConfig(Arrays.asList(SAMPLE_CLIENT_ROLE)))
|
||||
.addCondition(ClientUpdateContextConditionFactory.PROVIDER_ID,
|
||||
|
@ -409,7 +409,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
successfulLoginAndLogout(clientId, clientSecret);
|
||||
|
||||
// update policies
|
||||
updatePolicy((new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Koushinsareta Porishii Sono Ichi", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
updatePolicy((new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Koushinsareta Porishii Sono Ichi", Boolean.TRUE)
|
||||
.addCondition(ClientRolesConditionFactory.PROVIDER_ID,
|
||||
createClientRolesConditionConfig(Arrays.asList(SAMPLE_CLIENT_ROLE)))
|
||||
.addCondition(ClientUpdateContextConditionFactory.PROVIDER_ID,
|
||||
|
@ -421,7 +421,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// update profiles
|
||||
updateProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Koushinsareta Purofairu Sono Ichi", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Koushinsareta Purofairu Sono Ichi")
|
||||
.addExecutor(PKCEEnforceExecutorFactory.PROVIDER_ID,
|
||||
createPKCEEnforceExecutorConfig(Boolean.TRUE))
|
||||
.toRepresentation());
|
||||
|
@ -434,7 +434,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// update profiles
|
||||
updateProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Sarani Koushinsareta Purofairu Sono Ichi", Boolean.FALSE, null).toRepresentation());
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Sarani Koushinsareta Purofairu Sono Ichi").toRepresentation());
|
||||
|
||||
updateClientByAdmin(cid, (ClientRepresentation clientRep) -> {
|
||||
OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setPkceCodeChallengeMethod(null);
|
||||
|
@ -473,11 +473,11 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
String profileAlphaName = "MyProfile-alpha";
|
||||
String profileBetaName = "MyProfile-beta";
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(profileAlphaName, "Pierwszy Profil", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(profileAlphaName, "Pierwszy Profil")
|
||||
.addExecutor(SecureClientAuthEnforceExecutorFactory.PROVIDER_ID,
|
||||
createSecureClientAuthEnforceExecutorConfig(Boolean.TRUE, Arrays.asList(ClientIdAndSecretAuthenticator.PROVIDER_ID), ClientIdAndSecretAuthenticator.PROVIDER_ID))
|
||||
.toRepresentation()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(profileBetaName, "Drugi Profil", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(profileBetaName, "Drugi Profil")
|
||||
.addExecutor(PKCEEnforceExecutorFactory.PROVIDER_ID,
|
||||
createPKCEEnforceExecutorConfig(Boolean.TRUE))
|
||||
.toRepresentation()
|
||||
|
@ -488,14 +488,14 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
String policyAlphaName = "MyPolicy-alpha";
|
||||
String policyBetaName = "MyPolicy-beta";
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(policyAlphaName, "Pierwsza Zasada", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(policyAlphaName, "Pierwsza Zasada", Boolean.TRUE)
|
||||
.addCondition(ClientRolesConditionFactory.PROVIDER_ID,
|
||||
createClientRolesConditionConfig(Arrays.asList(roleAlphaName, roleZetaName)))
|
||||
.addCondition(ClientUpdateContextConditionFactory.PROVIDER_ID,
|
||||
createClientUpdateContextConditionConfig(Arrays.asList(ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER)))
|
||||
.addProfile(profileAlphaName)
|
||||
.toRepresentation()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(policyBetaName, "Drugi Zasada", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(policyBetaName, "Drugi Zasada", Boolean.TRUE)
|
||||
.addCondition(ClientRolesConditionFactory.PROVIDER_ID,
|
||||
createClientRolesConditionConfig(Arrays.asList(roleBetaName, roleZetaName)))
|
||||
.addProfile(profileBetaName)
|
||||
|
@ -530,7 +530,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
public void testIntentionalExceptionOnCondition() throws Exception {
|
||||
// register policies
|
||||
String json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Fyrsta Stefnan", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Fyrsta Stefnan", Boolean.TRUE)
|
||||
.addCondition(TestRaiseExeptionConditionFactory.PROVIDER_ID,
|
||||
createTestRaiseExeptionConditionConfig())
|
||||
.toRepresentation()
|
||||
|
@ -549,7 +549,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
public void testAnyClientCondition() throws Exception {
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Le Premier Profil", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Le Premier Profil")
|
||||
.addExecutor(SecureSessionEnforceExecutorFactory.PROVIDER_ID, null)
|
||||
.toRepresentation()
|
||||
).toString();
|
||||
|
@ -557,7 +557,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// register policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "La Premiere Politique", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "La Premiere Politique", Boolean.TRUE)
|
||||
.addCondition(AnyClientConditionFactory.PROVIDER_ID,
|
||||
createAnyClientConditionConfig())
|
||||
.addProfile(PROFILE_NAME)
|
||||
|
@ -590,7 +590,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
public void testConditionWithoutNoConfiguration() throws Exception {
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Die Erste Politik", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Die Erste Politik")
|
||||
.addExecutor(SecureClientAuthEnforceExecutorFactory.PROVIDER_ID, null)
|
||||
.toRepresentation()
|
||||
).toString();
|
||||
|
@ -598,22 +598,22 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// register policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy("MyPolicy-ClientAccessTypeCondition", "Die Erste Politik", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy("MyPolicy-ClientAccessTypeCondition", "Die Erste Politik", Boolean.TRUE)
|
||||
.addCondition(ClientAccessTypeConditionFactory.PROVIDER_ID, null)
|
||||
.addProfile(PROFILE_NAME)
|
||||
.toRepresentation()
|
||||
).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy("MyPolicy-ClientUpdateSourceGroupsCondition", "Die Zweite Politik", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy("MyPolicy-ClientUpdateSourceGroupsCondition", "Die Zweite Politik", Boolean.TRUE)
|
||||
.addCondition(ClientUpdateSourceGroupsConditionFactory.PROVIDER_ID, null)
|
||||
.addProfile(PROFILE_NAME)
|
||||
.toRepresentation()
|
||||
).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy("MyPolicy-ClientUpdateSourceRolesCondition", "Die Dritte Politik", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy("MyPolicy-ClientUpdateSourceRolesCondition", "Die Dritte Politik", Boolean.TRUE)
|
||||
.addCondition(ClientUpdateSourceRolesConditionFactory.PROVIDER_ID, null)
|
||||
.addProfile(PROFILE_NAME)
|
||||
.toRepresentation()
|
||||
).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy("MyPolicy-ClientUpdateContextCondition", "Die Vierte Politik", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy("MyPolicy-ClientUpdateContextCondition", "Die Vierte Politik", Boolean.TRUE)
|
||||
.addCondition(ClientUpdateContextConditionFactory.PROVIDER_ID, null)
|
||||
.addProfile(PROFILE_NAME)
|
||||
.toRepresentation()
|
||||
|
@ -637,7 +637,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
public void testClientUpdateSourceHostsCondition() throws Exception {
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Prvni Profil", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Prvni Profil")
|
||||
.addExecutor(SecureClientAuthEnforceExecutorFactory.PROVIDER_ID,
|
||||
createSecureClientAuthEnforceExecutorConfig(
|
||||
Boolean.FALSE,
|
||||
|
@ -650,8 +650,8 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// register policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Prvni Politika", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
.addCondition(ClientUpdateSourceHostsConditionFactory.PROVIDER_ID,
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Prvni Politika", Boolean.TRUE)
|
||||
.addCondition(ClientUpdateSourceHostsConditionFactory.PROVIDER_ID,
|
||||
createClientUpdateSourceHostsConditionConfig(Arrays.asList("localhost", "127.0.0.1")))
|
||||
.addProfile(PROFILE_NAME)
|
||||
.toRepresentation()
|
||||
|
@ -671,8 +671,8 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// update policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Aktualizovana Prvni Politika", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
.addCondition(ClientUpdateSourceHostsConditionFactory.PROVIDER_ID,
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Aktualizovana Prvni Politika", Boolean.TRUE)
|
||||
.addCondition(ClientUpdateSourceHostsConditionFactory.PROVIDER_ID,
|
||||
createClientUpdateSourceHostsConditionConfig(Arrays.asList("example.com")))
|
||||
.addProfile(PROFILE_NAME)
|
||||
.toRepresentation()
|
||||
|
@ -692,7 +692,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
public void testClientUpdateSourceGroupsCondition() throws Exception {
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Den Forste Profil", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Den Forste Profil")
|
||||
.addExecutor(SecureClientAuthEnforceExecutorFactory.PROVIDER_ID,
|
||||
createSecureClientAuthEnforceExecutorConfig(
|
||||
Boolean.FALSE,
|
||||
|
@ -705,7 +705,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// register policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Den Forste Politik", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Den Forste Politik", Boolean.TRUE)
|
||||
.addCondition(ClientUpdateSourceGroupsConditionFactory.PROVIDER_ID,
|
||||
createClientUpdateSourceGroupsConditionConfig(Arrays.asList("topGroup")))
|
||||
.addProfile(PROFILE_NAME)
|
||||
|
@ -732,7 +732,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
public void testClientUpdateSourceRolesCondition() throws Exception {
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Il Primo Profilo", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Il Primo Profilo")
|
||||
.addExecutor(SecureClientAuthEnforceExecutorFactory.PROVIDER_ID,
|
||||
createSecureClientAuthEnforceExecutorConfig(
|
||||
Boolean.FALSE,
|
||||
|
@ -745,9 +745,9 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// register policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "La Prima Politica", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "La Prima Politica", Boolean.TRUE)
|
||||
.addCondition(ClientUpdateSourceRolesConditionFactory.PROVIDER_ID,
|
||||
createClientUpdateSourceRolesConditionConfig(Arrays.asList(AdminRoles.CREATE_CLIENT)))
|
||||
createClientUpdateSourceRolesConditionConfig(Arrays.asList(Constants.REALM_MANAGEMENT_CLIENT_ID + "." + AdminRoles.CREATE_CLIENT)))
|
||||
.addProfile(PROFILE_NAME)
|
||||
.toRepresentation()
|
||||
).toString();
|
||||
|
@ -772,7 +772,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
public void testClientScopesCondition() throws Exception {
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Het Eerste Profiel", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Het Eerste Profiel")
|
||||
.addExecutor(PKCEEnforceExecutorFactory.PROVIDER_ID,
|
||||
createPKCEEnforceExecutorConfig(Boolean.TRUE))
|
||||
.toRepresentation()
|
||||
|
@ -781,7 +781,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// register policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Het Eerste Beleid", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Het Eerste Beleid", Boolean.TRUE)
|
||||
.addCondition(ClientScopesConditionFactory.PROVIDER_ID,
|
||||
createClientScopesConditionConfig(ClientScopesConditionFactory.OPTIONAL, Arrays.asList("offline_access", "microprofile-jwt")))
|
||||
.addProfile(PROFILE_NAME)
|
||||
|
@ -815,7 +815,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
public void testClientAccessTypeCondition() throws Exception {
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "El Primer Perfil", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "El Primer Perfil")
|
||||
.addExecutor(SecureSessionEnforceExecutorFactory.PROVIDER_ID, null)
|
||||
.toRepresentation()
|
||||
).toString();
|
||||
|
@ -823,7 +823,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// register policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "La Primera Plitica", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "La Primera Plitica", Boolean.TRUE)
|
||||
.addCondition(ClientAccessTypeConditionFactory.PROVIDER_ID,
|
||||
createClientAccessTypeConditionConfig(Arrays.asList(ClientAccessTypeConditionFactory.TYPE_CONFIDENTIAL)))
|
||||
.addProfile(PROFILE_NAME)
|
||||
|
@ -854,7 +854,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
public void testSecureResponseTypeExecutor() throws Exception {
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "O Primeiro Perfil", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "O Primeiro Perfil")
|
||||
.addExecutor(SecureResponseTypeExecutorFactory.PROVIDER_ID, null)
|
||||
.toRepresentation()
|
||||
).toString();
|
||||
|
@ -862,7 +862,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// register policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "A Primeira Politica", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "A Primeira Politica", Boolean.TRUE)
|
||||
.addCondition(ClientRolesConditionFactory.PROVIDER_ID,
|
||||
createClientRolesConditionConfig(Arrays.asList(SAMPLE_CLIENT_ROLE)))
|
||||
.addProfile(PROFILE_NAME)
|
||||
|
@ -921,7 +921,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
Integer availablePeriod = Integer.valueOf(SecureRequestObjectExecutor.DEFAULT_AVAILABLE_PERIOD + 400);
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Prvy Profil", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Prvy Profil")
|
||||
.addExecutor(SecureRequestObjectExecutorFactory.PROVIDER_ID,
|
||||
createSecureRequestObjectExecutorConfig(availablePeriod, null))
|
||||
.toRepresentation()
|
||||
|
@ -930,7 +930,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// register policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Prva Politika", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Prva Politika", Boolean.TRUE)
|
||||
.addCondition(ClientRolesConditionFactory.PROVIDER_ID,
|
||||
createClientRolesConditionConfig(Arrays.asList(SAMPLE_CLIENT_ROLE)))
|
||||
.addProfile(PROFILE_NAME)
|
||||
|
@ -1046,7 +1046,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// update profile : no configuration - "nbf" check and available period is 3600 sec
|
||||
json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Prvy Profil", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Prvy Profil")
|
||||
.addExecutor(SecureRequestObjectExecutorFactory.PROVIDER_ID, null)
|
||||
.toRepresentation()
|
||||
).toString();
|
||||
|
@ -1078,7 +1078,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// update profile : not check "nbf"
|
||||
json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Prvy Profil", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Prvy Profil")
|
||||
.addExecutor(SecureRequestObjectExecutorFactory.PROVIDER_ID,
|
||||
createSecureRequestObjectExecutorConfig(null, Boolean.FALSE))
|
||||
.toRepresentation()
|
||||
|
@ -1109,7 +1109,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
public void testSecureSessionEnforceExecutor() throws Exception {
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Den Forste Profilen", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Den Forste Profilen")
|
||||
.addExecutor(SecureSessionEnforceExecutorFactory.PROVIDER_ID, null)
|
||||
.toRepresentation()
|
||||
).toString();
|
||||
|
@ -1119,7 +1119,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
String roleAlphaName = "sample-client-role-alpha";
|
||||
String roleBetaName = "sample-client-role-beta";
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Den Forste Politikken", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Den Forste Politikken", Boolean.TRUE)
|
||||
.addCondition(ClientRolesConditionFactory.PROVIDER_ID,
|
||||
createClientRolesConditionConfig(Arrays.asList(roleBetaName)))
|
||||
.addProfile(PROFILE_NAME)
|
||||
|
@ -1164,7 +1164,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
public void testSecureSigningAlgorithmEnforceExecutor() throws Exception {
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Den Forsta Profilen", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Den Forsta Profilen")
|
||||
.addExecutor(SecureSigningAlgorithmEnforceExecutorFactory.PROVIDER_ID, null)
|
||||
.toRepresentation()
|
||||
).toString();
|
||||
|
@ -1172,7 +1172,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// register policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Den Forsta Policyn", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Den Forsta Policyn", Boolean.TRUE)
|
||||
.addCondition(ClientUpdateContextConditionFactory.PROVIDER_ID,
|
||||
createClientUpdateContextConditionConfig(Arrays.asList(
|
||||
ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER,
|
||||
|
@ -1237,7 +1237,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// update profiles, ES256 enforced
|
||||
json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Den Forsta Profilen", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Den Forsta Profilen")
|
||||
.addExecutor(SecureSigningAlgorithmEnforceExecutorFactory.PROVIDER_ID,
|
||||
createSecureSigningAlgorithmEnforceExecutorConfig(org.keycloak.crypto.Algorithm.ES256))
|
||||
.toRepresentation()
|
||||
|
@ -1261,7 +1261,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// update profiles, fall back to PS256
|
||||
json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Den Forsta Profilen", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Den Forsta Profilen")
|
||||
.addExecutor(SecureSigningAlgorithmEnforceExecutorFactory.PROVIDER_ID,
|
||||
createSecureSigningAlgorithmEnforceExecutorConfig(org.keycloak.crypto.Algorithm.RS512))
|
||||
.toRepresentation()
|
||||
|
@ -1318,7 +1318,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// update profiles, enforce ES256
|
||||
json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Den Forsta Profilen", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Den Forsta Profilen")
|
||||
.addExecutor(SecureSigningAlgorithmEnforceExecutorFactory.PROVIDER_ID,
|
||||
createSecureSigningAlgorithmEnforceExecutorConfig(org.keycloak.crypto.Algorithm.ES256))
|
||||
.toRepresentation()
|
||||
|
@ -1343,7 +1343,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
public void testSecureClientRegisteringUriEnforceExecutor() throws Exception {
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Ensimmainen Profiili", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Ensimmainen Profiili")
|
||||
.addExecutor(SecureClientRegisteringUriEnforceExecutorFactory.PROVIDER_ID, null)
|
||||
.toRepresentation()
|
||||
).toString();
|
||||
|
@ -1351,7 +1351,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// register policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Ensimmainen Politiikka", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Ensimmainen Politiikka", Boolean.TRUE)
|
||||
.addCondition(ClientUpdateContextConditionFactory.PROVIDER_ID,
|
||||
createClientUpdateContextConditionConfig(Arrays.asList(
|
||||
ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER,
|
||||
|
@ -1388,6 +1388,18 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
});
|
||||
assertEquals(false, getClientByAdmin(cid).isServiceAccountsEnabled());
|
||||
|
||||
// update policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Paivitetyn Ensimmaisen Politiikka", Boolean.TRUE)
|
||||
.addCondition(ClientUpdateContextConditionFactory.PROVIDER_ID,
|
||||
createClientUpdateContextConditionConfig(Arrays.asList(
|
||||
ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER,
|
||||
ClientUpdateContextConditionFactory.BY_REGISTRATION_ACCESS_TOKEN)))
|
||||
.addProfile(PROFILE_NAME)
|
||||
.toRepresentation()
|
||||
).toString();
|
||||
updatePolicies(json);
|
||||
|
||||
try {
|
||||
updateClientDynamically(clientId, (OIDCClientRepresentation clientRep) -> {
|
||||
clientRep.setRedirectUris(Collections.singletonList("https://newredirect/*"));
|
||||
|
@ -1531,10 +1543,11 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
public void testSecureSigningAlgorithmForSignedJwtEnforceExecutorWithSecureAlg() throws Exception {
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Ensimmainen Profiili", Boolean.FALSE, null)
|
||||
.addExecutor(SecureSigningAlgorithmForSignedJwtEnforceExecutorFactory.PROVIDER_ID, createSecureSigningAlgorithmForSignedJwtEnforceExecutorConfig(Boolean.FALSE))
|
||||
.toRepresentation()
|
||||
).toString();
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Ensimmainen Profiili")
|
||||
.addExecutor(SecureSigningAlgorithmForSignedJwtEnforceExecutorFactory.PROVIDER_ID, createSecureSigningAlgorithmForSignedJwtEnforceExecutorConfig(Boolean.TRUE)
|
||||
).toRepresentation()
|
||||
)
|
||||
.toString();
|
||||
updateProfiles(json);
|
||||
|
||||
// register policies
|
||||
|
@ -1542,7 +1555,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
String roleZetaName = "sample-client-role-zeta";
|
||||
String roleCommonName = "sample-client-role-common";
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Den Forste Politikken", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Den Forste Politikken", Boolean.TRUE)
|
||||
.addCondition(ClientRolesConditionFactory.PROVIDER_ID,
|
||||
createClientRolesConditionConfig(Arrays.asList(roleAlphaName, roleZetaName)))
|
||||
.addProfile(PROFILE_NAME)
|
||||
|
@ -1622,7 +1635,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
public void testSecureSigningAlgorithmForSignedJwtEnforceExecutorWithNotSecureAlg() throws Exception {
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Ensimmainen Profiili", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Ensimmainen Profiili")
|
||||
.addExecutor(SecureSigningAlgorithmForSignedJwtEnforceExecutorFactory.PROVIDER_ID, createSecureSigningAlgorithmForSignedJwtEnforceExecutorConfig(Boolean.FALSE))
|
||||
.toRepresentation()
|
||||
).toString();
|
||||
|
@ -1633,7 +1646,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
String roleZetaName = "sample-client-role-zeta";
|
||||
String roleCommonName = "sample-client-role-common";
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Den Forste Politikken", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Den Forste Politikken", Boolean.TRUE)
|
||||
.addCondition(ClientRolesConditionFactory.PROVIDER_ID,
|
||||
createClientRolesConditionConfig(Arrays.asList(roleAlphaName, roleZetaName)))
|
||||
.addProfile(PROFILE_NAME)
|
||||
|
@ -1683,7 +1696,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Az Elso Profil", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Az Elso Profil")
|
||||
.addExecutor(HolderOfKeyEnforceExecutorFactory.PROVIDER_ID,
|
||||
createHolderOfKeyEnforceExecutorConfig(Boolean.TRUE))
|
||||
.addExecutor(SecureSigningAlgorithmForSignedJwtEnforceExecutorFactory.PROVIDER_ID,
|
||||
|
@ -1694,7 +1707,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// register policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Az Elso Politika", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Az Elso Politika", Boolean.TRUE)
|
||||
.addCondition(AnyClientConditionFactory.PROVIDER_ID,
|
||||
createAnyClientConditionConfig())
|
||||
.addProfile(PROFILE_NAME)
|
||||
|
@ -1715,7 +1728,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
public void testNegativeLogicCondition() throws Exception {
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Den Forste Profilen", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Den Forste Profilen")
|
||||
.addExecutor(SecureSessionEnforceExecutorFactory.PROVIDER_ID, null)
|
||||
.toRepresentation()
|
||||
).toString();
|
||||
|
@ -1723,7 +1736,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// register policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "La Premiere Politique", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "La Premiere Politique", Boolean.TRUE)
|
||||
.addCondition(AnyClientConditionFactory.PROVIDER_ID, createAnyClientConditionConfig())
|
||||
.addProfile(PROFILE_NAME)
|
||||
.toRepresentation()
|
||||
|
@ -1740,7 +1753,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
failLoginWithoutSecureSessionParameter(clientId, ERR_MSG_MISSING_NONCE);
|
||||
|
||||
// update policies
|
||||
updatePolicy((new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "La Premiere Politique", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
updatePolicy((new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "La Premiere Politique", Boolean.TRUE)
|
||||
.addCondition(AnyClientConditionFactory.PROVIDER_ID, createAnyClientConditionConfig(Boolean.TRUE))
|
||||
.addProfile(PROFILE_NAME)
|
||||
.toRepresentation());
|
||||
|
@ -1748,7 +1761,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
successfulLoginAndLogout(clientId, clientSecret);
|
||||
|
||||
// update policies
|
||||
updatePolicy((new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "La Premiere Politique", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
updatePolicy((new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "La Premiere Politique", Boolean.TRUE)
|
||||
.addCondition(AnyClientConditionFactory.PROVIDER_ID, createAnyClientConditionConfig(Boolean.FALSE))
|
||||
.addProfile(PROFILE_NAME)
|
||||
.toRepresentation());
|
||||
|
@ -1763,7 +1776,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
public void testExtendedClientPolicyIntefacesForClientRegistrationPolicyMigration() throws Exception {
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Den Forste Profilen", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Den Forste Profilen")
|
||||
.addExecutor(TestRaiseExeptionExecutorFactory.PROVIDER_ID, null)
|
||||
.toRepresentation()
|
||||
).toString();
|
||||
|
@ -1771,7 +1784,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// register policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "La Premiere Politique", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "La Premiere Politique", Boolean.TRUE)
|
||||
.addCondition(AnyClientConditionFactory.PROVIDER_ID, createAnyClientConditionConfig())
|
||||
.addProfile(PROFILE_NAME)
|
||||
.toRepresentation()
|
||||
|
@ -1811,36 +1824,19 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testOverwriteBuiltinProfileNotAllowed() throws Exception {
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile("builtin-default-profile", "Pershyy Profil", Boolean.FALSE, null)
|
||||
.addExecutor(SecureClientAuthEnforceExecutorFactory.PROVIDER_ID,
|
||||
createSecureClientAuthEnforceExecutorConfig(Boolean.TRUE,
|
||||
Arrays.asList(JWTClientAuthenticator.PROVIDER_ID, JWTClientSecretAuthenticator.PROVIDER_ID, X509ClientAuthenticator.PROVIDER_ID),
|
||||
X509ClientAuthenticator.PROVIDER_ID))
|
||||
.toRepresentation()
|
||||
).toString();
|
||||
try {
|
||||
updateProfiles(json);
|
||||
} catch (ClientPolicyException cpe) {
|
||||
assertEquals("update profiles failed", cpe.getError());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdatePolicyWithoutNameNotAllowd() throws Exception {
|
||||
public void testUpdatePolicyWithoutNameNotAllowed() throws Exception {
|
||||
// register policies
|
||||
String json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(null, "La Premiere Politique", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(null, "La Premiere Politique", Boolean.TRUE)
|
||||
.addCondition(AnyClientConditionFactory.PROVIDER_ID, createAnyClientConditionConfig())
|
||||
.addProfile(PROFILE_NAME)
|
||||
.toRepresentation()
|
||||
).toString();
|
||||
try {
|
||||
updatePolicies(json);
|
||||
fail();
|
||||
} catch (ClientPolicyException cpe) {
|
||||
assertEquals("update profiles failed", cpe.getError());
|
||||
assertEquals("update policies failed", cpe.getError());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1848,7 +1844,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
public void testConfidentialClientAcceptExecutorExecutor() throws Exception {
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Erstes Profil", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Erstes Profil")
|
||||
.addExecutor(ConfidentialClientAcceptExecutorFactory.PROVIDER_ID, null)
|
||||
.toRepresentation()
|
||||
).toString();
|
||||
|
@ -1856,7 +1852,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// register policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Erstes Politik", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Erstes Politik", Boolean.TRUE)
|
||||
.addCondition(ClientRolesConditionFactory.PROVIDER_ID,
|
||||
createClientRolesConditionConfig(Arrays.asList(SAMPLE_CLIENT_ROLE)))
|
||||
.addProfile(PROFILE_NAME)
|
||||
|
@ -1897,7 +1893,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
public void testConsentRequiredExecutorExecutor() throws Exception {
|
||||
// register profiles
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Test Profile", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(PROFILE_NAME, "Test Profile")
|
||||
.addExecutor(ConsentRequiredExecutorFactory.PROVIDER_ID, null)
|
||||
.toRepresentation()
|
||||
).toString();
|
||||
|
@ -1905,7 +1901,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// register policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Test Policy", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Test Policy", Boolean.TRUE)
|
||||
.addCondition(AnyClientConditionFactory.PROVIDER_ID,
|
||||
createAnyClientConditionConfig())
|
||||
.addProfile(PROFILE_NAME)
|
||||
|
@ -2064,7 +2060,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
// register profiles
|
||||
String profileName = "MyProfile";
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(profileName, "Primum Profile", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(profileName, "Primum Profile")
|
||||
.addExecutor(SecureClientAuthEnforceExecutorFactory.PROVIDER_ID,
|
||||
createSecureClientAuthEnforceExecutorConfig(Boolean.FALSE,
|
||||
Arrays.asList(JWTClientAuthenticator.PROVIDER_ID, JWTClientSecretAuthenticator.PROVIDER_ID, X509ClientAuthenticator.PROVIDER_ID),
|
||||
|
@ -2075,7 +2071,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// register policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(policyName, "Primum Consilium", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(policyName, "Primum Consilium", Boolean.TRUE)
|
||||
.addCondition(ClientUpdateContextConditionFactory.PROVIDER_ID,
|
||||
createClientUpdateContextConditionConfig(Arrays.asList(ClientUpdateContextConditionFactory.BY_AUTHENTICATED_USER)))
|
||||
.addProfile(profileName)
|
||||
|
@ -2088,7 +2084,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
// register profiles
|
||||
String profileName = "MyProfile";
|
||||
String json = (new ClientProfilesBuilder()).addProfile(
|
||||
(new ClientProfileBuilder()).createProfile(profileName, "Primul Profil", Boolean.FALSE, null)
|
||||
(new ClientProfileBuilder()).createProfile(profileName, "Primul Profil")
|
||||
.addExecutor(SecureClientAuthEnforceExecutorFactory.PROVIDER_ID,
|
||||
createSecureClientAuthEnforceExecutorConfig(Boolean.TRUE,
|
||||
Arrays.asList(ClientIdAndSecretAuthenticator.PROVIDER_ID, JWTClientAuthenticator.PROVIDER_ID),
|
||||
|
@ -2101,7 +2097,7 @@ public class ClientPoliciesTest extends AbstractClientPoliciesTest {
|
|||
|
||||
// register policies
|
||||
json = (new ClientPoliciesBuilder()).addPolicy(
|
||||
(new ClientPolicyBuilder()).createPolicy(policyName, "Prima Politica", Boolean.FALSE, Boolean.TRUE, null, null)
|
||||
(new ClientPolicyBuilder()).createPolicy(policyName, "Prima Politica", Boolean.TRUE)
|
||||
.addCondition(ClientRolesConditionFactory.PROVIDER_ID,
|
||||
createClientRolesConditionConfig(Arrays.asList(SAMPLE_CLIENT_ROLE)))
|
||||
.addCondition(ClientUpdateContextConditionFactory.PROVIDER_ID,
|
||||
|
|
|
@ -16,7 +16,7 @@ public class InternalComponentRepresentation implements FetchOnServerWrapper<Com
|
|||
|
||||
@Override
|
||||
public FetchOnServer getRunOnServer() {
|
||||
return (FetchOnServer) session -> ModelToRepresentation.toRepresentation(session.getContext().getRealm(), true);
|
||||
return (FetchOnServer) session -> ModelToRepresentation.toRepresentation(session, session.getContext().getRealm(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -53,7 +53,7 @@ public class RunOnServerTest extends AbstractKeycloakTest {
|
|||
|
||||
RealmRepresentation realmRep = testingClient.server().fetch(session -> {
|
||||
RealmModel master = session.realms().getRealm(realmName);
|
||||
return ModelToRepresentation.toRepresentation(master, true);
|
||||
return ModelToRepresentation.toRepresentation(session, master, true);
|
||||
}, RealmRepresentation.class);
|
||||
|
||||
assertEquals(realmName, realmRep.getRealm());
|
||||
|
|
|
@ -96,3 +96,6 @@ log4j.logger.org.keycloak.services.clientregistration.policy=debug
|
|||
|
||||
# Enable to log short stack traces for log entries enabled with StackUtil.getShortStackTrace() calls
|
||||
# log4j.logger.org.keycloak.STACK_TRACE=trace
|
||||
|
||||
# Client policies
|
||||
#log4j.logger.org.keycloak.services.clientpolicy=trace
|
||||
|
|
|
@ -110,3 +110,6 @@ log4j.logger.org.apache.directory.server.ldap.LdapProtocolHandler=error
|
|||
#log4j.logger.org.keycloak.credential.WebAuthnCredentialProvider=debug
|
||||
#log4j.logger.org.keycloak.authentication.requiredactions.WebAuthnRegister=debug
|
||||
#log4j.logger.org.keycloak.authentication.authenticators.browser.WebAuthnAuthenticator=debug
|
||||
|
||||
# Client policies
|
||||
#log4j.logger.org.keycloak.services.clientpolicy=trace
|
||||
|
|
|
@ -844,6 +844,46 @@ max-clients.tooltip=It will not be allowed to register a new client if count of
|
|||
client-scopes=Client Scopes
|
||||
client-scopes.tooltip=Client scopes allow you to define a common set of protocol mappers and roles, which are shared between multiple clients
|
||||
|
||||
# Client Policies
|
||||
realm-tab-client-policies=Client Policies
|
||||
client-policies-profiles=Profiles
|
||||
client-policies-profiles.tooltip=Client Profile allows to setup set of executors, which are enforced for various actions done with the client. Actions can be admin actions like creating or updating client, or user actions like authentication to the client.
|
||||
client-policies-policies=Policies
|
||||
client-policies-policies.tooltip=Client Policy allows to bind client profiles with various conditions to specify when exactly is enforced behaviour specified by executors of the particular client profile.
|
||||
client-profiles-form-view=Form View
|
||||
client-profiles-json-editor=JSON Editor
|
||||
global=Global
|
||||
executors=Executors
|
||||
client-profile-name.tooltip=Name of the client profile. Must be unique within the realm
|
||||
client-profile-executors.tooltip=Executors, which will be applied for this client profile
|
||||
no-executors-available=No Executors Available
|
||||
push-profile-to-json=Push Profile to JSON
|
||||
executor-type=Executor Type
|
||||
create-executor=Create Executor
|
||||
client-policy-name.tooltip=Name of the client policy. Must be unique within the realm.
|
||||
client-policy-enabled.tooltip=Specifies if client policy is enabled. Disabled policies are not considered at all during evaluation of client requests.
|
||||
conditions=Conditions
|
||||
client-policy-conditions.tooltip=Conditions, which will be evaluated to determine if client policy should be applied during particular action or not.
|
||||
no-conditions-available=No Conditions Available
|
||||
condition-type=Condition Type
|
||||
create-condition=Create Condition
|
||||
client-profiles=Client Profiles
|
||||
client-profiles.tooltip=Client Profiles applied on this policy
|
||||
add-profile.placeholder=Add client profile ...
|
||||
no-client-profiles-configured=No client profiles configured
|
||||
|
||||
clientscopes-condition.label=Expected Scopes
|
||||
clientscopes-condition.tooltip=The list of expected client scopes. Condition evaluates to true if specified client request matches some of the client scopes. It depends also whether it should be default or optional client scope based on the 'Scope Type' configured.
|
||||
client-accesstype.label=Client Access Type
|
||||
client-accesstype.tooltip=Access Type of the client, for which the condition will be applied.
|
||||
clientroles-condition.label=Client Roles
|
||||
clientroles-condition.tooltip=Client roles, which will be checked during this condition evaluation. Condition evaluates to true if client has at least one client role with the name as the client roles specified in the configuration.
|
||||
clientupdatesourcegroups-condition.label=Groups
|
||||
clientupdatesourcegroups-condition.tooltip=Name of groups to check. Condition evaluates to true if the entity, who creates/updates client is member of some of the specified groups. Configured groups are specified by their simple name, which must match to the name of the Keycloak group. No support for group hierarchy is used here.
|
||||
clientupdate-trusted-hosts.label=Trusted hosts
|
||||
clientupdate-trusted-hosts.tooltip=List of Hosts, which are trusted. In case that client registration/update request comes from the host/domain specified in this configuration, condition evaluates to true. You can use hostnames or IP addresses. If you use star at the beginning (for example '*.example.com' ) then whole domain example.com will be trusted.
|
||||
clientupdatesourceroles-condition.label=Updating entity role
|
||||
clientupdatesourceroles-condition.tooltip=The condition is checked during client registration/update requests and it evaluates to true if the entity (usually user), who is creating/updating client is member of the specified role. For reference the realm role, you can use the realm role name like 'my_realm_role' . For reference client role, you can use the client_id.role_name for example 'my_client.my_client_role' will refer to client role 'my_client_role' of client 'my_client'.
|
||||
|
||||
groups=Groups
|
||||
|
||||
|
|
|
@ -330,6 +330,168 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
},
|
||||
controller : 'ClientRegPolicyDetailCtrl'
|
||||
})
|
||||
.when('/realms/:realm/client-policies/profiles', {
|
||||
templateUrl : resourceUrl + '/partials/client-policies-profiles-list.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
clientProfiles : function(ClientPoliciesProfilesLoader) {
|
||||
return ClientPoliciesProfilesLoader.loadClientProfiles('true');
|
||||
},
|
||||
},
|
||||
controller : 'ClientPoliciesProfilesListCtrl'
|
||||
})
|
||||
.when('/realms/:realm/client-policies/profiles-json', {
|
||||
templateUrl : resourceUrl + '/partials/client-policies-profiles-json.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
clientProfiles : function(ClientPoliciesProfilesLoader) {
|
||||
return ClientPoliciesProfilesLoader.loadClientProfiles('false');
|
||||
}
|
||||
},
|
||||
controller : 'ClientPoliciesProfilesJsonCtrl'
|
||||
})
|
||||
.when('/realms/:realm/client-policies/profiles-create', {
|
||||
templateUrl : resourceUrl + '/partials/client-policies-profiles-edit.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
clientProfiles : function(ClientPoliciesProfilesLoader) {
|
||||
return ClientPoliciesProfilesLoader.loadClientProfiles('false');
|
||||
}
|
||||
},
|
||||
controller : 'ClientPoliciesProfilesEditCtrl'
|
||||
})
|
||||
.when('/realms/:realm/client-policies/profiles-update/:profileName', {
|
||||
templateUrl : resourceUrl + '/partials/client-policies-profiles-edit.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
clientProfiles : function(ClientPoliciesProfilesLoader) {
|
||||
return ClientPoliciesProfilesLoader.loadClientProfiles('true');
|
||||
}
|
||||
},
|
||||
controller : 'ClientPoliciesProfilesEditCtrl'
|
||||
})
|
||||
.when('/realms/:realm/client-policies/profiles-update/:profileName/create-executor', {
|
||||
templateUrl : resourceUrl + '/partials/client-policies-profiles-edit-executor.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
clientProfiles : function(ClientPoliciesProfilesLoader) {
|
||||
return ClientPoliciesProfilesLoader.loadClientProfiles('false');
|
||||
},
|
||||
serverInfo : function(ServerInfoLoader) {
|
||||
return ServerInfoLoader();
|
||||
}
|
||||
},
|
||||
controller : 'ClientPoliciesProfilesEditExecutorCtrl'
|
||||
})
|
||||
.when('/realms/:realm/client-policies/profiles-update/:profileName/update-executor/:executorIndex', {
|
||||
templateUrl : resourceUrl + '/partials/client-policies-profiles-edit-executor.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
clientProfiles : function(ClientPoliciesProfilesLoader) {
|
||||
return ClientPoliciesProfilesLoader.loadClientProfiles('true');
|
||||
},
|
||||
serverInfo : function(ServerInfoLoader) {
|
||||
return ServerInfoLoader();
|
||||
}
|
||||
},
|
||||
controller : 'ClientPoliciesProfilesEditExecutorCtrl'
|
||||
})
|
||||
.when('/realms/:realm/client-policies/policies', {
|
||||
templateUrl : resourceUrl + '/partials/client-policies-list.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
clientPolicies : function(ClientPoliciesLoader) {
|
||||
return ClientPoliciesLoader();
|
||||
}
|
||||
},
|
||||
controller : 'ClientPoliciesListCtrl'
|
||||
})
|
||||
.when('/realms/:realm/client-policies/policies-json', {
|
||||
templateUrl : resourceUrl + '/partials/client-policies-json.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
clientPolicies : function(ClientPoliciesLoader) {
|
||||
return ClientPoliciesLoader();
|
||||
}
|
||||
},
|
||||
controller : 'ClientPoliciesJsonCtrl'
|
||||
})
|
||||
.when('/realms/:realm/client-policies/policy-create', {
|
||||
templateUrl : resourceUrl + '/partials/client-policies-policy-edit.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
clientProfiles : function(ClientPoliciesProfilesLoader) {
|
||||
return ClientPoliciesProfilesLoader.loadClientProfiles('true');
|
||||
},
|
||||
clientPolicies : function(ClientPoliciesLoader) {
|
||||
return ClientPoliciesLoader();
|
||||
}
|
||||
},
|
||||
controller : 'ClientPoliciesEditCtrl'
|
||||
})
|
||||
.when('/realms/:realm/client-policies/policies-update/:policyName', {
|
||||
templateUrl : resourceUrl + '/partials/client-policies-policy-edit.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
clientProfiles : function(ClientPoliciesProfilesLoader) {
|
||||
return ClientPoliciesProfilesLoader.loadClientProfiles('true');
|
||||
},
|
||||
clientPolicies : function(ClientPoliciesLoader) {
|
||||
return ClientPoliciesLoader();
|
||||
}
|
||||
},
|
||||
controller : 'ClientPoliciesEditCtrl'
|
||||
})
|
||||
.when('/realms/:realm/client-policies/policies-update/:policyName/create-condition', {
|
||||
templateUrl : resourceUrl + '/partials/client-policies-policy-edit-condition.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
clientPolicies : function(ClientPoliciesLoader) {
|
||||
return ClientPoliciesLoader();
|
||||
},
|
||||
serverInfo : function(ServerInfoLoader) {
|
||||
return ServerInfoLoader();
|
||||
}
|
||||
},
|
||||
controller : 'ClientPoliciesEditConditionCtrl'
|
||||
})
|
||||
.when('/realms/:realm/client-policies/policies-update/:policyName/update-condition/:conditionIndex', {
|
||||
templateUrl : resourceUrl + '/partials/client-policies-policy-edit-condition.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
clientPolicies : function(ClientPoliciesLoader) {
|
||||
return ClientPoliciesLoader();
|
||||
},
|
||||
serverInfo : function(ServerInfoLoader) {
|
||||
return ServerInfoLoader();
|
||||
}
|
||||
},
|
||||
controller : 'ClientPoliciesEditConditionCtrl'
|
||||
})
|
||||
.when('/realms/:realm/keys', {
|
||||
templateUrl : resourceUrl + '/partials/realm-keys.html',
|
||||
resolve : {
|
||||
|
|
|
@ -2966,6 +2966,655 @@ module.controller('ClientRegPolicyDetailCtrl', function ($scope, realm, clientRe
|
|||
|
||||
});
|
||||
|
||||
module.controller('ClientPoliciesProfilesListCtrl', function($scope, realm, clientProfiles, ClientPoliciesProfiles, Dialog, Notifications, $route, $location) {
|
||||
console.log('ClientPoliciesProfilesListCtrl');
|
||||
$scope.realm = realm;
|
||||
$scope.clientProfiles = clientProfiles;
|
||||
|
||||
$scope.removeClientProfile = function(clientProfile) {
|
||||
console.log("Deleting client profile from the JSON: " + clientProfile.name);
|
||||
|
||||
for (var i=0 ; i < $scope.clientProfiles.profiles.length ; i++) {
|
||||
var currentProfile = $scope.clientProfiles.profiles[i];
|
||||
if (currentProfile.name === clientProfile.name) {
|
||||
$scope.clientProfiles.profiles.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ClientPoliciesProfiles.update({
|
||||
realm: realm.realm,
|
||||
}, $scope.clientProfiles, function () {
|
||||
$route.reload();
|
||||
Notifications.success("The client profile was deleted.");
|
||||
}, function(errorResponse) {
|
||||
Notifications.error('Failed to delete client profile. Check server log for the details');
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
module.controller('ClientPoliciesProfilesJsonCtrl', function($scope, realm, clientProfiles, ClientPoliciesProfiles, Dialog, Notifications, $route, $location) {
|
||||
console.log('ClientPoliciesProfilesJsonCtrl');
|
||||
$scope.realm = realm;
|
||||
$scope.clientProfilesString = angular.toJson(clientProfiles, true);
|
||||
|
||||
$scope.save = function() {
|
||||
var clientProfilesObj = null;
|
||||
try {
|
||||
var clientProfilesObj = angular.fromJson($scope.clientProfilesString);
|
||||
} catch (e) {
|
||||
Notifications.error("Provided JSON is incorrect. See browser javascript console for the details");
|
||||
console.log(e);
|
||||
return;
|
||||
}
|
||||
var clientProfilesCompressed = angular.toJson(clientProfilesObj, false);
|
||||
|
||||
ClientPoliciesProfiles.update({
|
||||
realm: realm.realm,
|
||||
}, clientProfilesCompressed, function () {
|
||||
$route.reload();
|
||||
Notifications.success("The client profiles configuration was updated.");
|
||||
}, function(errorResponse) {
|
||||
Notifications.error('Failed to update client profiles. Check browser javascript console and server log for the details');
|
||||
console.log("Error response when updating client profiles JSON: Status: " + errorResponse.status +
|
||||
", statusText: " + errorResponse.statusText + ", data: " + errorResponse.data);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.reset = function() {
|
||||
$route.reload();
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
module.controller('ClientPoliciesProfilesEditCtrl', function($scope, realm, clientProfiles, ClientPoliciesProfiles, Dialog, Notifications, $route, $location) {
|
||||
var targetProfileName = $route.current.params.profileName;
|
||||
$scope.createNew = targetProfileName == null;
|
||||
if ($scope.createNew) {
|
||||
console.log('ClientPoliciesProfilesEditCtrl: creating new profile');
|
||||
} else {
|
||||
console.log('ClientPoliciesProfilesEditCtrl: updating profile ' + targetProfileName);
|
||||
}
|
||||
|
||||
$scope.realm = realm;
|
||||
$scope.editedProfile = null;
|
||||
|
||||
function getProfileByName(profilesArray) {
|
||||
if (!profilesArray) return null;
|
||||
for (var i=0 ; i < profilesArray.length ; i++) {
|
||||
var currentProfile = profilesArray[i];
|
||||
if (targetProfileName === currentProfile.name) {
|
||||
return currentProfile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($scope.createNew) {
|
||||
$scope.editedProfile = {
|
||||
name: "",
|
||||
executors: []
|
||||
};
|
||||
} else {
|
||||
var globalProfile = false;
|
||||
$scope.editedProfile = getProfileByName(clientProfiles.profiles);
|
||||
if (!$scope.editedProfile) {
|
||||
$scope.editedProfile = getProfileByName(clientProfiles.globalProfiles);
|
||||
globalProfile = true;
|
||||
}
|
||||
|
||||
if ($scope.editedProfile == null) {
|
||||
console.log("Profile of name " + targetProfileName + " not found");
|
||||
throw 'Profile not found';
|
||||
}
|
||||
}
|
||||
|
||||
$scope.readOnly = !$scope.access.manageRealm || globalProfile;
|
||||
|
||||
$scope.removeExecutor = function(executorIndex) {
|
||||
console.log("remove executor of index " + executorIndex);
|
||||
|
||||
// Delete executor
|
||||
$scope.editedProfile.executors.splice(executorIndex, 1);
|
||||
|
||||
ClientPoliciesProfiles.update({
|
||||
realm: realm.realm,
|
||||
}, clientProfiles, function () {
|
||||
Notifications.success("The executor was deleted.");
|
||||
}, function(errorResponse) {
|
||||
Notifications.error('Failed to delete executor. Check server log for the details');
|
||||
});
|
||||
}
|
||||
|
||||
$scope.save = function() {
|
||||
if (!$scope.editedProfile.name || $scope.editedProfile.name === '') {
|
||||
Notifications.error('Name must be provided');
|
||||
return;
|
||||
}
|
||||
|
||||
if ($scope.createNew) {
|
||||
clientProfiles.profiles.push($scope.editedProfile);
|
||||
}
|
||||
|
||||
ClientPoliciesProfiles.update({
|
||||
realm: realm.realm,
|
||||
}, clientProfiles, function () {
|
||||
if ($scope.createNew) {
|
||||
Notifications.success("The client profile was created.");
|
||||
$location.url('/realms/' + realm.realm + '/client-policies/profiles-update/' + $scope.editedProfile.name);
|
||||
} else {
|
||||
Notifications.success("The client profile was updated.");
|
||||
$location.url('/realms/' + realm.realm + '/client-policies/profiles');
|
||||
}
|
||||
}, function(errorResponse) {
|
||||
if ($scope.createNew) {
|
||||
Notifications.error('Failed to create client profile. Check server log for the details');
|
||||
} else {
|
||||
Notifications.error('Failed to update client profile. Check server log for the details');
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
$scope.back = function() {
|
||||
$location.url('/realms/' + realm.realm + '/client-policies/profiles');
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
module.controller('ClientPoliciesProfilesEditExecutorCtrl', function($scope, realm, serverInfo, clientProfiles, ClientPoliciesProfiles, ComponentUtils, Dialog, Notifications, $route, $location) {
|
||||
var updatedExecutorIndex = $route.current.params.executorIndex;
|
||||
var targetProfileName = $route.current.params.profileName;
|
||||
$scope.createNew = updatedExecutorIndex == null;
|
||||
if ($scope.createNew) {
|
||||
console.log('ClientPoliciesProfilesEditExecutorCtrl: adding executor to profile ' + targetProfileName);
|
||||
} else {
|
||||
console.log('ClientPoliciesProfilesEditExecutorCtrl: updating executor with index ' + updatedExecutorIndex + ' of profile ' + targetProfileName);
|
||||
}
|
||||
$scope.realm = realm;
|
||||
|
||||
function getProfileByName(profilesArray) {
|
||||
if (!profilesArray) return null;
|
||||
for (var i=0 ; i < profilesArray.length ; i++) {
|
||||
var currentProfile = profilesArray[i];
|
||||
if (targetProfileName === currentProfile.name) {
|
||||
return currentProfile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var globalProfile = false;
|
||||
var editedProfile = getProfileByName(clientProfiles.profiles);
|
||||
if (!editedProfile) {
|
||||
editedProfile = getProfileByName(clientProfiles.globalProfiles);
|
||||
globalProfile = true;
|
||||
}
|
||||
if (editedProfile == null) {
|
||||
throw 'Client profile of specified name not found';
|
||||
}
|
||||
|
||||
$scope.readOnly = !$scope.access.manageRealm || globalProfile;
|
||||
|
||||
$scope.executorTypes = serverInfo.componentTypes['org.keycloak.services.clientpolicy.executor.ClientPolicyExecutorProvider'];
|
||||
|
||||
for (var j=0 ; j < $scope.executorTypes.length ; j++) {
|
||||
var currExecutorType = $scope.executorTypes[j];
|
||||
if (currExecutorType.properties) {
|
||||
console.log("Adjusting executorType: " + currExecutorType.id);
|
||||
ComponentUtils.addMvOptionsToMultivaluedLists(currExecutorType.properties);
|
||||
}
|
||||
}
|
||||
|
||||
function getExecutorByIndex(clientProfile, executorIndex) {
|
||||
if (clientProfile.executors.length <= executorIndex) {
|
||||
console.error('Client profile does not have executor of specified index');
|
||||
$location.path('/notfound');
|
||||
return null;
|
||||
} else {
|
||||
return clientProfile.executors[executorIndex];
|
||||
}
|
||||
}
|
||||
|
||||
if ($scope.createNew) {
|
||||
// make first type the default
|
||||
$scope.executorType = $scope.executorTypes[0];
|
||||
var oldExecutorType = $scope.executorType;
|
||||
initConfig();
|
||||
|
||||
$scope.$watch('executorType', function() {
|
||||
if (!angular.equals($scope.executorType, oldExecutorType)) {
|
||||
oldExecutorType = $scope.executorType;
|
||||
initConfig();
|
||||
}
|
||||
}, true);
|
||||
} else {
|
||||
var exec = getExecutorByIndex(editedProfile, updatedExecutorIndex);
|
||||
if (exec) {
|
||||
$scope.executor = {
|
||||
config: exec.configuration
|
||||
};
|
||||
|
||||
$scope.executorType = null;
|
||||
for (var j=0 ; j < $scope.executorTypes.length ; j++) {
|
||||
var currentExType = $scope.executorTypes[j];
|
||||
if (exec.executor === currentExType.id) {
|
||||
$scope.executorType = currentExType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function toDefaultValue(configProperty) {
|
||||
if (configProperty.type === 'MultivaluedString' || configProperty.type === 'MultivaluedList') {
|
||||
if (configProperty.defaultValue) {
|
||||
return configProperty.defaultValue;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
if (configProperty.defaultValue !== undefined) {
|
||||
return configProperty.defaultValue;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function initConfig() {
|
||||
console.log("Initialized config now. ConfigType is: " + $scope.executorType.id);
|
||||
$scope.executor = {
|
||||
config: {}
|
||||
};
|
||||
|
||||
for (let i = 0; i < $scope.executorType.properties.length; i++) {
|
||||
let configProperty = $scope.executorType.properties[i];
|
||||
$scope.executor.config[configProperty.name] = toDefaultValue(configProperty);
|
||||
}
|
||||
}
|
||||
|
||||
$scope.save = function() {
|
||||
console.log("save: " + $scope.executorType.id);
|
||||
|
||||
var executorName = $scope.executorType.id;
|
||||
if (!editedProfile.executors) {
|
||||
editedProfile.executors = [];
|
||||
}
|
||||
|
||||
ComponentUtils.removeLastEmptyValue($scope.executor.config);
|
||||
|
||||
if ($scope.createNew) {
|
||||
var selectedExecutor = {
|
||||
executor: $scope.executorType.id,
|
||||
configuration: $scope.executor.config
|
||||
};
|
||||
editedProfile.executors.push(selectedExecutor);
|
||||
} else {
|
||||
var currentExecutor = getExecutorByIndex(editedProfile, updatedExecutorIndex);
|
||||
if (currentExecutor) {
|
||||
currentExecutor.configuration = $scope.executor.config;
|
||||
}
|
||||
}
|
||||
|
||||
ClientPoliciesProfiles.update({
|
||||
realm: realm.realm,
|
||||
}, clientProfiles, function () {
|
||||
if ($scope.createNew) {
|
||||
Notifications.success("Executor created successfully");
|
||||
} else {
|
||||
Notifications.success("Executor updated successfully");
|
||||
}
|
||||
$location.url('/realms/' + realm.realm + '/client-policies/profiles-update/' + editedProfile.name);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
$location.url('/realms/' + realm.realm + '/client-policies/profiles-update/' + editedProfile.name);
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
module.controller('ClientPoliciesListCtrl', function($scope, realm, clientPolicies, ClientPolicies, Dialog, Notifications, $route, $location) {
|
||||
console.log('ClientPoliciesListCtrl');
|
||||
$scope.realm = realm;
|
||||
$scope.clientPolicies = clientPolicies;
|
||||
|
||||
$scope.removeClientPolicy = function(clientPolicy) {
|
||||
console.log("Deleting client policy from the JSON: " + clientPolicy.name);
|
||||
|
||||
for (var i=0 ; i < $scope.clientPolicies.policies.length ; i++) {
|
||||
var currentPolicy = $scope.clientPolicies.policies[i];
|
||||
if (currentPolicy.name === clientPolicy.name) {
|
||||
$scope.clientPolicies.policies.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ClientPolicies.update({
|
||||
realm: realm.realm,
|
||||
}, $scope.clientPolicies, function () {
|
||||
$route.reload();
|
||||
Notifications.success("The client policy was deleted.");
|
||||
}, function(errorResponse) {
|
||||
Notifications.error('Failed to delete client policy. Check server log for the details');
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
module.controller('ClientPoliciesJsonCtrl', function($scope, realm, clientPolicies, Dialog, Notifications, ClientPolicies, $route, $location) {
|
||||
console.log('ClientPoliciesJsonCtrl');
|
||||
$scope.realm = realm;
|
||||
$scope.clientPoliciesString = angular.toJson(clientPolicies, true);
|
||||
|
||||
$scope.save = function() {
|
||||
var clientPoliciesObj = null;
|
||||
try {
|
||||
var clientPoliciesObj = angular.fromJson($scope.clientPoliciesString);
|
||||
} catch (e) {
|
||||
Notifications.error("Provided JSON is incorrect. See browser javascript console for the details");
|
||||
console.log(e);
|
||||
return;
|
||||
}
|
||||
var clientPoliciesCompressed = angular.toJson(clientPoliciesObj, false);
|
||||
|
||||
ClientPolicies.update({
|
||||
realm: realm.realm,
|
||||
}, clientPoliciesCompressed, function () {
|
||||
$route.reload();
|
||||
Notifications.success("The client policies configuration was updated.");
|
||||
}, function(errorResponse) {
|
||||
Notifications.error('Failed to update client policies. Check browser javascript console and server log for the details');
|
||||
console.log("Error response when updating client policies JSON: Status: " + errorResponse.status +
|
||||
", statusText: " + errorResponse.statusText + ", data: " + errorResponse.data);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.reset = function() {
|
||||
$route.reload();
|
||||
};
|
||||
});
|
||||
|
||||
module.controller('ClientPoliciesEditCtrl', function($scope, realm, clientProfiles, clientPolicies, ClientPolicies, Dialog, Notifications, $route, $location) {
|
||||
var targetPolicyName = $route.current.params.policyName;
|
||||
$scope.createNew = targetPolicyName == null;
|
||||
if ($scope.createNew) {
|
||||
console.log('ClientPoliciesEditCtrl: creating new policy');
|
||||
} else {
|
||||
console.log('ClientPoliciesEditCtrl: updating policy ' + targetPolicyName);
|
||||
}
|
||||
|
||||
$scope.realm = realm;
|
||||
$scope.clientPolicies = clientPolicies;
|
||||
$scope.clientProfiles = clientProfiles;
|
||||
$scope.editedPolicy = null;
|
||||
|
||||
if ($scope.createNew) {
|
||||
$scope.editedPolicy = {
|
||||
name: "",
|
||||
enabled: true,
|
||||
profiles: [],
|
||||
conditions: []
|
||||
};
|
||||
} else {
|
||||
for (var i=0 ; i < $scope.clientPolicies.policies.length ; i++) {
|
||||
var currentPolicy = $scope.clientPolicies.policies[i];
|
||||
if (targetPolicyName === currentPolicy.name) {
|
||||
$scope.editedPolicy = currentPolicy;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($scope.editedPolicy == null) {
|
||||
console.log("Policy of name " + targetPolicyName + " not found");
|
||||
throw 'Policy not found';
|
||||
}
|
||||
}
|
||||
|
||||
$scope.readOnly = !$scope.access.manageRealm;
|
||||
|
||||
$scope.availableProfiles = [];
|
||||
var allClientProfiles = clientProfiles.profiles;
|
||||
if (clientProfiles.globalProfiles) {
|
||||
allClientProfiles = allClientProfiles.concat(clientProfiles.globalProfiles);
|
||||
}
|
||||
for (var k=0 ; k<allClientProfiles.length ; k++) {
|
||||
var profileName = allClientProfiles[k].name;
|
||||
if (!$scope.editedPolicy.profiles || !$scope.editedPolicy.profiles.includes(profileName)) {
|
||||
$scope.availableProfiles.push(profileName);
|
||||
}
|
||||
}
|
||||
|
||||
$scope.removeCondition = function(conditionIndex) {
|
||||
console.log("remove condition of index " + conditionIndex);
|
||||
|
||||
// Delete condition
|
||||
$scope.editedPolicy.conditions.splice(conditionIndex, 1);
|
||||
|
||||
ClientPolicies.update({
|
||||
realm: realm.realm,
|
||||
}, $scope.clientPolicies, function () {
|
||||
Notifications.success("The condition was deleted.");
|
||||
}, function(errorResponse) {
|
||||
Notifications.error('Failed to delete condition. Check server log for the details');
|
||||
});
|
||||
}
|
||||
|
||||
$scope.save = function() {
|
||||
if (!$scope.editedPolicy.name || $scope.editedPolicy.name === '') {
|
||||
Notifications.error('Name must be provided');
|
||||
return;
|
||||
}
|
||||
|
||||
if ($scope.createNew) {
|
||||
$scope.clientPolicies.policies.push($scope.editedPolicy);
|
||||
}
|
||||
|
||||
ClientPolicies.update({
|
||||
realm: realm.realm,
|
||||
}, $scope.clientPolicies, function () {
|
||||
if ($scope.createNew) {
|
||||
Notifications.success("The client policy was created.");
|
||||
$location.url('/realms/' + realm.realm + '/client-policies/policies-update/' + $scope.editedPolicy.name);
|
||||
} else {
|
||||
Notifications.success("The client policy was updated.");
|
||||
$location.url('/realms/' + realm.realm + '/client-policies/policies');
|
||||
}
|
||||
}, function(errorResponse) {
|
||||
if ($scope.createNew) {
|
||||
Notifications.error('Failed to create client policy. Check server log for the details');
|
||||
} else {
|
||||
Notifications.error('Failed to update client policy. Check server log for the details');
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
$scope.back = function() {
|
||||
$location.url('/realms/' + realm.realm + '/client-policies/policies');
|
||||
};
|
||||
|
||||
|
||||
function moveProfileAndUpdatePolicy(arrayFrom, arrayTo, profileName, notificationsMessage) {
|
||||
for (var i=0 ; i<arrayFrom.length ; i++) {
|
||||
if (arrayFrom[i] === profileName) {
|
||||
arrayFrom.splice(i, 1);
|
||||
arrayTo.push(profileName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ClientPolicies.update({
|
||||
realm: realm.realm,
|
||||
}, $scope.clientPolicies, function () {
|
||||
Notifications.success(notificationsMessage);
|
||||
}, function(errorResponse) {
|
||||
Notifications.error('Failed to update profiles of the policy. Check server log for the details');
|
||||
});
|
||||
}
|
||||
|
||||
$scope.addProfile = function(profileName) {
|
||||
console.log("addProfile: " + profileName);
|
||||
moveProfileAndUpdatePolicy($scope.availableProfiles, $scope.editedPolicy.profiles, profileName, "Profile added to the policy");
|
||||
};
|
||||
|
||||
$scope.removeProfile = function(profileName) {
|
||||
console.log("removeProfile: " + profileName);
|
||||
moveProfileAndUpdatePolicy( $scope.editedPolicy.profiles, $scope.availableProfiles, profileName, "Profile removed from the policy");
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.controller('ClientPoliciesEditConditionCtrl', function($scope, realm, serverInfo, clientPolicies, ClientPolicies, Components, ComponentUtils, Dialog, Notifications, $route, $location) {
|
||||
var updatedConditionIndex = $route.current.params.conditionIndex;
|
||||
var targetPolicyName = $route.current.params.policyName;
|
||||
$scope.createNew = updatedConditionIndex == null;
|
||||
if ($scope.createNew) {
|
||||
console.log('ClientPoliciesEditConditionCtrl: adding condition to policy ' + targetPolicyName);
|
||||
} else {
|
||||
console.log('ClientPoliciesEditConditionCtrl: updating condition with index ' + updatedConditionIndex + ' of policy ' + targetPolicyName);
|
||||
}
|
||||
$scope.realm = realm;
|
||||
|
||||
var editedPolicy = null;
|
||||
for (var i=0 ; i < clientPolicies.policies.length ; i++) {
|
||||
var currentPolicy = clientPolicies.policies[i];
|
||||
if (targetPolicyName === currentPolicy.name) {
|
||||
editedPolicy = currentPolicy;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (editedPolicy == null) {
|
||||
throw 'Client policy of specified name not found';
|
||||
}
|
||||
|
||||
$scope.readOnly = !$scope.access.manageRealm;
|
||||
|
||||
$scope.conditionTypes = serverInfo.componentTypes['org.keycloak.services.clientpolicy.condition.ClientPolicyConditionProvider'];
|
||||
|
||||
for (var j=0 ; j < $scope.conditionTypes.length ; j++) {
|
||||
var currConditionType = $scope.conditionTypes[j];
|
||||
if (currConditionType.properties) {
|
||||
console.log("Adjusting conditionType: " + currConditionType.id);
|
||||
ComponentUtils.addMvOptionsToMultivaluedLists(currConditionType.properties);
|
||||
}
|
||||
}
|
||||
|
||||
function getConditionByIndex(clientPolicy, conditionIndex) {
|
||||
if (clientPolicy.conditions.length <= conditionIndex) {
|
||||
console.error('Client policy does not have condition of specified index');
|
||||
$location.path('/notfound');
|
||||
return null;
|
||||
} else {
|
||||
return clientPolicy.conditions[conditionIndex];
|
||||
}
|
||||
}
|
||||
|
||||
if ($scope.createNew) {
|
||||
// make first type the default
|
||||
$scope.conditionType = $scope.conditionTypes[0];
|
||||
var oldConditionType = $scope.conditionType;
|
||||
initConfig();
|
||||
|
||||
$scope.$watch('conditionType', function() {
|
||||
if (!angular.equals($scope.conditionType, oldConditionType)) {
|
||||
oldConditionType = $scope.conditionType;
|
||||
initConfig();
|
||||
}
|
||||
}, true);
|
||||
} else {
|
||||
var cond = getConditionByIndex(editedPolicy, updatedConditionIndex);
|
||||
if (cond) {
|
||||
$scope.condition = {
|
||||
config: cond.configuration
|
||||
};
|
||||
|
||||
$scope.conditionType = null;
|
||||
for (var j=0 ; j < $scope.conditionTypes.length ; j++) {
|
||||
var currentCndType = $scope.conditionTypes[j];
|
||||
if (cond.condition === currentCndType.id) {
|
||||
$scope.conditionType = currentCndType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function toDefaultValue(configProperty) {
|
||||
if (configProperty.type === 'MultivaluedString' || configProperty.type === 'MultivaluedList') {
|
||||
if (configProperty.defaultValue) {
|
||||
return configProperty.defaultValue;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
if (configProperty.defaultValue !== undefined) {
|
||||
return configProperty.defaultValue;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function initConfig() {
|
||||
console.log("Initialized config now. ConfigType is: " + $scope.conditionType.id);
|
||||
$scope.condition = {
|
||||
config: {}
|
||||
};
|
||||
|
||||
for (let i = 0; i < $scope.conditionType.properties.length; i++) {
|
||||
let configProperty = $scope.conditionType.properties[i];
|
||||
$scope.condition.config[configProperty.name] = toDefaultValue(configProperty);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$scope.save = function() {
|
||||
console.log("save: " + $scope.conditionType.id);
|
||||
|
||||
var conditionName = $scope.conditionType.id;
|
||||
if (!editedPolicy.conditions) {
|
||||
editedPolicy.conditions = [];
|
||||
}
|
||||
|
||||
ComponentUtils.removeLastEmptyValue($scope.condition.config);
|
||||
|
||||
var selectedCondition;
|
||||
if ($scope.createNew) {
|
||||
var selectedCondition = {
|
||||
condition: $scope.conditionType.id,
|
||||
configuration: $scope.condition.config
|
||||
};
|
||||
editedPolicy.conditions.push(selectedCondition);
|
||||
} else {
|
||||
var currentCondition = getConditionByIndex(editedPolicy, updatedConditionIndex);
|
||||
if (currentCondition) {
|
||||
currentCondition.configuration = $scope.condition.config;
|
||||
}
|
||||
}
|
||||
|
||||
ClientPolicies.update({
|
||||
realm: realm.realm,
|
||||
}, clientPolicies, function () {
|
||||
if ($scope.createNew) {
|
||||
Notifications.success("Condition created successfully");
|
||||
} else {
|
||||
Notifications.success("Condition updated successfully");
|
||||
}
|
||||
$location.url('/realms/' + realm.realm + '/client-policies/policies-update/' + editedPolicy.name);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
$location.url('/realms/' + realm.realm + '/client-policies/policies-update/' + editedPolicy.name);
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
module.controller('RealmImportCtrl', function($scope, realm, $route,
|
||||
Notifications, $modal, $resource) {
|
||||
$scope.rawContent = {};
|
||||
|
|
|
@ -563,8 +563,25 @@ module.factory('ClientRegistrationPolicyProvidersLoader', function(Loader, Clien
|
|||
});
|
||||
});
|
||||
|
||||
module.factory('ClientPoliciesProfilesLoader', function(Loader, ClientPoliciesProfiles, $route , $q) {
|
||||
var clientPoliciesLoader = {};
|
||||
|
||||
clientPoliciesLoader.loadClientProfiles = function(includeGlobalProfiles) {
|
||||
return Loader.get(ClientPoliciesProfiles, function() {
|
||||
return {
|
||||
realm : $route.current.params.realm,
|
||||
includeGlobalProfiles : includeGlobalProfiles
|
||||
}
|
||||
})();
|
||||
};
|
||||
|
||||
return clientPoliciesLoader;
|
||||
});
|
||||
|
||||
|
||||
|
||||
module.factory('ClientPoliciesLoader', function(Loader, ClientPolicies, $route) {
|
||||
return Loader.get(ClientPolicies, function() {
|
||||
return {
|
||||
realm: $route.current.params.realm
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2198,6 +2198,27 @@ module.factory('ClientRegistrationPolicyProviders', function($resource) {
|
|||
});
|
||||
});
|
||||
|
||||
module.factory('ClientPoliciesProfiles', function($resource) {
|
||||
return $resource(authUrl + '/admin/realms/:realm/client-policies/profiles?include-global-profiles=:includeGlobalProfiles', {
|
||||
realm : '@realm',
|
||||
includeGlobalProfiles : '@includeGlobalProfiles'
|
||||
}, {
|
||||
update : {
|
||||
method : 'PUT'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('ClientPolicies', function($resource) {
|
||||
return $resource(authUrl + '/admin/realms/:realm/client-policies/policies', {
|
||||
realm : '@realm',
|
||||
}, {
|
||||
update : {
|
||||
method : 'PUT'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('LDAPMapperSync', function($resource) {
|
||||
return $resource(authUrl + '/admin/realms/:realm/user-storage/:parentId/mappers/:mapperId/sync', {
|
||||
realm : '@realm',
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
<!--
|
||||
~ 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.
|
||||
~
|
||||
-->
|
||||
|
||||
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||
<kc-tabs-realm></kc-tabs-realm>
|
||||
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<li>
|
||||
<a href="#/realms/{{realm.realm}}/client-policies/profiles">{{:: 'client-policies-profiles' | translate}}</a>
|
||||
<kc-tooltip>{{:: 'client-policies-profiles.tooltip' | translate}}</kc-tooltip>
|
||||
</li>
|
||||
<li class="active">
|
||||
<a href="#/realms/{{realm.realm}}/client-policies/policies">{{:: 'client-policies-policies' | translate}}</a>
|
||||
<kc-tooltip>{{:: 'client-policies-policies.tooltip' | translate}}</kc-tooltip>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<li><a href="#/realms/{{realm.realm}}/client-policies/policies">{{:: 'client-profiles-form-view' | translate}}</a></li>
|
||||
<li class="active"><a href="#/realms/{{realm.realm}}/client-policies/policies-json">{{:: 'client-profiles-json-editor' | translate}}</a></li>
|
||||
</ul>
|
||||
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||
|
||||
<filedset>
|
||||
<div class="form-group">
|
||||
<div class="col-md-10">
|
||||
<div>
|
||||
<textarea id="clientPoliciesConfig" name="clientPoliciesConfig" data-ng-model="clientPoliciesString" class="form-control ng-binding" rows="20" ></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-10">
|
||||
<button class="btn btn-primary" data-ng-click="save()">{{:: 'save' | translate}}</button>
|
||||
<button class="btn btn-default" data-ng-click="reset()">{{:: 'reset' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</filedset>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<kc-menu></kc-menu>
|
|
@ -0,0 +1,74 @@
|
|||
<!--
|
||||
~ 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.
|
||||
~
|
||||
-->
|
||||
|
||||
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||
<kc-tabs-realm></kc-tabs-realm>
|
||||
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<li>
|
||||
<a href="#/realms/{{realm.realm}}/client-policies/profiles">{{:: 'client-policies-profiles' | translate}}</a>
|
||||
<kc-tooltip>{{:: 'client-policies-profiles.tooltip' | translate}}</kc-tooltip>
|
||||
</li>
|
||||
<li class="active">
|
||||
<a href="#/realms/{{realm.realm}}/client-policies/policies">{{:: 'client-policies-policies' | translate}}</a>
|
||||
<kc-tooltip>{{:: 'client-policies-policies.tooltip' | translate}}</kc-tooltip>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<li class="active"><a href="#/realms/{{realm.realm}}/client-policies/policies">{{:: 'client-profiles-form-view' | translate}}</a></li>
|
||||
<li><a href="#/realms/{{realm.realm}}/client-policies/policies-json">{{:: 'client-profiles-json-editor' | translate}}</a></li>
|
||||
</ul>
|
||||
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||
|
||||
<fieldset>
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="kc-table-actions" colspan="6">
|
||||
<div class="form-inline">
|
||||
<div class="pull-right" data-ng-show="access.manageRealm">
|
||||
<a href="#/realms/{{realm.realm}}/client-policies/policy-create" class="btn btn-default">{{:: 'create' | translate}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{:: 'name' | translate}}</th>
|
||||
<th>{{:: 'description' | translate}}</th>
|
||||
<th>{{:: 'enabled' | translate}}</th>
|
||||
<th colspan="2">{{:: 'actions' | translate}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="clientPolicy in clientPolicies.policies">
|
||||
<td><a href="#/realms/{{realm.realm}}/client-policies/policies-update/{{clientPolicy.name}}">{{clientPolicy.name}}</a></td>
|
||||
<td>{{clientPolicy.description}}</td>
|
||||
<td translate="{{clientPolicy.enabled}}"></td>
|
||||
<td class="kc-action-cell" data-ng-hide="clientPolicy.builtin" kc-open="/realms/{{realm.realm}}/client-policies/policies-update/{{clientPolicy.name}}">{{:: 'edit' | translate}}</td>
|
||||
<td class="kc-action-cell" data-ng-hide="clientPolicy.builtin" data-ng-click="removeClientPolicy(clientPolicy)">{{:: 'delete' | translate}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</fieldset>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<kc-menu></kc-menu>
|
|
@ -0,0 +1,58 @@
|
|||
<!--
|
||||
~ 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.
|
||||
~
|
||||
-->
|
||||
|
||||
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||
|
||||
<h1 data-ng-hide="createNew">{{conditionType.id|capitalize}}</h1>
|
||||
<h1 data-ng-show="createNew">{{:: 'create-condition' | translate}}</h1>
|
||||
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="readOnly">
|
||||
<fieldset>
|
||||
<div class="form-group" data-ng-show="createNew">
|
||||
<label class="col-md-2 control-label" for="conditionTypeCreate">{{:: 'condition-type' | translate}}</label>
|
||||
<div class="col-sm-6">
|
||||
<div>
|
||||
<select class="form-control" id="conditionTypeCreate"
|
||||
ng-model="conditionType"
|
||||
ng-options="conditionType.id for (conditionKey, conditionType) in conditionTypes">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<kc-tooltip>{{conditionType.helpText}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix" data-ng-hide="createNew">
|
||||
<label class="col-md-2 control-label" for="conditionType">{{:: 'condition-type' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="conditionType" type="text" ng-model="conditionType.id" data-ng-readonly="true">
|
||||
</div>
|
||||
<kc-tooltip>{{conditionType.helpText}}</kc-tooltip>
|
||||
</div>
|
||||
<kc-provider-config config="condition.config" properties="conditionType.properties" realm="realm"></kc-provider-config>
|
||||
</fieldset>
|
||||
|
||||
<div class="form-group" data-ng-hide="readOnly">
|
||||
<div class="col-md-10 col-md-offset-2">
|
||||
<button kc-save>{{:: 'save' | translate}}</button>
|
||||
<button kc-cancel data-ng-click="cancel()">{{:: 'cancel' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<kc-menu></kc-menu>
|
|
@ -0,0 +1,148 @@
|
|||
<!--
|
||||
~ 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.
|
||||
~
|
||||
-->
|
||||
|
||||
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||
<kc-tabs-realm></kc-tabs-realm>
|
||||
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<li>
|
||||
<a href="#/realms/{{realm.realm}}/client-policies/profiles">{{:: 'client-policies-profiles' | translate}}</a>
|
||||
<kc-tooltip>{{:: 'client-policies-profiles.tooltip' | translate}}</kc-tooltip>
|
||||
</li>
|
||||
<li class="active">
|
||||
<a href="#/realms/{{realm.realm}}/client-policies/policies">{{:: 'client-policies-policies' | translate}}</a>
|
||||
<kc-tooltip>{{:: 'client-policies-policies.tooltip' | translate}}</kc-tooltip>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<li class="active"><a href="#/realms/{{realm.realm}}/client-policies/policies">{{:: 'client-profiles-form-view' | translate}}</a></li>
|
||||
<li><a href="#/realms/{{realm.realm}}/client-policies/policies-json">{{:: 'client-profiles-json-editor' | translate}}</a></li>
|
||||
</ul>
|
||||
|
||||
<form class="form-horizontal" name="realmForm" novalidate>
|
||||
|
||||
<fieldset class="border-top" kc-read-only="readOnly">
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="clientPolicyName">{{:: 'name' | translate}} <span class="required">*</span></label>
|
||||
<div class="col-sm-6">
|
||||
<input class="form-control" type="text" id="clientPolicyName" name="clientPolicyName" data-ng-model="editedPolicy.name" autofocus required>
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'client-policy-name.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="description">{{:: 'description' | translate}} </label>
|
||||
<div class="col-md-6">
|
||||
<textarea class="form-control" rows="5" cols="50" id="description" name="description" data-ng-model="editedPolicy.description"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group clearfix block">
|
||||
<label class="col-md-2 control-label" for="enabled">{{:: 'enabled' | translate}}</label>
|
||||
<div class="col-sm-6">
|
||||
<input ng-model="editedPolicy.enabled" name="enabled" id="enabled" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'client-policy-enabled.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
|
||||
<fieldset data-ng-hide="readOnly">
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-10 col-md-offset-2">
|
||||
<button kc-save>{{:: 'save' | translate}}</button>
|
||||
<button kc-cancel data-ng-click="back()">{{:: 'back' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
|
||||
<fieldset data-ng-hide="createNew">
|
||||
|
||||
<legend><span class="text">{{:: 'conditions' | translate}}</span> <kc-tooltip>{{:: 'client-policy-conditions.tooltip' | translate}}</kc-tooltip></legend>
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr data-ng-hide="readOnly">
|
||||
<th class="kc-table-actions" colspan="3">
|
||||
<div class="form-inline">
|
||||
<div class="pull-right">
|
||||
<a href="#/realms/{{realm.realm}}/client-policies/policies-update/{{editedPolicy.name}}/create-condition" class="btn btn-default">{{:: 'create' | translate}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr data-ng-show="editedPolicy.conditions && editedPolicy.conditions.length > 0">
|
||||
<th>{{:: 'type' | translate}}</th>
|
||||
<th colspan="2">{{:: 'actions' | translate}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="condition in editedPolicy.conditions">
|
||||
<td><a href="#/realms/{{realm.realm}}/client-policies/policies-update/{{editedPolicy.name}}/update-condition/{{$index}}">{{condition.condition}}</a></td>
|
||||
<td class="kc-action-cell" data-ng-hide="readOnly" kc-open="/realms/{{realm.realm}}/client-policies/policies-update/{{editedPolicy.name}}/update-condition/{{$index}}">{{:: 'edit' | translate}}</td>
|
||||
<td class="kc-action-cell" data-ng-hide="readOnly" data-ng-click="removeCondition($index)">{{:: 'delete' | translate}}</td>
|
||||
</tr>
|
||||
<tr data-ng-show="!editedPolicy.conditions || editedPolicy.conditions.length == 0">
|
||||
<td>{{:: 'no-conditions-available' | translate}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</fieldset>
|
||||
|
||||
<fieldset data-ng-hide="createNew">
|
||||
<legend><span class="text">{{:: 'client-profiles' | translate}}</span></legend><kc-tooltip>{{:: 'client-profiles.tooltip' | translate}}</kc-tooltip>
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr data-ng-hide="readOnly || availableProfiles.length == 0">
|
||||
<th colspan="5" class="kc-table-actions">
|
||||
<div class="pull-right">
|
||||
<div>
|
||||
<select class="form-control" ng-model="selectedProfile"
|
||||
ng-options="p for p in availableProfiles"
|
||||
data-ng-change="addProfile(selectedProfile); selectedProfile = null">
|
||||
<option value="" disabled selected>{{:: 'add-profile.placeholder' | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr data-ng-show="editedPolicy.profiles && editedPolicy.profiles.length > 0">
|
||||
<th>{{:: 'name' | translate}}</th>
|
||||
<th>{{:: 'actions' | translate}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="profileName in editedPolicy.profiles">
|
||||
<td><a href="#/realms/{{realm.realm}}/client-policies/profiles-update/{{profileName}}">{{profileName}}</a></td>
|
||||
<td class="kc-action-cell" data-ng-hide="readOnly" data-ng-click="removeProfile(profileName)">{{:: 'delete' | translate}}</td>
|
||||
</tr>
|
||||
<tr data-ng-show="!editedPolicy.profiles || editedPolicy.profiles.length == 0">
|
||||
<td class="text-muted">{{:: 'no-client-profiles-configured' | translate}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</fieldset>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<kc-menu></kc-menu>
|
|
@ -0,0 +1,58 @@
|
|||
<!--
|
||||
~ 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.
|
||||
~
|
||||
-->
|
||||
|
||||
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||
|
||||
<h1 data-ng-hide="createNew">{{executorType.id|capitalize}}</h1>
|
||||
<h1 data-ng-show="createNew">{{:: 'create-executor' | translate}}</h1>
|
||||
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="readOnly">
|
||||
<fieldset>
|
||||
<div class="form-group" data-ng-show="createNew">
|
||||
<label class="col-md-2 control-label" for="executorTypeCreate">{{:: 'executor-type' | translate}}</label>
|
||||
<div class="col-sm-6">
|
||||
<div>
|
||||
<select class="form-control" id="executorTypeCreate"
|
||||
ng-model="executorType"
|
||||
ng-options="executorType.id for (executorKey, executorType) in executorTypes">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<kc-tooltip>{{executorType.helpText}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix" data-ng-hide="createNew">
|
||||
<label class="col-md-2 control-label" for="executorType">{{:: 'executor-type' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="executorType" type="text" ng-model="executorType.id" data-ng-readonly="true">
|
||||
</div>
|
||||
<kc-tooltip>{{executorType.helpText}}</kc-tooltip>
|
||||
</div>
|
||||
<kc-provider-config config="executor.config" properties="executorType.properties" realm="realm"></kc-provider-config>
|
||||
</fieldset>
|
||||
|
||||
<div class="form-group" data-ng-hide="readOnly">
|
||||
<div class="col-md-10 col-md-offset-2">
|
||||
<button kc-save>{{:: 'save' | translate}}</button>
|
||||
<button kc-cancel data-ng-click="cancel()">{{:: 'cancel' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<kc-menu></kc-menu>
|
|
@ -0,0 +1,105 @@
|
|||
<!--
|
||||
~ 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.
|
||||
~
|
||||
-->
|
||||
|
||||
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||
<kc-tabs-realm></kc-tabs-realm>
|
||||
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<li class="active">
|
||||
<a href="#/realms/{{realm.realm}}/client-policies/profiles">{{:: 'client-policies-profiles' | translate}}</a>
|
||||
<kc-tooltip>{{:: 'client-policies-profiles.tooltip' | translate}}</kc-tooltip>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#/realms/{{realm.realm}}/client-policies/policies">{{:: 'client-policies-policies' | translate}}</a>
|
||||
<kc-tooltip>{{:: 'client-policies-policies.tooltip' | translate}}</kc-tooltip>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<li class="active"><a href="#/realms/{{realm.realm}}/client-policies/profiles">{{:: 'client-profiles-form-view' | translate}}</a></li>
|
||||
<li><a href="#/realms/{{realm.realm}}/client-policies/profiles-json">{{:: 'client-profiles-json-editor' | translate}}</a></li>
|
||||
</ul>
|
||||
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="readOnly">
|
||||
|
||||
<fieldset class="border-top">
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="clientProfileName">{{:: 'name' | translate}} <span class="required">*</span></label>
|
||||
<div class="col-sm-6">
|
||||
<input class="form-control" type="text" id="clientProfileName" name="clientProfileName" data-ng-model="editedProfile.name" autofocus required>
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'client-profile-name.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="description">{{:: 'description' | translate}} </label>
|
||||
<div class="col-md-6">
|
||||
<textarea class="form-control" rows="5" cols="50" id="description" name="description" data-ng-model="editedProfile.description"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-10 col-md-offset-2">
|
||||
<button kc-save>{{:: 'save' | translate}}</button>
|
||||
<button kc-cancel data-ng-click="back()">{{:: 'back' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
|
||||
<fieldset data-ng-hide="createNew">
|
||||
|
||||
<legend><span class="text">{{:: 'executors' | translate}}</span> <kc-tooltip>{{:: 'client-profile-executors.tooltip' | translate}}</kc-tooltip></legend>
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr data-ng-hide="readOnly">
|
||||
<th class="kc-table-actions" colspan="3">
|
||||
<div class="form-inline">
|
||||
<div class="pull-right">
|
||||
<a href="#/realms/{{realm.realm}}/client-policies/profiles-update/{{editedProfile.name}}/create-executor" class="btn btn-default">{{:: 'create' | translate}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr data-ng-show="editedProfile.executors && editedProfile.executors.length > 0">
|
||||
<th>{{:: 'type' | translate}}</th>
|
||||
<th colspan="2">{{:: 'actions' | translate}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="executor in editedProfile.executors">
|
||||
<td><a href="#/realms/{{realm.realm}}/client-policies/profiles-update/{{editedProfile.name}}/update-executor/{{$index}}">{{executor.executor}}</a></td>
|
||||
<td class="kc-action-cell" data-ng-hide="readOnly" kc-open="/realms/{{realm.realm}}/client-policies/profiles-update/{{editedProfile.name}}/update-executor/{{$index}}">{{:: 'edit' | translate}}</td>
|
||||
<td class="kc-action-cell" data-ng-hide="readOnly" data-ng-click="removeExecutor($index)">{{:: 'delete' | translate}}</td>
|
||||
</tr>
|
||||
<tr data-ng-show="!editedProfile.executors || editedProfile.executors.length == 0">
|
||||
<td>{{:: 'no-executors-available' | translate}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</fieldset>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<kc-menu></kc-menu>
|
|
@ -0,0 +1,60 @@
|
|||
<!--
|
||||
~ 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.
|
||||
~
|
||||
-->
|
||||
|
||||
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||
<kc-tabs-realm></kc-tabs-realm>
|
||||
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<li class="active">
|
||||
<a href="#/realms/{{realm.realm}}/client-policies/profiles">{{:: 'client-policies-profiles' | translate}}</a>
|
||||
<kc-tooltip>{{:: 'client-policies-profiles.tooltip' | translate}}</kc-tooltip>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#/realms/{{realm.realm}}/client-policies/policies">{{:: 'client-policies-policies' | translate}}</a>
|
||||
<kc-tooltip>{{:: 'client-policies-policies.tooltip' | translate}}</kc-tooltip>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<li><a href="#/realms/{{realm.realm}}/client-policies/profiles">{{:: 'client-profiles-form-view' | translate}}</a></li>
|
||||
<li class="active"><a href="#/realms/{{realm.realm}}/client-policies/profiles-json">{{:: 'client-profiles-json-editor' | translate}}</a></li>
|
||||
</ul>
|
||||
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||
|
||||
<filedset>
|
||||
<div class="form-group">
|
||||
<div class="col-md-10">
|
||||
<div>
|
||||
<textarea id="clientProfilesConfig" name="clientProfilesConfig" data-ng-model="clientProfilesString" class="form-control ng-binding" rows="20" ></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-10">
|
||||
<button class="btn btn-primary" data-ng-click="save()">{{:: 'save' | translate}}</button>
|
||||
<button class="btn btn-default" data-ng-click="reset()">{{:: 'reset' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</filedset>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<kc-menu></kc-menu>
|
|
@ -0,0 +1,81 @@
|
|||
<!--
|
||||
~ 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.
|
||||
~
|
||||
-->
|
||||
|
||||
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||
<kc-tabs-realm></kc-tabs-realm>
|
||||
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<li class="active">
|
||||
<a href="#/realms/{{realm.realm}}/client-policies/profiles">{{:: 'client-policies-profiles' | translate}}</a>
|
||||
<kc-tooltip>{{:: 'client-policies-profiles.tooltip' | translate}}</kc-tooltip>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#/realms/{{realm.realm}}/client-policies/policies">{{:: 'client-policies-policies' | translate}}</a>
|
||||
<kc-tooltip>{{:: 'client-policies-policies.tooltip' | translate}}</kc-tooltip>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<li class="active"><a href="#/realms/{{realm.realm}}/client-policies/profiles">{{:: 'client-profiles-form-view' | translate}}</a></li>
|
||||
<li><a href="#/realms/{{realm.realm}}/client-policies/profiles-json">{{:: 'client-profiles-json-editor' | translate}}</a></li>
|
||||
</ul>
|
||||
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||
|
||||
<fieldset>
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="kc-table-actions" colspan="6">
|
||||
<div class="form-inline">
|
||||
<div class="pull-right" data-ng-show="access.manageRealm">
|
||||
<a href="#/realms/{{realm.realm}}/client-policies/profiles-create" class="btn btn-default">{{:: 'create' | translate}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{:: 'name' | translate}}</th>
|
||||
<th>{{:: 'description' | translate}}</th>
|
||||
<th>{{:: 'global' | translate}}</th>
|
||||
<th colspan="2">{{:: 'actions' | translate}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="clientProfile in clientProfiles.globalProfiles">
|
||||
<td><a href="#/realms/{{realm.realm}}/client-policies/profiles-update/{{clientProfile.name}}">{{clientProfile.name}}</a></td>
|
||||
<td>{{clientProfile.description}}</td>
|
||||
<td>{{:: 'true' | translate}}</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr ng-repeat="clientProfile in clientProfiles.profiles">
|
||||
<td><a href="#/realms/{{realm.realm}}/client-policies/profiles-update/{{clientProfile.name}}">{{clientProfile.name}}</a></td>
|
||||
<td>{{clientProfile.description}}</td>
|
||||
<td>{{:: 'false' | translate}}</td>
|
||||
<td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/client-policies/profiles-update/{{clientProfile.name}}">{{:: 'edit' | translate}}</td>
|
||||
<td class="kc-action-cell" data-ng-click="removeClientProfile(clientProfile)">{{:: 'delete' | translate}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</fieldset>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<kc-menu></kc-menu>
|
|
@ -26,6 +26,7 @@
|
|||
|| path[2] == 'theme-settings'
|
||||
|| path[2] == 'localization'
|
||||
|| path[2] == 'token-settings'
|
||||
|| path[2] == 'client-policies'
|
||||
|| path[2] == 'client-registration'
|
||||
|| path[2] == 'cache-settings'
|
||||
|| path[2] == 'client-initial-access'
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
<option value="" selected> {{:: 'selectOne' | translate}} </option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6" data-ng-if="option.type == 'MultivaluedList'">
|
||||
<input ui-select2="option.mvOptions" ng-model="config[ option.name ]" data-placeholder="{{:: 'selectMultiple' | translate}}..."/>
|
||||
</div>
|
||||
<div class="col-md-6" data-ng-if="option.type == 'Role'">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
<li ng-class="{active: path[2] == 'cache-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/cache-settings">{{:: 'realm-tab-cache' | translate}}</a></li>
|
||||
<li ng-class="{active: path[2] == 'token-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/token-settings">{{:: 'realm-tab-tokens' | translate}}</a></li>
|
||||
<li ng-class="{active: path[2] == 'client-registration'}" data-ng-show="access.viewClients"><a href="#/realms/{{realm.realm}}/client-registration/client-initial-access">{{:: 'realm-tab-client-registration' | translate}}</a></li>
|
||||
<li ng-class="{active: path[2] == 'client-policies'}" data-ng-show="access.viewRealm && serverInfo.featureEnabled('CLIENT_POLICIES')">
|
||||
<a href="#/realms/{{realm.realm}}/client-policies/profiles">{{:: 'realm-tab-client-policies' | translate}}</a>
|
||||
</li>
|
||||
<li ng-class="{active: path[2] == 'defense'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/defense/headers">{{:: 'realm-tab-security-defenses' | translate}}</a></li>
|
||||
</ul>
|
||||
</div>
|
Loading…
Reference in a new issue