keycloak-uncached

Changes

Details

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 655d8d1..0ed8763 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
@@ -23,9 +23,7 @@ import java.util.List;
 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;
@@ -74,6 +72,16 @@ public class AggregatePolicyProviderFactory implements PolicyProviderFactory<Agg
         verifyCircularReference(policy, new ArrayList<>());
     }
 
+    @Override
+    public AggregatePolicyRepresentation toRepresentation(Policy policy, AggregatePolicyRepresentation representation) {
+        return representation;
+    }
+
+    @Override
+    public Class<AggregatePolicyRepresentation> getRepresentationType() {
+        return AggregatePolicyRepresentation.class;
+    }
+
     private void verifyCircularReference(Policy policy, List<String> ids) {
         if (!policy.getType().equals("aggregate")) {
             return;
diff --git a/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyAdminResource.java b/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyAdminResource.java
index a9bdbb0..ad0b722 100644
--- a/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyAdminResource.java
+++ b/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyAdminResource.java
@@ -17,13 +17,14 @@
 package org.keycloak.authorization.policy.provider.drools;
 
 import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
-import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.RulePolicyRepresentation;
 import org.kie.api.runtime.KieContainer;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
 /**
@@ -39,24 +40,24 @@ public class DroolsPolicyAdminResource implements PolicyProviderAdminService {
 
     @Path("/resolveModules")
     @POST
-    @Consumes("application/json")
+    @Consumes(MediaType.APPLICATION_JSON)
     @Produces("application/json")
-    public Response resolveModules(PolicyRepresentation policy) {
+    public Response resolveModules(RulePolicyRepresentation policy) {
         return Response.ok(getContainer(policy).getKieBaseNames()).build();
     }
 
     @Path("/resolveSessions")
     @POST
-    @Consumes("application/json")
-    @Produces("application/json")
-    public Response resolveSessions(PolicyRepresentation policy) {
-        return Response.ok(getContainer(policy).getKieSessionNamesInKieBase(policy.getConfig().get("moduleName"))).build();
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response resolveSessions(RulePolicyRepresentation policy) {
+        return Response.ok(getContainer(policy).getKieSessionNamesInKieBase(policy.getModuleName())).build();
     }
 
-    private KieContainer getContainer(PolicyRepresentation policy) {
-        String groupId = policy.getConfig().get("mavenArtifactGroupId");
-        String artifactId = policy.getConfig().get("mavenArtifactId");
-        String version = policy.getConfig().get("mavenArtifactVersion");
+    private KieContainer getContainer(RulePolicyRepresentation policy) {
+        String groupId = policy.getArtifactGroupId();
+        String artifactId = policy.getArtifactId();
+        String version = policy.getArtifactVersion();
         return this.factory.getKieContainer(groupId, artifactId, version);
     }
 }
diff --git a/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyProviderFactory.java b/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyProviderFactory.java
index 8bbed33..1fb3c1f 100644
--- a/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyProviderFactory.java
+++ b/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyProviderFactory.java
@@ -13,8 +13,8 @@ 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.AbstractPolicyRepresentation;
 import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.RulePolicyRepresentation;
 import org.kie.api.KieServices;
 import org.kie.api.KieServices.Factory;
 import org.kie.api.runtime.KieContainer;
@@ -22,7 +22,7 @@ import org.kie.api.runtime.KieContainer;
 /**
  * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
  */
-public class DroolsPolicyProviderFactory implements PolicyProviderFactory {
+public class DroolsPolicyProviderFactory implements PolicyProviderFactory<RulePolicyRepresentation> {
 
     private KieServices ks;
     private final Map<String, DroolsPolicy> containers = Collections.synchronizedMap(new HashMap<>());
@@ -61,12 +61,14 @@ public class DroolsPolicyProviderFactory implements PolicyProviderFactory {
     }
 
     @Override
-    public void onCreate(Policy policy, AbstractPolicyRepresentation representation, AuthorizationProvider authorization) {
+    public void onCreate(Policy policy, RulePolicyRepresentation representation, AuthorizationProvider authorization) {
+        updateConfig(policy, representation);
         update(policy);
     }
 
     @Override
-    public void onUpdate(Policy policy, AbstractPolicyRepresentation representation, AuthorizationProvider authorization) {
+    public void onUpdate(Policy policy, RulePolicyRepresentation representation, AuthorizationProvider authorization) {
+        updateConfig(policy, representation);
         update(policy);
     }
 
@@ -81,6 +83,23 @@ public class DroolsPolicyProviderFactory implements PolicyProviderFactory {
     }
 
     @Override
+    public RulePolicyRepresentation toRepresentation(Policy policy, RulePolicyRepresentation representation) {
+        representation.setArtifactGroupId(policy.getConfig().get("mavenArtifactGroupId"));
+        representation.setArtifactId(policy.getConfig().get("mavenArtifactId"));
+        representation.setArtifactVersion(policy.getConfig().get("mavenArtifactVersion"));
+        representation.setScannerPeriod(policy.getConfig().get("scannerPeriod"));
+        representation.setScannerPeriodUnit(policy.getConfig().get("scannerPeriodUnit"));
+        representation.setSessionName(policy.getConfig().get("sessionName"));
+        representation.setModuleName(policy.getConfig().get("moduleName"));
+        return representation;
+    }
+
+    @Override
+    public Class<RulePolicyRepresentation> getRepresentationType() {
+        return RulePolicyRepresentation.class;
+    }
+
+    @Override
     public void init(Config.Scope config) {
         this.ks = Factory.get();
     }
@@ -100,6 +119,20 @@ public class DroolsPolicyProviderFactory implements PolicyProviderFactory {
         return "rules";
     }
 
+    private void updateConfig(Policy policy, RulePolicyRepresentation representation) {
+        Map<String, String> config = policy.getConfig();
+
+        config.put("mavenArtifactGroupId", representation.getArtifactGroupId());
+        config.put("mavenArtifactId", representation.getArtifactId());
+        config.put("mavenArtifactVersion", representation.getArtifactVersion());
+        config.put("scannerPeriod", representation.getScannerPeriod());
+        config.put("scannerPeriodUnit", representation.getScannerPeriodUnit());
+        config.put("sessionName", representation.getSessionName());
+        config.put("moduleName", representation.getModuleName());
+
+        policy.setConfig(config);
+    }
+
     void update(Policy policy) {
         remove(policy);
         this.containers.put(policy.getId(), new DroolsPolicy(this.ks, policy));
diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/RulePolicyRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/authorization/RulePolicyRepresentation.java
new file mode 100644
index 0000000..f24ecd4
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/authorization/RulePolicyRepresentation.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.representations.idm.authorization;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class RulePolicyRepresentation extends AbstractPolicyRepresentation {
+
+    private String artifactGroupId;
+    private String artifactId;
+    private String artifactVersion;
+    private String moduleName;
+    private String sessionName;
+    private String scannerPeriod;
+    private String scannerPeriodUnit;
+
+    @Override
+    public String getType() {
+        return "rules";
+    }
+
+    public String getArtifactGroupId() {
+        return artifactGroupId;
+    }
+
+    public void setArtifactGroupId(String artifactGroupId) {
+        this.artifactGroupId = artifactGroupId;
+    }
+
+    public String getArtifactId() {
+        return artifactId;
+    }
+
+    public void setArtifactId(String artifactId) {
+        this.artifactId = artifactId;
+    }
+
+    public String getArtifactVersion() {
+        return artifactVersion;
+    }
+
+    public void setArtifactVersion(String artifactVersion) {
+        this.artifactVersion = artifactVersion;
+    }
+
+    public String getModuleName() {
+        return moduleName;
+    }
+
+    public void setModuleName(String moduleName) {
+        this.moduleName = moduleName;
+    }
+
+    public String getSessionName() {
+        return sessionName;
+    }
+
+    public void setSessionName(String sessionName) {
+        this.sessionName = sessionName;
+    }
+
+    public String getScannerPeriod() {
+        return scannerPeriod;
+    }
+
+    public void setScannerPeriod(String scannerPeriod) {
+        this.scannerPeriod = scannerPeriod;
+    }
+
+    public String getScannerPeriodUnit() {
+        return scannerPeriodUnit;
+    }
+
+    public void setScannerPeriodUnit(String scannerPeriodUnit) {
+        this.scannerPeriodUnit = scannerPeriodUnit;
+    }
+}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/AggregatePoliciesResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/AggregatePoliciesResource.java
new file mode 100644
index 0000000..67f5d31
--- /dev/null
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/AggregatePoliciesResource.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.AggregatePolicyRepresentation;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface AggregatePoliciesResource {
+
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    Response create(AggregatePolicyRepresentation representation);
+
+    @Path("{id}")
+    AggregatePolicyResource findById(@PathParam("id") String id);
+
+    @Path("/search")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @NoCache
+    AggregatePolicyRepresentation findByName(@QueryParam("name") String name);
+}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/AggregatePolicyResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/AggregatePolicyResource.java
new file mode 100644
index 0000000..fc49314
--- /dev/null
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/AggregatePolicyResource.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.AggregatePolicyRepresentation;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface AggregatePolicyResource {
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @NoCache
+    AggregatePolicyRepresentation toRepresentation();
+
+    @PUT
+    @Consumes(MediaType.APPLICATION_JSON)
+    void update(AggregatePolicyRepresentation representation);
+
+    @DELETE
+    void remove();
+
+    @Path("/associatedPolicies")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @NoCache
+    List<PolicyRepresentation> associatedPolicies();
+
+    @Path("/dependentPolicies")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @NoCache
+    List<PolicyRepresentation> dependentPolicies();
+
+    @Path("/resources")
+    @GET
+    @Produces("application/json")
+    @NoCache
+    List<ResourceRepresentation> resources();
+
+}
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 e981652..4ce362d 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
@@ -80,4 +80,10 @@ public interface PoliciesResource {
 
     @Path("time")
     TimePoliciesResource time();
+
+    @Path("aggregate")
+    AggregatePoliciesResource aggregate();
+
+    @Path("rules")
+    RulePoliciesResource rule();
 }
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RulePoliciesResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RulePoliciesResource.java
new file mode 100644
index 0000000..6e05432
--- /dev/null
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RulePoliciesResource.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.RulePolicyRepresentation;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface RulePoliciesResource {
+
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    Response create(RulePolicyRepresentation representation);
+
+    @Path("{id}")
+    RulePolicyResource findById(@PathParam("id") String id);
+
+    @Path("/search")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @NoCache
+    RulePolicyRepresentation findByName(@QueryParam("name") String name);
+}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RulePolicyResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RulePolicyResource.java
new file mode 100644
index 0000000..9efe30b
--- /dev/null
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RulePolicyResource.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.RulePolicyRepresentation;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface RulePolicyResource {
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @NoCache
+    RulePolicyRepresentation toRepresentation();
+
+    @PUT
+    @Consumes(MediaType.APPLICATION_JSON)
+    void update(RulePolicyRepresentation representation);
+
+    @DELETE
+    void remove();
+
+    @Path("/associatedPolicies")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @NoCache
+    List<PolicyRepresentation> associatedPolicies();
+
+    @Path("/dependentPolicies")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @NoCache
+    List<PolicyRepresentation> dependentPolicies();
+
+    @Path("/resources")
+    @GET
+    @Produces("application/json")
+    @NoCache
+    List<ResourceRepresentation> resources();
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AggregatePolicyManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AggregatePolicyManagementTest.java
new file mode 100644
index 0000000..230b4ee
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AggregatePolicyManagementTest.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.admin.client.authorization;
+
+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.AggregatePoliciesResource;
+import org.keycloak.admin.client.resource.AggregatePolicyResource;
+import org.keycloak.admin.client.resource.AuthorizationResource;
+import org.keycloak.representations.idm.authorization.AggregatePolicyRepresentation;
+import org.keycloak.representations.idm.authorization.DecisionStrategy;
+import org.keycloak.representations.idm.authorization.Logic;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AggregatePolicyManagementTest extends AbstractPolicyManagementTest {
+
+    @Test
+    public void testCreate() {
+        AuthorizationResource authorization = getClient().authorization();
+        AggregatePolicyRepresentation representation = new AggregatePolicyRepresentation();
+
+        representation.setName("Aggregate Policy");
+        representation.setDescription("description");
+        representation.setDecisionStrategy(DecisionStrategy.CONSENSUS);
+        representation.setLogic(Logic.NEGATIVE);
+        representation.addPolicy("Only Marta Policy", "Only Kolo Policy");
+
+        assertCreated(authorization, representation);
+    }
+
+    @Test
+    public void testUpdate() {
+        AuthorizationResource authorization = getClient().authorization();
+        AggregatePolicyRepresentation representation = new AggregatePolicyRepresentation();
+
+        representation.setName("Update Aggregate Policy");
+        representation.setDescription("description");
+        representation.setDecisionStrategy(DecisionStrategy.CONSENSUS);
+        representation.setLogic(Logic.NEGATIVE);
+        representation.addPolicy("Only Marta Policy", "Only Kolo Policy");
+
+        assertCreated(authorization, representation);
+
+        representation.setName("changed");
+        representation.setDescription("changed");
+        representation.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE);
+        representation.setLogic(Logic.POSITIVE);
+        representation.getPolicies().clear();
+        representation.addPolicy("Only Kolo Policy");
+
+        AggregatePoliciesResource policies = authorization.policies().aggregate();
+        AggregatePolicyResource policy = policies.findById(representation.getId());
+
+        policy.update(representation);
+        assertRepresentation(representation, policy);
+    }
+
+    @Test
+    public void testDelete() {
+        AuthorizationResource authorization = getClient().authorization();
+        AggregatePolicyRepresentation representation = new AggregatePolicyRepresentation();
+
+        representation.setName("Test Delete Policy");
+        representation.addPolicy("Only Marta Policy");
+
+        AggregatePoliciesResource policies = authorization.policies().aggregate();
+        Response response = policies.create(representation);
+        AggregatePolicyRepresentation created = response.readEntity(AggregatePolicyRepresentation.class);
+
+        policies.findById(created.getId()).remove();
+
+        AggregatePolicyResource removed = policies.findById(created.getId());
+
+        try {
+            removed.toRepresentation();
+            fail("Policy not removed");
+        } catch (NotFoundException ignore) {
+
+        }
+    }
+
+    private void assertCreated(AuthorizationResource authorization, AggregatePolicyRepresentation representation) {
+        AggregatePoliciesResource permissions = authorization.policies().aggregate();
+        Response response = permissions.create(representation);
+        AggregatePolicyRepresentation created = response.readEntity(AggregatePolicyRepresentation.class);
+        AggregatePolicyResource permission = permissions.findById(created.getId());
+        assertRepresentation(representation, permission);
+    }
+
+    private void assertRepresentation(AggregatePolicyRepresentation representation, AggregatePolicyResource policy) {
+        AggregatePolicyRepresentation actual = policy.toRepresentation();
+        assertRepresentation(representation, actual, () -> policy.resources(), () -> Collections.emptyList(), () -> policy.associatedPolicies());
+    }
+}
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
index f69ed2d..f6aefd7 100644
--- 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
@@ -35,7 +35,7 @@ import org.keycloak.representations.idm.authorization.Logic;
 /**
  * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
  */
-public class JSPolicyManagementTest extends AbstractPermissionManagementTest {
+public class JSPolicyManagementTest extends AbstractPolicyManagementTest {
 
     @Test
     public void testCreate() {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourcePermissionManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourcePermissionManagementTest.java
index 1deed22..71ef5e8 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourcePermissionManagementTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourcePermissionManagementTest.java
@@ -35,7 +35,7 @@ import org.keycloak.representations.idm.authorization.ResourcePermissionRepresen
 /**
  * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
  */
-public class ResourcePermissionManagementTest extends AbstractPermissionManagementTest {
+public class ResourcePermissionManagementTest extends AbstractPolicyManagementTest {
 
     @Test
     public void testCreateResourcePermission() {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/RolePolicyManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/RolePolicyManagementTest.java
index 1b4a701..c351ec3 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/RolePolicyManagementTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/RolePolicyManagementTest.java
@@ -24,7 +24,6 @@ import static org.junit.Assert.fail;
 import java.util.Collections;
 import java.util.stream.Collectors;
 
-import javax.management.relation.Role;
 import javax.ws.rs.NotFoundException;
 import javax.ws.rs.core.Response;
 
@@ -47,7 +46,7 @@ import org.keycloak.testsuite.util.RolesBuilder;
 /**
  * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
  */
-public class RolePolicyManagementTest extends AbstractPermissionManagementTest {
+public class RolePolicyManagementTest extends AbstractPolicyManagementTest {
 
     @Override
     protected RealmBuilder createTestRealm() {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/RulesPolicyManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/RulesPolicyManagementTest.java
new file mode 100644
index 0000000..69767b9
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/RulesPolicyManagementTest.java
@@ -0,0 +1,131 @@
+/*
+ * 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.RulePoliciesResource;
+import org.keycloak.admin.client.resource.RulePolicyResource;
+import org.keycloak.common.Version;
+import org.keycloak.representations.idm.authorization.DecisionStrategy;
+import org.keycloak.representations.idm.authorization.Logic;
+import org.keycloak.representations.idm.authorization.RulePolicyRepresentation;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class RulesPolicyManagementTest extends AbstractPolicyManagementTest {
+
+    @Test
+    public void testCreate() {
+        assertCreated(getClient().authorization(), createDefaultRepresentation("Rule Policy"));
+    }
+
+    @Test
+    public void testUpdate() {
+        AuthorizationResource authorization = getClient().authorization();
+        RulePolicyRepresentation representation = createDefaultRepresentation("Update Rule Policy");
+
+        assertCreated(authorization, representation);
+
+        representation.setName("changed");
+        representation.setDescription("changed");
+        representation.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE);
+        representation.setLogic(Logic.POSITIVE);
+        representation.setScannerPeriod("12");
+        representation.setScannerPeriodUnit("Days");
+        representation.setModuleName("PhotozAuthzContextualPolicy");
+        representation.setSessionName("MainContextualSession");
+
+        RulePoliciesResource policies = authorization.policies().rule();
+        RulePolicyResource policy = policies.findById(representation.getId());
+
+        policy.update(representation);
+
+        assertRepresentation(representation, policy);
+    }
+
+    @Test
+    public void testDelete() {
+        AuthorizationResource authorization = getClient().authorization();
+        RulePolicyRepresentation representation = createDefaultRepresentation("Delete Rule Policy");
+
+        RulePoliciesResource policies = authorization.policies().rule();
+        Response response = policies.create(representation);
+        RulePolicyRepresentation created = response.readEntity(RulePolicyRepresentation.class);
+
+        policies.findById(created.getId()).remove();
+
+        RulePolicyResource removed = policies.findById(created.getId());
+
+        try {
+            removed.toRepresentation();
+            fail("Policy not removed");
+        } catch (NotFoundException ignore) {
+
+        }
+    }
+
+    private RulePolicyRepresentation createDefaultRepresentation(String name) {
+        RulePolicyRepresentation representation = new RulePolicyRepresentation();
+
+        representation.setName(name);
+        representation.setDescription("description");
+        representation.setDecisionStrategy(DecisionStrategy.CONSENSUS);
+        representation.setLogic(Logic.NEGATIVE);
+        representation.setArtifactGroupId("org.keycloak");
+        representation.setArtifactId("photoz-authz-policy");
+        representation.setArtifactVersion(Version.VERSION);
+        representation.setModuleName("PhotozAuthzOwnerPolicy");
+        representation.setSessionName("MainOwnerSession");
+        representation.setScannerPeriod("1");
+        representation.setScannerPeriodUnit("Minutes");
+
+        return representation;
+    }
+
+    private void assertCreated(AuthorizationResource authorization, RulePolicyRepresentation representation) {
+        RulePoliciesResource permissions = authorization.policies().rule();
+        Response response = permissions.create(representation);
+        RulePolicyRepresentation created = response.readEntity(RulePolicyRepresentation.class);
+        RulePolicyResource permission = permissions.findById(created.getId());
+        assertRepresentation(representation, permission);
+    }
+
+    private void assertRepresentation(RulePolicyRepresentation expected, RulePolicyResource policy) {
+        RulePolicyRepresentation actual = policy.toRepresentation();
+        assertRepresentation(expected, actual, () -> policy.resources(), () -> Collections.emptyList(), () -> policy.associatedPolicies());
+        assertEquals(expected.getName(), actual.getName());
+        assertEquals(expected.getDescription(), actual.getDescription());
+        assertEquals(expected.getLogic(), actual.getLogic());
+        assertEquals(expected.getArtifactGroupId(), actual.getArtifactGroupId());
+        assertEquals(expected.getArtifactId(), actual.getArtifactId());
+        assertEquals(expected.getArtifactVersion(), actual.getArtifactVersion());
+        assertEquals(expected.getModuleName(), actual.getModuleName());
+        assertEquals(expected.getSessionName(), actual.getSessionName());
+        assertEquals(expected.getScannerPeriod(), actual.getScannerPeriod());
+        assertEquals(expected.getScannerPeriodUnit(), actual.getScannerPeriodUnit());
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ScopePermissionManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ScopePermissionManagementTest.java
index a833668..5db4817 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ScopePermissionManagementTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ScopePermissionManagementTest.java
@@ -33,7 +33,7 @@ import org.keycloak.representations.idm.authorization.ScopePermissionRepresentat
 /**
  * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
  */
-public class ScopePermissionManagementTest extends AbstractPermissionManagementTest {
+public class ScopePermissionManagementTest extends AbstractPolicyManagementTest {
 
     @Test
     public void testCreateResourceScopePermission() {
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
index 0c34705..6095363 100644
--- 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
@@ -35,7 +35,7 @@ import org.keycloak.representations.idm.authorization.Logic;
 /**
  * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
  */
-public class TimePolicyManagementTest extends AbstractPermissionManagementTest {
+public class TimePolicyManagementTest extends AbstractPolicyManagementTest {
 
     @Test
     public void testCreate() {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/UserPolicyManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/UserPolicyManagementTest.java
index 9a80d68..6628bca 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/UserPolicyManagementTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/UserPolicyManagementTest.java
@@ -43,7 +43,7 @@ import org.keycloak.testsuite.util.UserBuilder;
 /**
  * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
  */
-public class UserPolicyManagementTest extends AbstractPermissionManagementTest {
+public class UserPolicyManagementTest extends AbstractPolicyManagementTest {
 
     @Override
     protected RealmBuilder createTestRealm() {
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 2a41efe..37777aa 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
@@ -24,6 +24,7 @@ import org.keycloak.representations.idm.authorization.AggregatePolicyRepresentat
 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.RulePolicyRepresentation;
 import org.keycloak.representations.idm.authorization.TimePolicyRepresentation;
 import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
 import org.keycloak.testsuite.page.Form;
@@ -58,6 +59,9 @@ public class Policies extends Form {
     @Page
     private TimePolicy timePolicy;
 
+    @Page
+    private RulePolicy rulePolicy;
+
     public PoliciesTable policies() {
         return table;
     }
@@ -87,6 +91,10 @@ public class Policies extends Form {
             timePolicy.form().populate((TimePolicyRepresentation) expected);
             timePolicy.form().save();
             return (P) timePolicy;
+        } else if ("rules".equals(type)) {
+            rulePolicy.form().populate((RulePolicyRepresentation) expected);
+            rulePolicy.form().save();
+            return (P) rulePolicy;
         }
 
         return null;
@@ -110,6 +118,8 @@ public class Policies extends Form {
                     jsPolicy.form().populate((JSPolicyRepresentation) representation);
                 } else if ("time".equals(type)) {
                     timePolicy.form().populate((TimePolicyRepresentation) representation);
+                } else if ("rules".equals(type)) {
+                    rulePolicy.form().populate((RulePolicyRepresentation) representation);
                 }
 
                 return;
@@ -134,6 +144,8 @@ public class Policies extends Form {
                     return (P) jsPolicy;
                 } else if ("time".equals(type)) {
                     return (P) timePolicy;
+                } else if ("rules".equals(type)) {
+                    return (P) rulePolicy;
                 }
             }
         }
@@ -159,6 +171,8 @@ public class Policies extends Form {
                     jsPolicy.form().delete();
                 } else if ("time".equals(type)) {
                     timePolicy.form().delete();
+                } else if ("rules".equals(type)) {
+                    rulePolicy.form().delete();
                 }
 
                 return;
diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/RulePolicy.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/RulePolicy.java
new file mode 100644
index 0000000..6d46347
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/RulePolicy.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.RulePolicyRepresentation;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class RulePolicy implements PolicyTypeUI {
+
+    @Page
+    private RulePolicyForm form;
+
+    public RulePolicyForm form() {
+        return form;
+    }
+
+    public RulePolicyRepresentation toRepresentation() {
+        return form.toRepresentation();
+    }
+
+    public void update(RulePolicyRepresentation expected) {
+        form().populate(expected);
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/RulePolicyForm.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/RulePolicyForm.java
new file mode 100644
index 0000000..17b4d46
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/policy/RulePolicyForm.java
@@ -0,0 +1,114 @@
+/*
+ * 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.Logic;
+import org.keycloak.representations.idm.authorization.RulePolicyRepresentation;
+import org.keycloak.testsuite.page.Form;
+import org.keycloak.testsuite.util.WaitUtils;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class RulePolicyForm extends Form {
+
+    @FindBy(id = "name")
+    private WebElement name;
+
+    @FindBy(id = "description")
+    private WebElement description;
+
+    @FindBy(id = "artifactGroupId")
+    private WebElement artifactGroupId;
+
+    @FindBy(id = "artifactId")
+    private WebElement artifactId;
+
+    @FindBy(id = "artifactVersion")
+    private WebElement artifactVersion;
+
+    @FindBy(id = "moduleName")
+    private Select moduleName;
+
+    @FindBy(id = "sessionName")
+    private Select sessionName;
+
+    @FindBy(id = "scannerPeriod")
+    private WebElement scannerPeriod;
+
+    @FindBy(id = "scannerPeriodUnit")
+    private Select scannerPeriodUnit;
+
+    @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;
+
+    @FindBy(id = "resolveModule")
+    private WebElement resolveModuleButton;
+
+    public void populate(RulePolicyRepresentation expected) {
+        setInputValue(name, expected.getName());
+        setInputValue(description, expected.getDescription());
+        setInputValue(artifactGroupId, expected.getArtifactGroupId());
+        setInputValue(artifactId, expected.getArtifactId());
+        setInputValue(artifactVersion, expected.getArtifactVersion());
+
+        resolveModuleButton.click();
+        WaitUtils.waitForPageToLoad(driver);
+
+        moduleName.selectByVisibleText(expected.getModuleName());
+        WaitUtils.pause(1000);
+
+        sessionName.selectByVisibleText(expected.getSessionName());
+
+        setInputValue(scannerPeriod, expected.getScannerPeriod());
+        scannerPeriodUnit.selectByVisibleText(expected.getScannerPeriodUnit());
+        logic.selectByValue(expected.getLogic().name());
+
+        save();
+    }
+
+    public void delete() {
+        deleteButton.click();
+        confirmDelete.click();
+    }
+
+    public RulePolicyRepresentation toRepresentation() {
+        RulePolicyRepresentation representation = new RulePolicyRepresentation();
+
+        representation.setName(getInputValue(name));
+        representation.setDescription(getInputValue(description));
+        representation.setLogic(Logic.valueOf(logic.getFirstSelectedOption().getText().toUpperCase()));
+        representation.setArtifactGroupId(getInputValue(artifactGroupId));
+        representation.setArtifactId(getInputValue(artifactId));
+        representation.setArtifactVersion(getInputValue(artifactVersion));
+        representation.setModuleName(moduleName.getFirstSelectedOption().getText());
+        representation.setSessionName(sessionName.getFirstSelectedOption().getText());
+        representation.setScannerPeriod(getInputValue(scannerPeriod));
+        representation.setScannerPeriodUnit(scannerPeriodUnit.getFirstSelectedOption().getText());
+
+        return representation;
+    }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/RulePolicyManagementTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/RulePolicyManagementTest.java
new file mode 100644
index 0000000..09fb47a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/RulePolicyManagementTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.common.Version;
+import org.keycloak.representations.idm.authorization.Logic;
+import org.keycloak.representations.idm.authorization.RulePolicyRepresentation;
+import org.keycloak.testsuite.console.page.clients.authorization.policy.RulePolicy;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class RulePolicyManagementTest extends AbstractAuthorizationSettingsTest {
+
+    @Test
+    public void testUpdate() throws InterruptedException {
+        authorizationPage.navigateTo();
+        RulePolicyRepresentation expected = createDefaultRepresentation("Test Rule Policy");
+
+        expected = createPolicy(expected);
+
+        String previousName = expected.getName();
+
+        expected.setName("Changed " + previousName);
+        expected.setDescription("Changed description");
+        expected.setLogic(Logic.NEGATIVE);
+        expected.setModuleName("PhotozAuthzContextualPolicy");
+        expected.setSessionName("MainContextualSession");
+        expected.setScannerPeriod("12");
+        expected.setScannerPeriodUnit("Days");
+
+
+        authorizationPage.navigateTo();
+        authorizationPage.authorizationTabs().policies().update(previousName, expected);
+        assertAlertSuccess();
+
+        authorizationPage.navigateTo();
+        RulePolicy actual = authorizationPage.authorizationTabs().policies().name(expected.getName());
+
+        assertPolicy(expected, actual);
+    }
+
+    @Test
+    public void testDelete() throws InterruptedException {
+        authorizationPage.navigateTo();
+        RulePolicyRepresentation expected =createDefaultRepresentation("Delete Rule Policy");
+
+        expected = createPolicy(expected);
+        authorizationPage.navigateTo();
+        authorizationPage.authorizationTabs().policies().delete(expected.getName());
+        assertAlertSuccess();
+        authorizationPage.navigateTo();
+        assertNull(authorizationPage.authorizationTabs().policies().policies().findByName(expected.getName()));
+    }
+
+    private RulePolicyRepresentation createDefaultRepresentation(String name) {
+        RulePolicyRepresentation expected = new RulePolicyRepresentation();
+
+        expected.setName(name);
+        expected.setDescription("description");
+        expected.setArtifactGroupId("org.keycloak");
+        expected.setArtifactId("photoz-authz-policy");
+        expected.setArtifactVersion(Version.VERSION);
+        expected.setModuleName("PhotozAuthzOwnerPolicy");
+        expected.setSessionName("MainOwnerSession");
+        expected.setScannerPeriod("1");
+        expected.setScannerPeriodUnit("Minutes");
+
+        return expected;
+    }
+
+    private RulePolicyRepresentation createPolicy(RulePolicyRepresentation expected) {
+        RulePolicy policy = authorizationPage.authorizationTabs().policies().create(expected);
+        assertAlertSuccess();
+        return assertPolicy(expected, policy);
+    }
+
+    private RulePolicyRepresentation assertPolicy(RulePolicyRepresentation expected, RulePolicy policy) {
+        RulePolicyRepresentation actual = policy.toRepresentation();
+
+        assertEquals(expected.getName(), actual.getName());
+        assertEquals(expected.getDescription(), actual.getDescription());
+        assertEquals(expected.getLogic(), actual.getLogic());
+        assertEquals(expected.getArtifactGroupId(), actual.getArtifactGroupId());
+        assertEquals(expected.getArtifactId(), actual.getArtifactId());
+        assertEquals(expected.getArtifactVersion(), actual.getArtifactVersion());
+        assertEquals(expected.getModuleName(), actual.getModuleName());
+        assertEquals(expected.getSessionName(), actual.getSessionName());
+        assertEquals(expected.getScannerPeriod(), actual.getScannerPeriod());
+        assertEquals(expected.getScannerPeriodUnit(), actual.getScannerPeriodUnit());
+
+        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 9918041..aed7cbb 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
@@ -757,6 +757,8 @@ module.controller('ResourceServerPolicyDroolsDetailCtrl', function($scope, $http
                     policy = $scope.policy;
                 }
 
+                delete policy.config;
+
                 $http.post(authUrl + '/admin/realms/'+ $route.current.params.realm + '/clients/' + client.id + '/authz/resource-server/policy/rules/provider/resolveModules'
                         , policy).success(function(data) {
                             $scope.drools.moduleNames = data;
@@ -765,6 +767,8 @@ module.controller('ResourceServerPolicyDroolsDetailCtrl', function($scope, $http
             }
 
             $scope.resolveSessions = function() {
+                delete $scope.policy.config;
+
                 $http.post(authUrl + '/admin/realms/'+ $route.current.params.realm + '/clients/' + client.id + '/authz/resource-server/policy/rules/provider/resolveSessions'
                         , $scope.policy).success(function(data) {
                             $scope.drools.moduleSessions = data;
@@ -773,17 +777,21 @@ module.controller('ResourceServerPolicyDroolsDetailCtrl', function($scope, $http
         },
 
         onInitUpdate : function(policy) {
-            policy.config.scannerPeriod = parseInt(policy.config.scannerPeriod);
+            policy.scannerPeriod = parseInt(policy.scannerPeriod);
             $scope.resolveModules(policy);
         },
 
         onUpdate : function() {
-            $scope.policy.config.resources = JSON.stringify($scope.policy.config.resources);
+            delete $scope.policy.config;
         },
 
         onInitCreate : function(newPolicy) {
-            newPolicy.config.scannerPeriod = 1;
-            newPolicy.config.scannerPeriodUnit = 'Hours';
+            newPolicy.scannerPeriod = 1;
+            newPolicy.scannerPeriodUnit = 'Hours';
+        },
+
+        onCreate : function() {
+            delete $scope.policy.config;
         }
     }, realm, client, $scope);
 });
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-drools-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-drools-detail.html
index 2a75327..612a8a4 100644
--- a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-drools-detail.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-drools-detail.html
@@ -31,31 +31,31 @@
                 <kc-tooltip>{{:: 'authz-policy-description.tooltip' | translate}}</kc-tooltip>
             </div>
             <div class="form-group">
-                <label class="col-md-2 control-label" for="policy.config.mavenArtifactGroupId">{{:: 'authz-policy-drools-maven-artifact' | translate}} <span class="required" data-ng-show="create">*</span></label>
-                <button data-ng-click="resolveModules()" class="btn btn-primary">{{:: 'authz-policy-drools-maven-artifact-resolve' | translate}}</button>
+                <label class="col-md-2 control-label" for="artifactGroupId">{{:: 'authz-policy-drools-maven-artifact' | translate}} <span class="required" data-ng-show="create">*</span></label>
+                <button data-ng-click="resolveModules()" id="resolveModule" class="btn btn-primary">{{:: 'authz-policy-drools-maven-artifact-resolve' | translate}}</button>
                 <div class="col-sm-3">
-                    <input class="form-control" type="text" id="policy.config.mavenArtifactGroupId" name="policy.config.mavenArtifactGroupId" data-ng-model="policy.config.mavenArtifactGroupId" placeholder="Group Identifier" required>
+                    <input class="form-control" type="text" id="artifactGroupId" name="artifactGroupId" data-ng-model="policy.artifactGroupId" placeholder="Group Identifier" required>
                 </div>
                 <kc-tooltip>{{:: 'authz-policy-drools-maven-artifact.tooltip' | translate}}</kc-tooltip>
             </div>
             <div class="form-group">
-                <label class="col-md-2 control-label" for="policy.config.mavenArtifactId"></label>
+                <label class="col-md-2 control-label" for="artifactId"></label>
                 <div class="col-sm-3">
-                    <input class="form-control" type="text" id="policy.config.mavenArtifactId" name="policy.config.mavenArtifactId" data-ng-model="policy.config.mavenArtifactId" autofocus placeholder="Artifact Identifier" required>
+                    <input class="form-control" type="text" id="artifactId" name="artifactId" data-ng-model="policy.artifactId" autofocus placeholder="Artifact Identifier" required>
                 </div>
             </div>
             <div class="form-group">
-                <label class="col-md-2 control-label" for="policy.config.mavenArtifactVersion"></label>
+                <label class="col-md-2 control-label" for="artifactVersion"></label>
                 <div class="col-sm-3">
-                    <input class="form-control" type="text" id="policy.config.mavenArtifactVersion" name="policy.config.mavenArtifactVersion" data-ng-model="policy.config.mavenArtifactVersion" autofocus placeholder="Version" required>
+                    <input class="form-control" type="text" id="artifactVersion" name="artifactVersion" data-ng-model="policy.artifactVersion" autofocus placeholder="Version" required>
                 </div>
             </div>
             <div class="form-group">
-                <label class="col-md-2 control-label" for="policy.config.moduleName">{{:: 'authz-policy-drools-module' | translate}} <span class="required" data-ng-show="create">*</span></label>
+                <label class="col-md-2 control-label" for="moduleName">{{:: 'authz-policy-drools-module' | translate}} <span class="required" data-ng-show="create">*</span></label>
                 <div class="col-sm-3">
                     <div>
-                        <select class="form-control" id="policy.config.moduleName"
-                                ng-model="policy.config.moduleName"
+                        <select class="form-control" id="moduleName"
+                                ng-model="policy.moduleName"
                                 ng-options="moduleName as moduleName for moduleName in drools.moduleNames"
                                 ng-change="resolveSessions()"
                                 ng-disabled="!drools.moduleNames.length"
@@ -66,11 +66,11 @@
                 <kc-tooltip>{{:: 'authz-policy-drools-module.tooltip' | translate}}</kc-tooltip>
             </div>
             <div class="form-group">
-                <label class="col-md-2 control-label" for="policy.config.sessionName">{{:: 'authz-policy-drools-session' | translate}} <span class="required" data-ng-show="create">*</span></label>
+                <label class="col-md-2 control-label" for="sessionName">{{:: 'authz-policy-drools-session' | translate}} <span class="required" data-ng-show="create">*</span></label>
                 <div class="col-sm-3">
                     <div>
-                        <select class="form-control" id="policy.config.sessionName"
-                                ng-model="policy.config.sessionName"
+                        <select class="form-control" id="sessionName"
+                                ng-model="policy.sessionName"
                                 ng-options="sessionName as sessionName for sessionName in drools.moduleSessions"
                                 ng-disabled="!drools.moduleSessions.length"
                                 required>
@@ -80,14 +80,14 @@
                 <kc-tooltip>{{:: 'authz-policy-drools-session.tooltip' | translate}}</kc-tooltip>
             </div>
             <div class="form-group">
-                <label class="col-md-2 control-label" for="policy.config.scannerPeriod">{{:: 'authz-policy-drools-update-period' | translate}}</label>
+                <label class="col-md-2 control-label" for="scannerPeriod">{{:: 'authz-policy-drools-update-period' | translate}}</label>
                 <div class="col-md-6 time-selector">
-                    <input class="form-control" type="number" required min="1" max="31536000" data-ng-model="policy.config.scannerPeriod" id="policy.config.scannerPeriod"
-                           name="policy.config.scannerPeriod"
-                           ng-disabled="!policy.config.sessionName"/>
-                    <select class="form-control" name="policy.config.scannerPeriodUnit"
-                            data-ng-model="policy.config.scannerPeriodUnit"
-                            ng-disabled="!policy.config.sessionName">
+                    <input class="form-control" type="number" required min="1" max="31536000" data-ng-model="policy.scannerPeriod" id="scannerPeriod"
+                           name="scannerPeriod"
+                           ng-disabled="!policy.sessionName"/>
+                    <select class="form-control" id="scannerPeriodUnit" name="scannerPeriodUnit"
+                            data-ng-model="policy.scannerPeriodUnit"
+                            ng-disabled="!policy.sessionName">
                         <option value="Seconds">{{:: 'seconds' | translate}}</option>
                         <option value="Minutes">{{:: 'minutes' | translate}}</option>
                         <option value="Hours">{{:: 'hours' | translate}}</option>
@@ -97,10 +97,10 @@
                 <kc-tooltip>{{:: 'authz-policy-drools-update-period.tooltip' | translate}}</kc-tooltip>
             </div>
             <div class="form-group clearfix">
-                <label class="col-md-2 control-label" for="policy.logic">{{:: 'authz-policy-logic' | translate}}</label>
+                <label class="col-md-2 control-label" for="logic">{{:: 'authz-policy-logic' | translate}}</label>
 
                 <div class="col-sm-1">
-                    <select class="form-control" id="policy.logic"
+                    <select class="form-control" id="logic"
                             data-ng-model="policy.logic">
                         <option value="POSITIVE">{{:: 'authz-policy-logic-positive' | translate}}</option>
                         <option value="NEGATIVE">{{:: 'authz-policy-logic-negative' | translate}}</option>