killbill-aplcache

Details

diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SecurityResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SecurityResource.java
index 8f3b390..60e55b5 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SecurityResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SecurityResource.java
@@ -204,4 +204,22 @@ public class SecurityResource extends JaxRsResourceBase {
         securityApi.addRoleDefinition(json.getRole(), json.getPermissions(), context.createCallContextNoAccountId(createdBy, reason, comment, request));
         return Response.status(Status.CREATED).build();
     }
+
+
+    @TimedResource
+    @PUT
+    @Consumes(APPLICATION_JSON)
+    @Produces(APPLICATION_JSON)
+    @Path("/roles")
+    @ApiOperation(value = "Update a new role definition)")
+    public Response updateRoleDefinition(final RoleDefinitionJson json,
+                                    @HeaderParam(HDR_CREATED_BY) final String createdBy,
+                                    @HeaderParam(HDR_REASON) final String reason,
+                                    @HeaderParam(HDR_COMMENT) final String comment,
+                                    @javax.ws.rs.core.Context final HttpServletRequest request,
+                                    @javax.ws.rs.core.Context final UriInfo uriInfo) throws SecurityApiException {
+        securityApi.updateRoleDefinition(json.getRole(), json.getPermissions(), context.createCallContextNoAccountId(createdBy, reason, comment, request));
+        return Response.status(Status.OK).build();
+    }
+
 }
diff --git a/util/src/main/java/org/killbill/billing/util/security/api/DefaultSecurityApi.java b/util/src/main/java/org/killbill/billing/util/security/api/DefaultSecurityApi.java
index 70ed26c..3d30a3c 100644
--- a/util/src/main/java/org/killbill/billing/util/security/api/DefaultSecurityApi.java
+++ b/util/src/main/java/org/killbill/billing/util/security/api/DefaultSecurityApi.java
@@ -206,6 +206,12 @@ public class DefaultSecurityApi implements SecurityApi {
     }
 
     @Override
