Merge pull request #4054 from pedroigor/KEYCLOAK-3135

[KEYCLOAK-3135] - More changes to Policy Management API
This commit is contained in:
Pedro Igor 2017-04-24 17:44:07 -03:00 committed by GitHub
commit 5e57e84384
51 changed files with 3489 additions and 169 deletions

View file

@ -29,12 +29,13 @@ import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.representations.idm.authorization.AggregatePolicyRepresentation;
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class AggregatePolicyProviderFactory implements PolicyProviderFactory<PolicyRepresentation> {
public class AggregatePolicyProviderFactory implements PolicyProviderFactory<AggregatePolicyRepresentation> {
private AggregatePolicyProvider provider = new AggregatePolicyProvider();
@ -53,23 +54,23 @@ public class AggregatePolicyProviderFactory implements PolicyProviderFactory<Pol
return provider;
}
@Override
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer, AuthorizationProvider authorization) {
return null;
}
@Override
public PolicyProvider create(KeycloakSession session) {
return null;
}
@Override
public void onCreate(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) {
public void onCreate(Policy policy, AggregatePolicyRepresentation representation, AuthorizationProvider authorization) {
verifyCircularReference(policy, new ArrayList<>());
}
@Override
public void onUpdate(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) {
public void onUpdate(Policy policy, AggregatePolicyRepresentation representation, AuthorizationProvider authorization) {
verifyCircularReference(policy, new ArrayList<>());
}
@Override
public void onImport(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) {
verifyCircularReference(policy, new ArrayList<>());
}

View file

@ -1,30 +1,27 @@
package org.keycloak.authorization.policy.provider.js;
import java.util.function.Supplier;
import java.util.Map;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import org.keycloak.Config;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.policy.provider.PolicyProvider;
import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class JSPolicyProviderFactory implements PolicyProviderFactory {
public class JSPolicyProviderFactory implements PolicyProviderFactory<JSPolicyRepresentation> {
private JSPolicyProvider provider = new JSPolicyProvider(new Supplier<ScriptEngine>() {
@Override
public ScriptEngine get() {
return new ScriptEngineManager().getEngineByName("nashorn");
}
});
private static final String ENGINE = "nashorn";
private JSPolicyProvider provider = new JSPolicyProvider(() -> new ScriptEngineManager().getEngineByName(ENGINE));
@Override
public String getName() {
@ -42,13 +39,40 @@ public class JSPolicyProviderFactory implements PolicyProviderFactory {
}
@Override
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer, AuthorizationProvider authorization) {
public PolicyProvider create(KeycloakSession session) {
return null;
}
@Override
public PolicyProvider create(KeycloakSession session) {
return null;
public JSPolicyRepresentation toRepresentation(Policy policy, JSPolicyRepresentation representation) {
representation.setCode(policy.getConfig().get("code"));
return representation;
}
@Override
public Class<JSPolicyRepresentation> getRepresentationType() {
return JSPolicyRepresentation.class;
}
@Override
public void onCreate(Policy policy, JSPolicyRepresentation representation, AuthorizationProvider authorization) {
updatePolicy(policy, representation.getCode());
}
@Override
public void onUpdate(Policy policy, JSPolicyRepresentation representation, AuthorizationProvider authorization) {
updatePolicy(policy, representation.getCode());
}
@Override
public void onImport(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) {
updatePolicy(policy, representation.getConfig().get("code"));
}
private void updatePolicy(Policy policy, String code) {
Map<String, String> config = policy.getConfig();
config.put("code", code);
policy.setConfig(config);
}
@Override

View file

@ -33,21 +33,20 @@ public class TimePolicyProvider implements PolicyProvider {
static String DEFAULT_DATE_PATTERN = "yyyy-MM-dd hh:mm:ss";
private final SimpleDateFormat dateFormat;
private final Date currentDate;
public TimePolicyProvider() {
this.dateFormat = new SimpleDateFormat(DEFAULT_DATE_PATTERN);
this.currentDate = new Date();
}
@Override
public void evaluate(Evaluation evaluation) {
Policy policy = evaluation.getPolicy();
Date actualDate = new Date();
try {
String notBefore = policy.getConfig().get("nbf");
if (notBefore != null && !"".equals(notBefore)) {
if (this.currentDate.before(this.dateFormat.parse(format(notBefore)))) {
if (actualDate.before(this.dateFormat.parse(format(notBefore)))) {
evaluation.deny();
return;
}
@ -55,17 +54,17 @@ public class TimePolicyProvider implements PolicyProvider {
String notOnOrAfter = policy.getConfig().get("noa");
if (notOnOrAfter != null && !"".equals(notOnOrAfter)) {
if (this.currentDate.after(this.dateFormat.parse(format(notOnOrAfter)))) {
if (actualDate.after(this.dateFormat.parse(format(notOnOrAfter)))) {
evaluation.deny();
return;
}
}
if (isInvalid(Calendar.DAY_OF_MONTH, "dayMonth", policy)
|| isInvalid(Calendar.MONTH, "month", policy)
|| isInvalid(Calendar.YEAR, "year", policy)
|| isInvalid(Calendar.HOUR_OF_DAY, "hour", policy)
|| isInvalid(Calendar.MINUTE, "minute", policy)) {
if (isInvalid(actualDate, Calendar.DAY_OF_MONTH, "dayMonth", policy)
|| isInvalid(actualDate, Calendar.MONTH, "month", policy)
|| isInvalid(actualDate, Calendar.YEAR, "year", policy)
|| isInvalid(actualDate, Calendar.HOUR_OF_DAY, "hour", policy)
|| isInvalid(actualDate, Calendar.MINUTE, "minute", policy)) {
evaluation.deny();
return;
}
@ -76,10 +75,10 @@ public class TimePolicyProvider implements PolicyProvider {
}
}
private boolean isInvalid(int timeConstant, String configName, Policy policy) {
private boolean isInvalid(Date actualDate, int timeConstant, String configName, Policy policy) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(this.currentDate);
calendar.setTime(actualDate);
int dateField = calendar.get(timeConstant);

View file

@ -1,22 +1,22 @@
package org.keycloak.authorization.policy.provider.time;
import java.text.SimpleDateFormat;
import java.util.Map;
import org.keycloak.Config;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.policy.provider.PolicyProvider;
import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.TimePolicyRepresentation;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class TimePolicyProviderFactory implements PolicyProviderFactory<PolicyRepresentation> {
public class TimePolicyProviderFactory implements PolicyProviderFactory<TimePolicyRepresentation> {
private TimePolicyProvider provider = new TimePolicyProvider();
@ -35,46 +35,58 @@ public class TimePolicyProviderFactory implements PolicyProviderFactory<PolicyRe
return provider;
}
@Override
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer, AuthorizationProvider authorization) {
return new TimePolicyAdminResource();
}
@Override
public PolicyProvider create(KeycloakSession session) {
return null;
}
@Override
public void onCreate(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) {
validateConfig(policy);
}
private void validateConfig(Policy policy) {
String nbf = policy.getConfig().get("nbf");
String noa = policy.getConfig().get("noa");
if (nbf != null && noa != null) {
validateFormat(nbf);
validateFormat(noa);
}
public void onCreate(Policy policy, TimePolicyRepresentation representation, AuthorizationProvider authorization) {
updatePolicy(policy, representation);
}
@Override
public void onUpdate(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) {
validateConfig(policy);
public void onUpdate(Policy policy, TimePolicyRepresentation representation, AuthorizationProvider authorization) {
updatePolicy(policy, representation);
}
@Override
public void onRemove(Policy policy, AuthorizationProvider authorization) {
}
private void validateFormat(String date) {
try {
new SimpleDateFormat(TimePolicyProvider.DEFAULT_DATE_PATTERN).parse(TimePolicyProvider.format(date));
} catch (Exception e) {
throw new RuntimeException("Could not parse a date using format [" + date + "]");
@Override
public void onImport(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) {
policy.setConfig(representation.getConfig());
}
@Override
public Class<TimePolicyRepresentation> getRepresentationType() {
return TimePolicyRepresentation.class;
}
@Override
public TimePolicyRepresentation toRepresentation(Policy policy, TimePolicyRepresentation representation) {
Map<String, String> config = policy.getConfig();
representation.setDayMonth(config.get("dayMonth"));
representation.setDayMonthEnd(config.get("dayMonthEnd"));
representation.setMonth(config.get("month"));
representation.setMonthEnd(config.get("monthEnd"));
representation.setYear(config.get("year"));
representation.setYearEnd(config.get("yearEnd"));
representation.setHour(config.get("hour"));
representation.setHourEnd(config.get("hourEnd"));
representation.setMinute(config.get("minute"));
representation.setMinuteEnd(config.get("minuteEnd"));
representation.setNotBefore(config.get("nbf"));
representation.setNotOnOrAfter(config.get("noa"));
return representation;
}
@Override
@ -96,4 +108,44 @@ public class TimePolicyProviderFactory implements PolicyProviderFactory<PolicyRe
public String getId() {
return "time";
}
private void updatePolicy(Policy policy, TimePolicyRepresentation representation) {
String nbf = representation.getNotBefore();
String noa = representation.getNotOnOrAfter();
if (nbf != null && noa != null) {
validateFormat(nbf);
validateFormat(noa);
}
Map<String, String> config = policy.getConfig();
config.compute("nbf", (s, s2) -> nbf != null ? nbf : null);
config.compute("noa", (s, s2) -> noa != null ? noa : null);
config.compute("dayMonth", (s, s2) -> representation.getDayMonth() != null ? representation.getDayMonth() : null);
config.compute("dayMonthEnd", (s, s2) -> representation.getDayMonthEnd() != null ? representation.getDayMonthEnd() : null);
config.compute("month", (s, s2) -> representation.getMonth() != null ? representation.getMonth() : null);
config.compute("monthEnd", (s, s2) -> representation.getMonthEnd() != null ? representation.getMonthEnd() : null);
config.compute("year", (s, s2) -> representation.getYear() != null ? representation.getYear() : null);
config.compute("yearEnd", (s, s2) -> representation.getYearEnd() != null ? representation.getYearEnd() : null);
config.compute("hour", (s, s2) -> representation.getHour() != null ? representation.getHour() : null);
config.compute("hourEnd", (s, s2) -> representation.getHourEnd() != null ? representation.getHourEnd() : null);
config.compute("minute", (s, s2) -> representation.getMinute() != null ? representation.getMinute() : null);
config.compute("minuteEnd", (s, s2) -> representation.getMinuteEnd() != null ? representation.getMinuteEnd() : null);
policy.setConfig(config);
}
private void validateFormat(String date) {
try {
new SimpleDateFormat(TimePolicyProvider.DEFAULT_DATE_PATTERN).parse(TimePolicyProvider.format(date));
} catch (Exception e) {
throw new RuntimeException("Could not parse a date using format [" + date + "]");
}
}
}

View file

@ -88,6 +88,10 @@ public class AbstractPolicyRepresentation {
return policies;
}
public void setPolicies(Set<String> policies) {
this.policies = policies;
}
public void addPolicy(String... id) {
if (this.policies == null) {
this.policies = new HashSet<>();
@ -99,6 +103,10 @@ public class AbstractPolicyRepresentation {
return resources;
}
public void setResources(Set<String> resources) {
this.resources = resources;
}
public void addResource(String id) {
if (this.resources == null) {
this.resources = new HashSet<>();

View file

@ -1,7 +1,6 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
* Copyright 2016 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.
@ -15,14 +14,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.authorization.policy.provider.time;
import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
package org.keycloak.representations.idm.authorization;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class TimePolicyAdminResource implements PolicyProviderAdminService {
public class AggregatePolicyRepresentation extends AbstractPolicyRepresentation {
@Override
public String getType() {
return "aggregate";
}
}

View file

@ -0,0 +1,38 @@
/*
* Copyright 2016 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.authorization;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class JSPolicyRepresentation extends AbstractPolicyRepresentation {
private String code;
@Override
public String getType() {
return "js";
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}

View file

@ -26,6 +26,11 @@ public class RolePolicyRepresentation extends AbstractPolicyRepresentation {
private Set<RoleDefinition> roles;
@Override
public String getType() {
return "role";
}
public Set<RoleDefinition> getRoles() {
return roles;
}

View file

@ -0,0 +1,137 @@
/*
* Copyright 2016 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.authorization;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class TimePolicyRepresentation extends AbstractPolicyRepresentation {
private String notBefore;
private String notOnOrAfter;
private String dayMonth;
private String dayMonthEnd;
private String month;
private String monthEnd;
private String year;
private String yearEnd;
private String hour;
private String hourEnd;
private String minute;
private String minuteEnd;
@Override
public String getType() {
return "time";
}
public String getNotBefore() {
return notBefore;
}
public void setNotBefore(String notBefore) {
this.notBefore = notBefore;
}
public String getNotOnOrAfter() {
return notOnOrAfter;
}
public void setNotOnOrAfter(String notOnOrAfter) {
this.notOnOrAfter = notOnOrAfter;
}
public String getDayMonth() {
return dayMonth;
}
public void setDayMonth(String dayMonth) {
this.dayMonth = dayMonth;
}
public String getDayMonthEnd() {
return dayMonthEnd;
}
public void setDayMonthEnd(String dayMonthEnd) {
this.dayMonthEnd = dayMonthEnd;
}
public String getMonth() {
return month;
}
public void setMonth(String month) {
this.month = month;
}
public String getMonthEnd() {
return monthEnd;
}
public void setMonthEnd(String monthEnd) {
this.monthEnd = monthEnd;
}
public String getYear() {
return year;
}
public void setYear(String year) {
this.year = year;
}
public String getYearEnd() {
return yearEnd;
}
public void setYearEnd(String yearEnd) {
this.yearEnd = yearEnd;
}
public String getHour() {
return hour;
}
public void setHour(String hour) {
this.hour = hour;
}
public String getHourEnd() {
return hourEnd;
}
public void setHourEnd(String hourEnd) {
this.hourEnd = hourEnd;
}
public String getMinute() {
return minute;
}
public void setMinute(String minute) {
this.minute = minute;
}
public String getMinuteEnd() {
return minuteEnd;
}
public void setMinuteEnd(String minuteEnd) {
this.minuteEnd = minuteEnd;
}
}

View file

@ -26,6 +26,11 @@ public class UserPolicyRepresentation extends AbstractPolicyRepresentation {
private Set<String> users;
@Override
public String getType() {
return "user";
}
public Set<String> getUsers() {
return users;
}

View file

@ -0,0 +1,50 @@
/*
* Copyright 2016 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.admin.client.resource;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
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.authorization.JSPolicyRepresentation;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public interface JSPoliciesResource {
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
Response create(JSPolicyRepresentation representation);
@Path("{id}")
JSPolicyResource findById(@PathParam("id") String id);
@Path("/search")
@GET
@Produces(MediaType.APPLICATION_JSON)
@NoCache
JSPolicyRepresentation findByName(@QueryParam("name") String name);
}

View file

@ -0,0 +1,70 @@
/*
* Copyright 2016 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.admin.client.resource;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public interface JSPolicyResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
@NoCache
JSPolicyRepresentation toRepresentation();
@PUT
@Consumes(MediaType.APPLICATION_JSON)
void update(JSPolicyRepresentation representation);
@DELETE
void remove();
@Path("/associatedPolicies")
@GET
@Produces(MediaType.APPLICATION_JSON)
@NoCache
List<PolicyRepresentation> associatedPolicies();
@Path("/dependentPolicies")
@GET
@Produces(MediaType.APPLICATION_JSON)
@NoCache
List<PolicyRepresentation> dependentPolicies();
@Path("/resources")
@GET
@Produces("application/json")
@NoCache
List<ResourceRepresentation> resources();
}

View file

@ -74,4 +74,10 @@ public interface PoliciesResource {
@Path("user")
UserPoliciesResource users();
@Path("js")
JSPoliciesResource js();
@Path("time")
TimePoliciesResource time();
}

View file

@ -0,0 +1,50 @@
/*
* Copyright 2016 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.admin.client.resource;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
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.authorization.TimePolicyRepresentation;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public interface TimePoliciesResource {
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
Response create(TimePolicyRepresentation representation);
@Path("{id}")
TimePolicyResource findById(@PathParam("id") String id);
@Path("/search")
@GET
@Produces(MediaType.APPLICATION_JSON)
@NoCache
TimePolicyRepresentation findByName(@QueryParam("name") String name);
}

View file

@ -0,0 +1,69 @@
/*
* Copyright 2016 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.admin.client.resource;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.TimePolicyRepresentation;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public interface TimePolicyResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
@NoCache
TimePolicyRepresentation toRepresentation();
@PUT
@Consumes(MediaType.APPLICATION_JSON)
void update(TimePolicyRepresentation representation);
@DELETE
void remove();
@Path("/associatedPolicies")
@GET
@Produces(MediaType.APPLICATION_JSON)
@NoCache
List<PolicyRepresentation> associatedPolicies();
@Path("/dependentPolicies")
@GET
@Produces(MediaType.APPLICATION_JSON)
@NoCache
List<PolicyRepresentation> dependentPolicies();
@Path("/resources")
@GET
@Produces("application/json")
@NoCache
List<ResourceRepresentation> resources();
}

View file

@ -0,0 +1,117 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.admin.client.authorization;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.util.Collections;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.core.Response;
import org.junit.Test;
import org.keycloak.admin.client.resource.AuthorizationResource;
import org.keycloak.admin.client.resource.JSPoliciesResource;
import org.keycloak.admin.client.resource.JSPolicyResource;
import org.keycloak.representations.idm.authorization.DecisionStrategy;
import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
import org.keycloak.representations.idm.authorization.Logic;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class JSPolicyManagementTest extends AbstractPermissionManagementTest {
@Test
public void testCreate() {
AuthorizationResource authorization = getClient().authorization();
JSPolicyRepresentation representation = new JSPolicyRepresentation();
representation.setName("JS Policy");
representation.setDescription("description");
representation.setDecisionStrategy(DecisionStrategy.CONSENSUS);
representation.setLogic(Logic.NEGATIVE);
representation.setCode("$evaluation.grant();");
assertCreated(authorization, representation);
}
@Test
public void testUpdate() {
AuthorizationResource authorization = getClient().authorization();
JSPolicyRepresentation representation = new JSPolicyRepresentation();
representation.setName("Update JS Policy");
representation.setDescription("description");
representation.setDecisionStrategy(DecisionStrategy.CONSENSUS);
representation.setLogic(Logic.NEGATIVE);
representation.setCode("$evaluation.grant();");
assertCreated(authorization, representation);
representation.setName("changed");
representation.setDescription("changed");
representation.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE);
representation.setLogic(Logic.POSITIVE);
representation.setCode("$evaluation.deny()");
JSPoliciesResource policies = authorization.policies().js();
JSPolicyResource permission = policies.findById(representation.getId());
permission.update(representation);
assertRepresentation(representation, permission);
}
@Test
public void testDelete() {
AuthorizationResource authorization = getClient().authorization();
JSPolicyRepresentation representation = new JSPolicyRepresentation();
representation.setName("Test Delete Policy");
representation.setCode("$evaluation.grant()");
JSPoliciesResource policies = authorization.policies().js();
Response response = policies.create(representation);
JSPolicyRepresentation created = response.readEntity(JSPolicyRepresentation.class);
policies.findById(created.getId()).remove();
JSPolicyResource removed = policies.findById(created.getId());
try {
removed.toRepresentation();
fail("Permission not removed");
} catch (NotFoundException ignore) {
}
}
private void assertCreated(AuthorizationResource authorization, JSPolicyRepresentation representation) {
JSPoliciesResource permissions = authorization.policies().js();
Response response = permissions.create(representation);
JSPolicyRepresentation created = response.readEntity(JSPolicyRepresentation.class);
JSPolicyResource permission = permissions.findById(created.getId());
assertRepresentation(representation, permission);
}
private void assertRepresentation(JSPolicyRepresentation representation, JSPolicyResource permission) {
JSPolicyRepresentation actual = permission.toRepresentation();
assertRepresentation(representation, actual, () -> permission.resources(), () -> Collections.emptyList(), () -> permission.associatedPolicies());
assertEquals(representation.getCode(), actual.getCode());
}
}

View file

@ -0,0 +1,165 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.admin.client.authorization;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.util.Collections;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.core.Response;
import org.junit.Test;
import org.keycloak.admin.client.resource.AuthorizationResource;
import org.keycloak.admin.client.resource.TimePoliciesResource;
import org.keycloak.admin.client.resource.TimePolicyResource;
import org.keycloak.representations.idm.authorization.DecisionStrategy;
import org.keycloak.representations.idm.authorization.TimePolicyRepresentation;
import org.keycloak.representations.idm.authorization.Logic;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class TimePolicyManagementTest extends AbstractPermissionManagementTest {
@Test
public void testCreate() {
AuthorizationResource authorization = getClient().authorization();
assertCreated(authorization, createRepresentation("Time Policy"));
}
@Test
public void testUpdate() {
AuthorizationResource authorization = getClient().authorization();
TimePolicyRepresentation representation = createRepresentation("Update Time Policy");
assertCreated(authorization, representation);
representation.setName("changed");
representation.setDescription("changed");
representation.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE);
representation.setLogic(Logic.POSITIVE);
representation.setDayMonth("11");
representation.setDayMonthEnd("22");
representation.setMonth("7");
representation.setMonthEnd("9");
representation.setYear("2019");
representation.setYearEnd("2030");
representation.setHour("15");
representation.setHourEnd("23");
representation.setMinute("55");
representation.setMinuteEnd("58");
representation.setNotBefore("2019-01-01 00:00:00");
representation.setNotOnOrAfter("2019-02-03 00:00:00");
TimePoliciesResource policies = authorization.policies().time();
TimePolicyResource permission = policies.findById(representation.getId());
permission.update(representation);
assertRepresentation(representation, permission);
representation.setDayMonth(null);
representation.setDayMonthEnd(null);
representation.setMonth(null);
representation.setMonthEnd(null);
representation.setYear(null);
representation.setYearEnd(null);
representation.setHour(null);
representation.setHourEnd(null);
representation.setMinute(null);
representation.setMinuteEnd(null);
representation.setNotBefore(null);
representation.setNotOnOrAfter("2019-02-03 00:00:00");
permission.update(representation);
assertRepresentation(representation, permission);
representation.setNotOnOrAfter(null);
representation.setHour("2");
permission.update(representation);
assertRepresentation(representation, permission);
}
@Test
public void testDelete() {
AuthorizationResource authorization = getClient().authorization();
TimePolicyRepresentation representation = createRepresentation("Test Delete Policy");
TimePoliciesResource policies = authorization.policies().time();
Response response = policies.create(representation);
TimePolicyRepresentation created = response.readEntity(TimePolicyRepresentation.class);
policies.findById(created.getId()).remove();
TimePolicyResource removed = policies.findById(created.getId());
try {
removed.toRepresentation();
fail("Permission not removed");
} catch (NotFoundException ignore) {
}
}
private TimePolicyRepresentation createRepresentation(String name) {
TimePolicyRepresentation representation = new TimePolicyRepresentation();
representation.setName(name);
representation.setDescription("description");
representation.setDecisionStrategy(DecisionStrategy.CONSENSUS);
representation.setLogic(Logic.NEGATIVE);
representation.setDayMonth("1");
representation.setDayMonthEnd("2");
representation.setMonth("3");
representation.setMonthEnd("4");
representation.setYear("5");
representation.setYearEnd("6");
representation.setHour("7");
representation.setHourEnd("8");
representation.setMinute("9");
representation.setMinuteEnd("10");
representation.setNotBefore("2017-01-01 00:00:00");
representation.setNotOnOrAfter("2017-02-01 00:00:00");
return representation;
}
private void assertCreated(AuthorizationResource authorization, TimePolicyRepresentation representation) {
TimePoliciesResource permissions = authorization.policies().time();
Response response = permissions.create(representation);
TimePolicyRepresentation created = response.readEntity(TimePolicyRepresentation.class);
TimePolicyResource permission = permissions.findById(created.getId());
assertRepresentation(representation, permission);
}
private void assertRepresentation(TimePolicyRepresentation representation, TimePolicyResource permission) {
TimePolicyRepresentation actual = permission.toRepresentation();
assertRepresentation(representation, actual, () -> permission.resources(), () -> Collections.emptyList(), () -> permission.associatedPolicies());
assertEquals(representation.getDayMonth(), actual.getDayMonth());
assertEquals(representation.getDayMonthEnd(), actual.getDayMonthEnd());
assertEquals(representation.getMonth(), actual.getMonth());
assertEquals(representation.getMonthEnd(), actual.getMonthEnd());
assertEquals(representation.getYear(), actual.getYear());
assertEquals(representation.getYearEnd(), actual.getYearEnd());
assertEquals(representation.getHour(), actual.getHour());
assertEquals(representation.getHourEnd(), actual.getHourEnd());
assertEquals(representation.getMinute(), actual.getMinute());
assertEquals(representation.getMinuteEnd(), actual.getMinuteEnd());
assertEquals(representation.getNotBefore(), actual.getNotBefore());
assertEquals(representation.getNotOnOrAfter(), actual.getNotOnOrAfter());
}
}

View file

@ -16,8 +16,18 @@
*/
package org.keycloak.testsuite.console.page.clients.authorization.permission;
import static org.openqa.selenium.By.tagName;
import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
import org.keycloak.testsuite.console.page.clients.authorization.policy.PolicyTypeUI;
import org.keycloak.testsuite.page.Form;
import org.keycloak.testsuite.util.WaitUtils;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.ui.Select;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
@ -27,7 +37,79 @@ public class Permissions extends Form {
@FindBy(css = "table[class*='table']")
private PermissionsTable table;
@FindBy(id = "create-permission")
private Select createSelect;
@Page
private ResourcePermission resourcePermission;
public PermissionsTable permissions() {
return table;
}
public <P extends PolicyTypeUI> P create(AbstractPolicyRepresentation expected) {
String type = expected.getType();
createSelect.selectByValue(type);
if ("resource".equals(type)) {
resourcePermission.form().populate((ResourcePermissionRepresentation) expected);
resourcePermission.form().save();
return (P) resourcePermission;
} else if ("scope".equals(type)) {
return null;
}
return null;
}
public void update(String name, AbstractPolicyRepresentation representation) {
for (WebElement row : permissions().rows()) {
PolicyRepresentation actual = permissions().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
row.findElements(tagName("a")).get(0).click();
WaitUtils.waitForPageToLoad(driver);
String type = representation.getType();
if ("resource".equals(type)) {
resourcePermission.form().populate((ResourcePermissionRepresentation) representation);
}
return;
}
}
}
public <P extends PolicyTypeUI> P name(String name) {
for (WebElement row : permissions().rows()) {
PolicyRepresentation actual = permissions().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
row.findElements(tagName("a")).get(0).click();
WaitUtils.waitForPageToLoad(driver);
String type = actual.getType();
if ("resource".equals(type)) {
return (P) resourcePermission;
}
}
}
return null;
}
public void delete(String name) {
for (WebElement row : permissions().rows()) {
PolicyRepresentation actual = permissions().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
row.findElements(tagName("a")).get(0).click();
WaitUtils.waitForPageToLoad(driver);
String type = actual.getType();
if ("resource".equals(type)) {
resourcePermission.form().delete();
}
return;
}
}
}
}

View file

@ -0,0 +1,43 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.page.clients.authorization.permission;
import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
import org.keycloak.testsuite.console.page.clients.authorization.policy.PolicyTypeUI;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class ResourcePermission implements PolicyTypeUI {
@Page
private ResourcePermissionForm form;
public ResourcePermissionForm form() {
return form;
}
public ResourcePermissionRepresentation toRepresentation() {
return form.toRepresentation();
}
public void update(ResourcePermissionRepresentation expected) {
form().populate(expected);
}
}

View file

@ -0,0 +1,264 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.page.clients.authorization.permission;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.jboss.arquillian.graphene.fragment.Root;
import org.keycloak.representations.idm.authorization.DecisionStrategy;
import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
import org.keycloak.testsuite.page.Form;
import org.keycloak.testsuite.util.WaitUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.ui.Select;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class ResourcePermissionForm extends Form {
@FindBy(id = "name")
private WebElement name;
@FindBy(id = "description")
private WebElement description;
@FindBy(id = "decisionStrategy")
private Select decisionStrategy;
@FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='applyToResourceTypeFlag']]")
private OnOffSwitch resourceTypeSwitch;
@FindBy(id = "resourceType")
private WebElement resourceType;
@FindBy(xpath = "//i[contains(@class,'pficon-delete')]")
private WebElement deleteButton;
@FindBy(xpath = ACTIVE_DIV_XPATH + "/button[text()='Delete']")
private WebElement confirmDelete;
@FindBy(id = "s2id_policies")
private PolicyInput policyInput;
@FindBy(id = "s2id_resources")
private ResourceInput resourceInput;
public void populate(ResourcePermissionRepresentation expected) {
setInputValue(name, expected.getName());
setInputValue(description, expected.getDescription());
decisionStrategy.selectByValue(expected.getDecisionStrategy().name());
resourceTypeSwitch.setOn(expected.getResourceType() != null);
if (expected.getResourceType() != null) {
setInputValue(resourceType, expected.getResourceType());
} else {
resourceTypeSwitch.setOn(false);
Set<String> selectedResources = resourceInput.getSelected();
Set<String> resources = expected.getResources();
for (String resource : resources) {
if (!selectedResources.contains(resource)) {
resourceInput.select(resource);
}
}
for (String selected : selectedResources) {
boolean isSelected = false;
for (String resource : resources) {
if (selected.equals(resource)) {
isSelected = true;
break;
}
}
if (!isSelected) {
resourceInput.unSelect(selected, driver);
}
}
}
Set<String> selectedPolicies = policyInput.getSelected();
Set<String> policies = expected.getPolicies();
for (String policy : policies) {
if (!selectedPolicies.contains(policy)) {
policyInput.select(policy, driver);
}
}
for (String selected : selectedPolicies) {
boolean isSelected = false;
for (String policy : policies) {
if (selected.equals(policy)) {
isSelected = true;
break;
}
}
if (!isSelected) {
policyInput.unSelect(selected, driver);
}
}
WaitUtils.pause(1000);
save();
}
public void delete() {
deleteButton.click();
confirmDelete.click();
}
public ResourcePermissionRepresentation toRepresentation() {
ResourcePermissionRepresentation representation = new ResourcePermissionRepresentation();
representation.setName(getInputValue(name));
representation.setDescription(getInputValue(description));
representation.setDecisionStrategy(DecisionStrategy.valueOf(decisionStrategy.getFirstSelectedOption().getText().toUpperCase()));
representation.setPolicies(policyInput.getSelected());
representation.setResources(resourceInput.getSelected());
return representation;
}
public class PolicyInput {
@Root
private WebElement root;
@FindBy(xpath = "//input[contains(@class,'select2-input')]")
private WebElement search;
@FindBy(xpath = "//div[contains(@class,'select2-result-label')]")
private List<WebElement> result;
@FindBy(xpath = "//li[contains(@class,'select2-search-choice')]")
private List<WebElement> selection;
public void select(String name, WebDriver driver) {
root.click();
WaitUtils.pause(1000);
Actions actions = new Actions(driver);
actions.sendKeys(name).perform();
WaitUtils.pause(1000);
if (result.isEmpty()) {
actions.sendKeys(Keys.ESCAPE).perform();
return;
}
for (WebElement result : result) {
if (result.getText().equalsIgnoreCase(name)) {
result.click();
return;
}
}
}
public Set<String> getSelected() {
HashSet<String> values = new HashSet<>();
for (WebElement selected : selection) {
values.add(selected.findElements(By.tagName("div")).get(0).getText());
}
return values;
}
public void unSelect(String name, WebDriver driver) {
for (WebElement selected : selection) {
WebElement selection = selected.findElements(By.tagName("div")).get(0);
if (name.equals(selection.getText())) {
WebElement element = selection.findElement(By.xpath("//a[contains(@class,'select2-search-choice-close')]"));
JavascriptExecutor executor = (JavascriptExecutor) driver;
executor.executeScript("arguments[0].click();", element);
WaitUtils.pause(1000);
return;
}
}
}
}
public class ResourceInput {
@Root
private WebElement root;
@FindBy(xpath = "//input[contains(@class,'select2-input')]")
private WebElement search;
@FindBy(xpath = "//div[contains(@class,'select2-result-label')]")
private List<WebElement> result;
@FindBy(xpath = "//li[contains(@class,'select2-search-choice')]")
private List<WebElement> selection;
public void select(String name) {
root.click();
WaitUtils.pause(1000);
setInputValue(search, name);
WaitUtils.pause(1000);
if (result.isEmpty()) {
search.sendKeys(Keys.ESCAPE);
return;
}
for (WebElement result : result) {
if (result.getText().equalsIgnoreCase(name)) {
result.click();
return;
}
}
}
public Set<String> getSelected() {
HashSet<String> values = new HashSet<>();
for (WebElement selected : selection) {
values.add(selected.findElements(By.tagName("div")).get(0).getText());
}
return values;
}
public void unSelect(String name, WebDriver driver) {
for (WebElement selected : selection) {
if (name.equals(selected.findElements(By.tagName("div")).get(0).getText())) {
WebElement element = selected.findElement(By.xpath("//a[contains(@class,'select2-search-choice-close')]"));
JavascriptExecutor executor = (JavascriptExecutor) driver;
executor.executeScript("arguments[0].click();", element);
WaitUtils.pause(1000);
return;
}
}
}
}
}

View file

@ -0,0 +1,42 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.page.clients.authorization.policy;
import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.representations.idm.authorization.AggregatePolicyRepresentation;
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class AggregatePolicy implements PolicyTypeUI {
@Page
private AggregatePolicyForm form;
public AggregatePolicyForm form() {
return form;
}
public AggregatePolicyRepresentation toRepresentation() {
return form.toRepresentation();
}
public void update(AggregatePolicyRepresentation expected) {
form().populate(expected);
}
}

View file

@ -0,0 +1,165 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.page.clients.authorization.policy;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.jboss.arquillian.graphene.fragment.Root;
import org.keycloak.representations.idm.authorization.AggregatePolicyRepresentation;
import org.keycloak.representations.idm.authorization.Logic;
import org.keycloak.testsuite.page.Form;
import org.keycloak.testsuite.util.WaitUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.ui.Select;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class AggregatePolicyForm extends Form {
@FindBy(id = "name")
private WebElement name;
@FindBy(id = "description")
private WebElement description;
@FindBy(id = "logic")
private Select logic;
@FindBy(xpath = "//i[contains(@class,'pficon-delete')]")
private WebElement deleteButton;
@FindBy(id = "s2id_policies")
private PolicyInput policyInput;
@FindBy(xpath = ACTIVE_DIV_XPATH + "/button[text()='Delete']")
private WebElement confirmDelete;
public void populate(AggregatePolicyRepresentation expected) {
setInputValue(name, expected.getName());
setInputValue(description, expected.getDescription());
logic.selectByValue(expected.getLogic().name());
Set<String> selectedPolicies = policyInput.getSelected();
Set<String> policies = expected.getPolicies();
for (String policy : policies) {
if (!selectedPolicies.contains(policy)) {
policyInput.select(policy, driver);
}
}
for (String selected : selectedPolicies) {
boolean isSelected = false;
for (String policy : policies) {
if (selected.equals(policy)) {
isSelected = true;
break;
}
}
if (!isSelected) {
policyInput.unSelect(selected, driver);
}
}
save();
}
public void delete() {
deleteButton.click();
confirmDelete.click();
}
public AggregatePolicyRepresentation toRepresentation() {
AggregatePolicyRepresentation representation = new AggregatePolicyRepresentation();
representation.setName(getInputValue(name));
representation.setDescription(getInputValue(description));
representation.setLogic(Logic.valueOf(logic.getFirstSelectedOption().getText().toUpperCase()));
representation.setPolicies(policyInput.getSelected());
return representation;
}
public class PolicyInput {
@Root
private WebElement root;
@FindBy(xpath = "//input[contains(@class,'select2-input')]")
private WebElement search;
@FindBy(xpath = "//div[contains(@class,'select2-result-label')]")
private List<WebElement> result;
@FindBy(xpath = "//li[contains(@class,'select2-search-choice')]")
private List<WebElement> selection;
public void select(String name, WebDriver driver) {
root.click();
WaitUtils.pause(1000);
Actions actions = new Actions(driver);
actions.sendKeys(name).perform();
WaitUtils.pause(1000);
if (result.isEmpty()) {
actions.sendKeys(Keys.ESCAPE).perform();
return;
}
for (WebElement result : result) {
if (result.getText().equalsIgnoreCase(name)) {
result.click();
return;
}
}
}
public Set<String> getSelected() {
HashSet<String> values = new HashSet<>();
for (WebElement selected : selection) {
values.add(selected.findElements(By.tagName("div")).get(0).getText());
}
return values;
}
public void unSelect(String name, WebDriver driver) {
for (WebElement selected : selection) {
if (name.equals(selected.findElements(By.tagName("div")).get(0).getText())) {
WebElement element = selected.findElement(By.xpath("//a[contains(@class,'select2-search-choice-close')]"));
JavascriptExecutor executor = (JavascriptExecutor) driver;
executor.executeScript("arguments[0].click();", element);
WaitUtils.pause(1000);
return;
}
}
}
}
}

View file

@ -0,0 +1,42 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.page.clients.authorization.policy;
import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.representations.idm.authorization.AggregatePolicyRepresentation;
import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class JSPolicy implements PolicyTypeUI {
@Page
private JSPolicyForm form;
public JSPolicyForm form() {
return form;
}
public JSPolicyRepresentation toRepresentation() {
return form.toRepresentation();
}
public void update(JSPolicyRepresentation expected) {
form().populate(expected);
}
}

View file

@ -0,0 +1,77 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.page.clients.authorization.policy;
import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
import org.keycloak.representations.idm.authorization.Logic;
import org.keycloak.testsuite.page.Form;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.ui.Select;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class JSPolicyForm extends Form {
@FindBy(id = "name")
private WebElement name;
@FindBy(id = "description")
private WebElement description;
@FindBy(id = "logic")
private Select logic;
@FindBy(xpath = "//i[contains(@class,'pficon-delete')]")
private WebElement deleteButton;
@FindBy(xpath = ACTIVE_DIV_XPATH + "/button[text()='Delete']")
private WebElement confirmDelete;
public void populate(JSPolicyRepresentation expected) {
setInputValue(name, expected.getName());
setInputValue(description, expected.getDescription());
logic.selectByValue(expected.getLogic().name());
JavascriptExecutor scriptExecutor = (JavascriptExecutor) driver;
scriptExecutor.executeScript("angular.element(document.getElementById('code')).scope().policy.code = '" + expected.getCode() + "'");
save();
}
public void delete() {
deleteButton.click();
confirmDelete.click();
}
public JSPolicyRepresentation toRepresentation() {
JSPolicyRepresentation representation = new JSPolicyRepresentation();
representation.setName(getInputValue(name));
representation.setDescription(getInputValue(description));
representation.setLogic(Logic.valueOf(logic.getFirstSelectedOption().getText().toUpperCase()));
JavascriptExecutor scriptExecutor = (JavascriptExecutor) driver;
representation.setCode((String) scriptExecutor.executeScript("return angular.element(document.getElementById('code')).scope().policy.code;"));
return representation;
}
}

View file

@ -16,9 +16,21 @@
*/
package org.keycloak.testsuite.console.page.clients.authorization.policy;
import org.keycloak.testsuite.console.page.clients.authorization.permission.PermissionsTable;
import static org.openqa.selenium.By.tagName;
import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
import org.keycloak.representations.idm.authorization.AggregatePolicyRepresentation;
import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation;
import org.keycloak.representations.idm.authorization.TimePolicyRepresentation;
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
import org.keycloak.testsuite.page.Form;
import org.keycloak.testsuite.util.WaitUtils;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.ui.Select;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
@ -26,9 +38,131 @@ import org.openqa.selenium.support.FindBy;
public class Policies extends Form {
@FindBy(css = "table[class*='table']")
private PermissionsTable table;
private PoliciesTable table;
public PermissionsTable policies() {
@FindBy(id = "create-policy")
private Select createSelect;
@Page
private RolePolicy rolePolicy;
@Page
private UserPolicy userPolicy;
@Page
private AggregatePolicy aggregatePolicy;
@Page
private JSPolicy jsPolicy;
@Page
private TimePolicy timePolicy;
public PoliciesTable policies() {
return table;
}
public <P extends PolicyTypeUI> P create(AbstractPolicyRepresentation expected) {
String type = expected.getType();
createSelect.selectByValue(type);
if ("role".equals(type)) {
rolePolicy.form().populate((RolePolicyRepresentation) expected);
rolePolicy.form().save();
return (P) rolePolicy;
} else if ("user".equals(type)) {
userPolicy.form().populate((UserPolicyRepresentation) expected);
userPolicy.form().save();
return (P) userPolicy;
} else if ("aggregate".equals(type)) {
aggregatePolicy.form().populate((AggregatePolicyRepresentation) expected);
aggregatePolicy.form().save();
return (P) aggregatePolicy;
} else if ("js".equals(type)) {
jsPolicy.form().populate((JSPolicyRepresentation) expected);
jsPolicy.form().save();
return (P) jsPolicy;
} else if ("time".equals(type)) {
timePolicy.form().populate((TimePolicyRepresentation) expected);
timePolicy.form().save();
return (P) timePolicy;
}
return null;
}
public void update(String name, AbstractPolicyRepresentation representation) {
for (WebElement row : policies().rows()) {
PolicyRepresentation actual = policies().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
row.findElements(tagName("a")).get(0).click();
WaitUtils.waitForPageToLoad(driver);
String type = representation.getType();
if ("role".equals(type)) {
rolePolicy.form().populate((RolePolicyRepresentation) representation);
} else if ("user".equals(type)) {
userPolicy.form().populate((UserPolicyRepresentation) representation);
} else if ("aggregate".equals(type)) {
aggregatePolicy.form().populate((AggregatePolicyRepresentation) representation);
} else if ("js".equals(type)) {
jsPolicy.form().populate((JSPolicyRepresentation) representation);
} else if ("time".equals(type)) {
timePolicy.form().populate((TimePolicyRepresentation) representation);
}
return;
}
}
}
public <P extends PolicyTypeUI> P name(String name) {
for (WebElement row : policies().rows()) {
PolicyRepresentation actual = policies().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
row.findElements(tagName("a")).get(0).click();
WaitUtils.waitForPageToLoad(driver);
String type = actual.getType();
if ("role".equals(type)) {
return (P) rolePolicy;
} else if ("user".equals(type)) {
return (P) userPolicy;
} else if ("aggregate".equals(type)) {
return (P) aggregatePolicy;
} else if ("js".equals(type)) {
return (P) jsPolicy;
} else if ("time".equals(type)) {
return (P) timePolicy;
}
}
}
return null;
}
public void delete(String name) {
for (WebElement row : policies().rows()) {
PolicyRepresentation actual = policies().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
row.findElements(tagName("a")).get(0).click();
WaitUtils.waitForPageToLoad(driver);
String type = actual.getType();
if ("role".equals(type)) {
rolePolicy.form().delete();
} else if ("user".equals(type)) {
userPolicy.form().delete();
} else if ("aggregate".equals(type)) {
aggregatePolicy.form().delete();
} else if ("js".equals(type)) {
jsPolicy.form().delete();
} else if ("time".equals(type)) {
timePolicy.form().delete();
}
return;
}
}
}
}

View file

@ -0,0 +1,23 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.page.clients.authorization.policy;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public interface PolicyTypeUI {
}

View file

@ -0,0 +1,41 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.page.clients.authorization.policy;
import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class RolePolicy implements PolicyTypeUI {
@Page
private RolePolicyForm form;
public RolePolicyForm form() {
return form;
}
public RolePolicyRepresentation toRepresentation() {
return form.toRepresentation();
}
public void update(RolePolicyRepresentation expected) {
form().populate(expected);
}
}

View file

@ -0,0 +1,284 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.page.clients.authorization.policy;
import static org.openqa.selenium.By.tagName;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.jboss.arquillian.graphene.fragment.Root;
import org.keycloak.representations.idm.authorization.Logic;
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation;
import org.keycloak.testsuite.page.Form;
import org.keycloak.testsuite.util.WaitUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.ui.Select;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class RolePolicyForm extends Form {
@FindBy(id = "name")
private WebElement name;
@FindBy(id = "description")
private WebElement description;
@FindBy(id = "logic")
private Select logic;
@FindBy(xpath = "//i[contains(@class,'pficon-delete')]")
private WebElement deleteButton;
@FindBy(id = "s2id_roles")
private RolesInput realmRolesInput;
@FindBy(id = "clients")
private Select clientsSelect;
@FindBy(id = "s2id_clientRoles")
private ClientRolesInput clientRolesInput;
@FindBy(xpath = ACTIVE_DIV_XPATH + "/button[text()='Delete']")
private WebElement confirmDelete;
public void populate(RolePolicyRepresentation expected) {
setInputValue(name, expected.getName());
setInputValue(description, expected.getDescription());
logic.selectByValue(expected.getLogic().name());
Set<RolePolicyRepresentation.RoleDefinition> roles = expected.getRoles();
for (RolePolicyRepresentation.RoleDefinition role : roles) {
boolean clientRole = role.getId().indexOf('/') != -1;
if (clientRole) {
String[] parts = role.getId().split("/");
clientsSelect.selectByVisibleText(parts[0]);
clientRolesInput.select(parts[1], driver);
clientRolesInput.setRequired(parts[1], role);
} else {
realmRolesInput.select(role.getId(), driver);
realmRolesInput.setRequired(role.getId(), role);
}
}
unSelect(roles, realmRolesInput.getSelected());
unSelect(roles, clientRolesInput.getSelected());
save();
}
private void unSelect(Set<RolePolicyRepresentation.RoleDefinition> roles, Set<RolePolicyRepresentation.RoleDefinition> selection) {
for (RolePolicyRepresentation.RoleDefinition selected : selection) {
boolean isSelected = false;
for (RolePolicyRepresentation.RoleDefinition scope : roles) {
if (selected.getId().equals(scope.getId())) {
isSelected = true;
break;
}
}
if (!isSelected) {
boolean clientRole = selected.getId().indexOf('/') != -1;
if (clientRole) {
clientRolesInput.unSelect(selected.getId().split("/")[1], driver);
} else {
realmRolesInput.unSelect(selected.getId(), driver);
}
}
}
}
public void delete() {
deleteButton.click();
confirmDelete.click();
}
public RolePolicyRepresentation toRepresentation() {
RolePolicyRepresentation representation = new RolePolicyRepresentation();
representation.setName(getInputValue(name));
representation.setDescription(getInputValue(description));
representation.setLogic(Logic.valueOf(logic.getFirstSelectedOption().getText().toUpperCase()));
Set<RolePolicyRepresentation.RoleDefinition> roles = realmRolesInput.getSelected();
roles.addAll(clientRolesInput.getSelected());
representation.setRoles(roles);
return representation;
}
public class RolesInput extends AbstractRolesInput {
@Override
protected RolePolicyRepresentation.RoleDefinition getSelectedRoles(List<WebElement> tds) {
RolePolicyRepresentation.RoleDefinition selectedRole = new RolePolicyRepresentation.RoleDefinition();
selectedRole.setId(tds.get(0).getText());
selectedRole.setRequired(tds.get(1).findElement(By.tagName("input")).isSelected());
return selectedRole;
}
@Override
protected WebElement getRemoveButton(List<WebElement> tds) {
return tds.get(2);
}
@Override
protected List<WebElement> getSelectedElements() {
return root.findElements(By.xpath("(//table[@id='selected-realm-roles'])/tbody/tr"));
}
@Override
protected WebElement getRequiredColumn(List<WebElement> tds) {
return tds.get(1);
}
}
public class ClientRolesInput extends AbstractRolesInput {
@Override
protected WebElement getRemoveButton(List<WebElement> tds) {
return tds.get(3);
}
@Override
protected RolePolicyRepresentation.RoleDefinition getSelectedRoles(List<WebElement> tds) {
RolePolicyRepresentation.RoleDefinition selectedRole = new RolePolicyRepresentation.RoleDefinition();
selectedRole.setId(tds.get(1).getText() + "/" + tds.get(0).getText());
selectedRole.setRequired(tds.get(2).findElement(By.tagName("input")).isSelected());
return selectedRole;
}
@Override
protected List<WebElement> getSelectedElements() {
return root.findElements(By.xpath("(//table[@id='selected-client-roles'])/tbody/tr"));
}
@Override
protected WebElement getRequiredColumn(List<WebElement> tds) {
return tds.get(2);
}
}
public abstract class AbstractRolesInput {
@Root
protected WebElement root;
@FindBy(xpath = "//div[contains(@class,'select2-result-label')]")
private List<WebElement> result;
@FindBy(xpath = "//li[contains(@class,'select2-search-choice')]")
private List<WebElement> selection;
public void select(String roleId, WebDriver driver) {
root.click();
WaitUtils.pause(1000);
Actions actions = new Actions(driver);
actions.sendKeys(roleId).perform();
WaitUtils.pause(1000);
if (result.isEmpty()) {
actions.sendKeys(Keys.ESCAPE).perform();
return;
}
for (WebElement result : result) {
if (result.getText().equalsIgnoreCase(roleId)) {
result.click();
return;
}
}
}
public Set<RolePolicyRepresentation.RoleDefinition> getSelected() {
List<WebElement> realmRoles = getSelectedElements();
Set<RolePolicyRepresentation.RoleDefinition> values = new HashSet<>();
for (WebElement realmRole : realmRoles) {
List<WebElement> tds = realmRole.findElements(tagName("td"));
if (!(tds.isEmpty() || tds.get(0).getText().isEmpty())) {
values.add(getSelectedRoles(tds));
}
}
return values;
}
protected abstract RolePolicyRepresentation.RoleDefinition getSelectedRoles(List<WebElement> tds);
protected abstract List<WebElement> getSelectedElements();
public void unSelect(String name, WebDriver driver) {
Iterator<WebElement> iterator = getSelectedElements().iterator();
while (iterator.hasNext()) {
WebElement realmRole = iterator.next();
List<WebElement> tds = realmRole.findElements(tagName("td"));
if (!(tds.isEmpty() || tds.get(0).getText().isEmpty())) {
if (tds.get(0).getText().equals(name)) {
getRemoveButton(tds).findElement(By.tagName("button")).click();
return;
}
}
}
}
protected abstract WebElement getRemoveButton(List<WebElement> tds);
public void setRequired(String name, RolePolicyRepresentation.RoleDefinition role) {
Iterator<WebElement> iterator = getSelectedElements().iterator();
while (iterator.hasNext()) {
WebElement realmRole = iterator.next();
List<WebElement> tds = realmRole.findElements(tagName("td"));
if (!(tds.isEmpty() || tds.get(0).getText().isEmpty())) {
if (tds.get(0).getText().equals(name)) {
WebElement required = getRequiredColumn(tds).findElement(By.tagName("input"));
if (required.isSelected() && role.isRequired()) {
return;
} else if (!required.isSelected() && !role.isRequired()) {
return;
}
required.click();
return;
}
}
}
}
protected abstract WebElement getRequiredColumn(List<WebElement> tds);
}
}

View file

@ -0,0 +1,41 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.page.clients.authorization.policy;
import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.representations.idm.authorization.TimePolicyRepresentation;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class TimePolicy implements PolicyTypeUI {
@Page
private TimePolicyForm form;
public TimePolicyForm form() {
return form;
}
public TimePolicyRepresentation toRepresentation() {
return form.toRepresentation();
}
public void update(TimePolicyRepresentation expected) {
form().populate(expected);
}
}

View file

@ -0,0 +1,129 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.page.clients.authorization.policy;
import org.keycloak.representations.idm.authorization.TimePolicyRepresentation;
import org.keycloak.representations.idm.authorization.Logic;
import org.keycloak.testsuite.page.Form;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.ui.Select;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class TimePolicyForm extends Form {
@FindBy(id = "name")
private WebElement name;
@FindBy(id = "description")
private WebElement description;
@FindBy(id = "logic")
private Select logic;
@FindBy(id = "notBefore")
private WebElement notBefore;
@FindBy(id = "notOnOrAfter")
private WebElement notOnOrAfter;
@FindBy(id = "dayMonth")
private WebElement dayMonth;
@FindBy(id = "month")
private WebElement month;
@FindBy(id = "year")
private WebElement year;
@FindBy(id = "hour")
private WebElement hour;
@FindBy(id = "minute")
private WebElement minute;
@FindBy(id = "dayMonthEnd")
private WebElement dayMonthEnd;
@FindBy(id = "monthEnd")
private WebElement monthEnd;
@FindBy(id = "yearEnd")
private WebElement yearEnd;
@FindBy(id = "hourEnd")
private WebElement hourEnd;
@FindBy(id = "minuteEnd")
private WebElement minuteEnd;
@FindBy(xpath = "//i[contains(@class,'pficon-delete')]")
private WebElement deleteButton;
@FindBy(xpath = ACTIVE_DIV_XPATH + "/button[text()='Delete']")
private WebElement confirmDelete;
public void populate(TimePolicyRepresentation expected) {
setInputValue(name, expected.getName());
setInputValue(description, expected.getDescription());
logic.selectByValue(expected.getLogic().name());
setInputValue(notBefore, expected.getNotBefore());
setInputValue(notOnOrAfter, expected.getNotOnOrAfter());
setInputValue(dayMonth, expected.getDayMonth());
setInputValue(dayMonthEnd, expected.getDayMonthEnd());
setInputValue(month, expected.getMonth());
setInputValue(monthEnd, expected.getMonthEnd());
setInputValue(year, expected.getYear());
setInputValue(yearEnd, expected.getYearEnd());
setInputValue(hour, expected.getHour());
setInputValue(hourEnd, expected.getHourEnd());
setInputValue(minute, expected.getMinute());
setInputValue(minuteEnd, expected.getMinuteEnd());
save();
}
public void delete() {
deleteButton.click();
confirmDelete.click();
}
public TimePolicyRepresentation toRepresentation() {
TimePolicyRepresentation representation = new TimePolicyRepresentation();
representation.setName(getInputValue(name));
representation.setDescription(getInputValue(description));
representation.setLogic(Logic.valueOf(logic.getFirstSelectedOption().getText().toUpperCase()));
representation.setDayMonth(getInputValue(dayMonth));
representation.setDayMonthEnd(getInputValue(dayMonthEnd));
representation.setMonth(getInputValue(month));
representation.setMonthEnd(getInputValue(monthEnd));
representation.setYear(getInputValue(year));
representation.setYearEnd(getInputValue(yearEnd));
representation.setHour(getInputValue(hour));
representation.setHourEnd(getInputValue(hourEnd));
representation.setMinute(getInputValue(minute));
representation.setMinuteEnd(getInputValue(minuteEnd));
representation.setNotBefore(getInputValue(notBefore));
representation.setNotOnOrAfter(getInputValue(notOnOrAfter));
return representation;
}
}

View file

@ -0,0 +1,41 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.page.clients.authorization.policy;
import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class UserPolicy implements PolicyTypeUI {
@Page
private UserPolicyForm form;
public UserPolicyForm form() {
return form;
}
public UserPolicyRepresentation toRepresentation() {
return form.toRepresentation();
}
public void update(UserPolicyRepresentation expected) {
form().populate(expected);
}
}

View file

@ -0,0 +1,190 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.page.clients.authorization.policy;
import static org.openqa.selenium.By.tagName;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.jboss.arquillian.graphene.fragment.Root;
import org.keycloak.representations.idm.authorization.Logic;
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
import org.keycloak.testsuite.page.Form;
import org.keycloak.testsuite.util.WaitUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.ui.Select;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class UserPolicyForm extends Form {
@FindBy(id = "name")
private WebElement name;
@FindBy(id = "description")
private WebElement description;
@FindBy(id = "logic")
private Select logic;
@FindBy(xpath = "//i[contains(@class,'pficon-delete')]")
private WebElement deleteButton;
@FindBy(id = "s2id_users")
private UsersInput usersInput;
@FindBy(xpath = ACTIVE_DIV_XPATH + "/button[text()='Delete']")
private WebElement confirmDelete;
public void populate(UserPolicyRepresentation expected) {
setInputValue(name, expected.getName());
setInputValue(description, expected.getDescription());
logic.selectByValue(expected.getLogic().name());
Set<String> users = expected.getUsers();
for (String user : users) {
usersInput.select(user, driver);
}
unSelect(users, usersInput.getSelected());
save();
}
private void unSelect(Set<String> users, Set<String> selection) {
for (String selected : selection) {
boolean isSelected = false;
for (String user : users) {
if (selected.equals(user)) {
isSelected = true;
break;
}
}
if (!isSelected) {
usersInput.unSelect(selected, driver);
}
}
}
public void delete() {
deleteButton.click();
confirmDelete.click();
}
public UserPolicyRepresentation toRepresentation() {
UserPolicyRepresentation representation = new UserPolicyRepresentation();
representation.setName(getInputValue(name));
representation.setDescription(getInputValue(description));
representation.setLogic(Logic.valueOf(logic.getFirstSelectedOption().getText().toUpperCase()));
representation.setUsers(usersInput.getSelected());
return representation;
}
public class UsersInput extends AbstractUserInput {
@Override
protected WebElement getRemoveButton(List<WebElement> tds) {
return tds.get(1);
}
@Override
protected List<WebElement> getSelectedElements() {
return root.findElements(By.xpath("(//table[@id='selected-users'])/tbody/tr"));
}
}
public abstract class AbstractUserInput {
@Root
protected WebElement root;
@FindBy(xpath = "//div[contains(@class,'select2-result-label')]")
private List<WebElement> result;
@FindBy(xpath = "//li[contains(@class,'select2-search-choice')]")
private List<WebElement> selection;
public void select(String roleId, WebDriver driver) {
root.click();
WaitUtils.pause(1000);
Actions actions = new Actions(driver);
actions.sendKeys(roleId).perform();
WaitUtils.pause(1000);
if (result.isEmpty()) {
actions.sendKeys(Keys.ESCAPE).perform();
return;
}
for (WebElement result : result) {
if (result.getText().equalsIgnoreCase(roleId)) {
result.click();
return;
}
}
}
public Set<String> getSelected() {
List<WebElement> users = getSelectedElements();
Set<String> values = new HashSet<>();
for (WebElement user : users) {
List<WebElement> tds = user.findElements(tagName("td"));
if (!(tds.isEmpty() || tds.get(0).getText().isEmpty())) {
values.add(tds.get(0).getText());
}
}
return values;
}
protected abstract List<WebElement> getSelectedElements();
public void unSelect(String name, WebDriver driver) {
Iterator<WebElement> iterator = getSelectedElements().iterator();
while (iterator.hasNext()) {
WebElement realmRole = iterator.next();
List<WebElement> tds = realmRole.findElements(tagName("td"));
if (!(tds.isEmpty() || tds.get(0).getText().isEmpty())) {
if (tds.get(0).getText().equals(name)) {
getRemoveButton(tds).findElement(By.tagName("button")).click();
return;
}
}
}
}
protected abstract WebElement getRemoveButton(List<WebElement> tds);
}
}

View file

@ -75,6 +75,8 @@ public abstract class AbstractAuthorizationSettingsTest extends AbstractClientTe
clientSettingsPage.tabs().authorization();
assertTrue(authorizationPage.isCurrent());
newClient.setId(found.getId());
return newClient;
}
}

View file

@ -0,0 +1,147 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.authorization;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import java.util.stream.Collectors;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.admin.client.resource.AuthorizationResource;
import org.keycloak.admin.client.resource.PoliciesResource;
import org.keycloak.admin.client.resource.RolePoliciesResource;
import org.keycloak.admin.client.resource.RolesResource;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.authorization.AggregatePolicyRepresentation;
import org.keycloak.representations.idm.authorization.Logic;
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation;
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
import org.keycloak.testsuite.console.page.clients.authorization.policy.AggregatePolicy;
import org.keycloak.testsuite.console.page.clients.authorization.policy.UserPolicy;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class AggregatePolicyManagementTest extends AbstractAuthorizationSettingsTest {
@Before
public void configureTest() {
super.configureTest();
RolesResource realmRoles = testRealmResource().roles();
realmRoles.create(new RoleRepresentation("Role A", "", false));
realmRoles.create(new RoleRepresentation("Role B", "", false));
RolePolicyRepresentation policyA = new RolePolicyRepresentation();
policyA.setName("Policy A");
policyA.addRole("Role A");
AuthorizationResource authorization = testRealmResource().clients().get(newClient.getId()).authorization();
PoliciesResource policies = authorization.policies();
RolePoliciesResource roles = policies.roles();
roles.create(policyA);
RolePolicyRepresentation policyB = new RolePolicyRepresentation();
policyB.setName("Policy B");
policyB.addRole("Role B");
roles.create(policyB);
UserPolicyRepresentation policyC = new UserPolicyRepresentation();
policyC.setName("Policy C");
policyC.addUser("test");
policies.users().create(policyC);
}
@Test
public void testUpdate() throws InterruptedException {
authorizationPage.navigateTo();
AggregatePolicyRepresentation expected = new AggregatePolicyRepresentation();
expected.setName("Test Aggregate Policy");
expected.setDescription("description");
expected.addPolicy("Policy A");
expected.addPolicy("Policy B");
expected.addPolicy("Policy C");
expected = createPolicy(expected);
String previousName = expected.getName();
expected.setName("Changed Test Aggregate Policy");
expected.setDescription("Changed description");
expected.setLogic(Logic.NEGATIVE);
expected.setPolicies(expected.getPolicies().stream().filter(policy -> !policy.equals("Policy B")).collect(Collectors.toSet()));
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().policies().update(previousName, expected);
assertAlertSuccess();
authorizationPage.navigateTo();
AggregatePolicy actual = authorizationPage.authorizationTabs().policies().name(expected.getName());
assertPolicy(expected, actual);
}
@Test
public void testDeletePolicy() throws InterruptedException {
authorizationPage.navigateTo();
AggregatePolicyRepresentation expected = new AggregatePolicyRepresentation();
expected.setName("Test Aggregate Policy");
expected.setDescription("description");
expected.addPolicy("Policy C");
expected = createPolicy(expected);
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().policies().delete(expected.getName());
assertAlertSuccess();
authorizationPage.navigateTo();
assertNull(authorizationPage.authorizationTabs().policies().policies().findByName(expected.getName()));
}
private AggregatePolicyRepresentation createPolicy(AggregatePolicyRepresentation expected) {
AggregatePolicy policy = authorizationPage.authorizationTabs().policies().create(expected);
assertAlertSuccess();
return assertPolicy(expected, policy);
}
private AggregatePolicyRepresentation assertPolicy(AggregatePolicyRepresentation expected, AggregatePolicy policy) {
AggregatePolicyRepresentation actual = policy.toRepresentation();
assertEquals(expected.getName(), actual.getName());
assertEquals(expected.getDescription(), actual.getDescription());
assertEquals(expected.getLogic(), actual.getLogic());
assertNotNull(actual.getPolicies());
assertEquals(expected.getPolicies().size(), actual.getPolicies().size());
assertEquals(0, actual.getPolicies().stream().filter(actualPolicy -> !expected.getPolicies().stream()
.filter(expectedPolicy -> actualPolicy.equals(expectedPolicy))
.findFirst().isPresent())
.count());
return actual;
}
}

View file

@ -0,0 +1,93 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.authorization;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import org.junit.Test;
import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
import org.keycloak.representations.idm.authorization.Logic;
import org.keycloak.testsuite.console.page.clients.authorization.policy.JSPolicy;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class JSPolicyManagementTest extends AbstractAuthorizationSettingsTest {
@Test
public void testUpdate() throws InterruptedException {
authorizationPage.navigateTo();
JSPolicyRepresentation expected = new JSPolicyRepresentation();
expected.setName("Test JS Policy");
expected.setDescription("description");
expected.setCode("$evaluation.grant();");
expected = createPolicy(expected);
String previousName = expected.getName();
expected.setName("Changed Test JS Policy");
expected.setDescription("Changed description");
expected.setLogic(Logic.NEGATIVE);
expected.setCode("$evaluation.deny();");
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().policies().update(previousName, expected);
assertAlertSuccess();
authorizationPage.navigateTo();
JSPolicy actual = authorizationPage.authorizationTabs().policies().name(expected.getName());
assertPolicy(expected, actual);
}
@Test
public void testDeletePolicy() throws InterruptedException {
authorizationPage.navigateTo();
JSPolicyRepresentation expected = new JSPolicyRepresentation();
expected.setName("Test JS Policy");
expected.setDescription("description");
expected.setCode("$evaluation.deny();");
expected = createPolicy(expected);
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().policies().delete(expected.getName());
assertAlertSuccess();
authorizationPage.navigateTo();
assertNull(authorizationPage.authorizationTabs().policies().policies().findByName(expected.getName()));
}
private JSPolicyRepresentation createPolicy(JSPolicyRepresentation expected) {
JSPolicy policy = authorizationPage.authorizationTabs().policies().create(expected);
assertAlertSuccess();
return assertPolicy(expected, policy);
}
private JSPolicyRepresentation assertPolicy(JSPolicyRepresentation expected, JSPolicy policy) {
JSPolicyRepresentation actual = policy.toRepresentation();
assertEquals(expected.getName(), actual.getName());
assertEquals(expected.getDescription(), actual.getDescription());
assertEquals(expected.getLogic(), actual.getLogic());
assertEquals(expected.getCode(), actual.getCode());
return actual;
}
}

View file

@ -0,0 +1,182 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.authorization;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import java.util.stream.Collectors;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.admin.client.resource.AuthorizationResource;
import org.keycloak.admin.client.resource.PoliciesResource;
import org.keycloak.admin.client.resource.ResourcesResource;
import org.keycloak.admin.client.resource.RolePoliciesResource;
import org.keycloak.admin.client.resource.RolesResource;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.authorization.DecisionStrategy;
import org.keycloak.representations.idm.authorization.Logic;
import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation;
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
import org.keycloak.testsuite.console.page.clients.authorization.permission.ResourcePermission;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class ResourcePermissionManagementTest extends AbstractAuthorizationSettingsTest {
@Before
public void configureTest() {
super.configureTest();
RolesResource realmRoles = testRealmResource().roles();
realmRoles.create(new RoleRepresentation("Role A", "", false));
realmRoles.create(new RoleRepresentation("Role B", "", false));
RolePolicyRepresentation policyA = new RolePolicyRepresentation();
policyA.setName("Policy A");
policyA.addRole("Role A");
AuthorizationResource authorization = testRealmResource().clients().get(newClient.getId()).authorization();
PoliciesResource policies = authorization.policies();
RolePoliciesResource roles = policies.roles();
roles.create(policyA);
RolePolicyRepresentation policyB = new RolePolicyRepresentation();
policyB.setName("Policy B");
policyB.addRole("Role B");
roles.create(policyB);
UserPolicyRepresentation policyC = new UserPolicyRepresentation();
policyC.setName("Policy C");
policyC.addUser("test");
policies.users().create(policyC);
ResourcesResource resources = authorization.resources();
resources.create(new ResourceRepresentation("Resource A"));
resources.create(new ResourceRepresentation("Resource B"));
}
@Test
public void testUpdateResource() throws InterruptedException {
authorizationPage.navigateTo();
ResourcePermissionRepresentation expected = new ResourcePermissionRepresentation();
expected.setName("Test Resource A Permission");
expected.setDescription("description");
expected.addResource("Resource A");
expected.addPolicy("Policy A");
expected.addPolicy("Policy B");
expected.addPolicy("Policy C");
expected = createPermission(expected);
String previousName = expected.getName();
expected.setName("Changed Test Resource A Permission");
expected.setDescription("Changed description");
expected.setDecisionStrategy(DecisionStrategy.CONSENSUS);
expected.getResources().clear();
expected.addResource("Resource B");
expected.setPolicies(expected.getPolicies().stream().filter(policy -> !policy.equals("Policy B")).collect(Collectors.toSet()));
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().permissions().update(previousName, expected);
assertAlertSuccess();
authorizationPage.navigateTo();
ResourcePermission actual = authorizationPage.authorizationTabs().permissions().name(expected.getName());
assertPolicy(expected, actual);
}
@Test
public void testUpdateResourceType() throws InterruptedException {
authorizationPage.navigateTo();
ResourcePermissionRepresentation expected = new ResourcePermissionRepresentation();
expected.setName("Test Resource B Permission");
expected.setDescription("description");
expected.setResourceType("test-resource-type");
expected.addPolicy("Policy A");
expected.addPolicy("Policy B");
expected.addPolicy("Policy C");
expected = createPermission(expected);
String previousName = expected.getName();
expected.setName("Changed Test Resource B Permission");
expected.setDescription("Changed description");
expected.setDecisionStrategy(DecisionStrategy.CONSENSUS);
expected.setResourceType("changed-resource-type");
expected.setPolicies(expected.getPolicies().stream().filter(policy -> !policy.equals("Policy B")).collect(Collectors.toSet()));
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().permissions().update(previousName, expected);
assertAlertSuccess();
authorizationPage.navigateTo();
ResourcePermission actual = authorizationPage.authorizationTabs().permissions().name(expected.getName());
assertPolicy(expected, actual);
}
@Test
public void testDeletePolicy() throws InterruptedException {
authorizationPage.navigateTo();
ResourcePermissionRepresentation expected = new ResourcePermissionRepresentation();
expected.setName("Test Delete Resource Permission");
expected.setDescription("description");
expected.addResource("Resource B");
expected.addPolicy("Policy C");
expected = createPermission(expected);
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().permissions().delete(expected.getName());
assertAlertSuccess();
authorizationPage.navigateTo();
assertNull(authorizationPage.authorizationTabs().permissions().permissions().findByName(expected.getName()));
}
private ResourcePermissionRepresentation createPermission(ResourcePermissionRepresentation expected) {
ResourcePermission policy = authorizationPage.authorizationTabs().permissions().create(expected);
assertAlertSuccess();
return assertPolicy(expected, policy);
}
private ResourcePermissionRepresentation assertPolicy(ResourcePermissionRepresentation expected, ResourcePermission policy) {
ResourcePermissionRepresentation actual = policy.toRepresentation();
assertEquals(expected.getName(), actual.getName());
assertEquals(expected.getDescription(), actual.getDescription());
assertEquals(expected.getLogic(), actual.getLogic());
return actual;
}
}

View file

@ -0,0 +1,232 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.authorization;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.admin.client.resource.RolesResource;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.authorization.Logic;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation;
import org.keycloak.testsuite.console.page.clients.authorization.policy.RolePolicy;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class RolePolicyManagementTest extends AbstractAuthorizationSettingsTest {
@Before
public void configureTest() {
super.configureTest();
RolesResource realmRoles = testRealmResource().roles();
realmRoles.create(new RoleRepresentation("Realm Role A", "", false));
realmRoles.create(new RoleRepresentation("Realm Role B", "", false));
realmRoles.create(new RoleRepresentation("Realm Role C", "", false));
RolesResource clientRoles = testRealmResource().clients().get(newClient.getId()).roles();
clientRoles.create(new RoleRepresentation("Client Role A", "", false));
clientRoles.create(new RoleRepresentation("Client Role B", "", false));
clientRoles.create(new RoleRepresentation("Client Role C", "", false));
}
@Test
public void testUpdateRealmRoles() throws InterruptedException {
authorizationPage.navigateTo();
RolePolicyRepresentation expected = new RolePolicyRepresentation();
expected.setName("Test Realm Role Policy");
expected.setDescription("description");
expected.addRole("Realm Role A");
expected.addRole("Realm Role B");
expected.addRole("Realm Role C");
expected = createPolicy(expected);
String previousName = expected.getName();
expected.setName("Changed Test Realm Role Policy");
expected.setDescription("Changed description");
expected.setLogic(Logic.NEGATIVE);
expected.setRoles(expected.getRoles().stream().filter(roleDefinition -> !roleDefinition.getId().equals("Realm Role B")).collect(Collectors.toSet()));
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().policies().update(previousName, expected);
assertAlertSuccess();
authorizationPage.navigateTo();
RolePolicy actual = authorizationPage.authorizationTabs().policies().name(expected.getName());
expected = assertPolicy(expected, actual);
expected.getRoles().iterator().next().setRequired(true);
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().policies().update(expected.getName(), expected);
assertAlertSuccess();
expected = assertPolicy(expected, actual);
expected.getRoles().clear();
expected.addRole("Realm Role B", true);
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().policies().update(expected.getName(), expected);
assertAlertSuccess();
assertPolicy(expected, actual);
}
@Test
public void testUpdateClientRoles() throws InterruptedException {
authorizationPage.navigateTo();
RolePolicyRepresentation expected = new RolePolicyRepresentation();
expected.setName("Test Client Role Policy");
expected.setDescription("description");
String clientId = newClient.getClientId();
expected.addClientRole(clientId, "Client Role A");
expected.addClientRole(clientId, "Client Role B");
expected.addClientRole(clientId, "Client Role C");
expected = createPolicy(expected);
String previousName = expected.getName();
expected.setName("Changed Test Client Role Policy");
expected.setDescription("Changed description");
expected.setRoles(expected.getRoles().stream().filter(roleDefinition -> !roleDefinition.getId().contains("Client Role B")).collect(Collectors.toSet()));
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().policies().update(previousName, expected);
assertAlertSuccess();
authorizationPage.navigateTo();
RolePolicy actual = authorizationPage.authorizationTabs().policies().name(expected.getName());
expected = assertPolicy(expected, actual);
expected.getRoles().iterator().next().setRequired(true);
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().policies().update(expected.getName(), expected);
assertAlertSuccess();
expected = assertPolicy(expected, actual);
expected.getRoles().clear();
expected.addClientRole(clientId, "Client Role B", true);
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().policies().update(expected.getName(), expected);
assertAlertSuccess();
assertPolicy(expected, actual);
}
@Test
public void testRealmAndClientRoles() throws InterruptedException {
authorizationPage.navigateTo();
RolePolicyRepresentation expected = new RolePolicyRepresentation();
expected.setName("Test Realm And Client Role Policy");
expected.setDescription("description");
String clientId = newClient.getClientId();
expected.addRole("Realm Role A");
expected.addRole("Realm Role C");
expected.addClientRole(clientId, "Client Role A");
expected.addClientRole(clientId, "Client Role B");
expected.addClientRole(clientId, "Client Role C");
expected = createPolicy(expected);
expected.setRoles(expected.getRoles().stream().filter(roleDefinition -> !roleDefinition.getId().contains("Client Role B") && !roleDefinition.getId().contains("Realm Role A")).collect(Collectors.toSet()));
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().policies().update(expected.getName(), expected);
assertAlertSuccess();
authorizationPage.navigateTo();
RolePolicy actual = authorizationPage.authorizationTabs().policies().name(expected.getName());
expected = assertPolicy(expected, actual);
expected.getRoles().forEach(roleDefinition -> {
if (roleDefinition.getId().equals("Realm Role C")) {
roleDefinition.setRequired(true);
}
});
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().policies().update(expected.getName(), expected);
assertAlertSuccess();
expected = assertPolicy(expected, actual);
expected.getRoles().clear();
expected.addClientRole(clientId, "Client Role B", true);
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().policies().update(expected.getName(), expected);
assertAlertSuccess();
assertPolicy(expected, actual);
}
@Test
public void testDeletePolicy() throws InterruptedException {
authorizationPage.navigateTo();
RolePolicyRepresentation expected = new RolePolicyRepresentation();
expected.setName("Test Realm Role Policy");
expected.setDescription("description");
expected.addRole("Realm Role A");
expected.addRole("Realm Role B");
expected.addRole("Realm Role C");
expected = createPolicy(expected);
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().policies().delete(expected.getName());
assertAlertSuccess();
authorizationPage.navigateTo();
assertNull(authorizationPage.authorizationTabs().policies().policies().findByName(expected.getName()));
}
private RolePolicyRepresentation createPolicy(RolePolicyRepresentation expected) {
RolePolicy policy = authorizationPage.authorizationTabs().policies().create(expected);
assertAlertSuccess();
return assertPolicy(expected, policy);
}
private RolePolicyRepresentation assertPolicy(RolePolicyRepresentation expected, RolePolicy policy) {
RolePolicyRepresentation actual = policy.toRepresentation();
assertEquals(expected.getName(), actual.getName());
assertEquals(expected.getDescription(), actual.getDescription());
assertEquals(expected.getLogic(), actual.getLogic());
assertNotNull(actual.getRoles());
assertEquals(expected.getRoles().size(), actual.getRoles().size());
assertEquals(0, actual.getRoles().stream().filter(actualDefinition -> !expected.getRoles().stream()
.filter(roleDefinition -> actualDefinition.getId().contains(roleDefinition.getId()) && actualDefinition.isRequired() == roleDefinition.isRequired())
.findFirst().isPresent())
.count());
return actual;
}
}

View file

@ -0,0 +1,127 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.authorization;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import org.junit.Test;
import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
import org.keycloak.representations.idm.authorization.Logic;
import org.keycloak.representations.idm.authorization.TimePolicyRepresentation;
import org.keycloak.testsuite.console.page.clients.authorization.policy.JSPolicy;
import org.keycloak.testsuite.console.page.clients.authorization.policy.TimePolicy;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class TimePolicyManagementTest extends AbstractAuthorizationSettingsTest {
@Test
public void testUpdate() throws InterruptedException {
authorizationPage.navigateTo();
TimePolicyRepresentation expected = new TimePolicyRepresentation();
expected.setName("Test Time Policy");
expected.setDescription("description");
expected.setNotBefore("2017-01-01 00:00:00");
expected.setNotBefore("2018-01-01 00:00:00");
expected.setDayMonth("1");
expected.setDayMonthEnd("2");
expected.setMonth("3");
expected.setMonthEnd("4");
expected.setYear("5");
expected.setYearEnd("6");
expected.setHour("7");
expected.setHourEnd("8");
expected.setMinute("9");
expected.setMinuteEnd("10");
expected = createPolicy(expected);
String previousName = expected.getName();
expected.setName("Changed Test Time Policy");
expected.setDescription("Changed description");
expected.setLogic(Logic.NEGATIVE);
expected.setNotBefore("2018-01-01 00:00:00");
expected.setNotBefore("2019-01-01 00:00:00");
expected.setDayMonth("23");
expected.setDayMonthEnd("25");
expected.setMonth("11");
expected.setMonthEnd("12");
expected.setYear("2020");
expected.setYearEnd("2021");
expected.setHour("17");
expected.setHourEnd("18");
expected.setMinute("19");
expected.setMinuteEnd("20");
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().policies().update(previousName, expected);
assertAlertSuccess();
authorizationPage.navigateTo();
TimePolicy actual = authorizationPage.authorizationTabs().policies().name(expected.getName());
assertPolicy(expected, actual);
}
@Test
public void testDeletePolicy() throws InterruptedException {
authorizationPage.navigateTo();
TimePolicyRepresentation expected = new TimePolicyRepresentation();
expected.setName("Test Time Policy");
expected.setDescription("description");
expected.setNotBefore("2017-01-01 00:00:00");
expected.setNotBefore("2018-01-01 00:00:00");
expected.setDayMonth("1");
expected.setDayMonthEnd("2");
expected.setMonth("3");
expected.setMonthEnd("4");
expected.setYear("5");
expected.setYearEnd("6");
expected.setHour("7");
expected.setHourEnd("8");
expected.setMinute("9");
expected.setMinuteEnd("10");
expected = createPolicy(expected);
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().policies().delete(expected.getName());
assertAlertSuccess();
authorizationPage.navigateTo();
assertNull(authorizationPage.authorizationTabs().policies().policies().findByName(expected.getName()));
}
private TimePolicyRepresentation createPolicy(TimePolicyRepresentation expected) {
TimePolicy policy = authorizationPage.authorizationTabs().policies().create(expected);
assertAlertSuccess();
return assertPolicy(expected, policy);
}
private TimePolicyRepresentation assertPolicy(TimePolicyRepresentation expected, TimePolicy policy) {
TimePolicyRepresentation actual = policy.toRepresentation();
assertEquals(expected.getName(), actual.getName());
assertEquals(expected.getDescription(), actual.getDescription());
assertEquals(expected.getLogic(), actual.getLogic());
return actual;
}
}

View file

@ -0,0 +1,116 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.authorization;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import java.util.stream.Collectors;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.representations.idm.authorization.Logic;
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
import org.keycloak.testsuite.console.page.clients.authorization.policy.UserPolicy;
import org.keycloak.testsuite.util.UserBuilder;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class UserPolicyManagementTest extends AbstractAuthorizationSettingsTest {
@Before
public void configureTest() {
super.configureTest();
UsersResource users = testRealmResource().users();
users.create(UserBuilder.create().username("user a").build());
users.create(UserBuilder.create().username("user b").build());
users.create(UserBuilder.create().username("user c").build());
}
@Test
public void testUpdate() throws InterruptedException {
authorizationPage.navigateTo();
UserPolicyRepresentation expected = new UserPolicyRepresentation();
expected.setName("Test User Policy");
expected.setDescription("description");
expected.addUser("user a");
expected.addUser("user b");
expected.addUser("user c");
expected = createPolicy(expected);
String previousName = expected.getName();
expected.setName("Changed Test User Policy");
expected.setDescription("Changed description");
expected.setLogic(Logic.NEGATIVE);
expected.setUsers(expected.getUsers().stream().filter(user -> !user.equals("user b")).collect(Collectors.toSet()));
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().policies().update(previousName, expected);
assertAlertSuccess();
authorizationPage.navigateTo();
UserPolicy actual = authorizationPage.authorizationTabs().policies().name(expected.getName());
assertPolicy(expected, actual);
}
@Test
public void testDeletePolicy() throws InterruptedException {
authorizationPage.navigateTo();
UserPolicyRepresentation expected = new UserPolicyRepresentation();
expected.setName("Test User Policy");
expected.setDescription("description");
expected.addUser("user c");
expected = createPolicy(expected);
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().policies().delete(expected.getName());
assertAlertSuccess();
authorizationPage.navigateTo();
assertNull(authorizationPage.authorizationTabs().policies().policies().findByName(expected.getName()));
}
private UserPolicyRepresentation createPolicy(UserPolicyRepresentation expected) {
UserPolicy policy = authorizationPage.authorizationTabs().policies().create(expected);
assertAlertSuccess();
return assertPolicy(expected, policy);
}
private UserPolicyRepresentation assertPolicy(UserPolicyRepresentation expected, UserPolicy policy) {
UserPolicyRepresentation actual = policy.toRepresentation();
assertEquals(expected.getName(), actual.getName());
assertEquals(expected.getDescription(), actual.getDescription());
assertEquals(expected.getLogic(), actual.getLogic());
assertNotNull(actual.getUsers());
assertEquals(expected.getUsers().size(), actual.getUsers().size());
assertEquals(0, actual.getUsers().stream().filter(actualUser -> !expected.getUsers().stream()
.filter(expectedUser -> actualUser.equals(expectedUser))
.findFirst().isPresent())
.count());
return actual;
}
}

View file

@ -1340,6 +1340,8 @@ module.controller('ResourceServerPolicyUserDetailCtrl', function($scope, $route,
$scope.$watch('selectedUsers', function() {
if (!angular.equals($scope.selectedUsers, selectedUsers)) {
$scope.changed = true;
} else {
$scope.changed = false;
}
}, true);
},
@ -1413,8 +1415,11 @@ module.controller('ResourceServerPolicyClientDetailCtrl', function($scope, $rout
$scope.selectedClients.push(client);
}
$scope.removeFromList = function(list, index) {
list.splice(index, 1);
$scope.removeFromList = function(client) {
var index = $scope.selectedClients.indexOf(client);
if (index != -1) {
$scope.selectedClients.splice(index, 1);
}
}
},
@ -1435,6 +1440,8 @@ module.controller('ResourceServerPolicyClientDetailCtrl', function($scope, $rout
$scope.$watch('selectedClients', function() {
if (!angular.equals($scope.selectedClients, selectedClients)) {
$scope.changed = true;
} else {
$scope.changed = false;
}
}, true);
},
@ -1449,6 +1456,16 @@ module.controller('ResourceServerPolicyClientDetailCtrl', function($scope, $rout
$scope.policy.config.clients = JSON.stringify(clients);
},
onInitCreate : function() {
var selectedClients = [];
$scope.$watch('selectedClients', function() {
if (!angular.equals($scope.selectedClients, selectedClients)) {
$scope.changed = true;
}
}, true);
},
onCreate : function() {
var clients = [];
@ -1572,6 +1589,8 @@ module.controller('ResourceServerPolicyRoleDetailCtrl', function($scope, $route,
$scope.$watch('selectedRoles', function() {
if (!angular.equals($scope.selectedRoles, selectedRoles)) {
$scope.changed = true;
} else {
$scope.changed = false;
}
}, true);
},
@ -1589,6 +1608,7 @@ module.controller('ResourceServerPolicyRoleDetailCtrl', function($scope, $route,
}
$scope.policy.roles = roles;
delete $scope.policy.config;
},
onCreate : function() {
@ -1604,6 +1624,7 @@ module.controller('ResourceServerPolicyRoleDetailCtrl', function($scope, $route,
}
$scope.policy.roles = roles;
delete $scope.policy.config;
}
}, realm, client, $scope);
@ -1636,7 +1657,6 @@ module.controller('ResourceServerPolicyJSDetailCtrl', function($scope, $route, $
$scope.initEditor = function(editor){
editor.$blockScrolling = Infinity;
var session = editor.getSession();
session.setMode('ace/mode/javascript');
};
},
@ -1646,15 +1666,14 @@ module.controller('ResourceServerPolicyJSDetailCtrl', function($scope, $route, $
},
onUpdate : function() {
delete $scope.policy.config;
},
onInitCreate : function(newPolicy) {
newPolicy.config = {};
},
onCreate : function() {
delete $scope.policy.config;
}
}, realm, client, $scope);
});
@ -1669,60 +1688,63 @@ module.controller('ResourceServerPolicyTimeDetailCtrl', function($scope, $route,
},
onInitUpdate : function(policy) {
if (policy.config.dayMonth) {
policy.config.dayMonth = parseInt(policy.config.dayMonth);
if (policy.dayMonth) {
policy.dayMonth = parseInt(policy.dayMonth);
}
if (policy.config.dayMonthEnd) {
policy.config.dayMonthEnd = parseInt(policy.config.dayMonthEnd);
if (policy.dayMonthEnd) {
policy.dayMonthEnd = parseInt(policy.dayMonthEnd);
}
if (policy.config.month) {
policy.config.month = parseInt(policy.config.month);
if (policy.month) {
policy.month = parseInt(policy.month);
}
if (policy.config.monthEnd) {
policy.config.monthEnd = parseInt(policy.config.monthEnd);
if (policy.monthEnd) {
policy.monthEnd = parseInt(policy.monthEnd);
}
if (policy.config.year) {
policy.config.year = parseInt(policy.config.year);
if (policy.year) {
policy.year = parseInt(policy.year);
}
if (policy.config.yearEnd) {
policy.config.yearEnd = parseInt(policy.config.yearEnd);
if (policy.yearEnd) {
policy.yearEnd = parseInt(policy.yearEnd);
}
if (policy.config.hour) {
policy.config.hour = parseInt(policy.config.hour);
if (policy.hour) {
policy.hour = parseInt(policy.hour);
}
if (policy.config.hourEnd) {
policy.config.hourEnd = parseInt(policy.config.hourEnd);
if (policy.hourEnd) {
policy.hourEnd = parseInt(policy.hourEnd);
}
if (policy.config.minute) {
policy.config.minute = parseInt(policy.config.minute);
if (policy.minute) {
policy.minute = parseInt(policy.minute);
}
if (policy.config.minuteEnd) {
policy.config.minuteEnd = parseInt(policy.config.minuteEnd);
if (policy.minuteEnd) {
policy.minuteEnd = parseInt(policy.minuteEnd);
}
},
onUpdate : function() {
delete $scope.policy.config;
},
onInitCreate : function(newPolicy) {
newPolicy.config.expirationTime = 1;
newPolicy.config.expirationUnit = 'Minutes';
},
onCreate : function() {
delete $scope.policy.config;
}
}, realm, client, $scope);
$scope.isRequired = function () {
var policy = $scope.policy;
if (policy.config.noa || policy.config.nbf
|| policy.config.dayMonth
|| policy.config.month
|| policy.config.year
|| policy.config.hour
|| policy.config.minute) {
if (!policy) {
return true;
}
if (policy.notOnOrAfter || policy.notBefore
|| policy.dayMonth
|| policy.month
|| policy.year
|| policy.hour
|| policy.minute) {
return false;
}
return true;
@ -1767,42 +1789,49 @@ module.controller('ResourceServerPolicyAggregateDetailCtrl', function($scope, $r
},
onInitUpdate : function(policy) {
policy.config.applyPolicies = [];
ResourceServerPolicy.associatedPolicies({
realm : $route.current.params.realm,
client : client.id,
id : policy.id
}, function(policies) {
$scope.selectedPolicies = [];
for (i = 0; i < policies.length; i++) {
policies[i].text = policies[i].name;
$scope.policy.config.applyPolicies.push(policies[i]);
$scope.selectedPolicies.push(policies[i]);
}
var copy = angular.copy($scope.selectedPolicies);
$scope.$watch('selectedPolicies', function() {
if (!angular.equals($scope.selectedPolicies, copy)) {
$scope.changed = true;
}
}, true);
});
},
onUpdate : function() {
var policies = [];
for (i = 0; i < $scope.policy.config.applyPolicies.length; i++) {
policies.push($scope.policy.config.applyPolicies[i].id);
for (i = 0; i < $scope.selectedPolicies.length; i++) {
policies.push($scope.selectedPolicies[i].id);
}
$scope.policy.config.applyPolicies = JSON.stringify(policies);
$scope.policy.policies = policies;
delete $scope.policy.config;
},
onInitCreate : function(newPolicy) {
newPolicy.config = {};
newPolicy.decisionStrategy = 'UNANIMOUS';
},
onCreate : function() {
var policies = [];
for (i = 0; i < $scope.policy.config.applyPolicies.length; i++) {
policies.push($scope.policy.config.applyPolicies[i].id);
for (i = 0; i < $scope.selectedPolicies.length; i++) {
policies.push($scope.selectedPolicies[i].id);
}
$scope.policy.config.applyPolicies = JSON.stringify(policies);
$scope.policy.policies = policies;
delete $scope.policy.config;
}
}, realm, client, $scope);
});

View file

@ -1111,6 +1111,12 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, templates,
} else if ($scope.clientEdit.bearerOnly) {
$scope.clientEdit.serviceAccountsEnabled = false;
}
if ($scope.client.authorizationServicesEnabled && !$scope.clientEdit.authorizationServicesEnabled) {
Dialog.confirm("Disable Authorization Settings", "Are you sure you want to disable authorization ? Once you save your changes, all authorization settings associated with this client will be removed. This operation can not be reverted.", function () {
}, function () {
$scope.clientEdit.authorizationServicesEnabled = true;
});
}
}
$scope.$watch('clientEdit', function() {
@ -1240,15 +1246,6 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, templates,
$scope.cancel = function() {
$location.url("/realms/" + realm.realm + "/clients");
};
$scope.onAuthorizationSettingsChange = function () {
if ($scope.client.authorizationServicesEnabled && !$scope.clientEdit.authorizationServicesEnabled) {
Dialog.confirm("Disable Authorization Settings", "Are you sure you want to disable authorization ? Once you save your changes, all authorization settings associated with this client will be removed. This operation can not be reverted.", function () {
}, function () {
$scope.clientEdit.authorizationServicesEnabled = true;
});
}
}
});
module.controller('CreateClientCtrl', function($scope, realm, client, templates, $route, serverInfo, Client, ClientDescriptionConverter, $location, $modal, Dialog, Notifications) {

View file

@ -36,36 +36,36 @@
<kc-tooltip>{{:: 'authz-permission-resource-apply-to-resource-type.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group clearfix" data-ng-hide="applyToResourceTypeFlag">
<label class="col-md-2 control-label" for="reqActions">{{:: 'authz-resources' | translate}} <span class="required">*</span></label>
<label class="col-md-2 control-label" for="resources">{{:: 'authz-resources' | translate}} <span class="required">*</span></label>
<div class="col-md-6">
<input type="hidden" ui-select2="resourcesUiSelect" id="reqActions" data-ng-model="selectedResource" data-placeholder="{{:: 'authz-select-resource' | translate}}..." data-ng-required="!applyToResourceTypeFlag"/>
<input type="hidden" ui-select2="resourcesUiSelect" id="resources" data-ng-model="selectedResource" data-placeholder="{{:: 'authz-select-resource' | translate}}..." data-ng-required="!applyToResourceTypeFlag"/>
</div>
<kc-tooltip>{{:: 'authz-permission-resource-resource.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group clearfix" data-ng-show="applyToResourceTypeFlag">
<label class="col-md-2 control-label" for="policy.resourceType">{{:: 'authz-resource-type' | translate}} <span class="required">*</span></label>
<label class="col-md-2 control-label" for="resourceType">{{:: 'authz-resource-type' | translate}} <span class="required">*</span></label>
<div class="col-md-6">
<input class="form-control" type="text" id="policy.resourceType" name="policy.resourceType" data-ng-model="policy.resourceType" data-ng-required="applyToResourceTypeFlag">
<input class="form-control" type="text" id="resourceType" name="policy.resourceType" data-ng-model="policy.resourceType" data-ng-required="applyToResourceTypeFlag">
</div>
<kc-tooltip>{{:: 'authz-permission-resource-type.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="reqActions">{{:: 'authz-policy-apply-policy' | translate}} <span class="required">*</span></label>
<label class="col-md-2 control-label" for="policies">{{:: 'authz-policy-apply-policy' | translate}} <span class="required">*</span></label>
<div class="col-md-6">
<input type="hidden" ui-select2="policiesUiSelect" id="reqActions" data-ng-model="selectedPolicies" data-placeholder="{{:: 'authz-select-a-policy' | translate}}..." multiple required />
<input type="hidden" ui-select2="policiesUiSelect" id="policies" data-ng-model="selectedPolicies" data-placeholder="{{:: 'authz-select-a-policy' | translate}}..." multiple required />
</div>
<kc-tooltip>{{:: 'authz-policy-apply-policy.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="policy.decisionStrategy">{{:: 'authz-policy-decision-strategy' | translate}}</label>
<label class="col-md-2 control-label" for="decisionStrategy">{{:: 'authz-policy-decision-strategy' | translate}}</label>
<div class="col-sm-2">
<select class="form-control" id="policy.decisionStrategy"
<select class="form-control" id="decisionStrategy"
data-ng-model="policy.decisionStrategy"
ng-change="selectDecisionStrategy()">
<option value="UNANIMOUS">{{:: 'authz-policy-decision-strategy-unanimous' | translate}}</option>

View file

@ -50,6 +50,7 @@
<div class="pull-right">
<select class="form-control" ng-model="policyType"
ng-options="p.name for p in policyProviders track by p.type"
id="create-permission"
data-ng-change="addPolicy(policyType);">
<option value="" disabled selected>{{:: 'authz-create-permission' | translate}}...</option>
</select>

View file

@ -31,10 +31,10 @@
<kc-tooltip>{{:: 'authz-policy-description.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="reqActions">{{:: 'authz-policy-apply-policy' | translate}} <span class="required">*</span></label>
<label class="col-md-2 control-label" for="policies">{{:: 'authz-policy-apply-policy' | translate}} <span class="required">*</span></label>
<div class="col-md-6">
<input type="hidden" ui-select2="policiesUiSelect" id="reqActions" data-ng-model="policy.config.applyPolicies" data-placeholder="{{:: 'authz-select-a-policy' | translate}}..." multiple required />
<input type="hidden" ui-select2="policiesUiSelect" id="policies" data-ng-model="selectedPolicies" data-placeholder="{{:: 'authz-select-a-policy' | translate}}..." multiple required />
</div>
<kc-tooltip>{{:: 'authz-policy-apply-policy.tooltip' | translate}}</kc-tooltip>
</div>
@ -54,10 +54,10 @@
<kc-tooltip>{{:: 'authz-policy-decision-strategy.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="policy.logic">{{:: 'authz-policy-logic' | translate}}</label>
<label class="col-md-2 control-label" for="logic">{{:: 'authz-policy-logic' | translate}}</label>
<div class="col-sm-1">
<select class="form-control" id="policy.logic"
<select class="form-control" id="logic" name="logic"
data-ng-model="policy.logic">
<option value="POSITIVE">{{:: 'authz-policy-logic-positive' | translate}}</option>
<option value="NEGATIVE">{{:: 'authz-policy-logic-negative' | translate}}</option>

View file

@ -53,7 +53,7 @@
<tr ng-repeat="client in selectedClients | orderBy:'clientId'">
<td>{{client.clientId}}</td>
<td class="kc-action-cell">
<button class="btn btn-default btn-block btn-sm" ng-click="removeFromList(selectedClients, $index);">{{:: 'remove' | translate}}</button>
<button class="btn btn-default btn-block btn-sm" ng-click="removeFromList(client);">{{:: 'remove' | translate}}</button>
</td>
</tr>
<tr data-ng-show="!selectedClients.length">

View file

@ -33,17 +33,17 @@
<kc-tooltip>{{:: 'authz-policy-description.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="description">{{:: 'authz-policy-js-code' | translate}} </label>
<label class="col-md-2 control-label" for="code">{{:: 'authz-policy-js-code' | translate}} </label>
<div class="col-sm-6">
<div ui-ace="{ onLoad : initEditor }" data-ng-model="policy.config.code"></div>
<div ui-ace="{ onLoad : initEditor }" id="code" data-ng-model="policy.code"></div>
</div>
<kc-tooltip>{{:: 'authz-policy-js-code.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="policy.logic">{{:: 'authz-policy-logic' | translate}}</label>
<label class="col-md-2 control-label" for="logic">{{:: 'authz-policy-logic' | translate}}</label>
<div class="col-sm-1">
<select class="form-control" id="policy.logic"
<select class="form-control" id="logic"
data-ng-model="policy.logic">
<option value="POSITIVE">{{:: 'authz-policy-logic-positive' | translate}}</option>
<option value="NEGATIVE">{{:: 'authz-policy-logic-negative' | translate}}</option>

View file

@ -63,7 +63,7 @@
<div class="form-group clearfix" style="margin-top: -15px;">
<label class="col-md-2 control-label"></label>
<div class="col-sm-4" data-ng-show="hasRealmRole()">
<table class="table table-striped table-bordered">
<table class="table table-striped table-bordered" id="selected-realm-roles">
<thead>
<tr>
<th class="col-sm-5">{{:: 'name' | translate}}</th>
@ -114,7 +114,7 @@
<div class="form-group clearfix" style="margin-top: -15px;">
<label class="col-md-2 control-label"></label>
<div class="col-sm-4" data-ng-show="hasClientRole()">
<table class="table table-striped table-bordered">
<table class="table table-striped table-bordered" id="selected-client-roles">
<thead>
<tr>
<th class="col-sm-5">{{:: 'name' | translate}}</th>
@ -140,10 +140,10 @@
</div>
</div>
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="policy.logic">{{:: 'authz-policy-logic' | translate}}</label>
<label class="col-md-2 control-label" for="logic">{{:: 'authz-policy-logic' | translate}}</label>
<div class="col-sm-1">
<select class="form-control" id="policy.logic"
<select class="form-control" id="logic"
data-ng-model="policy.logic">
<option value="POSITIVE">{{:: 'authz-policy-logic-positive' | translate}}</option>
<option value="NEGATIVE">{{:: 'authz-policy-logic-negative' | translate}}</option>

View file

@ -34,66 +34,66 @@
<kc-tooltip>{{:: 'authz-policy-description.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="policy.config.nbf">{{:: 'not-before' | translate}}</label>
<label class="col-md-2 control-label" for="notBefore">{{:: 'not-before' | translate}}</label>
<div class="col-md-6 time-selector">
<input class="form-control" style="width: 150px" type="text" id="policy.config.nbf" name="notBefore" data-ng-model="policy.config.nbf" placeholder="yyyy-MM-dd hh:mm:ss" data-ng-required="isRequired()">
<input class="form-control" style="width: 150px" type="text" id="notBefore" name="notBefore" data-ng-model="policy.notBefore" placeholder="yyyy-MM-dd hh:mm:ss" data-ng-required="isRequired()">
</div>
<kc-tooltip>{{:: 'authz-policy-time-not-before.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="policy.config.noa">{{:: 'authz-policy-time-not-on-after' | translate}}</label>
<label class="col-md-2 control-label" for="notOnOrAfter">{{:: 'authz-policy-time-not-on-after' | translate}}</label>
<div class="col-md-6 time-selector">
<input class="form-control" style="width: 150px" type="text" id="policy.config.noa" name="policy.config.noa" data-ng-model="policy.config.noa" placeholder="yyyy-MM-dd hh:mm:ss" data-ng-required="isRequired()">
<input class="form-control" style="width: 150px" type="text" id="notOnOrAfter" name="notOnOrAfter" data-ng-model="policy.notOnOrAfter" placeholder="yyyy-MM-dd hh:mm:ss" data-ng-required="isRequired()">
</div>
<kc-tooltip>{{:: 'authz-policy-time-not-on-after.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="policy.config.noa">{{:: 'authz-policy-time-day-month' | translate}}</label>
<label class="col-md-2 control-label" for="dayMonth">{{:: 'authz-policy-time-day-month' | translate}}</label>
<div class="col-md-6 time-selector">
<input class="form-control" type="number" min="1" max="31" data-ng-model="policy.config.dayMonth" id="dayMonth" name="dayMonth" data-ng-required="isRequired()"/>&nbsp;&nbsp;to&nbsp;&nbsp;<input class="form-control" type="number" min="{{policy.config.dayMonth}}" max="31" data-ng-model="policy.config.dayMonthEnd" id="dayMonthEnd" name="dayMonthEnd"/>
<input class="form-control" type="number" min="1" max="31" data-ng-model="policy.dayMonth" id="dayMonth" name="dayMonth" data-ng-required="isRequired()"/>&nbsp;&nbsp;to&nbsp;&nbsp;<input class="form-control" type="number" min="{{policy.dayMonth}}" max="31" data-ng-model="policy.dayMonthEnd" id="dayMonthEnd" name="dayMonthEnd"/>
</div>
<kc-tooltip>{{:: 'authz-policy-time-day-month.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="policy.config.noa">{{:: 'authz-policy-time-month' | translate}}</label>
<label class="col-md-2 control-label" for="month">{{:: 'authz-policy-time-month' | translate}}</label>
<div class="col-md-6 time-selector">
<input class="form-control" type="number" min="1" max="12" data-ng-model="policy.config.month" id="month" name="month" data-ng-required="isRequired()"/>&nbsp;&nbsp;to&nbsp;&nbsp;<input class="form-control" type="number" min="{{policy.config.month}}" max="12" data-ng-model="policy.config.monthEnd" id="monthEnd" name="monthEnd"/>
<input class="form-control" type="number" min="1" max="12" data-ng-model="policy.month" id="month" name="month" data-ng-required="isRequired()"/>&nbsp;&nbsp;to&nbsp;&nbsp;<input class="form-control" type="number" min="{{policy.month}}" max="12" data-ng-model="policy.monthEnd" id="monthEnd" name="monthEnd"/>
</div>
<kc-tooltip>{{:: 'authz-policy-time-month.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="policy.config.noa">{{:: 'authz-policy-time-year' | translate}}</label>
<label class="col-md-2 control-label" for="year">{{:: 'authz-policy-time-year' | translate}}</label>
<div class="col-md-6 time-selector">
<input class="form-control" type="number" min="2016" max="2050" data-ng-model="policy.config.year" id="year" name="year" data-ng-required="isRequired()"/>&nbsp;&nbsp;to&nbsp;&nbsp;<input class="form-control" type="number" min="{{policy.config.year}}" max="2050" data-ng-model="policy.config.yearEnd" id="yearEnd" name="yearEnd"/>
<input class="form-control" type="number" data-ng-model="policy.year" id="year" name="year" data-ng-required="isRequired()"/>&nbsp;&nbsp;to&nbsp;&nbsp;<input class="form-control" type="number" min="{{policy.year}}" max="2050" data-ng-model="policy.yearEnd" id="yearEnd" name="yearEnd"/>
</div>
<kc-tooltip>{{:: 'authz-policy-time-year.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="policy.config.noa">{{:: 'authz-policy-time-hour' | translate}}</label>
<label class="col-md-2 control-label" for="hour">{{:: 'authz-policy-time-hour' | translate}}</label>
<div class="col-md-6 time-selector">
<input class="form-control" type="number" min="0" max="23" data-ng-model="policy.config.hour" id="hour" name="hour" data-ng-required="isRequired()"/>&nbsp;&nbsp;to&nbsp;&nbsp;<input class="form-control" type="number" min="{{policy.config.hour}}" max="23" data-ng-model="policy.config.hourEnd" id="hourEnd" name="hourEnd"/>
<input class="form-control" type="number" min="0" max="23" data-ng-model="policy.hour" id="hour" name="hour" data-ng-required="isRequired()"/>&nbsp;&nbsp;to&nbsp;&nbsp;<input class="form-control" type="number" min="{{policy.hour}}" max="23" data-ng-model="policy.hourEnd" id="hourEnd" name="hourEnd"/>
</div>
<kc-tooltip>{{:: 'authz-policy-time-hour.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="policy.config.noa">{{:: 'authz-policy-time-minute' | translate}}</label>
<label class="col-md-2 control-label" for="minute">{{:: 'authz-policy-time-minute' | translate}}</label>
<div class="col-md-6 time-selector">
<input class="form-control" type="number" min="0" max="59" data-ng-model="policy.config.minute" id="minute" name="minute" data-ng-required="isRequired()"/>&nbsp;&nbsp;to&nbsp;&nbsp;<input class="form-control" type="number" min="{{policy.config.minute}}" max="59" data-ng-model="policy.config.minuteEnd" id="minuteEnd" name="minuteEnd"/>
<input class="form-control" type="number" min="0" max="59" data-ng-model="policy.minute" id="minute" name="minute" data-ng-required="isRequired()"/>&nbsp;&nbsp;to&nbsp;&nbsp;<input class="form-control" type="number" min="{{policy.minute}}" max="59" data-ng-model="policy.minuteEnd" id="minuteEnd" name="minuteEnd"/>
</div>
<kc-tooltip>{{:: 'authz-policy-time-minute.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="policy.logic">{{:: 'authz-policy-logic' | translate}}</label>
<label class="col-md-2 control-label" for="logic">{{:: 'authz-policy-logic' | translate}}</label>
<div class="col-sm-1">
<select class="form-control" id="policy.logic"
<select class="form-control" id="logic"
data-ng-model="policy.logic">
<option value="POSITIVE">{{:: 'authz-policy-logic-positive' | translate}}</option>
<option value="NEGATIVE">{{:: 'authz-policy-logic-negative' | translate}}</option>

View file

@ -42,7 +42,7 @@
<div class="form-group clearfix" style="margin-top: -15px;">
<label class="col-md-2 control-label"></label>
<div class="col-sm-3">
<table class="table table-striped table-bordered">
<table class="table table-striped table-bordered" id="selected-users">
<thead>
<tr data-ng-hide="!selectedUsers.length">
<th>{{:: 'username' | translate}}</th>
@ -64,10 +64,10 @@
</div>
</div>
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="policy.logic">{{:: 'authz-policy-logic' | translate}}</label>
<label class="col-md-2 control-label" for="logic">{{:: 'authz-policy-logic' | translate}}</label>
<div class="col-sm-1">
<select class="form-control" id="policy.logic"
<select class="form-control" id="logic"
data-ng-model="policy.logic">
<option value="POSITIVE">{{:: 'authz-policy-logic-positive' | translate}}</option>
<option value="NEGATIVE">{{:: 'authz-policy-logic-negative' | translate}}</option>

View file

@ -50,7 +50,7 @@
<div class="pull-right">
<a id="hideDetails" data-ng-show="showDetailsFlag" class="btn btn-default" data-ng-click="showDetailsFlag = !showDetailsFlag;showDetails();" href="">{{:: 'authz-hide-details' | translate}}</a>
<a id="showDetails" data-ng-hide="showDetailsFlag" class="btn btn-default" data-ng-click="showDetailsFlag = !showDetailsFlag;showDetails();" href="">{{:: 'authz-show-details' | translate}}</a>
<select class="form-control" ng-model="policyType"
<select id="create-policy" class="form-control" ng-model="policyType"
ng-options="p.name for p in policyProviders track by p.type"
data-ng-change="addPolicy(policyType);">
<option value="" disabled selected>{{:: 'authz-create-policy' | translate}}...</option>

View file

@ -114,7 +114,7 @@
<label class="col-md-2 control-label" for="authorizationServicesEnabled">{{:: 'authz-authorization-services-enabled' | translate}}</label>
<kc-tooltip>{{:: 'authz-authorization-services-enabled.tooltip' | translate}}</kc-tooltip>
<div class="col-md-6">
<input ng-model="clientEdit.authorizationServicesEnabled" ng-click="onAuthorizationSettingsChange()" name="authorizationServicesEnabled" id="authorizationServicesEnabled" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
<input ng-model="clientEdit.authorizationServicesEnabled" name="authorizationServicesEnabled" id="authorizationServicesEnabled" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
</div>
</div>
<div class="form-group clearfix block" data-ng-show="protocol == 'saml'">