adds RbacRoleControllerRestTest + RbacRoleRepositoryIntegrationTest + fix duplicate key
This commit is contained in:
parent
57cf316c00
commit
212b1077c8
@ -1,9 +1,6 @@
|
|||||||
package net.hostsharing.hsadminng.rbac.rbacrole;
|
package net.hostsharing.hsadminng.rbac.rbacrole;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.*;
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.Setter;
|
|
||||||
import org.hibernate.annotations.Formula;
|
import org.hibernate.annotations.Formula;
|
||||||
import org.springframework.data.annotation.Immutable;
|
import org.springframework.data.annotation.Immutable;
|
||||||
|
|
||||||
@ -14,6 +11,7 @@ import java.util.UUID;
|
|||||||
@Table(name = "rbacrole_rv")
|
@Table(name = "rbacrole_rv")
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
|
@ToString
|
||||||
@Immutable
|
@Immutable
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@ -25,16 +23,16 @@ public class RbacRoleEntity {
|
|||||||
@Column(name="objectuuid")
|
@Column(name="objectuuid")
|
||||||
private UUID objectUuid;
|
private UUID objectUuid;
|
||||||
|
|
||||||
@Column(name="roletype")
|
|
||||||
@Enumerated(EnumType.STRING)
|
|
||||||
private RbacRoleType roleType;
|
|
||||||
|
|
||||||
@Column(name="objecttable")
|
@Column(name="objecttable")
|
||||||
private String objectTable;
|
private String objectTable;
|
||||||
|
|
||||||
@Column(name="objectidname")
|
@Column(name="objectidname")
|
||||||
private String objectIdName;
|
private String objectIdName;
|
||||||
|
|
||||||
|
@Column(name="roletype")
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private RbacRoleType roleType;
|
||||||
|
|
||||||
@Formula("objectTable||'#'||objectIdName||'.'||roleType")
|
@Formula("objectTable||'#'||objectIdName||'.'||roleType")
|
||||||
private String roleName;
|
private String roleName;
|
||||||
}
|
}
|
||||||
|
@ -1,58 +1,17 @@
|
|||||||
package net.hostsharing.hsadminng.rbac.rbacrole;
|
package net.hostsharing.hsadminng.rbac.rbacrole;
|
||||||
|
|
||||||
import org.springframework.data.domain.Page;
|
|
||||||
import org.springframework.data.domain.Pageable;
|
|
||||||
import org.springframework.data.domain.Sort;
|
|
||||||
import org.springframework.data.repository.Repository;
|
import org.springframework.data.repository.Repository;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public interface RbacRoleRepository extends Repository<RbacRoleEntity, UUID> {
|
public interface RbacRoleRepository extends Repository<RbacRoleEntity, UUID> {
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves an entity by its id.
|
|
||||||
*
|
|
||||||
* @param id must not be {@literal null}.
|
|
||||||
* @return the entity with the given id or {@literal Optional#empty()} if none found.
|
|
||||||
* @throws IllegalArgumentException if {@literal id} is {@literal null}.
|
|
||||||
*/
|
|
||||||
Optional<RbacRoleEntity> findByUuid(UUID id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether an entity with the given id exists.
|
|
||||||
*
|
|
||||||
* @param id must not be {@literal null}.
|
|
||||||
* @return {@literal true} if an entity with the given id exists, {@literal false} otherwise.
|
|
||||||
* @throws IllegalArgumentException if {@literal id} is {@literal null}.
|
|
||||||
*/
|
|
||||||
boolean existsByUuid(RbacRoleEntity id);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all instances of the type.
|
* Returns all instances of the type.
|
||||||
*
|
*
|
||||||
* @return all entities
|
* @return all entities
|
||||||
*/
|
*/
|
||||||
Iterable<RbacRoleEntity> findAll();
|
List<RbacRoleEntity> findAll();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns all entities sorted by the given options.
|
|
||||||
*
|
|
||||||
* @param sort the {@link Sort} specification to sort the results by, can be {@link Sort#unsorted()}, must not be
|
|
||||||
* {@literal null}.
|
|
||||||
* @return all entities sorted by the given options
|
|
||||||
*/
|
|
||||||
List<RbacRoleEntity> findAll(Sort sort);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a {@link Page} of entities meeting the paging restriction provided in the {@link Pageable} object.
|
|
||||||
*
|
|
||||||
* @param pageable the pageable to request a paged result, can be {@link Pageable#unpaged()}, must not be
|
|
||||||
* {@literal null}.
|
|
||||||
* @return a page of entities
|
|
||||||
*/
|
|
||||||
Page<RbacRoleEntity> findAll(Pageable pageable);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,7 +179,6 @@ declare
|
|||||||
userUuid uuid;
|
userUuid uuid;
|
||||||
begin
|
begin
|
||||||
raise notice 'will createRole for %', roleDescriptor;
|
raise notice 'will createRole for %', roleDescriptor;
|
||||||
raise notice 'will createRole for % % %', roleDescriptor.objecttable, roleDescriptor.objectuuid, roleDescriptor.roletype;
|
|
||||||
roleUuid = createRole(roleDescriptor);
|
roleUuid = createRole(roleDescriptor);
|
||||||
|
|
||||||
call grantPermissionsToRole(roleUuid, permissions.permissionUuids);
|
call grantPermissionsToRole(roleUuid, permissions.permissionUuids);
|
||||||
|
@ -24,7 +24,7 @@ create or replace function packageOwner(pac package)
|
|||||||
returns null on null input
|
returns null on null input
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
begin
|
begin
|
||||||
return roleDescriptor('package', pac.uuid, 'admin');
|
return roleDescriptor('package', pac.uuid, 'owner');
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
create or replace function packageAdmin(pac package)
|
create or replace function packageAdmin(pac package)
|
||||||
|
@ -23,7 +23,7 @@ create or replace procedure createPackageTestData(
|
|||||||
loop
|
loop
|
||||||
CONTINUE WHEN cust.reference < minCustomerReference;
|
CONTINUE WHEN cust.reference < minCustomerReference;
|
||||||
|
|
||||||
for t in 0..randominrange(1, 2)
|
for t in 0..2
|
||||||
loop
|
loop
|
||||||
pacName = cust.prefix || to_char(t, 'fm00');
|
pacName = cust.prefix || to_char(t, 'fm00');
|
||||||
currentTask = 'creating RBAC test package #' || pacName || ' for customer ' || cust.prefix || ' #' ||
|
currentTask = 'creating RBAC test package #' || pacName || ' for customer ' || cust.prefix || ' #' ||
|
||||||
@ -59,4 +59,3 @@ do language plpgsql $$
|
|||||||
end;
|
end;
|
||||||
$$;
|
$$;
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
package net.hostsharing.hsadminng.rbac.rbacrole;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.context.Context;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
import static net.hostsharing.hsadminng.rbac.rbacrole.TestRbacRole.*;
|
||||||
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
@WebMvcTest(RbacRoleController.class)
|
||||||
|
class RbacRoleControllerRestTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
MockMvc mockMvc;
|
||||||
|
@MockBean
|
||||||
|
Context contextMock;
|
||||||
|
@MockBean
|
||||||
|
RbacRoleRepository rbacRoleRepository;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void apiCustomersWillReturnCustomersFromRepository() throws Exception {
|
||||||
|
|
||||||
|
// given
|
||||||
|
when(rbacRoleRepository.findAll()).thenReturn(
|
||||||
|
asList(hostmasterRole, customerXxxOwner, customerXxxAdmin));
|
||||||
|
|
||||||
|
// when
|
||||||
|
mockMvc.perform(MockMvcRequestBuilders
|
||||||
|
.get("/api/rbacroles")
|
||||||
|
.header("current-user", "mike@hostsharing.net")
|
||||||
|
.accept(MediaType.APPLICATION_JSON))
|
||||||
|
|
||||||
|
// then
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$", hasSize(3)))
|
||||||
|
.andExpect(jsonPath("$[0].roleName", is("global#hostsharing.admin")))
|
||||||
|
.andExpect(jsonPath("$[1].roleName", is("customer#xxx.owner")))
|
||||||
|
.andExpect(jsonPath("$[2].roleName", is("customer#xxx.admin")))
|
||||||
|
.andExpect(jsonPath("$[2].uuid", is(customerXxxAdmin.getUuid().toString())))
|
||||||
|
.andExpect(jsonPath("$[2].objectUuid", is(customerXxxAdmin.getObjectUuid().toString())))
|
||||||
|
.andExpect(jsonPath("$[2].objectTable", is(customerXxxAdmin.getObjectTable().toString())))
|
||||||
|
.andExpect(jsonPath("$[2].objectIdName", is(customerXxxAdmin.getObjectIdName().toString())));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,169 @@
|
|||||||
|
package net.hostsharing.hsadminng.rbac.rbacrole;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.context.Context;
|
||||||
|
import org.junit.jupiter.api.Nested;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.orm.jpa.JpaSystemException;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
import javax.transaction.Transactional;
|
||||||
|
|
||||||
|
import static net.hostsharing.test.JpaAttempt.attempt;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@DataJpaTest
|
||||||
|
@ComponentScan(basePackageClasses = { Context.class, RbacRoleRepository.class })
|
||||||
|
class RbacRoleRepositoryIntegrationTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
Context context;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
RbacRoleRepository rbacRoleRepository;
|
||||||
|
|
||||||
|
@Autowired EntityManager em;
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class FindAllRbacRoles {
|
||||||
|
|
||||||
|
private static final String[] ALL_TEST_DATA_ROLES = new String[] {
|
||||||
|
// @formatter:off
|
||||||
|
"global#hostsharing.admin",
|
||||||
|
"customer#aaa.admin", "customer#aaa.owner", "customer#aaa.tenant",
|
||||||
|
"package#aaa00.admin", "package#aaa00.owner", "package#aaa00.tenant",
|
||||||
|
"package#aaa01.admin", "package#aaa01.owner", "package#aaa01.tenant",
|
||||||
|
"package#aaa02.admin", "package#aaa02.owner", "package#aaa02.tenant",
|
||||||
|
"customer#aab.admin", "customer#aab.owner", "customer#aab.tenant",
|
||||||
|
"package#aab00.admin", "package#aab00.owner", "package#aab00.tenant",
|
||||||
|
"package#aab01.admin", "package#aab01.owner", "package#aab01.tenant",
|
||||||
|
"package#aab02.admin", "package#aab02.owner", "package#aab02.tenant",
|
||||||
|
"customer#aac.admin", "customer#aac.owner", "customer#aac.tenant",
|
||||||
|
"package#aac00.admin", "package#aac00.owner", "package#aac00.tenant",
|
||||||
|
"package#aac01.admin", "package#aac01.owner", "package#aac01.tenant",
|
||||||
|
"package#aac02.admin", "package#aac02.owner", "package#aac02.tenant"
|
||||||
|
// @formatter:on
|
||||||
|
};
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void hostsharingAdmin_withoutAssumedRole_canViewAllRbacRoles() {
|
||||||
|
// given
|
||||||
|
currentUser("mike@hostsharing.net");
|
||||||
|
|
||||||
|
// when
|
||||||
|
final var result = rbacRoleRepository.findAll();
|
||||||
|
|
||||||
|
// then
|
||||||
|
exactlyTheseRbacRolesAreReturned(result, ALL_TEST_DATA_ROLES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void hostsharingAdmin_withAssumedHostsharingAdminRole_canViewAllRbacRoles() {
|
||||||
|
given:
|
||||||
|
currentUser("mike@hostsharing.net");
|
||||||
|
assumedRoles("global#hostsharing.admin");
|
||||||
|
|
||||||
|
// when
|
||||||
|
final var result = rbacRoleRepository.findAll();
|
||||||
|
|
||||||
|
then:
|
||||||
|
exactlyTheseRbacRolesAreReturned(result, ALL_TEST_DATA_ROLES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void RbacRoleAdmin_withoutAssumedRole_canViewOnlyItsOwnRbacRole() {
|
||||||
|
// given:
|
||||||
|
currentUser("admin@aaa.example.com");
|
||||||
|
|
||||||
|
// when:
|
||||||
|
final var result = rbacRoleRepository.findAll();
|
||||||
|
|
||||||
|
// then:
|
||||||
|
exactlyTheseRbacRolesAreReturned(
|
||||||
|
result,
|
||||||
|
// @formatter:off
|
||||||
|
"customer#aaa.admin", "customer#aaa.tenant",
|
||||||
|
"package#aaa00.admin", "package#aaa00.owner", "package#aaa00.tenant",
|
||||||
|
"package#aaa01.admin", "package#aaa01.owner", "package#aaa01.tenant",
|
||||||
|
"package#aaa02.admin", "package#aaa02.owner", "package#aaa02.tenant"
|
||||||
|
// @formatter:on
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void RbacRoleAdmin_withAssumedOwnedPackageAdminRole_canViewOnlyItsOwnRbacRole() {
|
||||||
|
currentUser("admin@aaa.example.com");
|
||||||
|
assumedRoles("package#aaa00.admin");
|
||||||
|
|
||||||
|
final var result = rbacRoleRepository.findAll();
|
||||||
|
|
||||||
|
exactlyTheseRbacRolesAreReturned(result, "customer#aaa.tenant", "package#aaa00.tenant", "package#aaa00.admin");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void RbacRoleAdmin_withAssumedAlienPackageAdminRole_cannotViewAnyRbacRole() {
|
||||||
|
// given:
|
||||||
|
currentUser("admin@aaa.example.com");
|
||||||
|
assumedRoles("package#aab00.admin");
|
||||||
|
|
||||||
|
// when
|
||||||
|
final var attempt = attempt(
|
||||||
|
em,
|
||||||
|
() -> rbacRoleRepository.findAll());
|
||||||
|
|
||||||
|
// then
|
||||||
|
attempt.assertExceptionWithRootCauseMessage(
|
||||||
|
JpaSystemException.class,
|
||||||
|
"user admin@aaa.example.com .* has no permission to assume role package#aab00#admin");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void unknownUser_withoutAssumedRole_cannotViewAnyRbacRoles() {
|
||||||
|
currentUser("unknown@example.org");
|
||||||
|
|
||||||
|
final var attempt = attempt(
|
||||||
|
em,
|
||||||
|
() -> rbacRoleRepository.findAll());
|
||||||
|
|
||||||
|
attempt.assertExceptionWithRootCauseMessage(
|
||||||
|
JpaSystemException.class,
|
||||||
|
"hsadminng.currentUser defined as unknown@example.org, but does not exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Transactional
|
||||||
|
void unknownUser_withAssumedRbacRoleRole_cannotViewAnyRbacRoles() {
|
||||||
|
currentUser("unknown@example.org");
|
||||||
|
assumedRoles("RbacRole#aaa.admin");
|
||||||
|
|
||||||
|
final var attempt = attempt(
|
||||||
|
em,
|
||||||
|
() -> rbacRoleRepository.findAll());
|
||||||
|
|
||||||
|
attempt.assertExceptionWithRootCauseMessage(
|
||||||
|
JpaSystemException.class,
|
||||||
|
"hsadminng.currentUser defined as unknown@example.org, but does not exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void currentUser(final String currentUser) {
|
||||||
|
context.setCurrentUser(currentUser);
|
||||||
|
assertThat(context.getCurrentUser()).as("precondition").isEqualTo(currentUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
void assumedRoles(final String assumedRoles) {
|
||||||
|
context.assumeRoles(assumedRoles);
|
||||||
|
assertThat(context.getAssumedRoles()).as("precondition").containsExactly(assumedRoles.split(";"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void exactlyTheseRbacRolesAreReturned(final Iterable<RbacRoleEntity> actualResult, final String... rbacRoleNames) {
|
||||||
|
assertThat(actualResult)
|
||||||
|
//.hasSize(rbacRoleNames.length)
|
||||||
|
.extracting(RbacRoleEntity::getRoleName)
|
||||||
|
.containsExactlyInAnyOrder(rbacRoleNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package net.hostsharing.hsadminng.rbac.rbacrole;
|
||||||
|
|
||||||
|
import static java.util.UUID.randomUUID;
|
||||||
|
|
||||||
|
public class TestRbacRole {
|
||||||
|
|
||||||
|
public static final RbacRoleEntity hostmasterRole = rbacRole("global", "hostsharing", RbacRoleType.admin);
|
||||||
|
static final RbacRoleEntity customerXxxOwner = rbacRole("customer", "xxx", RbacRoleType.owner);
|
||||||
|
static final RbacRoleEntity customerXxxAdmin = rbacRole("customer", "xxx", RbacRoleType.admin);
|
||||||
|
|
||||||
|
static public RbacRoleEntity rbacRole(final String objectTable, final String objectIdName, final RbacRoleType roleType) {
|
||||||
|
return new RbacRoleEntity(randomUUID(), randomUUID(), objectTable, objectIdName, roleType, objectTable+'#'+objectIdName+'.'+roleType);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user