adds RbacRoleControllerRestTest + RbacRoleRepositoryIntegrationTest + fix duplicate key

This commit is contained in:
Michael Hoennig 2022-08-04 09:11:11 +02:00
parent 57cf316c00
commit 212b1077c8
8 changed files with 246 additions and 54 deletions

View File

@ -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;
} }

View File

@ -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);
} }

View File

@ -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);

View File

@ -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)

View File

@ -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;
$$; $$;
--// --//

View File

@ -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())));
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}