API for roles

Jens Pelzetter 2020-06-03 17:56:10 +02:00
parent 632805d9ac
commit 7d787f98bd
3 changed files with 204 additions and 83 deletions

View File

@ -5,6 +5,8 @@
*/ */
package org.libreccm.api.admin.security; package org.libreccm.api.admin.security;
import org.libreccm.api.ExtractedIdentifier;
import org.libreccm.api.IdentifierExtractor;
import org.libreccm.core.CcmObjectRepository; import org.libreccm.core.CcmObjectRepository;
import org.libreccm.core.CoreConstants; import org.libreccm.core.CoreConstants;
import org.libreccm.api.admin.security.dto.RoleData; import org.libreccm.api.admin.security.dto.RoleData;
@ -36,12 +38,14 @@ import org.libreccm.security.Party;
import org.libreccm.security.PartyRepository; import org.libreccm.security.PartyRepository;
import org.libreccm.security.Permission; import org.libreccm.security.Permission;
import org.libreccm.security.PermissionManager; import org.libreccm.security.PermissionManager;
import org.libreccm.security.PermissionRepository;
import org.libreccm.security.RequiresPrivilege; import org.libreccm.security.RequiresPrivilege;
import org.libreccm.security.Role; import org.libreccm.security.Role;
import org.libreccm.security.RoleManager; import org.libreccm.security.RoleManager;
import org.libreccm.security.RoleRepository; import org.libreccm.security.RoleRepository;
import java.net.URI; import java.net.URI;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.ws.rs.WebApplicationException; import javax.ws.rs.WebApplicationException;
@ -57,12 +61,18 @@ public class RolesApi {
@Inject @Inject
private CcmObjectRepository ccmObjectRepository; private CcmObjectRepository ccmObjectRepository;
@Inject
private IdentifierExtractor identifierExtractor;
@Inject @Inject
private PartyRepository partyRepository; private PartyRepository partyRepository;
@Inject @Inject
private PermissionManager permissionManager; private PermissionManager permissionManager;
@Inject
private PermissionRepository permissionRepository;
@Inject @Inject
private SecurityApiRepository repository; private SecurityApiRepository repository;
@ -270,14 +280,56 @@ public class RolesApi {
) )
) )
); );
permission = permissionManager.grantPrivilege( if (permissionRepository.existsPermission(
privilege, role, object privilege, role, object
); )) {
return Response.ok(
String.format(
"A permission granting privilege %s on object %s to "
+ "role %s already exists.",
privilege,
object.getDisplayName(),
role.getName()
)
).build();
} else {
permission = permissionManager.grantPrivilege(
privilege, role, object
);
return Response.created(
URI.create(
String.format(
"/api/admin/roles/%s/permissions/UUID-%s",
role.getName(),
permission.getUuid()
)
)
).build();
}
} else { } else {
permission = permissionManager.grantPrivilege(privilege, role); if (permissionRepository.existsPermission(privilege, role)) {
} return Response.ok(
String.format(
"A permission granting the privilege %s to "
+ "role %s already exists.",
privilege,
role.getName()
)
).build();
} else {
permission = permissionManager.grantPrivilege(privilege, role);
throw new UnsupportedOperationException(); return Response.created(
URI.create(
String.format(
"/api/admin/roles/%s/permissions/UUID-%s",
role.getName(),
permission.getUuid()
)
)
).build();
}
}
} }
@DELETE @DELETE
@ -286,10 +338,56 @@ public class RolesApi {
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public Response removePermission( public Response removePermission(
@PathParam("roleIdentifier") final String roleIdentifier, @PathParam("roleIdentifier")
@PathParam("permissionIdentifier") final String permissionIdentifier final String roleIdentifier,
@PathParam("permissionIdentifier")
final String permissionIdentifierParam
) { ) {
throw new UnsupportedOperationException(); final Role role = repository.findRole(roleIdentifier);
final ExtractedIdentifier permissionIdentifier = identifierExtractor
.extractIdentifier(roleIdentifier);
final Permission permission;
switch (permissionIdentifier.getType()) {
case ID:
permission = permissionRepository
.findById(
Long.parseLong(permissionIdentifier.getIdentifier())
)
.orElseThrow(
() -> new WebApplicationException(
String.format(
"No permission with ID %s found.",
permissionIdentifier.getIdentifier()),
Response.Status.NOT_FOUND
)
);
break;
case UUID:
permission = permissionRepository
.findByUuid(permissionIdentifier.getIdentifier())
.orElseThrow(
() -> new WebApplicationException(
String.format(
"No permission with UUID %s found.",
permissionIdentifier.getIdentifier()
),
Response.Status.NOT_FOUND
)
);
break;
default:
return Response
.status(Response.Status.BAD_REQUEST)
.entity("Permissions can only be identified by ID or UUID.")
.build();
}
permissionRepository.delete(permission);
return Response.ok().build();
} }
} }

