fix after review

This commit is contained in:
ggmaleva 2021-03-04 16:54:34 +03:00
parent a454a09f7b
commit 69f37c1fa4
16 changed files with 265 additions and 117 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,8 @@
package com.rbkmoney.orgmanager.exception;
public class AccessDeniedException extends RuntimeException {
public AccessDeniedException(String message) {
super(message);
}
}

View File

@ -0,0 +1,8 @@
package com.rbkmoney.orgmanager.exception;
public class BouncerException extends RuntimeException {
public BouncerException(String message, Throwable cause) {
super(message, cause);
}
}

View File

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

View File

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

View File

@ -0,0 +1,11 @@
package com.rbkmoney.orgmanager.service;
public interface ResourceAccessService {
void checkRights();
void checkOrganizationRights(String orgId);
void checkMemberRights(String orgId, String memberId);
}

View File

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

View File

@ -1,11 +0,0 @@
package com.rbkmoney.orgmanager.service;
public interface RightService {
boolean haveRights();
boolean haveOrganizationRights(String orgId);
boolean haveMemberRights(String orgId, String memberId);
}

View File

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

View File

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

View File

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

View File

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

View File

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