mirror of
https://github.com/valitydev/org-manager.git
synced 2024-11-06 08:25:21 +00:00
fix after review
This commit is contained in:
parent
a454a09f7b
commit
69f37c1fa4
@ -0,0 +1,14 @@
|
|||||||
|
package com.rbkmoney.orgmanager.config.properties;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "access-check")
|
||||||
|
@Data
|
||||||
|
public class AccessProperties {
|
||||||
|
|
||||||
|
private Boolean enabled;
|
||||||
|
|
||||||
|
}
|
@ -9,10 +9,10 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
@Data
|
@Data
|
||||||
public class BouncerProperties {
|
public class BouncerProperties {
|
||||||
|
|
||||||
private Boolean enabled;
|
|
||||||
private String contextFragmentId;
|
private String contextFragmentId;
|
||||||
private String deploymentId;
|
private String deploymentId;
|
||||||
private String authMethod;
|
private String authMethod;
|
||||||
private String realm;
|
private String realm;
|
||||||
|
private String ruleSetId;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import com.rbkmoney.orgmanager.service.InvitationService;
|
|||||||
import com.rbkmoney.orgmanager.service.KeycloakService;
|
import com.rbkmoney.orgmanager.service.KeycloakService;
|
||||||
import com.rbkmoney.orgmanager.service.OrganizationRoleService;
|
import com.rbkmoney.orgmanager.service.OrganizationRoleService;
|
||||||
import com.rbkmoney.orgmanager.service.OrganizationService;
|
import com.rbkmoney.orgmanager.service.OrganizationService;
|
||||||
import com.rbkmoney.orgmanager.service.RightService;
|
import com.rbkmoney.orgmanager.service.ResourceAccessService;
|
||||||
import com.rbkmoney.swag.organizations.api.OrgsApi;
|
import com.rbkmoney.swag.organizations.api.OrgsApi;
|
||||||
import com.rbkmoney.swag.organizations.model.InlineObject;
|
import com.rbkmoney.swag.organizations.model.InlineObject;
|
||||||
import com.rbkmoney.swag.organizations.model.InlineObject1;
|
import com.rbkmoney.swag.organizations.model.InlineObject1;
|
||||||
@ -22,7 +22,6 @@ import com.rbkmoney.swag.organizations.model.RoleId;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@ -38,7 +37,7 @@ public class OrgsController implements OrgsApi {
|
|||||||
private final InvitationService invitationService;
|
private final InvitationService invitationService;
|
||||||
private final OrganizationRoleService organizationRoleService;
|
private final OrganizationRoleService organizationRoleService;
|
||||||
private final KeycloakService keycloakService;
|
private final KeycloakService keycloakService;
|
||||||
private final RightService rightService;
|
private final ResourceAccessService resourceAccessService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResponseEntity<Organization> createOrg(
|
public ResponseEntity<Organization> createOrg(
|
||||||
@ -47,11 +46,7 @@ public class OrgsController implements OrgsApi {
|
|||||||
String xIdempotencyKey) {
|
String xIdempotencyKey) {
|
||||||
log.info("Create organization: requestId={}, idempontencyKey={}, organization={}", xRequestID, xIdempotencyKey,
|
log.info("Create organization: requestId={}, idempontencyKey={}, organization={}", xRequestID, xIdempotencyKey,
|
||||||
organization);
|
organization);
|
||||||
if (!rightService.haveRights()) {
|
resourceAccessService.checkRights();
|
||||||
return ResponseEntity
|
|
||||||
.status(HttpStatus.FORBIDDEN)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
AccessToken accessToken = keycloakService.getAccessToken();
|
AccessToken accessToken = keycloakService.getAccessToken();
|
||||||
return organizationService.create(accessToken.getSubject(), organization, xIdempotencyKey);
|
return organizationService.create(accessToken.getSubject(), organization, xIdempotencyKey);
|
||||||
}
|
}
|
||||||
@ -61,11 +56,7 @@ public class OrgsController implements OrgsApi {
|
|||||||
String xRequestID,
|
String xRequestID,
|
||||||
String orgId) {
|
String orgId) {
|
||||||
log.info("Get organization: requestId={}, orgId={}", xRequestID, orgId);
|
log.info("Get organization: requestId={}, orgId={}", xRequestID, orgId);
|
||||||
if (!rightService.haveOrganizationRights(orgId)) {
|
resourceAccessService.checkOrganizationRights(orgId);
|
||||||
return ResponseEntity
|
|
||||||
.status(HttpStatus.FORBIDDEN)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
return organizationService.get(orgId);
|
return organizationService.get(orgId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,22 +66,14 @@ public class OrgsController implements OrgsApi {
|
|||||||
String orgId,
|
String orgId,
|
||||||
String userId) {
|
String userId) {
|
||||||
log.info("Get organization member: requestId={}, orgId={}, userId={}", xRequestID, orgId, userId);
|
log.info("Get organization member: requestId={}, orgId={}, userId={}", xRequestID, orgId, userId);
|
||||||
if (!rightService.haveMemberRights(orgId, userId)) {
|
resourceAccessService.checkMemberRights(orgId, userId);
|
||||||
return ResponseEntity
|
|
||||||
.status(HttpStatus.FORBIDDEN)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
return organizationService.getMember(userId);
|
return organizationService.getMember(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResponseEntity<MemberOrgListResult> listOrgMembers(String xRequestID, String orgId) {
|
public ResponseEntity<MemberOrgListResult> listOrgMembers(String xRequestID, String orgId) {
|
||||||
log.info("List organization members: requestId={}, orgId={}", xRequestID, orgId);
|
log.info("List organization members: requestId={}, orgId={}", xRequestID, orgId);
|
||||||
if (!rightService.haveOrganizationRights(orgId)) {
|
resourceAccessService.checkOrganizationRights(orgId);
|
||||||
return ResponseEntity
|
|
||||||
.status(HttpStatus.FORBIDDEN)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
return organizationService.listMembers(orgId);
|
return organizationService.listMembers(orgId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,11 +100,7 @@ public class OrgsController implements OrgsApi {
|
|||||||
@Override
|
@Override
|
||||||
public ResponseEntity<InvitationListResult> listInvitations(String xRequestID, String orgId, InvitationStatusName status) {
|
public ResponseEntity<InvitationListResult> listInvitations(String xRequestID, String orgId, InvitationStatusName status) {
|
||||||
log.info("List invitations: requestId={}, orgId={}, status={}", xRequestID, orgId, status);
|
log.info("List invitations: requestId={}, orgId={}, status={}", xRequestID, orgId, status);
|
||||||
if (!rightService.haveOrganizationRights(orgId)) {
|
resourceAccessService.checkOrganizationRights(orgId);
|
||||||
return ResponseEntity
|
|
||||||
.status(HttpStatus.FORBIDDEN)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
return invitationService.list(orgId, status);
|
return invitationService.list(orgId, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,21 +125,13 @@ public class OrgsController implements OrgsApi {
|
|||||||
@Override
|
@Override
|
||||||
public ResponseEntity<RoleAvailableListResult> listOrgRoles(String xRequestID, String orgId) {
|
public ResponseEntity<RoleAvailableListResult> listOrgRoles(String xRequestID, String orgId) {
|
||||||
log.info("List organization roles: requestId={}, orgId={}", xRequestID, orgId);
|
log.info("List organization roles: requestId={}, orgId={}", xRequestID, orgId);
|
||||||
if (!rightService.haveOrganizationRights(orgId)) {
|
resourceAccessService.checkOrganizationRights(orgId);
|
||||||
return ResponseEntity
|
|
||||||
.status(HttpStatus.FORBIDDEN)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
return organizationRoleService.list(orgId);
|
return organizationRoleService.list(orgId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResponseEntity<Organization> patchOrg(String xRequestID, String orgId, InlineObject inlineObject) {
|
public ResponseEntity<Organization> patchOrg(String xRequestID, String orgId, InlineObject inlineObject) {
|
||||||
if (!rightService.haveOrganizationRights(orgId)) {
|
resourceAccessService.checkOrganizationRights(orgId);
|
||||||
return ResponseEntity
|
|
||||||
.status(HttpStatus.FORBIDDEN)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
return organizationService.modify(orgId, inlineObject.getName());
|
return organizationService.modify(orgId, inlineObject.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,11 +152,7 @@ public class OrgsController implements OrgsApi {
|
|||||||
String orgId,
|
String orgId,
|
||||||
String userId) {
|
String userId) {
|
||||||
log.info("Expel member organization: requestId={}, orgId={}, userId={}", xRequestID, orgId, userId);
|
log.info("Expel member organization: requestId={}, orgId={}, userId={}", xRequestID, orgId, userId);
|
||||||
if (!rightService.haveMemberRights(orgId, userId)) {
|
resourceAccessService.checkMemberRights(orgId, userId);
|
||||||
return ResponseEntity
|
|
||||||
.status(HttpStatus.FORBIDDEN)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
return organizationService.expelOrgMember(orgId, userId);
|
return organizationService.expelOrgMember(orgId, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ package com.rbkmoney.orgmanager.controller;
|
|||||||
import com.rbkmoney.orgmanager.entity.OrganizationEntityPageable;
|
import com.rbkmoney.orgmanager.entity.OrganizationEntityPageable;
|
||||||
import com.rbkmoney.orgmanager.service.KeycloakService;
|
import com.rbkmoney.orgmanager.service.KeycloakService;
|
||||||
import com.rbkmoney.orgmanager.service.OrganizationService;
|
import com.rbkmoney.orgmanager.service.OrganizationService;
|
||||||
import com.rbkmoney.orgmanager.service.RightService;
|
import com.rbkmoney.orgmanager.service.ResourceAccessService;
|
||||||
import com.rbkmoney.swag.organizations.api.UserApi;
|
import com.rbkmoney.swag.organizations.api.UserApi;
|
||||||
import com.rbkmoney.swag.organizations.model.OrganizationJoinRequest;
|
import com.rbkmoney.swag.organizations.model.OrganizationJoinRequest;
|
||||||
import com.rbkmoney.swag.organizations.model.OrganizationMembership;
|
import com.rbkmoney.swag.organizations.model.OrganizationMembership;
|
||||||
@ -11,7 +11,6 @@ import com.rbkmoney.swag.organizations.model.OrganizationSearchResult;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@ -22,18 +21,14 @@ public class UserController implements UserApi {
|
|||||||
|
|
||||||
private final OrganizationService organizationService;
|
private final OrganizationService organizationService;
|
||||||
private final KeycloakService keycloakService;
|
private final KeycloakService keycloakService;
|
||||||
private final RightService rightService;
|
private final ResourceAccessService resourceAccessService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResponseEntity<Void> cancelOrgMembership(
|
public ResponseEntity<Void> cancelOrgMembership(
|
||||||
String xRequestID,
|
String xRequestID,
|
||||||
String orgId) {
|
String orgId) {
|
||||||
log.info("Cancel org membership: orgId={}", orgId);
|
log.info("Cancel org membership: orgId={}", orgId);
|
||||||
if (!rightService.haveOrganizationRights(orgId)) {
|
resourceAccessService.checkOrganizationRights(orgId);
|
||||||
return ResponseEntity
|
|
||||||
.status(HttpStatus.FORBIDDEN)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
AccessToken accessToken = keycloakService.getAccessToken();
|
AccessToken accessToken = keycloakService.getAccessToken();
|
||||||
return organizationService.cancelOrgMembership(orgId, accessToken.getSubject(), accessToken.getEmail());
|
return organizationService.cancelOrgMembership(orgId, accessToken.getSubject(), accessToken.getEmail());
|
||||||
}
|
}
|
||||||
@ -43,11 +38,7 @@ public class UserController implements UserApi {
|
|||||||
String xRequestID,
|
String xRequestID,
|
||||||
String orgId) {
|
String orgId) {
|
||||||
log.info("Inquire org membership: orgId={}", orgId);
|
log.info("Inquire org membership: orgId={}", orgId);
|
||||||
if (!rightService.haveOrganizationRights(orgId)) {
|
resourceAccessService.checkOrganizationRights(orgId);
|
||||||
return ResponseEntity
|
|
||||||
.status(HttpStatus.FORBIDDEN)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
AccessToken accessToken = keycloakService.getAccessToken();
|
AccessToken accessToken = keycloakService.getAccessToken();
|
||||||
return organizationService.getMembership(orgId, accessToken.getSubject(), accessToken.getEmail());
|
return organizationService.getMembership(orgId, accessToken.getSubject(), accessToken.getEmail());
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.rbkmoney.orgmanager.exception;
|
||||||
|
|
||||||
|
public class AccessDeniedException extends RuntimeException {
|
||||||
|
|
||||||
|
public AccessDeniedException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.rbkmoney.orgmanager.exception;
|
||||||
|
|
||||||
|
public class BouncerException extends RuntimeException {
|
||||||
|
|
||||||
|
public BouncerException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.rbkmoney.orgmanager.exception;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.context.request.WebRequest;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
|
||||||
|
|
||||||
|
@ControllerAdvice
|
||||||
|
public class RestExceptionHandler extends ResponseEntityExceptionHandler {
|
||||||
|
|
||||||
|
@ExceptionHandler(value = {AccessDeniedException.class})
|
||||||
|
protected ResponseEntity<Object> handleAccessDeniedException(AccessDeniedException ex, WebRequest request) {
|
||||||
|
// TODO возможно выдавать сообщение с ошибкой?
|
||||||
|
return ResponseEntity
|
||||||
|
.status(HttpStatus.FORBIDDEN)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -4,7 +4,9 @@ import com.rbkmoney.bouncer.decisions.ArbiterSrv;
|
|||||||
import com.rbkmoney.bouncer.decisions.Context;
|
import com.rbkmoney.bouncer.decisions.Context;
|
||||||
import com.rbkmoney.bouncer.decisions.Judgement;
|
import com.rbkmoney.bouncer.decisions.Judgement;
|
||||||
import com.rbkmoney.bouncer.decisions.Resolution;
|
import com.rbkmoney.bouncer.decisions.Resolution;
|
||||||
|
import com.rbkmoney.orgmanagement.UserNotFound;
|
||||||
import com.rbkmoney.orgmanager.config.properties.BouncerProperties;
|
import com.rbkmoney.orgmanager.config.properties.BouncerProperties;
|
||||||
|
import com.rbkmoney.orgmanager.exception.BouncerException;
|
||||||
import com.rbkmoney.orgmanager.service.dto.BouncerContextDto;
|
import com.rbkmoney.orgmanager.service.dto.BouncerContextDto;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.thrift.TException;
|
import org.apache.thrift.TException;
|
||||||
@ -20,22 +22,15 @@ public class BouncerServiceImpl implements BouncerService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean havePrivileges(BouncerContextDto bouncerContext) {
|
public boolean havePrivileges(BouncerContextDto bouncerContext) {
|
||||||
if (!bouncerProperties.getEnabled()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return passJudgement(bouncerContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean passJudgement(BouncerContextDto bouncerContext) {
|
|
||||||
try {
|
try {
|
||||||
Context context = bouncerContextFactory.buildContext(bouncerContext);
|
Context context = bouncerContextFactory.buildContext(bouncerContext);
|
||||||
// TODO откуда брать ruleSetId ?
|
Judgement judge = bouncerClient.judge(bouncerProperties.getRuleSetId(), context);
|
||||||
Judgement judge = bouncerClient.judge("ruleSetId", context);
|
|
||||||
Resolution resolution = judge.getResolution();
|
Resolution resolution = judge.getResolution();
|
||||||
return resolution.isSetAllowed();
|
return resolution.isSetAllowed();
|
||||||
|
} catch (UserNotFound e) {
|
||||||
|
throw new BouncerException("Error while build bouncer context", e);
|
||||||
} catch (TException e) {
|
} catch (TException e) {
|
||||||
// TODO что делаем при исключении?
|
throw new BouncerException("Error while call bouncer", e);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.rbkmoney.orgmanager.service;
|
||||||
|
|
||||||
|
public interface ResourceAccessService {
|
||||||
|
|
||||||
|
void checkRights();
|
||||||
|
|
||||||
|
void checkOrganizationRights(String orgId);
|
||||||
|
|
||||||
|
void checkMemberRights(String orgId, String memberId);
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package com.rbkmoney.orgmanager.service;
|
package com.rbkmoney.orgmanager.service;
|
||||||
|
|
||||||
|
import com.rbkmoney.orgmanager.config.properties.AccessProperties;
|
||||||
|
import com.rbkmoney.orgmanager.exception.AccessDeniedException;
|
||||||
import com.rbkmoney.orgmanager.service.dto.BouncerContextDto;
|
import com.rbkmoney.orgmanager.service.dto.BouncerContextDto;
|
||||||
import com.rbkmoney.orgmanager.util.StackUtils;
|
import com.rbkmoney.orgmanager.util.StackUtils;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -9,33 +11,49 @@ import org.springframework.stereotype.Service;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class RightServiceImpl implements RightService {
|
public class ResourceAccessServiceImpl implements ResourceAccessService {
|
||||||
|
|
||||||
|
private final AccessProperties accessProperties;
|
||||||
private final BouncerService bouncerService;
|
private final BouncerService bouncerService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean haveRights() {
|
public void checkRights() {
|
||||||
|
if (!accessProperties.getEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
String callerMethodName = StackUtils.getCallerMethodName();
|
String callerMethodName = StackUtils.getCallerMethodName();
|
||||||
BouncerContextDto bouncerContext = BouncerContextDto.builder()
|
BouncerContextDto bouncerContext = BouncerContextDto.builder()
|
||||||
.operationName(callerMethodName)
|
.operationName(callerMethodName)
|
||||||
.build();
|
.build();
|
||||||
log.info("Check the user's rights to perform the operation {}", callerMethodName);
|
log.info("Check the user's rights to perform the operation {}", callerMethodName);
|
||||||
return bouncerService.havePrivileges(bouncerContext);
|
if (!bouncerService.havePrivileges(bouncerContext)) {
|
||||||
|
throw new AccessDeniedException(
|
||||||
|
String.format("No rights to perform %s", callerMethodName));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean haveOrganizationRights(String orgId) {
|
public void checkOrganizationRights(String orgId) {
|
||||||
|
if (!accessProperties.getEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
String callerMethodName = StackUtils.getCallerMethodName();
|
String callerMethodName = StackUtils.getCallerMethodName();
|
||||||
BouncerContextDto bouncerContext = BouncerContextDto.builder()
|
BouncerContextDto bouncerContext = BouncerContextDto.builder()
|
||||||
.operationName(callerMethodName)
|
.operationName(callerMethodName)
|
||||||
.organizationId(orgId)
|
.organizationId(orgId)
|
||||||
.build();
|
.build();
|
||||||
log.info("Check the user's rights to perform the operation {} in organization {}", callerMethodName, orgId);
|
log.info("Check the user's rights to perform the operation {} in organization {}", callerMethodName, orgId);
|
||||||
return bouncerService.havePrivileges(bouncerContext);
|
if (!bouncerService.havePrivileges(bouncerContext)) {
|
||||||
|
throw new AccessDeniedException(
|
||||||
|
String.format("No rights to perform %s in %s", callerMethodName, orgId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean haveMemberRights(String orgId, String memberId) {
|
public void checkMemberRights(String orgId, String memberId) {
|
||||||
|
if (!accessProperties.getEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
String callerMethodName = StackUtils.getCallerMethodName();
|
String callerMethodName = StackUtils.getCallerMethodName();
|
||||||
BouncerContextDto bouncerContext = BouncerContextDto.builder()
|
BouncerContextDto bouncerContext = BouncerContextDto.builder()
|
||||||
.operationName(callerMethodName)
|
.operationName(callerMethodName)
|
||||||
@ -44,6 +62,9 @@ public class RightServiceImpl implements RightService {
|
|||||||
.build();
|
.build();
|
||||||
log.info("Check the user's rights to perform the operation {} in organization {} with member {}",
|
log.info("Check the user's rights to perform the operation {} in organization {} with member {}",
|
||||||
callerMethodName, orgId, memberId);
|
callerMethodName, orgId, memberId);
|
||||||
return bouncerService.havePrivileges(bouncerContext);
|
if (!bouncerService.havePrivileges(bouncerContext)) {
|
||||||
|
throw new AccessDeniedException(
|
||||||
|
String.format("No rights to perform %s in %s with %s", callerMethodName, orgId, memberId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,11 +0,0 @@
|
|||||||
package com.rbkmoney.orgmanager.service;
|
|
||||||
|
|
||||||
public interface RightService {
|
|
||||||
|
|
||||||
boolean haveRights();
|
|
||||||
|
|
||||||
boolean haveOrganizationRights(String orgId);
|
|
||||||
|
|
||||||
boolean haveMemberRights(String orgId, String memberId);
|
|
||||||
|
|
||||||
}
|
|
@ -8,13 +8,11 @@ import java.util.Optional;
|
|||||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
public class StackUtils {
|
public class StackUtils {
|
||||||
|
|
||||||
private static final String CALLER_NOT_EXIST = "Caller method doesn't exist";
|
|
||||||
|
|
||||||
public static String getCallerMethodName() {
|
public static String getCallerMethodName() {
|
||||||
Optional<StackWalker.StackFrame> callerFrame = StackWalker.getInstance()
|
Optional<StackWalker.StackFrame> callerFrame = StackWalker.getInstance()
|
||||||
.walk(s -> s.skip(2).findFirst());
|
.walk(s -> s.skip(2).findFirst());
|
||||||
if (callerFrame.isEmpty()) {
|
if (callerFrame.isEmpty()) {
|
||||||
return CALLER_NOT_EXIST;
|
throw new RuntimeException("Can't get caller method name");
|
||||||
}
|
}
|
||||||
return callerFrame.get().getMethodName();
|
return callerFrame.get().getMethodName();
|
||||||
}
|
}
|
||||||
|
@ -72,8 +72,11 @@ dashboard:
|
|||||||
bouncer:
|
bouncer:
|
||||||
url: http://localhost:8022/change_it
|
url: http://localhost:8022/change_it
|
||||||
networkTimeout: 10000
|
networkTimeout: 10000
|
||||||
enabled: false
|
|
||||||
context-fragment-id: orgmgmt
|
context-fragment-id: orgmgmt
|
||||||
deployment-id: production
|
deployment-id: production
|
||||||
auth-method: SessionToken
|
auth-method: SessionToken
|
||||||
realm: external
|
realm: external
|
||||||
|
rule-set-id: change_it
|
||||||
|
|
||||||
|
access-check:
|
||||||
|
enabled: false
|
@ -3,20 +3,17 @@ package com.rbkmoney.orgmanager.controller;
|
|||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.rbkmoney.orgmanager.OrgManagerApplication;
|
import com.rbkmoney.orgmanager.OrgManagerApplication;
|
||||||
import com.rbkmoney.orgmanager.entity.MemberEntity;
|
import com.rbkmoney.orgmanager.entity.MemberEntity;
|
||||||
import com.rbkmoney.orgmanager.entity.MemberRoleEntity;
|
|
||||||
import com.rbkmoney.orgmanager.entity.OrganizationEntity;
|
import com.rbkmoney.orgmanager.entity.OrganizationEntity;
|
||||||
|
import com.rbkmoney.orgmanager.exception.AccessDeniedException;
|
||||||
import com.rbkmoney.orgmanager.repository.InvitationRepositoryTest;
|
import com.rbkmoney.orgmanager.repository.InvitationRepositoryTest;
|
||||||
import com.rbkmoney.orgmanager.repository.MemberRepository;
|
import com.rbkmoney.orgmanager.repository.MemberRepository;
|
||||||
import com.rbkmoney.orgmanager.repository.OrganizationRepository;
|
import com.rbkmoney.orgmanager.repository.OrganizationRepository;
|
||||||
import com.rbkmoney.orgmanager.service.OrganizationService;
|
import com.rbkmoney.orgmanager.service.OrganizationService;
|
||||||
|
import com.rbkmoney.orgmanager.service.ResourceAccessService;
|
||||||
import com.rbkmoney.orgmanager.util.TestData;
|
import com.rbkmoney.orgmanager.util.TestData;
|
||||||
import com.rbkmoney.swag.organizations.model.InvitationRequest;
|
import com.rbkmoney.swag.organizations.model.InvitationRequest;
|
||||||
import com.rbkmoney.swag.organizations.model.Invitee;
|
|
||||||
import com.rbkmoney.swag.organizations.model.InviteeContact;
|
|
||||||
import com.rbkmoney.swag.organizations.model.MemberRole;
|
import com.rbkmoney.swag.organizations.model.MemberRole;
|
||||||
import com.rbkmoney.swag.organizations.model.MemberRoleScope;
|
|
||||||
import com.rbkmoney.swag.organizations.model.OrganizationMembership;
|
import com.rbkmoney.swag.organizations.model.OrganizationMembership;
|
||||||
import com.rbkmoney.swag.organizations.model.ResourceScopeId;
|
|
||||||
import com.rbkmoney.swag.organizations.model.RoleId;
|
import com.rbkmoney.swag.organizations.model.RoleId;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@ -32,14 +29,11 @@ import org.springframework.test.context.TestPropertySource;
|
|||||||
import org.springframework.test.context.junit4.SpringRunner;
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import static org.hamcrest.core.Is.is;
|
import static org.hamcrest.core.Is.is;
|
||||||
import static org.hamcrest.core.IsAnything.anything;
|
import static org.hamcrest.core.IsAnything.anything;
|
||||||
|
import static org.mockito.Mockito.doThrow;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
@ -81,6 +75,9 @@ public class OrgsControllerTest extends AbstractControllerTest {
|
|||||||
@SpyBean
|
@SpyBean
|
||||||
private OrganizationService organizationService;
|
private OrganizationService organizationService;
|
||||||
|
|
||||||
|
@SpyBean
|
||||||
|
private ResourceAccessService resourceAccessService;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
keycloakOpenIdStub.givenStub();
|
keycloakOpenIdStub.givenStub();
|
||||||
@ -88,6 +85,18 @@ public class OrgsControllerTest extends AbstractControllerTest {
|
|||||||
organizationRepository.save(organizationEntity);
|
organizationRepository.save(organizationEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void expelOrgMemberWithoutAccess() throws Exception {
|
||||||
|
doThrow(new AccessDeniedException("Access denied")).when(resourceAccessService)
|
||||||
|
.checkMemberRights(ORGANIZATION_ID, MEMBER_ID);
|
||||||
|
|
||||||
|
mockMvc.perform(delete(String.format("/orgs/%s/members/%s", ORGANIZATION_ID, MEMBER_ID))
|
||||||
|
.contentType("application/json")
|
||||||
|
.header("Authorization", "Bearer " + generateRBKadminJwt())
|
||||||
|
.header("X-Request-ID", "testRequestId"))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void assignMemberRoleTest() throws Exception {
|
public void assignMemberRoleTest() throws Exception {
|
||||||
MemberRole memberRole = TestData.buildMemberRole();
|
MemberRole memberRole = TestData.buildMemberRole();
|
||||||
|
@ -10,6 +10,7 @@ import com.rbkmoney.bouncer.decisions.RulesetNotFound;
|
|||||||
import com.rbkmoney.orgmanagement.UserNotFound;
|
import com.rbkmoney.orgmanagement.UserNotFound;
|
||||||
import com.rbkmoney.orgmanager.TestObjectFactory;
|
import com.rbkmoney.orgmanager.TestObjectFactory;
|
||||||
import com.rbkmoney.orgmanager.config.properties.BouncerProperties;
|
import com.rbkmoney.orgmanager.config.properties.BouncerProperties;
|
||||||
|
import com.rbkmoney.orgmanager.exception.BouncerException;
|
||||||
import com.rbkmoney.orgmanager.service.dto.BouncerContextDto;
|
import com.rbkmoney.orgmanager.service.dto.BouncerContextDto;
|
||||||
import org.apache.thrift.TException;
|
import org.apache.thrift.TException;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
@ -18,7 +19,10 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
|||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
@ -33,36 +37,24 @@ class BouncerServiceImplTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private BouncerContextFactory bouncerContextFactory;
|
private BouncerContextFactory bouncerContextFactory;
|
||||||
|
|
||||||
private BouncerProperties bouncerProperties;
|
|
||||||
|
|
||||||
private BouncerService bouncerService;
|
private BouncerService bouncerService;
|
||||||
|
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
bouncerProperties = new BouncerProperties();
|
BouncerProperties bouncerProperties = new BouncerProperties();
|
||||||
bouncerProperties.setEnabled(Boolean.TRUE);
|
bouncerProperties.setRuleSetId(TestObjectFactory.randomString());
|
||||||
bouncerService = new BouncerServiceImpl(bouncerContextFactory, bouncerClient, bouncerProperties);
|
bouncerService = new BouncerServiceImpl(bouncerContextFactory, bouncerClient, bouncerProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void havePrivilegesWithNotEnabledBouncer() {
|
|
||||||
bouncerProperties.setEnabled(Boolean.FALSE);
|
|
||||||
BouncerContextDto bouncerContext = TestObjectFactory.testBouncerContextDto();
|
|
||||||
|
|
||||||
boolean result = bouncerService.havePrivileges(bouncerContext);
|
|
||||||
|
|
||||||
assertTrue(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void havePrivilegesWithIncorrectBuildContext() throws TException {
|
void havePrivilegesWithIncorrectBuildContext() throws TException {
|
||||||
BouncerContextDto bouncerContext = TestObjectFactory.testBouncerContextDto();
|
BouncerContextDto bouncerContext = TestObjectFactory.testBouncerContextDto();
|
||||||
when(bouncerContextFactory.buildContext(bouncerContext)).thenThrow(new UserNotFound());
|
when(bouncerContextFactory.buildContext(bouncerContext)).thenThrow(new UserNotFound());
|
||||||
|
|
||||||
boolean result = bouncerService.havePrivileges(bouncerContext);
|
var exception = assertThrows(BouncerException.class, () -> bouncerService.havePrivileges(bouncerContext));
|
||||||
|
|
||||||
assertFalse(result);
|
assertThat(exception.getMessage(), containsString("Error while build bouncer context"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -71,9 +63,9 @@ class BouncerServiceImplTest {
|
|||||||
when(bouncerContextFactory.buildContext(bouncerContext)).thenReturn(new Context());
|
when(bouncerContextFactory.buildContext(bouncerContext)).thenReturn(new Context());
|
||||||
when(bouncerClient.judge(anyString(), any(Context.class))).thenThrow(new RulesetNotFound());
|
when(bouncerClient.judge(anyString(), any(Context.class))).thenThrow(new RulesetNotFound());
|
||||||
|
|
||||||
boolean result = bouncerService.havePrivileges(bouncerContext);
|
var exception = assertThrows(BouncerException.class, () -> bouncerService.havePrivileges(bouncerContext));
|
||||||
|
|
||||||
assertFalse(result);
|
assertThat(exception.getMessage(), containsString("Error while call bouncer"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -0,0 +1,121 @@
|
|||||||
|
package com.rbkmoney.orgmanager.service;
|
||||||
|
|
||||||
|
import com.rbkmoney.orgmanager.TestObjectFactory;
|
||||||
|
import com.rbkmoney.orgmanager.config.properties.AccessProperties;
|
||||||
|
import com.rbkmoney.orgmanager.exception.AccessDeniedException;
|
||||||
|
import com.rbkmoney.orgmanager.service.dto.BouncerContextDto;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@ExtendWith(SpringExtension.class)
|
||||||
|
class ResourceAccessServiceImplTest {
|
||||||
|
|
||||||
|
private AccessProperties accessProperties;
|
||||||
|
@Mock
|
||||||
|
private BouncerService bouncerService;
|
||||||
|
|
||||||
|
private ResourceAccessService resourceAccessService;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
accessProperties = new AccessProperties();
|
||||||
|
accessProperties.setEnabled(true);
|
||||||
|
resourceAccessService = new ResourceAccessServiceImpl(accessProperties, bouncerService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void checkNotEnabled() {
|
||||||
|
accessProperties.setEnabled(false);
|
||||||
|
|
||||||
|
assertDoesNotThrow(() -> resourceAccessService.checkRights());
|
||||||
|
|
||||||
|
verify(bouncerService, times(0)).havePrivileges(any(BouncerContextDto.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void checkRightsWithoutAccess() {
|
||||||
|
when(bouncerService.havePrivileges(any(BouncerContextDto.class))).thenReturn(false);
|
||||||
|
|
||||||
|
var exception = assertThrows(AccessDeniedException.class, () -> resourceAccessService.checkRights());
|
||||||
|
|
||||||
|
assertThat(exception.getMessage(), containsString("No rights to perform"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void checkRightsSuccess() {
|
||||||
|
when(bouncerService.havePrivileges(any(BouncerContextDto.class))).thenReturn(true);
|
||||||
|
assertDoesNotThrow(() -> resourceAccessService.checkRights());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void checkOrganizationNotEnabled() {
|
||||||
|
accessProperties.setEnabled(false);
|
||||||
|
var orgId = "test";
|
||||||
|
|
||||||
|
assertDoesNotThrow(() -> resourceAccessService.checkOrganizationRights(orgId));
|
||||||
|
|
||||||
|
verify(bouncerService, times(0)).havePrivileges(any(BouncerContextDto.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void checkOrganizationRightsWithoutAccess() {
|
||||||
|
String orgId = TestObjectFactory.randomString();
|
||||||
|
when(bouncerService.havePrivileges(any(BouncerContextDto.class))).thenReturn(false);
|
||||||
|
|
||||||
|
var exception = assertThrows(AccessDeniedException.class,
|
||||||
|
() -> resourceAccessService.checkOrganizationRights(orgId));
|
||||||
|
|
||||||
|
assertThat(exception.getMessage(), stringContainsInOrder("No rights to perform", orgId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void checkOrganizationRightsSuccess() {
|
||||||
|
when(bouncerService.havePrivileges(any(BouncerContextDto.class))).thenReturn(true);
|
||||||
|
assertDoesNotThrow(() -> resourceAccessService.checkOrganizationRights(anyString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void checkMemberNotEnabled() {
|
||||||
|
accessProperties.setEnabled(false);
|
||||||
|
var orgId = "test";
|
||||||
|
var memberId = "test";
|
||||||
|
|
||||||
|
assertDoesNotThrow(() -> resourceAccessService.checkMemberRights(orgId, memberId));
|
||||||
|
|
||||||
|
verify(bouncerService, times(0)).havePrivileges(any(BouncerContextDto.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void checkMemberRightsWithoutAccess() {
|
||||||
|
String orgId = TestObjectFactory.randomString();
|
||||||
|
String memberId = TestObjectFactory.randomString();
|
||||||
|
when(bouncerService.havePrivileges(any(BouncerContextDto.class))).thenReturn(false);
|
||||||
|
|
||||||
|
var exception = assertThrows(AccessDeniedException.class,
|
||||||
|
() -> resourceAccessService.checkMemberRights(orgId, memberId));
|
||||||
|
|
||||||
|
assertThat(exception.getMessage(), stringContainsInOrder("No rights to perform", orgId, memberId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void checkMemberRightsSuccess() {
|
||||||
|
String orgId = TestObjectFactory.randomString();
|
||||||
|
String memberId = TestObjectFactory.randomString();
|
||||||
|
when(bouncerService.havePrivileges(any(BouncerContextDto.class))).thenReturn(true);
|
||||||
|
assertDoesNotThrow(() -> resourceAccessService.checkMemberRights(orgId, memberId));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user