implements rbac-grants get-by-id
This commit is contained in:
parent
a66ed8e59f
commit
5ea8069608
@ -25,6 +25,27 @@ public class RbacGrantController implements RbacgrantsApi {
|
||||
@Autowired
|
||||
private RbacGrantRepository rbacGrantRepository;
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseEntity<RbacGrantResource> getGrantById(
|
||||
final String currentUser,
|
||||
final String assumedRoles,
|
||||
final UUID grantedRoleUuid,
|
||||
final UUID granteeUserUuid) {
|
||||
|
||||
context.setCurrentUser(currentUser);
|
||||
if (assumedRoles != null && !assumedRoles.isBlank()) {
|
||||
context.assumeRoles(assumedRoles);
|
||||
}
|
||||
|
||||
final var id = new RbacGrantId(granteeUserUuid, grantedRoleUuid);
|
||||
final var result = rbacGrantRepository.findById(id);
|
||||
if (result == null) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
return ResponseEntity.ok(map(result, RbacGrantResource.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseEntity<List<RbacGrantResource>> listUserGrants(
|
||||
|
@ -18,6 +18,7 @@ import java.util.UUID;
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class RbacGrantEntity {
|
||||
|
||||
@Column(name = "grantedbyroleidname", updatable = false, insertable = false)
|
||||
private String grantedByRoleIdName;
|
||||
|
||||
|
@ -8,6 +8,13 @@ import java.util.List;
|
||||
|
||||
public interface RbacGrantRepository extends Repository<RbacGrantEntity, RbacGrantId> {
|
||||
|
||||
@Query(value = """
|
||||
select g from RbacGrantEntity as g
|
||||
where g.grantedRoleUuid=:#{#rbacGrantId.grantedRoleUuid}
|
||||
and g.granteeUserUuid=:#{#rbacGrantId.granteeUserUuid}
|
||||
""")
|
||||
RbacGrantEntity findById(RbacGrantId rbacGrantId);
|
||||
|
||||
List<RbacGrantEntity> findAll();
|
||||
|
||||
void save(final RbacGrantEntity grant);
|
||||
|
@ -48,7 +48,15 @@ public class RbacUserController implements RbacusersApi {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly=true)
|
||||
public ResponseEntity<List<RbacUserPermissionResource>> getUserById(
|
||||
final String currentUser,
|
||||
final String assumedRoles,
|
||||
final String userName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseEntity<List<RbacUserResource>> listUsers(
|
||||
@RequestHeader(name = "current-user") final String currentUserName,
|
||||
@RequestHeader(name = "assumed-roles", required = false) final String assumedRoles,
|
||||
@ -62,7 +70,7 @@ public class RbacUserController implements RbacusersApi {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly=true)
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseEntity<List<RbacUserPermissionResource>> listUserPermissions(
|
||||
@RequestHeader(name = "current-user") final String currentUserName,
|
||||
@RequestHeader(name = "assumed-roles", required = false) final String assumedRoles,
|
||||
|
@ -3,7 +3,6 @@ package net.hostsharing.hsadminng.rbac.rbacuser;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
@ -17,8 +16,9 @@ public interface RbacUserRepository extends Repository<RbacUserEntity, UUID> {
|
||||
""")
|
||||
List<RbacUserEntity> findByOptionalNameLike(String userName);
|
||||
|
||||
@Query(value = "select uuid from rbacuser where name=:userName", nativeQuery = true)
|
||||
UUID findUuidByName(String userName);
|
||||
// bypasses the restricted view, to be able to grant rights to arbitrary user
|
||||
@Query(value = "select * from rbacuser where name=:userName", nativeQuery = true)
|
||||
RbacUserEntity findByName(String userName);
|
||||
|
||||
RbacUserEntity findByUuid(UUID uuid);
|
||||
|
||||
@ -32,7 +32,7 @@ public interface RbacUserRepository extends Repository<RbacUserEntity, UUID> {
|
||||
*/
|
||||
@Modifying
|
||||
@Query(value = "insert into RBacUser_RV (uuid, name) values( :#{#newUser.uuid}, :#{#newUser.name})", nativeQuery = true)
|
||||
void insert(@Param("newUser") final RbacUserEntity newUser);
|
||||
void insert(final RbacUserEntity newUser);
|
||||
|
||||
default RbacUserEntity create(final RbacUserEntity rbacUserEntity) {
|
||||
if (rbacUserEntity.getUuid() == null) {
|
||||
|
@ -13,8 +13,11 @@ paths:
|
||||
/api/rbac-users:
|
||||
$ref: "./api-definition/rbac-users.yaml"
|
||||
|
||||
/api/rbac-users/{userName}/permissions:
|
||||
$ref: "./api-definition/rbac-users-permissions.yaml"
|
||||
/api/rbac-users/{userUuid}:
|
||||
$ref: "./api-definition/rbac-users-with-id.yaml"
|
||||
|
||||
/api/rbac-users/{userUuid}/permissions:
|
||||
$ref: "./api-definition/rbac-users-with-id-permissions.yaml"
|
||||
|
||||
/api/rbac-roles:
|
||||
$ref: "./api-definition/rbac-roles.yaml"
|
||||
@ -23,7 +26,7 @@ paths:
|
||||
$ref: "./api-definition/rbac-grants.yaml"
|
||||
|
||||
/api/rbac-grants/{grantedRoleUuid}/{granteeUserUuid}:
|
||||
$ref: "./api-definition/rbac-grants-id.yaml"
|
||||
$ref: "./api-definition/rbac-grants-with-id.yaml"
|
||||
|
||||
# HS
|
||||
|
||||
|
@ -6,11 +6,20 @@ components:
|
||||
RbacGrant:
|
||||
type: object
|
||||
properties:
|
||||
grantedByRoleIdName:
|
||||
type: string
|
||||
grantedByRoleUuid:
|
||||
type: string
|
||||
format: uuid
|
||||
assumed:
|
||||
type: boolean
|
||||
grantedRoleIdName:
|
||||
type: string
|
||||
grantedRoleUuid:
|
||||
type: string
|
||||
format: uuid
|
||||
granteeUserName:
|
||||
type: string
|
||||
granteeUserUuid:
|
||||
type: string
|
||||
format: uuid
|
||||
|
@ -1,30 +0,0 @@
|
||||
delete:
|
||||
tags:
|
||||
- rbacgrants
|
||||
operationId: revokeRoleFromUser
|
||||
parameters:
|
||||
- $ref: './api-definition/auth.yaml#/components/parameters/currentUser'
|
||||
- $ref: './api-definition/auth.yaml#/components/parameters/assumedRoles'
|
||||
- name: grantedRoleUuid
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: UUID of the granted role.
|
||||
- name: granteeUserUuid
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: UUID of the user to whom the role was granted.
|
||||
responses:
|
||||
"204":
|
||||
description: No Content
|
||||
"401":
|
||||
$ref: './api-definition/error-responses.yaml#/components/responses/Unauthorized'
|
||||
"403":
|
||||
$ref: './api-definition/error-responses.yaml#/components/responses/Forbidden'
|
||||
"404":
|
||||
$ref: './api-definition/error-responses.yaml#/components/responses/NotFound'
|
65
src/main/resources/api-definition/rbac-grants-with-id.yaml
Normal file
65
src/main/resources/api-definition/rbac-grants-with-id.yaml
Normal file
@ -0,0 +1,65 @@
|
||||
get:
|
||||
tags:
|
||||
- rbacgrants
|
||||
operationId: getGrantById
|
||||
parameters:
|
||||
- $ref: './api-definition/auth.yaml#/components/parameters/currentUser'
|
||||
- $ref: './api-definition/auth.yaml#/components/parameters/assumedRoles'
|
||||
- name: grantedRoleUuid
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: UUID of the granted role.
|
||||
- name: granteeUserUuid
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: UUID of the user to whom the role was granted.
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
'application/json':
|
||||
schema:
|
||||
$ref: './api-definition/rbac-grant-schemas.yaml#/components/schemas/RbacGrant'
|
||||
"401":
|
||||
$ref: './api-definition/error-responses.yaml#/components/responses/Unauthorized'
|
||||
"403":
|
||||
$ref: './api-definition/error-responses.yaml#/components/responses/Forbidden'
|
||||
"404":
|
||||
$ref: './api-definition/error-responses.yaml#/components/responses/NotFound'
|
||||
|
||||
delete:
|
||||
tags:
|
||||
- rbacgrants
|
||||
operationId: revokeRoleFromUser
|
||||
parameters:
|
||||
- $ref: './api-definition/auth.yaml#/components/parameters/currentUser'
|
||||
- $ref: './api-definition/auth.yaml#/components/parameters/assumedRoles'
|
||||
- name: grantedRoleUuid
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: UUID of the granted role.
|
||||
- name: granteeUserUuid
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: UUID of the user to whom the role was granted.
|
||||
responses:
|
||||
"204":
|
||||
description: No Content
|
||||
"401":
|
||||
$ref: './api-definition/error-responses.yaml#/components/responses/Unauthorized'
|
||||
"403":
|
||||
$ref: './api-definition/error-responses.yaml#/components/responses/Forbidden'
|
||||
"404":
|
||||
$ref: './api-definition/error-responses.yaml#/components/responses/NotFound'
|
@ -13,7 +13,7 @@ get:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: './api-definition/rbac-grant-schemas.yaml#/components/schemas/RbacGrant'
|
||||
$ref: './rbac-grant-schemas.yaml#/components/schemas/RbacGrant'
|
||||
|
||||
post:
|
||||
tags:
|
||||
|
27
src/main/resources/api-definition/rbac-users-with-id.yaml
Normal file
27
src/main/resources/api-definition/rbac-users-with-id.yaml
Normal file
@ -0,0 +1,27 @@
|
||||
get:
|
||||
tags:
|
||||
- rbacusers
|
||||
description: 'Fetch a single user by its id, if visible for the current subject.'
|
||||
operationId: getUserById
|
||||
parameters:
|
||||
- $ref: './api-definition/auth.yaml#/components/parameters/currentUser'
|
||||
- $ref: './api-definition/auth.yaml#/components/parameters/assumedRoles'
|
||||
- name: userName
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
'application/json':
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: './api-definition/rbac-user-schemas.yaml#/components/schemas/RbacUserPermission'
|
||||
|
||||
"401":
|
||||
$ref: './api-definition/error-responses.yaml#/components/responses/Unauthorized'
|
||||
"403":
|
||||
$ref: './api-definition/error-responses.yaml#/components/responses/Forbidden'
|
@ -27,6 +27,7 @@ import java.util.UUID;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assumptions.assumeThat;
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
|
||||
@SpringBootTest(
|
||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
@ -57,6 +58,67 @@ class RbacGrantControllerAcceptanceTest {
|
||||
@Autowired
|
||||
JpaAttempt jpaAttempt;
|
||||
|
||||
@Nested
|
||||
class GetGrantById {
|
||||
|
||||
@Test
|
||||
@Accepts({ "GRT:R(Read)" })
|
||||
void customerAdmin_withAssumedPacketAdminRole_canReadPacketAdminsGrantById() {
|
||||
// given
|
||||
final var givenCurrentUserAsPackageAdmin = new Subject("admin@aaa.example.com");
|
||||
final var givenGranteeUser = findRbacUserByName("aaa00@aaa.example.com");
|
||||
final var givenGrantedRole = findRbacRoleByName("package#aaa00.admin");
|
||||
|
||||
// when
|
||||
final var grant = givenCurrentUserAsPackageAdmin.getGrantById()
|
||||
.forGrantedRole(givenGrantedRole).toGranteeUser(givenGranteeUser);
|
||||
|
||||
// then
|
||||
grant.assertThat()
|
||||
.statusCode(200)
|
||||
.body("grantedByRoleIdName", is("customer#aaa.admin"))
|
||||
.body("grantedRoleIdName", is("package#aaa00.admin"))
|
||||
.body("granteeUserName", is("aaa00@aaa.example.com"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Accepts({ "GRT:R(Read)" })
|
||||
void packageAdmin_withoutAssumedRole_canReadItsOwnGrantById() {
|
||||
// given
|
||||
final var givenCurrentUserAsPackageAdmin = new Subject("aaa00@aaa.example.com");
|
||||
final var givenGranteeUser = findRbacUserByName("aaa00@aaa.example.com");
|
||||
final var givenGrantedRole = findRbacRoleByName("package#aaa00.admin");
|
||||
|
||||
// when
|
||||
final var grant = givenCurrentUserAsPackageAdmin.getGrantById()
|
||||
.forGrantedRole(givenGrantedRole).toGranteeUser(givenGranteeUser);
|
||||
|
||||
// then
|
||||
grant.assertThat()
|
||||
.statusCode(200)
|
||||
.body("grantedByRoleIdName", is("customer#aaa.admin"))
|
||||
.body("grantedRoleIdName", is("package#aaa00.admin"))
|
||||
.body("granteeUserName", is("aaa00@aaa.example.com"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Accepts({ "GRT:R(Read)" })
|
||||
void packageAdmin_withAssumedUnixUserAdmin_canNotReadItsOwnGrantById() {
|
||||
// given
|
||||
final var givenCurrentUserAsPackageAdmin = new Subject("aaa00@aaa.example.com", "unixuser#aaa00-aaaa.admin");
|
||||
final var givenGranteeUser = findRbacUserByName("aaa00@aaa.example.com");
|
||||
final var givenGrantedRole = findRbacRoleByName("package#aaa00.admin");
|
||||
|
||||
// when
|
||||
final var grant = givenCurrentUserAsPackageAdmin.getGrantById()
|
||||
.forGrantedRole(givenGrantedRole).toGranteeUser(givenGranteeUser);
|
||||
|
||||
// then
|
||||
grant.assertThat()
|
||||
.statusCode(404);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class GrantRoleToUser {
|
||||
|
||||
@ -166,6 +228,10 @@ class RbacGrantControllerAcceptanceTest {
|
||||
this.assumedRole = assumedRole;
|
||||
}
|
||||
|
||||
public Subject(final String currentUser) {
|
||||
this(currentUser, "");
|
||||
}
|
||||
|
||||
GrantFixture grantsRole(final RbacRoleEntity givenOwnPackageAdminRole) {
|
||||
return new GrantFixture(givenOwnPackageAdminRole);
|
||||
}
|
||||
@ -174,6 +240,10 @@ class RbacGrantControllerAcceptanceTest {
|
||||
return new RevokeFixture(givenOwnPackageAdminRole);
|
||||
}
|
||||
|
||||
GetGrantByIdFixture getGrantById() {
|
||||
return new GetGrantByIdFixture();
|
||||
}
|
||||
|
||||
class GrantFixture {
|
||||
|
||||
private Subject grantingSubject = Subject.this;
|
||||
@ -252,6 +322,34 @@ class RbacGrantControllerAcceptanceTest {
|
||||
.then(); // @formatter:on
|
||||
}
|
||||
}
|
||||
|
||||
private class GetGrantByIdFixture {
|
||||
|
||||
private Subject currentSubject = Subject.this;
|
||||
private RbacRoleEntity grantedRole;
|
||||
private boolean assumed;
|
||||
private RbacUserEntity granteeUser;
|
||||
|
||||
GetGrantByIdFixture forGrantedRole(final RbacRoleEntity grantedRole) {
|
||||
this.grantedRole = grantedRole;
|
||||
return this;
|
||||
}
|
||||
|
||||
ValidatableResponse toGranteeUser(final RbacUserEntity granteeUser) {
|
||||
this.granteeUser = granteeUser;
|
||||
|
||||
return RestAssured // @formatter:ff
|
||||
.given()
|
||||
.header("current-user", currentSubject.currentUser)
|
||||
.header("assumed-roles", currentSubject.assumedRole)
|
||||
.port(port)
|
||||
.when()
|
||||
.get("http://localhost/api/rbac-grants/%s/%s".formatted(
|
||||
grantedRole.getUuid(), granteeUser.getUuid()
|
||||
))
|
||||
.then(); // @formatter:on
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void assumeGrantExists(final Subject grantingSubject, final String expectedGrant) {
|
||||
@ -275,6 +373,13 @@ class RbacGrantControllerAcceptanceTest {
|
||||
).returnedValue();
|
||||
}
|
||||
|
||||
RbacUserEntity findRbacUserByName(final String userName) {
|
||||
return jpaAttempt.transacted(() -> {
|
||||
context.setCurrentUser("mike@hostsharing.net");
|
||||
return rbacUserRepository.findByName(userName);
|
||||
}).returnedValue();
|
||||
}
|
||||
|
||||
RbacRoleEntity findRbacRoleByName(final String roleName) {
|
||||
return jpaAttempt.transacted(() -> {
|
||||
context.setCurrentUser("mike@hostsharing.net");
|
||||
|
@ -108,7 +108,7 @@ class RbacGrantRepositoryIntegrationTest {
|
||||
// given
|
||||
currentUser("admin@aaa.example.com");
|
||||
assumedRoles("customer#aaa.admin");
|
||||
final var givenArbitraryUserUuid = rbacUserRepository.findUuidByName("aac00@aac.example.com");
|
||||
final var givenArbitraryUserUuid = rbacUserRepository.findByName("aac00@aac.example.com").getUuid();
|
||||
final var givenOwnPackageRoleUuid = rbacRoleRepository.findByRoleName("package#aaa00.admin").getUuid();
|
||||
|
||||
// when
|
||||
@ -132,9 +132,7 @@ class RbacGrantRepositoryIntegrationTest {
|
||||
@Transactional(propagation = Propagation.NEVER)
|
||||
public void packageAdmin_canNotGrantPackageOwnerRole() {
|
||||
// given
|
||||
record Given(RbacUserEntity arbitraryUser, UUID packageOwnerRoleUuid) {
|
||||
|
||||
}
|
||||
record Given(RbacUserEntity arbitraryUser, UUID packageOwnerRoleUuid) {}
|
||||
final var given = jpaAttempt.transacted(() -> {
|
||||
// to find the uuids of we need to have access rights to these
|
||||
currentUser("admin@aaa.example.com");
|
||||
@ -247,7 +245,7 @@ class RbacGrantRepositoryIntegrationTest {
|
||||
private RbacGrantEntity create(GrantBuilder with) {
|
||||
currentUser(with.byUserName);
|
||||
assumedRoles(with.assumedRole);
|
||||
final var givenArbitraryUserUuid = rbacUserRepository.findUuidByName(with.granteeUserName);
|
||||
final var givenArbitraryUserUuid = rbacUserRepository.findByName(with.granteeUserName).getUuid();
|
||||
final var givenOwnPackageRoleUuid = rbacRoleRepository.findByRoleName(with.grantedRole).getUuid();
|
||||
|
||||
final var grant = RbacGrantEntity.builder()
|
||||
|
Loading…
Reference in New Issue
Block a user