+    public void updateRoleDefinition(final String role, final List<String> permissions, final CallContext callContext) throws SecurityApiException {
+        final List<String> sanitizedPermissions = sanitizeAndValidatePermissions(permissions);
+        userDao.updateRoleDefinition(role, sanitizedPermissions, callContext.getUserName());
+    }
+
+    @Override
     public List<String> getRoleDefinition(final String role, final TenantContext tenantContext) {
         final List<RolesPermissionsModelDao> permissionsModelDao = userDao.getRoleDefinition(role);
         return ImmutableList.copyOf(Iterables.transform(permissionsModelDao, new Function<RolesPermissionsModelDao, String>() {
diff --git a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/DefaultUserDao.java b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/DefaultUserDao.java
index 013f859..1d9757d 100644
--- a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/DefaultUserDao.java
+++ b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/DefaultUserDao.java
@@ -17,8 +17,11 @@
 
 package org.killbill.billing.util.security.shiro.dao;
 
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
+import javax.annotation.Nullable;
 import javax.inject.Inject;
 
 import org.apache.shiro.crypto.RandomNumberGenerator;
@@ -113,6 +116,50 @@ public class DefaultUserDao implements UserDao {
     }
 
     @Override
+    public void updateRoleDefinition(final String role, final List<String> permissions, final String createdBy) throws SecurityApiException {
+        final DateTime createdDate = clock.getUTCNow();
+        inTransactionWithExceptionHandling(new TransactionCallback<Void>() {
+            @Override
+            public Void inTransaction(final Handle handle, final TransactionStatus status) throws Exception {
+                final RolesPermissionsSqlDao rolesPermissionsSqlDao = handle.attach(RolesPermissionsSqlDao.class);
+                final List<RolesPermissionsModelDao> existingPermissions = rolesPermissionsSqlDao.getByRoleName(role);
+                if (existingPermissions.isEmpty()) {
+                    throw new SecurityApiException(ErrorCode.SECURITY_INVALID_ROLE, role);
+                }
+
+                final Iterable<RolesPermissionsModelDao> toBeDeleted = Iterables.filter(existingPermissions, new Predicate<RolesPermissionsModelDao>() {
+                    @Override
+                    public boolean apply(final RolesPermissionsModelDao input) {
+                        return !permissions.contains(input.getPermission());
+                    }
+                });
+
+                final Iterable<String> toBeAdded = Iterables.filter(permissions, new Predicate<String>() {
+                    @Override
+                    public boolean apply(final String input) {
+                        for (RolesPermissionsModelDao e : existingPermissions) {
+                            if (e.getPermission().equals(input)) {
+                                return false;
+                            }
+                        }
+                        return true;
+                    }
+                });
+
+                for (RolesPermissionsModelDao d : toBeDeleted) {
+                    rolesPermissionsSqlDao.unactiveEvent(d.getRecordId(), createdDate, createdBy);
+                }
+
+                for (final String permission : toBeAdded) {
+                    rolesPermissionsSqlDao.create(new RolesPermissionsModelDao(role, permission, createdDate, createdBy));
+                }
+                return null;
+            }
+        });
+
+    }
+
+    @Override
     public List<RolesPermissionsModelDao> getRoleDefinition(final String role) {
         return dbi.inTransaction(new TransactionCallback<List<RolesPermissionsModelDao>>() {
             @Override
diff --git a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.java b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.java
index dccee99..ad4187f 100644
--- a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.java
+++ b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.java
@@ -19,6 +19,10 @@ package org.killbill.billing.util.security.shiro.dao;
 
 import java.util.List;
 
+import org.joda.time.DateTime;
+import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.util.audit.ChangeType;
+import org.killbill.billing.util.entity.dao.Audited;
 import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.Bind;
@@ -37,4 +41,12 @@ public interface RolesPermissionsSqlDao extends Transactional<RolesPermissionsSq
 
     @SqlUpdate
     public void create(@SmartBindBean final RolesPermissionsModelDao rolesPermissions);
+
+    @SqlUpdate
+    @Audited(ChangeType.UPDATE)
+    public void unactiveEvent(@Bind("recordId") final Long recordId,
+                              @Bind("createdDate")  final DateTime createdDate,
+                              @Bind("createdBy")  final String createdBy);
+
+
 }
diff --git a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/UserDao.java b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/UserDao.java
index 142e13d..f0b4427 100644
--- a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/UserDao.java
+++ b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/UserDao.java
@@ -29,6 +29,8 @@ public interface UserDao {
 
     public void addRoleDefinition(String role, List<String> permissions, String createdBy) throws SecurityApiException;
 
+    public void updateRoleDefinition(String role, List<String> permissions, String createdBy) throws SecurityApiException;
+
     public List<RolesPermissionsModelDao> getRoleDefinition(String role);
 
     public void updateUserPassword(String username, String password, String createdBy) throws SecurityApiException;
diff --git a/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.sql.stg b/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.sql.stg
index febc7ee..1d13de4 100644
--- a/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.sql.stg
+++ b/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.sql.stg
@@ -58,3 +58,16 @@ where role_name = :roleName
 and is_active
 ;
 >>
+
+unactiveEvent() ::= <<
+update <tableName()>
+set
+is_active = false
+, updated_by = :createdBy
+, updated_date = :createdDate
+where
+record_id = :recordId
+<AND_CHECK_TENANT("")>
+;
+>>
+
diff --git a/util/src/test/java/org/killbill/billing/util/security/shiro/realm/TestKillBillJdbcRealm.java b/util/src/test/java/org/killbill/billing/util/security/shiro/realm/TestKillBillJdbcRealm.java
index 30f90af..a2804e0 100644
--- a/util/src/test/java/org/killbill/billing/util/security/shiro/realm/TestKillBillJdbcRealm.java
+++ b/util/src/test/java/org/killbill/billing/util/security/shiro/realm/TestKillBillJdbcRealm.java
@@ -19,6 +19,8 @@ package org.killbill.billing.util.security.shiro.realm;
 
 import java.util.List;
 
+import javax.validation.constraints.AssertTrue;
+
 import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.authc.AuthenticationException;
 import org.apache.shiro.authc.AuthenticationToken;
@@ -178,6 +180,33 @@ public class TestKillBillJdbcRealm extends UtilTestSuiteWithEmbeddedDB {
             Assert.fail("Subject should not have rights to create tag definitions");
         } catch (AuthorizationException e) {
         }
+    }
+
+    @Test(groups = "slow")
+    public void testUpdateRoleDefinition() throws SecurityApiException {
+
+        final String username = "siskiyou";
+        final String password = "siskiyou33";
+
+        securityApi.addRoleDefinition("original", ImmutableList.of("account:*", "invoice", "tag:create_tag_definition"), callContext);
+        securityApi.addUserRoles(username, password, ImmutableList.of("restricted"), callContext);
+
+        final AuthenticationToken goodToken = new UsernamePasswordToken(username, password);
+
+        final List<String> roleDefinition = securityApi.getRoleDefinition("original", callContext);
+        Assert.assertEquals(roleDefinition.size(), 3);
+        Assert.assertTrue(roleDefinition.contains("account:*"));
+        Assert.assertTrue(roleDefinition.contains("invoice:*"));
+        Assert.assertTrue(roleDefinition.contains("tag:create_tag_definition"));
+
+        securityApi.updateRoleDefinition("original", ImmutableList.of("account:*", "payment", "tag:create_tag_definition", "entitlement:create"), callContext);
+
+        final List<String> updatedRoleDefinition = securityApi.getRoleDefinition("original", callContext);
+        Assert.assertEquals(updatedRoleDefinition.size(), 4);
+        Assert.assertTrue(updatedRoleDefinition.contains("account:*"));
+        Assert.assertTrue(updatedRoleDefinition.contains("payment:*"));
+        Assert.assertTrue(updatedRoleDefinition.contains("tag:create_tag_definition"));
+        Assert.assertTrue(updatedRoleDefinition.contains("entitlement:create"));
 
     }