View File

@ -57,8 +57,10 @@ public class PermissionManager implements Serializable {
@SuppressWarnings("PMD.LongVariable") @SuppressWarnings("PMD.LongVariable")
private static final String QUERY_PARAM_OBJECT = "object"; private static final String QUERY_PARAM_OBJECT = "object";
@SuppressWarnings("PMD.LongVariable") @SuppressWarnings("PMD.LongVariable")
private static final String QUERY_PARAM_GRANTEE = "grantee"; private static final String QUERY_PARAM_GRANTEE = "grantee";
@SuppressWarnings("PMD.LongVariable") @SuppressWarnings("PMD.LongVariable")
private static final String QUERY_PARAM_PRIVILEGE = "privilege"; private static final String QUERY_PARAM_PRIVILEGE = "privilege";
@ -166,11 +168,15 @@ public class PermissionManager implements Serializable {
"Can't grant a permission on object NULL."); "Can't grant a permission on object NULL.");
} }
if (existsInheritedPermission(privilege, grantee, object)) { if (permissionRepository.existsInheritedPermission(
privilege, grantee, object
)) {
revokePrivilege(privilege, grantee, object); revokePrivilege(privilege, grantee, object);
} }
if (existsPermission(privilege, grantee, object)) { if (permissionRepository.existsPermission(
privilege, grantee, object
)) {
return null; return null;
} else { } else {
final Permission permission = new Permission(); final Permission permission = new Permission();
@ -360,7 +366,9 @@ public class PermissionManager implements Serializable {
final CcmObject object, final CcmObject object,
final CcmObject inheritedFrom) { final CcmObject inheritedFrom) {
if (!existsPermission(privilege, grantee, object)) { if (!permissionRepository.existsPermission(
privilege, grantee, object
)) {
final Permission permission = new Permission(); final Permission permission = new Permission();
permission.setGrantee(grantee); permission.setGrantee(grantee);
permission.setGrantedPrivilege(privilege); permission.setGrantedPrivilege(privilege);
@ -380,17 +388,19 @@ public class PermissionManager implements Serializable {
} }
/** /**
* Grants a privilege to a role. If the privilege was already granted, the * Grants a privilege to a role.If the privilege was already granted, the
* method does nothing. * method does nothing.
* *
* @param privilege The privilege to grant. * @param privilege The privilege to grant.
* @param grantee The role to which the privilege is granted. * @param grantee The role to which the privilege is granted.
*
* @return The newly granted permission.
*/ */
@AuthorizationRequired @AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public void grantPrivilege(final String privilege, public Permission grantPrivilege(final String privilege,
final Role grantee) { final Role grantee) {
if (privilege == null || privilege.isEmpty()) { if (privilege == null || privilege.isEmpty()) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Can't grant a permission without a privilege."); "Can't grant a permission without a privilege.");
@ -401,7 +411,7 @@ public class PermissionManager implements Serializable {
"Can't grant a permission to grantee null."); "Can't grant a permission to grantee null.");
} }
if (!existsPermission(privilege, grantee)) { if (!permissionRepository.existsPermission(privilege, grantee)) {
final Permission permission = new Permission(); final Permission permission = new Permission();
permission.setGrantee(grantee); permission.setGrantee(grantee);
permission.setGrantedPrivilege(privilege); permission.setGrantedPrivilege(privilege);
@ -411,7 +421,7 @@ public class PermissionManager implements Serializable {
entityManager.persist(permission); entityManager.persist(permission);
return permission; return permission;
} else{ } else {
// ToDo // ToDo
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@ -453,9 +463,10 @@ public class PermissionManager implements Serializable {
grantee.getName(), grantee.getName(),
object.getUuid()); object.getUuid());
if (existsPermission(privilege, grantee, object) if (permissionRepository.existsPermission(privilege, grantee, object)
|| existsInheritedPermission(privilege, grantee, object)) { || permissionRepository.existsInheritedPermission(
privilege, grantee, object
)) {
LOGGER.debug("There is a permission for the provided parameters, " LOGGER.debug("There is a permission for the provided parameters, "
+ "revoking it..."); + "revoking it...");
@ -512,7 +523,7 @@ public class PermissionManager implements Serializable {
"Can't revoke a permission from grantee null."); "Can't revoke a permission from grantee null.");
} }
if (existsPermission(privilege, grantee)) { if (permissionRepository.existsPermission(privilege, grantee)) {
final Query query = entityManager.createQuery( final Query query = entityManager.createQuery(
"DELETE FROM Permission p " "DELETE FROM Permission p "
+ "WHERE p.grantedPrivilege = :privilege " + "WHERE p.grantedPrivilege = :privilege "
@ -622,60 +633,4 @@ public class PermissionManager implements Serializable {
} }
} }
/**
* Checks if a not inherited permission granting the provided
* {@code privilege} on the provided {@code object} to the provided
* {@code role} exists.
*
* @param privilege The privilege granted by the permission.
* @param grantee The role to which the privilege was granted.
* @param object The object on which the privilege is granted.
*
* @return {@code true} if there is a matching permission, {@code false} if
* not.
*/
private boolean existsPermission(final String privilege,
final Role grantee,
final CcmObject object) {
final TypedQuery<Long> query = entityManager.createNamedQuery(
"Permission.existsDirectForPrivilegeRoleObject", Long.class);
query.setParameter(QUERY_PARAM_PRIVILEGE, privilege);
query.setParameter(QUERY_PARAM_GRANTEE, grantee);
query.setParameter(QUERY_PARAM_OBJECT, object);
return query.getSingleResult() > 0;
}
private boolean existsInheritedPermission(final String privilege,
final Role grantee,
final CcmObject object) {
final TypedQuery<Long> query = entityManager.createNamedQuery(
"Permission.existsInheritedForPrivilegeRoleObject", Long.class);
query.setParameter(QUERY_PARAM_PRIVILEGE, privilege);
query.setParameter(QUERY_PARAM_GRANTEE, grantee);
query.setParameter(QUERY_PARAM_OBJECT, object);
return query.getSingleResult() > 0;
}
/**
* Checks if a permission granting the provided {@code privilege}to the
* provided {@code role} exists.
*
* @param privilege The privilege granted by the permission.
* @param grantee The role to which the privilege was granted.
*
* @return {@code true} if there is a matching permission, {@code false} if
* not.
*/
private boolean existsPermission(final String privilege,
final Role grantee) {
final TypedQuery<Long> query = entityManager.createNamedQuery(
"Permission.existsForPrivilegeAndRole", Long.class);
query.setParameter(QUERY_PARAM_PRIVILEGE, privilege);
query.setParameter(QUERY_PARAM_GRANTEE, grantee);
return query.getSingleResult() > 0;
}
} }

View File

@ -19,6 +19,7 @@
package org.libreccm.security; package org.libreccm.security;
import org.libreccm.core.AbstractEntityRepository; import org.libreccm.core.AbstractEntityRepository;
import org.libreccm.core.CcmObject;
import javax.enterprise.context.RequestScoped; import javax.enterprise.context.RequestScoped;
import javax.persistence.NoResultException; import javax.persistence.NoResultException;
@ -39,6 +40,15 @@ public class PermissionRepository
private static final long serialVersionUID = -4240674229117593486L; private static final long serialVersionUID = -4240674229117593486L;
@SuppressWarnings("PMD.LongVariable")
private static final String QUERY_PARAM_OBJECT = "object";
@SuppressWarnings("PMD.LongVariable")
private static final String QUERY_PARAM_GRANTEE = "grantee";
@SuppressWarnings("PMD.LongVariable")
private static final String QUERY_PARAM_PRIVILEGE = "privilege";
@Override @Override
public Class<Permission> getEntityClass() { public Class<Permission> getEntityClass() {
return Permission.class; return Permission.class;
@ -63,14 +73,14 @@ public class PermissionRepository
} }
@Override @Override
public void initNewEntity(final Permission permission) { public void initNewEntity(final Permission permission) {
permission.setUuid(UUID.randomUUID().toString()); permission.setUuid(UUID.randomUUID().toString());
} }
public Optional<Permission> findByUuid(final String uuid) { public Optional<Permission> findByUuid(final String uuid) {
final TypedQuery<Permission> query = getEntityManager() final TypedQuery<Permission> query = getEntityManager()
.createNamedQuery("Permission.findByUuid", Permission.class); .createNamedQuery("Permission.findByUuid", Permission.class);
query.setParameter("uuid", uuid); query.setParameter("uuid", uuid);
return getSingleResult(query); return getSingleResult(query);
@ -106,4 +116,62 @@ public class PermissionRepository
} }
} }
/**
* Checks if a not inherited permission granting the provided
* {@code privilege} on the provided {@code object} to the provided
* {@code role} exists.
*
* @param privilege The privilege granted by the permission.
* @param grantee The role to which the privilege was granted.
* @param object The object on which the privilege is granted.
*
* @return {@code true} if there is a matching permission, {@code false} if
* not.
*/
public boolean existsPermission(final String privilege,
final Role grantee,
final CcmObject object) {
final TypedQuery<Long> query = getEntityManager()
.createNamedQuery(
"Permission.existsDirectForPrivilegeRoleObject", Long.class
);
query.setParameter(QUERY_PARAM_PRIVILEGE, privilege);
query.setParameter(QUERY_PARAM_GRANTEE, grantee);
query.setParameter(QUERY_PARAM_OBJECT, object);
return query.getSingleResult() > 0;
}
public boolean existsInheritedPermission(final String privilege,
final Role grantee,
final CcmObject object) {
final TypedQuery<Long> query = getEntityManager().createNamedQuery(
"Permission.existsInheritedForPrivilegeRoleObject", Long.class);
query.setParameter(QUERY_PARAM_PRIVILEGE, privilege);
query.setParameter(QUERY_PARAM_GRANTEE, grantee);
query.setParameter(QUERY_PARAM_OBJECT, object);
return query.getSingleResult() > 0;
}
/**
* Checks if a permission granting the provided {@code privilege}to the
* provided {@code role} exists.
*
* @param privilege The privilege granted by the permission.
* @param grantee The role to which the privilege was granted.
*
* @return {@code true} if there is a matching permission, {@code false} if
* not.
*/
public boolean existsPermission(final String privilege,
final Role grantee) {
final TypedQuery<Long> query = getEntityManager().createNamedQuery(
"Permission.existsForPrivilegeAndRole", Long.class);
query.setParameter(QUERY_PARAM_PRIVILEGE, privilege);
query.setParameter(QUERY_PARAM_GRANTEE, grantee);
return query.getSingleResult() > 0;
}
} }