From e0f753bcf5ae44b9a8e9d1a8eac4c44aee0778f4 Mon Sep 17 00:00:00 2001 From: Pedro Igor Date: Mon, 24 Apr 2017 07:34:02 -0300 Subject: [PATCH 1/3] [KEYCLOAK-3135] - More changes to Policy Management API --- .../provider/js/JSPolicyProviderFactory.java | 52 ++++-- .../provider/time/TimePolicyProvider.java | 21 ++- .../time/TimePolicyProviderFactory.java | 108 +++++++++--- .../authorization/JSPolicyRepresentation.java | 23 ++- .../TimePolicyRepresentation.java | 132 ++++++++++++++ .../client/resource/JSPoliciesResource.java | 50 ++++++ .../client/resource/JSPolicyResource.java | 70 ++++++++ .../client/resource/PoliciesResource.java | 6 + .../client/resource/TimePoliciesResource.java | 50 ++++++ .../client/resource/TimePolicyResource.java | 69 ++++++++ .../authorization/JSPolicyManagementTest.java | 117 +++++++++++++ .../TimePolicyManagementTest.java | 165 ++++++++++++++++++ .../resources/js/authz/authz-controller.js | 69 ++++---- .../resource-server-policy-js-detail.html | 2 +- .../resource-server-policy-time-detail.html | 28 +-- 15 files changed, 851 insertions(+), 111 deletions(-) rename authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyAdminResource.java => core/src/main/java/org/keycloak/representations/idm/authorization/JSPolicyRepresentation.java (57%) create mode 100644 core/src/main/java/org/keycloak/representations/idm/authorization/TimePolicyRepresentation.java create mode 100644 integration/admin-client/src/main/java/org/keycloak/admin/client/resource/JSPoliciesResource.java create mode 100644 integration/admin-client/src/main/java/org/keycloak/admin/client/resource/JSPolicyResource.java create mode 100644 integration/admin-client/src/main/java/org/keycloak/admin/client/resource/TimePoliciesResource.java create mode 100644 integration/admin-client/src/main/java/org/keycloak/admin/client/resource/TimePolicyResource.java create mode 100644 testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/JSPolicyManagementTest.java create mode 100644 testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/TimePolicyManagementTest.java diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/js/JSPolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/js/JSPolicyProviderFactory.java index 617727f7c3..1a1ed34ecc 100644 --- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/js/JSPolicyProviderFactory.java +++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/js/JSPolicyProviderFactory.java @@ -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 Pedro Igor */ -public class JSPolicyProviderFactory implements PolicyProviderFactory { +public class JSPolicyProviderFactory implements PolicyProviderFactory { - private JSPolicyProvider provider = new JSPolicyProvider(new Supplier() { - @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 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 config = policy.getConfig(); + config.put("code", code); + policy.setConfig(config); } @Override diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProvider.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProvider.java index 7ce4c6ea35..6a383e3ada 100644 --- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProvider.java +++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProvider.java @@ -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); diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProviderFactory.java index 920cf45e5c..a3958b9202 100644 --- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProviderFactory.java +++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProviderFactory.java @@ -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 Pedro Igor */ -public class TimePolicyProviderFactory implements PolicyProviderFactory { +public class TimePolicyProviderFactory implements PolicyProviderFactory { private TimePolicyProvider provider = new TimePolicyProvider(); @@ -35,46 +35,58 @@ public class TimePolicyProviderFactory implements PolicyProviderFactory getRepresentationType() { + return TimePolicyRepresentation.class; + } + + @Override + public TimePolicyRepresentation toRepresentation(Policy policy, TimePolicyRepresentation representation) { + Map 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 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 + "]"); + } + } } diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyAdminResource.java b/core/src/main/java/org/keycloak/representations/idm/authorization/JSPolicyRepresentation.java similarity index 57% rename from authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyAdminResource.java rename to core/src/main/java/org/keycloak/representations/idm/authorization/JSPolicyRepresentation.java index 7c2206af93..ed37a6d2a3 100644 --- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyAdminResource.java +++ b/core/src/main/java/org/keycloak/representations/idm/authorization/JSPolicyRepresentation.java @@ -1,13 +1,12 @@ /* - * 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. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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, @@ -15,14 +14,20 @@ * 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 Pedro Igor */ -public class TimePolicyAdminResource implements PolicyProviderAdminService { +public class JSPolicyRepresentation extends AbstractPolicyRepresentation { + private String code; + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } } diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/TimePolicyRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/authorization/TimePolicyRepresentation.java new file mode 100644 index 0000000000..e4115e19dc --- /dev/null +++ b/core/src/main/java/org/keycloak/representations/idm/authorization/TimePolicyRepresentation.java @@ -0,0 +1,132 @@ +/* + * 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 Pedro Igor + */ +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; + + 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; + } +} diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/JSPoliciesResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/JSPoliciesResource.java new file mode 100644 index 0000000000..a6788eb001 --- /dev/null +++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/JSPoliciesResource.java @@ -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 Pedro Igor + */ +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); +} diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/JSPolicyResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/JSPolicyResource.java new file mode 100644 index 0000000000..433d71eefb --- /dev/null +++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/JSPolicyResource.java @@ -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 Pedro Igor + */ +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 associatedPolicies(); + + @Path("/dependentPolicies") + @GET + @Produces(MediaType.APPLICATION_JSON) + @NoCache + List dependentPolicies(); + + @Path("/resources") + @GET + @Produces("application/json") + @NoCache + List resources(); + +} diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/PoliciesResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/PoliciesResource.java index 433a1125ad..e98165221f 100644 --- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/PoliciesResource.java +++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/PoliciesResource.java @@ -74,4 +74,10 @@ public interface PoliciesResource { @Path("user") UserPoliciesResource users(); + + @Path("js") + JSPoliciesResource js(); + + @Path("time") + TimePoliciesResource time(); } diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/TimePoliciesResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/TimePoliciesResource.java new file mode 100644 index 0000000000..326bebe405 --- /dev/null +++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/TimePoliciesResource.java @@ -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 Pedro Igor + */ +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); +} diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/TimePolicyResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/TimePolicyResource.java new file mode 100644 index 0000000000..560c06a09c --- /dev/null +++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/TimePolicyResource.java @@ -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 Pedro Igor + */ +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 associatedPolicies(); + + @Path("/dependentPolicies") + @GET + @Produces(MediaType.APPLICATION_JSON) + @NoCache + List dependentPolicies(); + + @Path("/resources") + @GET + @Produces("application/json") + @NoCache + List resources(); + +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/JSPolicyManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/JSPolicyManagementTest.java new file mode 100644 index 0000000000..f69ed2d819 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/JSPolicyManagementTest.java @@ -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 Pedro Igor + */ +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()); + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/TimePolicyManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/TimePolicyManagementTest.java new file mode 100644 index 0000000000..0c34705364 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/TimePolicyManagementTest.java @@ -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 Pedro Igor + */ +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()); + } +} diff --git a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js index ed5620ca5a..a032243e23 100644 --- a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js +++ b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js @@ -1636,7 +1636,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 +1645,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 +1667,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; diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-js-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-js-detail.html index fb2fbc49cb..6e3951526d 100644 --- a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-js-detail.html +++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-js-detail.html @@ -35,7 +35,7 @@
-
+
{{:: 'authz-policy-js-code.tooltip' | translate}}
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-time-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-time-detail.html index 517773470f..e265804bd7 100644 --- a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-time-detail.html +++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-time-detail.html @@ -34,58 +34,58 @@ {{:: 'authz-policy-description.tooltip' | translate}}
- +
- +
{{:: 'authz-policy-time-not-before.tooltip' | translate}}
- +
- +
{{:: 'authz-policy-time-not-on-after.tooltip' | translate}}
- +
-   to   +   to  
{{:: 'authz-policy-time-day-month.tooltip' | translate}}
- +
-   to   +   to  
{{:: 'authz-policy-time-month.tooltip' | translate}}
- +
-   to   +   to  
{{:: 'authz-policy-time-year.tooltip' | translate}}
- +
-   to   +   to  
{{:: 'authz-policy-time-hour.tooltip' | translate}}
- +
-   to   +   to  
{{:: 'authz-policy-time-minute.tooltip' | translate}}
From dfec691de0df2b17978ef32c23d5197df2e840dd Mon Sep 17 00:00:00 2001 From: Pedro Igor Date: Mon, 24 Apr 2017 08:39:08 -0300 Subject: [PATCH 2/3] [KEYCLOAK-3135] - Fixing cancel button --- .../AggregatePolicyProviderFactory.java | 5 +++ .../resources/js/authz/authz-controller.js | 42 +++++++++++++++---- .../admin/resources/js/controllers/clients.js | 15 +++---- ...source-server-policy-aggregate-detail.html | 2 +- .../resource-server-policy-client-detail.html | 2 +- .../resources/partials/client-detail.html | 2 +- 6 files changed, 49 insertions(+), 19 deletions(-) diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/aggregated/AggregatePolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/aggregated/AggregatePolicyProviderFactory.java index 73443d1f06..0cfbabd55e 100644 --- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/aggregated/AggregatePolicyProviderFactory.java +++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/aggregated/AggregatePolicyProviderFactory.java @@ -73,6 +73,11 @@ public class AggregatePolicyProviderFactory implements PolicyProviderFactory()); } + @Override + public void onImport(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) { + verifyCircularReference(policy, new ArrayList<>()); + } + private void verifyCircularReference(Policy policy, List ids) { if (!policy.getType().equals("aggregate")) { return; diff --git a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js index a032243e23..3db9401325 100644 --- a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js +++ b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js @@ -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); @@ -1774,18 +1795,25 @@ module.controller('ResourceServerPolicyAggregateDetailCtrl', function($scope, $r 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); @@ -1799,8 +1827,8 @@ module.controller('ResourceServerPolicyAggregateDetailCtrl', function($scope, $r 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); diff --git a/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js b/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js index 108d609b98..a2cbea4c84 100755 --- a/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js +++ b/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js @@ -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) { diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-aggregate-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-aggregate-detail.html index 2544d3c2d4..adb586b039 100644 --- a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-aggregate-detail.html +++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-aggregate-detail.html @@ -34,7 +34,7 @@
- +
{{:: 'authz-policy-apply-policy.tooltip' | translate}} diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-client-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-client-detail.html index 634b836913..dda34a2ae7 100644 --- a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-client-detail.html +++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-client-detail.html @@ -53,7 +53,7 @@ {{client.clientId}} - + diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html index 6b890e5cf5..3eb084f44d 100755 --- a/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html +++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html @@ -114,7 +114,7 @@ {{:: 'authz-authorization-services-enabled.tooltip' | translate}}
- +
From 5972c94dc8ef88c5e37d7f958d09efba507c4762 Mon Sep 17 00:00:00 2001 From: Pedro Igor Date: Mon, 24 Apr 2017 16:50:23 -0300 Subject: [PATCH 3/3] [KEYCLOAK-3135] - More UI tests --- .../AggregatePolicyProviderFactory.java | 12 +- .../AbstractPolicyRepresentation.java | 8 + .../AggregatePolicyRepresentation.java | 28 ++ .../authorization/JSPolicyRepresentation.java | 5 + .../RolePolicyRepresentation.java | 5 + .../TimePolicyRepresentation.java | 5 + .../UserPolicyRepresentation.java | 5 + .../authorization/permission/Permissions.java | 82 +++++ .../permission/ResourcePermission.java | 43 +++ .../permission/ResourcePermissionForm.java | 264 ++++++++++++++++ .../authorization/policy/AggregatePolicy.java | 42 +++ .../policy/AggregatePolicyForm.java | 165 ++++++++++ .../authorization/policy/JSPolicy.java | 42 +++ .../authorization/policy/JSPolicyForm.java | 77 +++++ .../authorization/policy/Policies.java | 140 ++++++++- .../authorization/policy/PolicyTypeUI.java | 23 ++ .../authorization/policy/RolePolicy.java | 41 +++ .../authorization/policy/RolePolicyForm.java | 284 ++++++++++++++++++ .../authorization/policy/TimePolicy.java | 41 +++ .../authorization/policy/TimePolicyForm.java | 129 ++++++++ .../authorization/policy/UserPolicy.java | 41 +++ .../authorization/policy/UserPolicyForm.java | 190 ++++++++++++ .../AbstractAuthorizationSettingsTest.java | 2 + .../AggregatePolicyManagementTest.java | 147 +++++++++ .../authorization/JSPolicyManagementTest.java | 93 ++++++ .../ResourcePermissionManagementTest.java | 182 +++++++++++ .../RolePolicyManagementTest.java | 232 ++++++++++++++ .../TimePolicyManagementTest.java | 127 ++++++++ .../UserPolicyManagementTest.java | 116 +++++++ .../resources/js/authz/authz-controller.js | 8 +- ...esource-server-policy-resource-detail.html | 16 +- .../resource-server-permission-list.html | 1 + ...source-server-policy-aggregate-detail.html | 8 +- .../resource-server-policy-js-detail.html | 8 +- .../resource-server-policy-role-detail.html | 8 +- .../resource-server-policy-time-detail.html | 12 +- .../resource-server-policy-user-detail.html | 6 +- .../policy/resource-server-policy-list.html | 2 +- 38 files changed, 2595 insertions(+), 45 deletions(-) create mode 100644 core/src/main/java/org/keycloak/representations/idm/authorization/AggregatePolicyRepresentation.java create mode 100644 testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/permission/ResourcePermission.java create mode 100644 testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/permission/ResourcePermissionForm.java create mode 100644 testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/AggregatePolicy.java create mode 100644 testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/AggregatePolicyForm.java create mode 100644 testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/JSPolicy.java create mode 100644 testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/JSPolicyForm.java create mode 100644 testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/PolicyTypeUI.java create mode 100644 testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/RolePolicy.java create mode 100644 testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/RolePolicyForm.java create mode 100644 testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/TimePolicy.java create mode 100644 testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/TimePolicyForm.java create mode 100644 testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/UserPolicy.java create mode 100644 testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/UserPolicyForm.java create mode 100644 testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/AggregatePolicyManagementTest.java create mode 100644 testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/JSPolicyManagementTest.java create mode 100644 testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/ResourcePermissionManagementTest.java create mode 100644 testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/RolePolicyManagementTest.java create mode 100644 testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/TimePolicyManagementTest.java create mode 100644 testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/UserPolicyManagementTest.java diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/aggregated/AggregatePolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/aggregated/AggregatePolicyProviderFactory.java index 0cfbabd55e..655d8d1d4f 100644 --- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/aggregated/AggregatePolicyProviderFactory.java +++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/aggregated/AggregatePolicyProviderFactory.java @@ -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 Pedro Igor */ -public class AggregatePolicyProviderFactory implements PolicyProviderFactory { +public class AggregatePolicyProviderFactory implements PolicyProviderFactory { private AggregatePolicyProvider provider = new AggregatePolicyProvider(); @@ -53,23 +54,18 @@ public class AggregatePolicyProviderFactory implements PolicyProviderFactory()); } @Override - public void onUpdate(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) { + public void onUpdate(Policy policy, AggregatePolicyRepresentation representation, AuthorizationProvider authorization) { verifyCircularReference(policy, new ArrayList<>()); } diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/AbstractPolicyRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/authorization/AbstractPolicyRepresentation.java index e0be8006a3..6d19a84373 100644 --- a/core/src/main/java/org/keycloak/representations/idm/authorization/AbstractPolicyRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/authorization/AbstractPolicyRepresentation.java @@ -88,6 +88,10 @@ public class AbstractPolicyRepresentation { return policies; } + public void setPolicies(Set 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 resources) { + this.resources = resources; + } + public void addResource(String id) { if (this.resources == null) { this.resources = new HashSet<>(); diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/AggregatePolicyRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/authorization/AggregatePolicyRepresentation.java new file mode 100644 index 0000000000..6ac123814c --- /dev/null +++ b/core/src/main/java/org/keycloak/representations/idm/authorization/AggregatePolicyRepresentation.java @@ -0,0 +1,28 @@ +/* + * 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 Pedro Igor + */ +public class AggregatePolicyRepresentation extends AbstractPolicyRepresentation { + + @Override + public String getType() { + return "aggregate"; + } +} diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/JSPolicyRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/authorization/JSPolicyRepresentation.java index ed37a6d2a3..13217922d2 100644 --- a/core/src/main/java/org/keycloak/representations/idm/authorization/JSPolicyRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/authorization/JSPolicyRepresentation.java @@ -23,6 +23,11 @@ public class JSPolicyRepresentation extends AbstractPolicyRepresentation { private String code; + @Override + public String getType() { + return "js"; + } + public String getCode() { return code; } diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/RolePolicyRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/authorization/RolePolicyRepresentation.java index 2a89710623..a4f29738f4 100644 --- a/core/src/main/java/org/keycloak/representations/idm/authorization/RolePolicyRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/authorization/RolePolicyRepresentation.java @@ -26,6 +26,11 @@ public class RolePolicyRepresentation extends AbstractPolicyRepresentation { private Set roles; + @Override + public String getType() { + return "role"; + } + public Set getRoles() { return roles; } diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/TimePolicyRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/authorization/TimePolicyRepresentation.java index e4115e19dc..8b8e66a5d6 100644 --- a/core/src/main/java/org/keycloak/representations/idm/authorization/TimePolicyRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/authorization/TimePolicyRepresentation.java @@ -34,6 +34,11 @@ public class TimePolicyRepresentation extends AbstractPolicyRepresentation { private String minute; private String minuteEnd; + @Override + public String getType() { + return "time"; + } + public String getNotBefore() { return notBefore; } diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/UserPolicyRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/authorization/UserPolicyRepresentation.java index dc38e65a77..239e55ffa4 100644 --- a/core/src/main/java/org/keycloak/representations/idm/authorization/UserPolicyRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/authorization/UserPolicyRepresentation.java @@ -26,6 +26,11 @@ public class UserPolicyRepresentation extends AbstractPolicyRepresentation { private Set users; + @Override + public String getType() { + return "user"; + } + public Set getUsers() { return users; } diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/permission/Permissions.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/permission/Permissions.java index c29ab76fcf..9900247a86 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/permission/Permissions.java +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/permission/Permissions.java @@ -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 Pedro Igor @@ -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 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 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; + } + } + } } \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/permission/ResourcePermission.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/permission/ResourcePermission.java new file mode 100644 index 0000000000..d6c4f3a158 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/permission/ResourcePermission.java @@ -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 Pedro Igor + */ +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); + } +} diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/permission/ResourcePermissionForm.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/permission/ResourcePermissionForm.java new file mode 100644 index 0000000000..87facb3494 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/permission/ResourcePermissionForm.java @@ -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 Pedro Igor + */ +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 selectedResources = resourceInput.getSelected(); + Set 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 selectedPolicies = policyInput.getSelected(); + Set 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 result; + + @FindBy(xpath = "//li[contains(@class,'select2-search-choice')]") + private List 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 getSelected() { + HashSet 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 result; + + @FindBy(xpath = "//li[contains(@class,'select2-search-choice')]") + private List 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 getSelected() { + HashSet 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; + } + } + } + } +} \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/AggregatePolicy.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/AggregatePolicy.java new file mode 100644 index 0000000000..3a27d2b448 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/AggregatePolicy.java @@ -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 Pedro Igor + */ +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); + } +} diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/AggregatePolicyForm.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/AggregatePolicyForm.java new file mode 100644 index 0000000000..c1d5f212b6 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/AggregatePolicyForm.java @@ -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 Pedro Igor + */ +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 selectedPolicies = policyInput.getSelected(); + Set 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 result; + + @FindBy(xpath = "//li[contains(@class,'select2-search-choice')]") + private List 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 getSelected() { + HashSet 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; + } + } + } + } +} \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/JSPolicy.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/JSPolicy.java new file mode 100644 index 0000000000..94fbb08473 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/JSPolicy.java @@ -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 Pedro Igor + */ +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); + } +} diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/JSPolicyForm.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/JSPolicyForm.java new file mode 100644 index 0000000000..e83585b9bb --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/JSPolicyForm.java @@ -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 Pedro Igor + */ +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; + } +} \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/Policies.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/Policies.java index 36a198d004..2a41efefc4 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/Policies.java +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/Policies.java @@ -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 Pedro Igor @@ -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 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 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; + } + } + } } \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/PolicyTypeUI.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/PolicyTypeUI.java new file mode 100644 index 0000000000..ba3609d0bd --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/PolicyTypeUI.java @@ -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 Pedro Igor + */ +public interface PolicyTypeUI { +} diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/RolePolicy.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/RolePolicy.java new file mode 100644 index 0000000000..8d4be910b0 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/RolePolicy.java @@ -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 Pedro Igor + */ +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); + } +} diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/RolePolicyForm.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/RolePolicyForm.java new file mode 100644 index 0000000000..29ae5355ce --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/RolePolicyForm.java @@ -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 Pedro Igor + */ +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 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 roles, Set 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 roles = realmRolesInput.getSelected(); + + roles.addAll(clientRolesInput.getSelected()); + + representation.setRoles(roles); + + return representation; + } + + public class RolesInput extends AbstractRolesInput { + @Override + protected RolePolicyRepresentation.RoleDefinition getSelectedRoles(List 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 tds) { + return tds.get(2); + } + + @Override + protected List getSelectedElements() { + return root.findElements(By.xpath("(//table[@id='selected-realm-roles'])/tbody/tr")); + } + + @Override + protected WebElement getRequiredColumn(List tds) { + return tds.get(1); + } + } + + public class ClientRolesInput extends AbstractRolesInput { + @Override + protected WebElement getRemoveButton(List tds) { + return tds.get(3); + } + + @Override + protected RolePolicyRepresentation.RoleDefinition getSelectedRoles(List 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 getSelectedElements() { + return root.findElements(By.xpath("(//table[@id='selected-client-roles'])/tbody/tr")); + } + + @Override + protected WebElement getRequiredColumn(List tds) { + return tds.get(2); + } + } + + public abstract class AbstractRolesInput { + + @Root + protected WebElement root; + + @FindBy(xpath = "//div[contains(@class,'select2-result-label')]") + private List result; + + @FindBy(xpath = "//li[contains(@class,'select2-search-choice')]") + private List 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 getSelected() { + List realmRoles = getSelectedElements(); + Set values = new HashSet<>(); + + for (WebElement realmRole : realmRoles) { + List 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 tds); + + protected abstract List getSelectedElements(); + + public void unSelect(String name, WebDriver driver) { + Iterator iterator = getSelectedElements().iterator(); + + while (iterator.hasNext()) { + WebElement realmRole = iterator.next(); + List 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 tds); + + public void setRequired(String name, RolePolicyRepresentation.RoleDefinition role) { + Iterator iterator = getSelectedElements().iterator(); + + while (iterator.hasNext()) { + WebElement realmRole = iterator.next(); + List 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 tds); + } +} \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/TimePolicy.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/TimePolicy.java new file mode 100644 index 0000000000..ce2a20a8d0 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/TimePolicy.java @@ -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 Pedro Igor + */ +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); + } +} diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/TimePolicyForm.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/TimePolicyForm.java new file mode 100644 index 0000000000..5c31f3373f --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/TimePolicyForm.java @@ -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 Pedro Igor + */ +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; + } +} \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/UserPolicy.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/UserPolicy.java new file mode 100644 index 0000000000..cd5b8ebb2e --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/UserPolicy.java @@ -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 Pedro Igor + */ +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); + } +} diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/UserPolicyForm.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/UserPolicyForm.java new file mode 100644 index 0000000000..46caad04a9 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/UserPolicyForm.java @@ -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 Pedro Igor + */ +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 users = expected.getUsers(); + + for (String user : users) { + usersInput.select(user, driver); + } + + unSelect(users, usersInput.getSelected()); + + save(); + } + + private void unSelect(Set users, Set 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 tds) { + return tds.get(1); + } + + @Override + protected List 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 result; + + @FindBy(xpath = "//li[contains(@class,'select2-search-choice')]") + private List 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 getSelected() { + List users = getSelectedElements(); + Set values = new HashSet<>(); + + for (WebElement user : users) { + List tds = user.findElements(tagName("td")); + if (!(tds.isEmpty() || tds.get(0).getText().isEmpty())) { + values.add(tds.get(0).getText()); + } + } + + return values; + } + + protected abstract List getSelectedElements(); + + public void unSelect(String name, WebDriver driver) { + Iterator iterator = getSelectedElements().iterator(); + + while (iterator.hasNext()) { + WebElement realmRole = iterator.next(); + List 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 tds); + } +} \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/AbstractAuthorizationSettingsTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/AbstractAuthorizationSettingsTest.java index 5bb5449c4c..276985e190 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/AbstractAuthorizationSettingsTest.java +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/AbstractAuthorizationSettingsTest.java @@ -75,6 +75,8 @@ public abstract class AbstractAuthorizationSettingsTest extends AbstractClientTe clientSettingsPage.tabs().authorization(); assertTrue(authorizationPage.isCurrent()); + newClient.setId(found.getId()); + return newClient; } } diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/AggregatePolicyManagementTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/AggregatePolicyManagementTest.java new file mode 100644 index 0000000000..2051ac3919 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/AggregatePolicyManagementTest.java @@ -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 Pedro Igor + */ +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; + } +} diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/JSPolicyManagementTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/JSPolicyManagementTest.java new file mode 100644 index 0000000000..fffce15f9b --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/JSPolicyManagementTest.java @@ -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 Pedro Igor + */ +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; + } +} diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/ResourcePermissionManagementTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/ResourcePermissionManagementTest.java new file mode 100644 index 0000000000..a4ab7ef91a --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/ResourcePermissionManagementTest.java @@ -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 Pedro Igor + */ +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; + } +} diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/RolePolicyManagementTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/RolePolicyManagementTest.java new file mode 100644 index 0000000000..713b93ae1e --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/RolePolicyManagementTest.java @@ -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 Pedro Igor + */ +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; + } +} diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/TimePolicyManagementTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/TimePolicyManagementTest.java new file mode 100644 index 0000000000..9e9d2e8479 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/TimePolicyManagementTest.java @@ -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 Pedro Igor + */ +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; + } +} diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/UserPolicyManagementTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/UserPolicyManagementTest.java new file mode 100644 index 0000000000..ed19bc5556 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/UserPolicyManagementTest.java @@ -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 Pedro Igor + */ +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; + } +} diff --git a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js index 3db9401325..99180416e9 100644 --- a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js +++ b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js @@ -1789,7 +1789,6 @@ module.controller('ResourceServerPolicyAggregateDetailCtrl', function($scope, $r }, onInitUpdate : function(policy) { - policy.config.applyPolicies = []; ResourceServerPolicy.associatedPolicies({ realm : $route.current.params.realm, client : client.id, @@ -1816,11 +1815,11 @@ module.controller('ResourceServerPolicyAggregateDetailCtrl', function($scope, $r 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'; }, @@ -1831,7 +1830,8 @@ module.controller('ResourceServerPolicyAggregateDetailCtrl', function($scope, $r policies.push($scope.selectedPolicies[i].id); } - $scope.policy.config.applyPolicies = JSON.stringify(policies); + $scope.policy.policies = policies; + delete $scope.policy.config; } }, realm, client, $scope); }); diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/permission/provider/resource-server-policy-resource-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/permission/provider/resource-server-policy-resource-detail.html index 7a5ba6d993..221a90219c 100644 --- a/themes/src/main/resources/theme/base/admin/resources/partials/authz/permission/provider/resource-server-policy-resource-detail.html +++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/permission/provider/resource-server-policy-resource-detail.html @@ -36,36 +36,36 @@ {{:: 'authz-permission-resource-apply-to-resource-type.tooltip' | translate}}

- +
- +
{{:: 'authz-permission-resource-resource.tooltip' | translate}}
- +
- +
{{:: 'authz-permission-resource-type.tooltip' | translate}}
- +
- +
{{:: 'authz-policy-apply-policy.tooltip' | translate}}
- +
- diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-aggregate-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-aggregate-detail.html index adb586b039..4af440bdfe 100644 --- a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-aggregate-detail.html +++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-aggregate-detail.html @@ -31,10 +31,10 @@ {{:: 'authz-policy-description.tooltip' | translate}}
- +
- +
{{:: 'authz-policy-apply-policy.tooltip' | translate}}
@@ -54,10 +54,10 @@ {{:: 'authz-policy-decision-strategy.tooltip' | translate}}
- +
- diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-role-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-role-detail.html index f9c2aca17d..47e563a236 100644 --- a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-role-detail.html +++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-role-detail.html @@ -63,7 +63,7 @@
- +
@@ -114,7 +114,7 @@
-
{{:: 'name' | translate}}
+
@@ -140,10 +140,10 @@
- +
- +
{{:: 'authz-policy-time-not-before.tooltip' | translate}}
- +
- +
{{:: 'authz-policy-time-not-on-after.tooltip' | translate}}
@@ -90,10 +90,10 @@ {{:: 'authz-policy-time-minute.tooltip' | translate}}
- +
-
{{:: 'name' | translate}}
+
@@ -64,10 +64,10 @@
- +
-
{{:: 'username' | translate}}