mirror of
https://github.com/valitydev/org-manager.git
synced 2024-11-06 08:25:21 +00:00
BJ-1016: Organization join (#3)
* BJ-1016: Organization join * tests fix * keycloak bump * org find refactor * Update src/main/java/com/rbkmoney/orgmanager/service/OrganizationService.java Co-authored-by: Alexander Romanov <a.romanov@rbkmoney.com> * Update src/main/java/com/rbkmoney/orgmanager/service/OrganizationService.java Co-authored-by: Alexander Romanov <a.romanov@rbkmoney.com> * keycloak config refactor * method name typo Co-authored-by: vitaxa <v.banin@rbkmoney.com> Co-authored-by: Alexander Romanov <a.romanov@rbkmoney.com>
This commit is contained in:
parent
7bb623537e
commit
b3b45c70f4
73
pom.xml
73
pom.xml
@ -24,7 +24,7 @@
|
||||
<dockerfile.base.service.tag>57e26d8ee999d7b0b50248c22afc63e6f926d276</dockerfile.base.service.tag>
|
||||
<dockerfile.registry>dr2.rbkmoney.com</dockerfile.registry>
|
||||
<shared.resources.version>0.3.6</shared.resources.version>
|
||||
<sonar.jacoco.reportPaths>${project.basedir}/target/jacoco.exec</sonar.jacoco.reportPaths>
|
||||
<keycloak.version>11.0.3</keycloak.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@ -52,7 +52,7 @@
|
||||
<dependency>
|
||||
<groupId>com.rbkmoney</groupId>
|
||||
<artifactId>swag-organizations</artifactId>
|
||||
<version>1.8-1de59d5-epic-server</version>
|
||||
<version>1.10-260e548-server</version>
|
||||
</dependency>
|
||||
|
||||
<!--spring-->
|
||||
@ -72,6 +72,40 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
<version>2.4.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-admin-client</artifactId>
|
||||
<version>${keycloak.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-client</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-multipart-provider</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-jackson2-provider</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-jaxb-provider</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-spring-security-adapter</artifactId>
|
||||
<version>${keycloak.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--third party-->
|
||||
<dependency>
|
||||
@ -98,6 +132,12 @@
|
||||
<artifactId>guava</artifactId>
|
||||
<version>29.0-jre</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openapitools</groupId>
|
||||
<artifactId>jackson-databind-nullable</artifactId>
|
||||
<version>0.2.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!--test-->
|
||||
<dependency>
|
||||
@ -105,6 +145,18 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-wiremock</artifactId>
|
||||
<version>2.2.4.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>0.9.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
@ -173,23 +225,6 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.5</version>
|
||||
<configuration>
|
||||
<destFile>${sonar.jacoco.reportPaths}</destFile>
|
||||
<append>true</append>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>agent</id>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
@ -2,9 +2,11 @@ package com.rbkmoney.orgmanager;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
|
||||
import org.springframework.boot.web.servlet.ServletComponentScan;
|
||||
|
||||
@ServletComponentScan
|
||||
@ConfigurationPropertiesScan
|
||||
@SpringBootApplication
|
||||
public class OrgManagerApplication extends SpringApplication {
|
||||
|
||||
|
130
src/main/java/com/rbkmoney/orgmanager/config/SecurityConfig.java
Normal file
130
src/main/java/com/rbkmoney/orgmanager/config/SecurityConfig.java
Normal file
@ -0,0 +1,130 @@
|
||||
package com.rbkmoney.orgmanager.config;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.rbkmoney.orgmanager.config.properties.KeyCloakProperties;
|
||||
import org.keycloak.adapters.KeycloakConfigResolver;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||
import org.keycloak.adapters.springsecurity.KeycloakSecurityComponents;
|
||||
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
|
||||
import org.keycloak.adapters.springsecurity.management.HttpSessionManager;
|
||||
import org.keycloak.representations.adapters.config.AdapterConfig;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.FilterType;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
|
||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@ComponentScan(
|
||||
basePackageClasses = KeycloakSecurityComponents.class,
|
||||
excludeFilters = @ComponentScan.Filter(
|
||||
type = FilterType.REGEX,
|
||||
pattern = "org.keycloak.adapters.springsecurity.management.HttpSessionManager"
|
||||
)
|
||||
)
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
|
||||
@ConditionalOnProperty(value = "auth.enabled", havingValue = "true")
|
||||
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
|
||||
|
||||
@Autowired
|
||||
private KeyCloakProperties keyCloakProperties;
|
||||
|
||||
@Override
|
||||
protected HttpSessionManager httpSessionManager() {
|
||||
return super.httpSessionManager();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
|
||||
return new NullAuthenticatedSessionStrategy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
super.configure(http);
|
||||
http
|
||||
.cors().and()
|
||||
.csrf().disable()
|
||||
.authorizeRequests()
|
||||
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
|
||||
.antMatchers(HttpMethod.GET, "/**/health").permitAll()
|
||||
.anyRequest().authenticated();
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
auth.authenticationProvider(keycloakAuthenticationProvider());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KeycloakConfigResolver keycloakConfigResolver() {
|
||||
return facade -> {
|
||||
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(adapterConfig());
|
||||
deployment.setNotBefore(keyCloakProperties.getNotBefore());
|
||||
return deployment;
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CorsConfigurationSource corsConfigurationSource() {
|
||||
CorsConfiguration configuration = new CorsConfiguration();
|
||||
configuration.applyPermitDefaultValues();
|
||||
configuration.addAllowedMethod(HttpMethod.PUT);
|
||||
configuration.addAllowedMethod(HttpMethod.DELETE);
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**", configuration);
|
||||
return source;
|
||||
}
|
||||
|
||||
private AdapterConfig adapterConfig() {
|
||||
String keycloakRealmPublicKey;
|
||||
if (!Strings.isNullOrEmpty(keyCloakProperties.getRealmPublicKeyFilePath())) {
|
||||
keycloakRealmPublicKey = readKeyFromFile(keyCloakProperties.getRealmPublicKeyFilePath());
|
||||
} else {
|
||||
keycloakRealmPublicKey = keyCloakProperties.getRealmPublicKey();
|
||||
}
|
||||
|
||||
AdapterConfig adapterConfig = new AdapterConfig();
|
||||
adapterConfig.setRealm(keyCloakProperties.getRealm());
|
||||
adapterConfig.setRealmKey(keycloakRealmPublicKey);
|
||||
adapterConfig.setResource(keyCloakProperties.getResource());
|
||||
adapterConfig.setAuthServerUrl(keyCloakProperties.getAuthServerUrl());
|
||||
adapterConfig.setUseResourceRoleMappings(true);
|
||||
adapterConfig.setBearerOnly(true);
|
||||
adapterConfig.setSslRequired(keyCloakProperties.getSslRequired());
|
||||
return adapterConfig;
|
||||
}
|
||||
|
||||
private String readKeyFromFile(String filePath) {
|
||||
try {
|
||||
List<String> strings = Files.readAllLines(Paths.get(filePath));
|
||||
strings.remove(strings.size() - 1);
|
||||
strings.remove(0);
|
||||
|
||||
return strings.stream().map(String::trim).collect(Collectors.joining());
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
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 = "keycloak")
|
||||
@Data
|
||||
public class KeyCloakProperties {
|
||||
|
||||
private String realm;
|
||||
|
||||
private String resource;
|
||||
|
||||
private String realmPublicKey;
|
||||
|
||||
private String realmPublicKeyFilePath;
|
||||
|
||||
private String authServerUrl;
|
||||
|
||||
private String sslRequired;
|
||||
|
||||
private int notBefore;
|
||||
|
||||
}
|
@ -41,9 +41,7 @@ public class OrgsController implements OrgsApi {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<InlineResponse2002> listOrgMembers(
|
||||
String xRequestID,
|
||||
String orgId) {
|
||||
public ResponseEntity<InlineResponse2001> listOrgMembers(String xRequestID, String orgId) {
|
||||
return organizationService.listMembers(orgId);
|
||||
}
|
||||
|
||||
@ -65,20 +63,13 @@ public class OrgsController implements OrgsApi {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<InlineResponse2003> listInvitations(
|
||||
String xRequestID,
|
||||
String orgId,
|
||||
InvitationStatusName status) {
|
||||
public ResponseEntity<InlineResponse2002> listInvitations(String xRequestID, String orgId, InvitationStatusName status) {
|
||||
return invitationService.list(orgId, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> revokeInvitation(
|
||||
String xRequestID,
|
||||
String orgId,
|
||||
String invitationId,
|
||||
InlineObject request) {
|
||||
return invitationService.revoke(invitationId, request);
|
||||
public ResponseEntity<Void> revokeInvitation(String xRequestID, String orgId, String invitationId, InlineObject inlineObject) {
|
||||
return invitationService.revoke(orgId, invitationId, inlineObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -90,9 +81,7 @@ public class OrgsController implements OrgsApi {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<InlineResponse2001> listOrgRoles(
|
||||
String xRequestID,
|
||||
String orgId) {
|
||||
public ResponseEntity<InlineResponse200> listOrgRoles(String xRequestID, String orgId) {
|
||||
return organizationRoleService.list(orgId);
|
||||
}
|
||||
|
||||
|
@ -1,38 +1,64 @@
|
||||
package com.rbkmoney.orgmanager.controller;
|
||||
|
||||
import com.rbkmoney.orgmanager.entity.OrganizationEntityPageable;
|
||||
import com.rbkmoney.orgmanager.service.KeycloakService;
|
||||
import com.rbkmoney.orgmanager.service.OrganizationService;
|
||||
import com.rbkmoney.swag.organizations.api.UserApi;
|
||||
import com.rbkmoney.swag.organizations.model.InlineResponse200;
|
||||
import com.rbkmoney.swag.organizations.model.OrganizationJoinRequest;
|
||||
import com.rbkmoney.swag.organizations.model.OrganizationMembership;
|
||||
import com.rbkmoney.swag.organizations.model.OrganizationSearchResult;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
public class UserController implements UserApi {
|
||||
|
||||
private final OrganizationService organizationService;
|
||||
private final KeycloakService keycloakService;
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> cancelOrgMembership(
|
||||
String xRequestID,
|
||||
String orgId) {
|
||||
throw new UnsupportedOperationException(); // TODO [a.romanov]: impl
|
||||
AccessToken accessToken = keycloakService.getAccessToken();
|
||||
|
||||
return organizationService.cancelOrgMembership(orgId, accessToken.getSubject(), accessToken.getEmail());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<OrganizationMembership> inquireOrgMembership(
|
||||
String xRequestID,
|
||||
String orgId) {
|
||||
throw new UnsupportedOperationException(); // TODO [a.romanov]: impl
|
||||
AccessToken accessToken = keycloakService.getAccessToken();
|
||||
|
||||
return organizationService.getMembership(orgId, accessToken.getSubject(), accessToken.getEmail());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<OrganizationMembership> joinOrg(
|
||||
String xRequestID,
|
||||
OrganizationJoinRequest body) {
|
||||
throw new UnsupportedOperationException(); // TODO [a.romanov]: impl
|
||||
AccessToken accessToken = keycloakService.getAccessToken();
|
||||
|
||||
return organizationService.joinOrganization(body.getInvitation(), accessToken.getSubject(), accessToken.getEmail());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<InlineResponse200> listOrgMembership(String xRequestID) {
|
||||
throw new UnsupportedOperationException(); // TODO [a.romanov]: impl
|
||||
public ResponseEntity<OrganizationSearchResult> listOrgMembership(String xRequestID, Integer limit, String continuationToken) {
|
||||
OrganizationEntityPageable organizationEntityPageable;
|
||||
if (continuationToken == null) {
|
||||
organizationEntityPageable = organizationService.findAllOrganizations(limit);
|
||||
} else {
|
||||
organizationEntityPageable = organizationService.findAllOrganizations(continuationToken, limit);
|
||||
}
|
||||
OrganizationSearchResult organizationSearchResult = new OrganizationSearchResult();
|
||||
organizationSearchResult.setContinuationToken(organizationEntityPageable.getContinuationToken());
|
||||
organizationSearchResult.setResults(organizationEntityPageable.getOrganizations());
|
||||
|
||||
return ResponseEntity.ok(organizationSearchResult);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import com.rbkmoney.swag.organizations.model.Invitation;
|
||||
import com.rbkmoney.swag.organizations.model.Invitee;
|
||||
import com.rbkmoney.swag.organizations.model.InviteeContact;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.openapitools.jackson.nullable.JsonNullable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
@ -48,7 +49,7 @@ public class InvitationConverter {
|
||||
.map(role -> memberRoleConverter.toEntity(role, orgId))
|
||||
.collect(toSet()))
|
||||
.metadata(jsonMapper.toJson(invitation.getMetadata()))
|
||||
.status(invitation.getStatus())
|
||||
.status(invitation.getStatus().get().toString())
|
||||
.acceptToken(UUID.randomUUID().toString()) // TODO [a.romanov]: token
|
||||
.build();
|
||||
}
|
||||
@ -68,7 +69,7 @@ public class InvitationConverter {
|
||||
.stream()
|
||||
.map(memberRoleConverter::toDomain)
|
||||
.collect(toSet())));
|
||||
invitation.setStatus(entity.getStatus());
|
||||
invitation.setStatus(JsonNullable.of(entity.getStatus()));
|
||||
|
||||
return invitation;
|
||||
}
|
||||
|
@ -17,8 +17,8 @@ public class MemberRoleConverter {
|
||||
.id(UUID.randomUUID().toString())
|
||||
.organizationId(orgId)
|
||||
.resourceId(role.getScope().getResourceId())
|
||||
.roleId(role.getRoleId().getValue())
|
||||
.scopeId(role.getScope().getId().getValue())
|
||||
.roleId(role.getRoleId().toString())
|
||||
.scopeId(role.getScope().getId().toString())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ public class OrganizationConverter {
|
||||
.id(UUID.randomUUID().toString())
|
||||
.createdAt(LocalDateTime.now())
|
||||
.name(organization.getName())
|
||||
.owner(organization.getOwner())
|
||||
.owner(organization.getOwner().toString())
|
||||
.metadata(jsonMapper.toJson(organization.getMetadata()))
|
||||
.build();
|
||||
}
|
||||
@ -33,6 +33,6 @@ public class OrganizationConverter {
|
||||
.createdAt(OffsetDateTime.of(entity.getCreatedAt(), ZoneOffset.UTC))
|
||||
.name(entity.getName())
|
||||
.owner(entity.getOwner())
|
||||
.metadata(jsonMapper.toMap(entity.getMetadata()));
|
||||
.metadata(entity.getMetadata() != null ? jsonMapper.toMap(entity.getMetadata()) : null);
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ public class MemberEntity implements Serializable {
|
||||
|
||||
@ToString.Exclude
|
||||
@EqualsAndHashCode.Exclude
|
||||
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
|
||||
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||
@JoinTable(
|
||||
name = "member_to_member_role",
|
||||
joinColumns = @JoinColumn(name = "member_id"),
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.rbkmoney.orgmanager.entity;
|
||||
|
||||
import lombok.*;
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.annotations.FetchMode;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
@ -20,7 +22,7 @@ public class OrganizationEntity implements Serializable {
|
||||
|
||||
@ToString.Exclude
|
||||
@EqualsAndHashCode.Exclude
|
||||
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
|
||||
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||
@JoinTable(
|
||||
name = "member_to_organization",
|
||||
joinColumns = @JoinColumn(name = "organization_id"),
|
||||
@ -29,7 +31,8 @@ public class OrganizationEntity implements Serializable {
|
||||
|
||||
@ToString.Exclude
|
||||
@EqualsAndHashCode.Exclude
|
||||
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
|
||||
@OneToMany(cascade = CascadeType.ALL)
|
||||
@Fetch(FetchMode.SUBSELECT)
|
||||
@JoinColumn(name = "organizationId")
|
||||
private Set<OrganizationRoleEntity> roles;
|
||||
|
||||
|
@ -0,0 +1,13 @@
|
||||
package com.rbkmoney.orgmanager.entity;
|
||||
|
||||
import com.rbkmoney.swag.organizations.model.Organization;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class OrganizationEntityPageable {
|
||||
private final String continuationToken;
|
||||
private final int limit;
|
||||
private final List<Organization> organizations;
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package com.rbkmoney.orgmanager.pagination;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@EqualsAndHashCode
|
||||
public class OffsetBasedPageRequest implements Pageable, Serializable {
|
||||
|
||||
private static final long serialVersionUID = -35826477329623545L;
|
||||
|
||||
private int limit;
|
||||
private long offset;
|
||||
private final Sort sort;
|
||||
|
||||
public OffsetBasedPageRequest(long offset, int limit, Sort sort) {
|
||||
if (offset < 0) {
|
||||
throw new IllegalArgumentException("Offset index must not be less than zero!");
|
||||
}
|
||||
|
||||
if (limit < 1) {
|
||||
throw new IllegalArgumentException("Limit must not be less than one!");
|
||||
}
|
||||
this.limit = limit;
|
||||
this.offset = offset;
|
||||
this.sort = sort;
|
||||
}
|
||||
|
||||
public OffsetBasedPageRequest(long offset, int limit) {
|
||||
this(offset, limit, Sort.unsorted());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPageNumber() {
|
||||
return Math.toIntExact(offset / limit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPageSize() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sort getSort() {
|
||||
return sort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pageable next() {
|
||||
return new OffsetBasedPageRequest(getOffset() + getPageSize(), getPageSize(), getSort());
|
||||
}
|
||||
|
||||
public OffsetBasedPageRequest previous() {
|
||||
return hasPrevious() ? new OffsetBasedPageRequest(getOffset() - getPageSize(), getPageSize(), getSort()) : this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Pageable previousOrFirst() {
|
||||
return hasPrevious() ? previous() : first();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pageable first() {
|
||||
return new OffsetBasedPageRequest(0, getPageSize(), getSort());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrevious() {
|
||||
return offset > limit;
|
||||
}
|
||||
|
||||
}
|
@ -5,9 +5,12 @@ import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface InvitationRepository extends JpaRepository<InvitationEntity, String> {
|
||||
|
||||
List<InvitationEntity> findByOrganizationIdAndStatus(String organizationId, String status);
|
||||
|
||||
Optional<InvitationEntity> findByAcceptToken(String token);
|
||||
}
|
||||
|
@ -2,8 +2,16 @@ package com.rbkmoney.orgmanager.repository;
|
||||
|
||||
import com.rbkmoney.orgmanager.entity.OrganizationEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface OrganizationRepository extends JpaRepository<OrganizationEntity, String> {
|
||||
|
||||
@Query(value = "SELECT * FROM org_manager.organization AS o WHERE o.id < ?1 ORDER BY o.id DESC LIMIT ?2",
|
||||
nativeQuery = true)
|
||||
List<OrganizationEntity> fetchAll(String continuationId, int limit);
|
||||
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import com.rbkmoney.orgmanager.entity.InvitationEntity;
|
||||
import com.rbkmoney.orgmanager.repository.InvitationRepository;
|
||||
import com.rbkmoney.orgmanager.repository.OrganizationRepository;
|
||||
import com.rbkmoney.swag.organizations.model.InlineObject;
|
||||
import com.rbkmoney.swag.organizations.model.InlineResponse2003;
|
||||
import com.rbkmoney.swag.organizations.model.InlineResponse2002;
|
||||
import com.rbkmoney.swag.organizations.model.Invitation;
|
||||
import com.rbkmoney.swag.organizations.model.InvitationStatusName;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -55,7 +55,7 @@ public class InvitationService {
|
||||
.body(invitation);
|
||||
}
|
||||
|
||||
public ResponseEntity<InlineResponse2003> list(String orgId, InvitationStatusName status) {
|
||||
public ResponseEntity<InlineResponse2002> list(String orgId, InvitationStatusName status) {
|
||||
boolean isOrganizationExist = organizationRepository.existsById(orgId);
|
||||
|
||||
if (!isOrganizationExist) {
|
||||
@ -71,11 +71,11 @@ public class InvitationService {
|
||||
|
||||
return ResponseEntity
|
||||
.status(HttpStatus.OK)
|
||||
.body(new InlineResponse2003()
|
||||
.body(new InlineResponse2002()
|
||||
.results(invitations));
|
||||
}
|
||||
|
||||
public ResponseEntity<Void> revoke(String invitationId, InlineObject request) {
|
||||
public ResponseEntity<Void> revoke(String orgId, String invitationId, InlineObject inlineObject) {
|
||||
Optional<InvitationEntity> entity = invitationRepository.findById(invitationId);
|
||||
|
||||
if (entity.isEmpty()) {
|
||||
@ -85,8 +85,8 @@ public class InvitationService {
|
||||
}
|
||||
|
||||
InvitationEntity updatedEntity = entity.get();
|
||||
updatedEntity.setStatus(request.getStatus().getValue());
|
||||
updatedEntity.setRevocationReason(request.getReason());
|
||||
updatedEntity.setStatus(inlineObject.getStatus().getValue());
|
||||
updatedEntity.setRevocationReason(inlineObject.getReason());
|
||||
|
||||
invitationRepository.save(updatedEntity);
|
||||
|
||||
|
@ -0,0 +1,19 @@
|
||||
package com.rbkmoney.orgmanager.service;
|
||||
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class KeycloakService {
|
||||
|
||||
public AccessToken getAccessToken() {
|
||||
KeycloakPrincipal keycloakPrincipal = (KeycloakPrincipal) SecurityContextHolder.getContext()
|
||||
.getAuthentication()
|
||||
.getPrincipal();
|
||||
|
||||
return keycloakPrincipal.getKeycloakSecurityContext().getToken();
|
||||
}
|
||||
|
||||
}
|
@ -5,7 +5,7 @@ import com.rbkmoney.orgmanager.entity.OrganizationEntity;
|
||||
import com.rbkmoney.orgmanager.entity.OrganizationRoleEntity;
|
||||
import com.rbkmoney.orgmanager.repository.OrganizationRepository;
|
||||
import com.rbkmoney.orgmanager.repository.OrganizationRoleRepository;
|
||||
import com.rbkmoney.swag.organizations.model.InlineResponse2001;
|
||||
import com.rbkmoney.swag.organizations.model.InlineResponse200;
|
||||
import com.rbkmoney.swag.organizations.model.Role;
|
||||
import com.rbkmoney.swag.organizations.model.RoleId;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -35,7 +35,7 @@ public class OrganizationRoleService {
|
||||
.build();
|
||||
}
|
||||
|
||||
Optional<OrganizationRoleEntity> entity = organizationRoleRepository.findByOrganizationIdAndRoleId(orgId, roleId.getValue());
|
||||
Optional<OrganizationRoleEntity> entity = organizationRoleRepository.findByOrganizationIdAndRoleId(orgId, roleId.toString());
|
||||
|
||||
Role role = organizationRoleConverter.toDomain(entity.get());
|
||||
return ResponseEntity
|
||||
@ -43,7 +43,7 @@ public class OrganizationRoleService {
|
||||
.body(role);
|
||||
}
|
||||
|
||||
public ResponseEntity<InlineResponse2001> list(String orgId) {
|
||||
public ResponseEntity<InlineResponse200> list(String orgId) {
|
||||
Optional<OrganizationEntity> entity = organizationRepository.findById(orgId);
|
||||
|
||||
if (entity.isEmpty()) {
|
||||
@ -59,7 +59,7 @@ public class OrganizationRoleService {
|
||||
|
||||
return ResponseEntity
|
||||
.status(HttpStatus.OK)
|
||||
.body(new InlineResponse2001()
|
||||
.body(new InlineResponse200()
|
||||
.results(roles));
|
||||
}
|
||||
}
|
||||
|
@ -2,18 +2,28 @@ package com.rbkmoney.orgmanager.service;
|
||||
|
||||
import com.rbkmoney.orgmanager.converter.MemberConverter;
|
||||
import com.rbkmoney.orgmanager.converter.OrganizationConverter;
|
||||
import com.rbkmoney.orgmanager.entity.InvitationEntity;
|
||||
import com.rbkmoney.orgmanager.entity.MemberEntity;
|
||||
import com.rbkmoney.orgmanager.entity.OrganizationEntity;
|
||||
import com.rbkmoney.orgmanager.entity.OrganizationEntityPageable;
|
||||
import com.rbkmoney.orgmanager.repository.InvitationRepository;
|
||||
import com.rbkmoney.orgmanager.repository.MemberRepository;
|
||||
import com.rbkmoney.orgmanager.repository.OrganizationRepository;
|
||||
import com.rbkmoney.swag.organizations.model.InlineResponse2002;
|
||||
import com.rbkmoney.swag.organizations.model.InlineResponse2001;
|
||||
import com.rbkmoney.swag.organizations.model.Member;
|
||||
import com.rbkmoney.swag.organizations.model.Organization;
|
||||
import com.rbkmoney.swag.organizations.model.OrganizationMembership;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.hibernate.Hibernate;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@ -23,10 +33,26 @@ import static java.util.stream.Collectors.toList;
|
||||
@RequiredArgsConstructor
|
||||
public class OrganizationService {
|
||||
|
||||
public static final Integer DEFAULT_ORG_LIMIT = 20;
|
||||
|
||||
private final OrganizationConverter organizationConverter;
|
||||
private final OrganizationRepository organizationRepository;
|
||||
private final MemberConverter memberConverter;
|
||||
private final MemberRepository memberRepository;
|
||||
private final InvitationRepository invitationRepository;
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Optional<OrganizationEntity> findById(String orgId) {
|
||||
Optional<OrganizationEntity> organizationEntityOptional = organizationRepository.findById(orgId);
|
||||
if (organizationEntityOptional.isPresent()) {
|
||||
OrganizationEntity organizationEntity = organizationEntityOptional.get();
|
||||
Hibernate.initialize(organizationEntity.getMembers());
|
||||
Hibernate.initialize(organizationEntity.getRoles());
|
||||
|
||||
return Optional.of(organizationEntity);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
// TODO [a.romanov]: idempotency
|
||||
public ResponseEntity<Organization> create(
|
||||
@ -57,6 +83,7 @@ public class OrganizationService {
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public ResponseEntity<Member> getMember(String userId) {
|
||||
Optional<MemberEntity> entity = memberRepository.findById(userId);
|
||||
|
||||
@ -72,7 +99,8 @@ public class OrganizationService {
|
||||
.body(member);
|
||||
}
|
||||
|
||||
public ResponseEntity<InlineResponse2002> listMembers(String orgId) {
|
||||
@Transactional
|
||||
public ResponseEntity<InlineResponse2001> listMembers(String orgId) {
|
||||
Optional<OrganizationEntity> entity = organizationRepository.findById(orgId);
|
||||
|
||||
if (entity.isEmpty()) {
|
||||
@ -88,8 +116,115 @@ public class OrganizationService {
|
||||
|
||||
return ResponseEntity
|
||||
.status(HttpStatus.OK)
|
||||
.body(new InlineResponse2002()
|
||||
.body(new InlineResponse2001()
|
||||
.results(members));
|
||||
|
||||
}
|
||||
|
||||
public OrganizationEntityPageable findAllOrganizations(int limit) {
|
||||
if (limit == 0) {
|
||||
limit = DEFAULT_ORG_LIMIT;
|
||||
}
|
||||
Page<OrganizationEntity> organizationEntitiesPage = organizationRepository.findAll(PageRequest.of(0, limit, Sort.by("id").descending()));
|
||||
List<OrganizationEntity> organizationEntities = organizationEntitiesPage.getContent();
|
||||
String continuationToken = null;
|
||||
if (organizationEntitiesPage.hasNext()) {
|
||||
continuationToken = organizationEntities.get(organizationEntities.size() - 1).getId();
|
||||
}
|
||||
List<Organization> organizations = organizationEntities
|
||||
.stream().map(organizationConverter::toDomain)
|
||||
.collect(toList());
|
||||
|
||||
|
||||
return new OrganizationEntityPageable(
|
||||
continuationToken,
|
||||
limit,
|
||||
organizations);
|
||||
}
|
||||
|
||||
public OrganizationEntityPageable findAllOrganizations(String continuationId, int limit) {
|
||||
if (limit == 0) {
|
||||
limit = DEFAULT_ORG_LIMIT;
|
||||
}
|
||||
List<OrganizationEntity> organizationEntities = organizationEntities = organizationRepository.fetchAll(continuationId, limit);
|
||||
String continuationToken = null;
|
||||
if (organizationEntities.size() > 1 && organizationEntities.size() > limit) {
|
||||
continuationToken = organizationEntities.get(organizationEntities.size() - 1).getId();
|
||||
}
|
||||
List<Organization> organizations = organizationEntities
|
||||
.stream().map(organizationConverter::toDomain)
|
||||
.collect(toList());
|
||||
|
||||
return new OrganizationEntityPageable(
|
||||
continuationToken,
|
||||
limit,
|
||||
organizations);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public ResponseEntity<Void> cancelOrgMembership(String orgId, String userId, String userEmail) {
|
||||
Optional<OrganizationEntity> organizationEntityOptional = organizationRepository.findById(orgId);
|
||||
|
||||
if (organizationEntityOptional.isEmpty()) return ResponseEntity.notFound().build();
|
||||
|
||||
Optional<MemberEntity> memberEntityOptional = memberRepository.findById(userId);
|
||||
|
||||
if (memberEntityOptional.isEmpty()) return ResponseEntity.notFound().build();
|
||||
|
||||
organizationEntityOptional.get().getMembers()
|
||||
.removeIf(memberEntity -> memberEntity.getId().equals(memberEntityOptional.get().getId()));
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public ResponseEntity<OrganizationMembership> getMembership(String orgId, String userId, String userEmail) {
|
||||
Optional<OrganizationEntity> organizationEntityOptional = organizationRepository.findById(orgId);
|
||||
|
||||
if (organizationEntityOptional.isEmpty()) return ResponseEntity.notFound().build();
|
||||
|
||||
Optional<MemberEntity> memberEntityOptional = memberRepository.findById(userId);
|
||||
|
||||
if (memberEntityOptional.isEmpty()) return ResponseEntity.notFound().build();
|
||||
|
||||
OrganizationMembership organizationMembership = new OrganizationMembership();
|
||||
organizationMembership.setMember(memberConverter.toDomain(memberEntityOptional.get()));
|
||||
organizationMembership.setOrg(organizationConverter.toDomain(organizationEntityOptional.get()));
|
||||
|
||||
return ResponseEntity.ok(organizationMembership);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public ResponseEntity<OrganizationMembership> joinOrganization(String token, String userId, String userEmail) {
|
||||
Optional<InvitationEntity> invitationEntityOptional = invitationRepository.findByAcceptToken(token);
|
||||
|
||||
if (invitationEntityOptional.isEmpty()) return ResponseEntity.notFound().build();
|
||||
|
||||
InvitationEntity invitationEntity = invitationEntityOptional.get();
|
||||
|
||||
Optional<OrganizationEntity> organizationEntityOptional = organizationRepository.findById(invitationEntity.getOrganizationId());
|
||||
|
||||
if (organizationEntityOptional.isEmpty()) return ResponseEntity.notFound().build();
|
||||
|
||||
OrganizationEntity organizationEntity = organizationEntityOptional.get();
|
||||
|
||||
MemberEntity memberEntity = findOrCreateMember(userId, userEmail);
|
||||
|
||||
organizationEntity.getMembers().add(memberEntity);
|
||||
|
||||
OrganizationMembership organizationMembership = new OrganizationMembership();
|
||||
organizationMembership.setMember(memberConverter.toDomain(memberEntity));
|
||||
organizationMembership.setOrg(organizationConverter.toDomain(organizationEntity));
|
||||
|
||||
return ResponseEntity.ok(organizationMembership);
|
||||
}
|
||||
|
||||
private MemberEntity findOrCreateMember(String userId, String userEmail) {
|
||||
Optional<MemberEntity> memberEntityOptional = memberRepository.findById(userId);
|
||||
if (memberEntityOptional.isEmpty()) {
|
||||
return memberRepository.save(new MemberEntity(userId, Collections.emptySet(), userEmail));
|
||||
}
|
||||
return memberEntityOptional.get();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -41,3 +41,14 @@ hibernate:
|
||||
info:
|
||||
version: '@project.version@'
|
||||
stage: dev
|
||||
|
||||
keycloak:
|
||||
realm: internal
|
||||
auth-server-url: http://keycloak:8080/auth
|
||||
resource: common-api
|
||||
not-before: 0
|
||||
ssl-required: none
|
||||
realm-public-key-file-path:
|
||||
realm-public-key:
|
||||
|
||||
auth.enabled: true
|
||||
|
@ -0,0 +1,58 @@
|
||||
package com.rbkmoney.orgmanager.controller;
|
||||
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.util.TestPropertyValues;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.*;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.time.Duration;
|
||||
import java.util.Base64;
|
||||
import java.util.Properties;
|
||||
|
||||
@Import(KeycloakTestConfig.class)
|
||||
public abstract class AbstractControllerTest {
|
||||
|
||||
@ClassRule
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:9.6")
|
||||
.withStartupTimeout(Duration.ofMinutes(5));
|
||||
|
||||
public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
|
||||
@Override
|
||||
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
|
||||
TestPropertyValues.of(
|
||||
"spring.datasource.url=" + postgres.getJdbcUrl(),
|
||||
"spring.datasource.username=" + postgres.getUsername(),
|
||||
"spring.datasource.password=" + postgres.getPassword(),
|
||||
"spring.flyway.url=" + postgres.getJdbcUrl(),
|
||||
"spring.flyway.user=" + postgres.getUsername(),
|
||||
"spring.flyway.password=" + postgres.getPassword())
|
||||
.and(configurableApplicationContext.getEnvironment().getActiveProfiles())
|
||||
.applyTo(configurableApplicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private KeycloakOpenIdStub keycloakOpenIdStub;
|
||||
|
||||
protected String generateJwt(long iat, long exp, String... roles) {
|
||||
return keycloakOpenIdStub.generateJwt(iat, exp, roles);
|
||||
}
|
||||
|
||||
protected String generateRBKadminJwt() {
|
||||
return keycloakOpenIdStub.generateJwt("RBKadmin");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package com.rbkmoney.orgmanager.controller;
|
||||
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.security.PrivateKey;
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
|
||||
public class JwtTokenBuilder {
|
||||
|
||||
public final static String DEFAULT_USERNAME = "Darth Vader";
|
||||
|
||||
public final static String DEFAULT_EMAIL = "darkside-the-best@mail.com";
|
||||
|
||||
private final String userId;
|
||||
|
||||
private final String username;
|
||||
|
||||
private final String email;
|
||||
|
||||
private final PrivateKey privateKey;
|
||||
|
||||
public JwtTokenBuilder(PrivateKey privateKey) {
|
||||
this(UUID.randomUUID().toString(), DEFAULT_USERNAME, DEFAULT_EMAIL, privateKey);
|
||||
}
|
||||
|
||||
public JwtTokenBuilder(String userId, String username, String email, PrivateKey privateKey) {
|
||||
this.userId = userId;
|
||||
this.username = username;
|
||||
this.email = email;
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public String generateJwtWithRoles(String issuer, String... roles) {
|
||||
long iat = Instant.now().getEpochSecond();
|
||||
long exp = iat + 60 * 10;
|
||||
return generateJwtWithRoles(iat, exp, issuer, roles);
|
||||
}
|
||||
|
||||
public String generateJwtWithRoles(long iat, long exp, String issuer, String... roles) {
|
||||
String payload;
|
||||
try {
|
||||
payload = new JSONObject()
|
||||
.put("jti", UUID.randomUUID().toString())
|
||||
.put("exp", exp)
|
||||
.put("nbf", "0")
|
||||
.put("iat", iat)
|
||||
.put("iss", issuer)
|
||||
.put("aud", "private-api")
|
||||
.put("sub", userId)
|
||||
.put("typ", "Bearer")
|
||||
.put("azp", "private-api")
|
||||
.put("resource_access", new JSONObject()
|
||||
.put("common-api", new JSONObject()
|
||||
.put("roles", new JSONArray(roles))))
|
||||
.put("preferred_username", username)
|
||||
.put("email", email).toString();
|
||||
} catch (JSONException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
String jwt = Jwts.builder()
|
||||
.setPayload(payload)
|
||||
.signWith(SignatureAlgorithm.RS256, privateKey)
|
||||
.compact();
|
||||
return jwt;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package com.rbkmoney.orgmanager.controller;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.*;
|
||||
|
||||
public class KeycloakOpenIdStub {
|
||||
|
||||
private final String keycloakRealm;
|
||||
private final String issuer;
|
||||
private final String openidConfig;
|
||||
private final JwtTokenBuilder jwtTokenBuilder;
|
||||
|
||||
public KeycloakOpenIdStub(String keycloakAuthServerUrl, String keycloakRealm, JwtTokenBuilder jwtTokenBuilder) {
|
||||
this.keycloakRealm = keycloakRealm;
|
||||
this.jwtTokenBuilder = jwtTokenBuilder;
|
||||
this.issuer = keycloakAuthServerUrl + "/realms/" + keycloakRealm;
|
||||
this.openidConfig = "{\n" +
|
||||
" \"issuer\": \"" + issuer + "\",\n" +
|
||||
" \"authorization_endpoint\": \"" + keycloakAuthServerUrl + "/realms/" + keycloakRealm + "/protocol/openid-connect/auth\",\n" +
|
||||
" \"token_endpoint\": \"" + keycloakAuthServerUrl + "/realms/" + keycloakRealm + "/protocol/openid-connect/token\",\n" +
|
||||
" \"token_introspection_endpoint\": \"" + keycloakAuthServerUrl + "/realms/" + keycloakRealm + "/protocol/openid-connect/token/introspect\",\n" +
|
||||
" \"userinfo_endpoint\": \"" + keycloakAuthServerUrl + "/realms/" + keycloakRealm + "/protocol/openid-connect/userinfo\",\n" +
|
||||
" \"end_session_endpoint\": \"" + keycloakAuthServerUrl + "/realms/" + keycloakRealm + "/protocol/openid-connect/logout\",\n" +
|
||||
" \"jwks_uri\": \"" + keycloakAuthServerUrl + "/realms/" + keycloakRealm + "/protocol/openid-connect/certs\",\n" +
|
||||
" \"check_session_iframe\": \"" + keycloakAuthServerUrl + "/realms/" + keycloakRealm + "/protocol/openid-connect/login-status-iframe.html\",\n" +
|
||||
" \"registration_endpoint\": \"" + keycloakAuthServerUrl + "/realms/" + keycloakRealm + "/clients-registrations/openid-connect\",\n" +
|
||||
" \"introspection_endpoint\": \"" + keycloakAuthServerUrl + "/realms/" + keycloakRealm + "/protocol/openid-connect/token/introspect\"\n" +
|
||||
"}";
|
||||
}
|
||||
|
||||
public void givenStub() {
|
||||
stubFor(get(urlEqualTo(String.format("/auth/realms/%s/.well-known/openid-configuration", keycloakRealm)))
|
||||
.willReturn(aResponse()
|
||||
.withHeader("Content-Type", "application/json")
|
||||
.withBody(openidConfig)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public String generateJwt(String... roles) {
|
||||
return jwtTokenBuilder.generateJwtWithRoles(issuer, roles);
|
||||
}
|
||||
|
||||
public String generateJwt(long iat, long exp, String... roles) {
|
||||
return jwtTokenBuilder.generateJwtWithRoles(iat, exp, issuer, roles);
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package com.rbkmoney.orgmanager.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.*;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Base64;
|
||||
import java.util.Properties;
|
||||
|
||||
@TestConfiguration
|
||||
public class KeycloakTestConfig {
|
||||
|
||||
@Bean
|
||||
public KeycloakOpenIdStub keycloakOpenIdStub(@Value("${keycloak.auth-server-url}") String keycloakAuthServerUrl,
|
||||
@Value("${keycloak.realm}") String keycloakRealm,
|
||||
JwtTokenBuilder jwtTokenBuilder) {
|
||||
return new KeycloakOpenIdStub(keycloakAuthServerUrl, keycloakRealm, jwtTokenBuilder);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JwtTokenBuilder JwtTokenBuilder(KeyPair keyPair) {
|
||||
return new JwtTokenBuilder(keyPair.getPrivate());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KeyPair keyPair() throws GeneralSecurityException {
|
||||
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
|
||||
keyGen.initialize(2048);
|
||||
return keyGen.generateKeyPair();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public static PropertySourcesPlaceholderConfigurer properties(KeyPair keyPair) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
|
||||
KeyFactory fact = KeyFactory.getInstance("RSA");
|
||||
X509EncodedKeySpec spec = fact.getKeySpec(keyPair.getPublic(), X509EncodedKeySpec.class);
|
||||
String publicKey = Base64.getEncoder().encodeToString(spec.getEncoded());
|
||||
PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer();
|
||||
Properties properties = new Properties();
|
||||
properties.load(new ClassPathResource("application.yml").getInputStream());
|
||||
properties.setProperty("keycloak.realm-public-key", publicKey);
|
||||
pspc.setProperties(properties);
|
||||
pspc.setLocalOverride(true);
|
||||
return pspc;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,254 @@
|
||||
package com.rbkmoney.orgmanager.controller;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.rbkmoney.orgmanager.OrgManagerApplication;
|
||||
import com.rbkmoney.orgmanager.entity.InvitationEntity;
|
||||
import com.rbkmoney.orgmanager.entity.MemberEntity;
|
||||
import com.rbkmoney.orgmanager.entity.MemberRoleEntity;
|
||||
import com.rbkmoney.orgmanager.entity.OrganizationEntity;
|
||||
import com.rbkmoney.orgmanager.repository.InvitationRepository;
|
||||
import com.rbkmoney.orgmanager.repository.InvitationRepositoryTest;
|
||||
import com.rbkmoney.orgmanager.repository.OrganizationRepository;
|
||||
import com.rbkmoney.orgmanager.service.OrganizationService;
|
||||
import com.rbkmoney.swag.organizations.model.InlineResponse2001;
|
||||
import com.rbkmoney.swag.organizations.model.OrganizationJoinRequest;
|
||||
import com.rbkmoney.swag.organizations.model.OrganizationMembership;
|
||||
import com.rbkmoney.swag.organizations.model.OrganizationSearchResult;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.mock.mockito.SpyBean;
|
||||
import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@DirtiesContext
|
||||
@SpringBootTest(
|
||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
classes = {OrgManagerApplication.class, UserController.class})
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration(initializers = InvitationRepositoryTest.Initializer.class)
|
||||
@AutoConfigureMockMvc
|
||||
@AutoConfigureWireMock(port = 0)
|
||||
@TestPropertySource(locations = "classpath:wiremock.properties")
|
||||
public class UserControllerTest extends AbstractControllerTest {
|
||||
|
||||
public static String ORGANIZATION_ID = "3Kf21K54ldE3";
|
||||
|
||||
public static String INVITATION_ID = "DL3Mc9dEqAlP";
|
||||
|
||||
public static String MEMBER_ID = "L6Mc2la1D9Rg";
|
||||
|
||||
public static String ACCEPT_TOKEN = "testToken";
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Autowired
|
||||
private InvitationRepository invitationRepository;
|
||||
|
||||
@Autowired
|
||||
private OrganizationRepository organizationRepository;
|
||||
|
||||
@Autowired
|
||||
private KeycloakOpenIdStub keycloakOpenIdStub;
|
||||
|
||||
@SpyBean
|
||||
private OrganizationService organizationService;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
keycloakOpenIdStub.givenStub();
|
||||
OrganizationEntity organizationEntity = buildOrganization();
|
||||
organizationRepository.save(organizationEntity);
|
||||
InvitationEntity invitationEntity = buildInvitation();
|
||||
invitationRepository.save(invitationEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void joinOrgTest() throws Exception {
|
||||
OrganizationJoinRequest organizationJoinRequest = new OrganizationJoinRequest();
|
||||
organizationJoinRequest.setInvitation(ACCEPT_TOKEN);
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(post("/user/membership")
|
||||
.contentType("application/json")
|
||||
.content(objectMapper.writeValueAsString(organizationJoinRequest))
|
||||
.header("Authorization", "Bearer " + generateRBKadminJwt())
|
||||
.header("X-Request-ID", "testRequestId")
|
||||
).andExpect(status().isOk()).andReturn();
|
||||
|
||||
ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
|
||||
verify(organizationService, atMostOnce()).joinOrganization(anyString(), argumentCaptor.capture(), anyString());
|
||||
String userId = argumentCaptor.getValue();
|
||||
|
||||
OrganizationMembership organizationMembership = objectMapper.readValue(
|
||||
mvcResult.getResponse().getContentAsString(), OrganizationMembership.class);
|
||||
Assert.assertEquals(ORGANIZATION_ID, organizationMembership.getOrg().getId());
|
||||
Assert.assertEquals(userId, organizationMembership.getMember().getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cancelOrgMembershipTest() throws Exception {
|
||||
String jwtToken = generateRBKadminJwt();
|
||||
|
||||
OrganizationJoinRequest organizationJoinRequest = new OrganizationJoinRequest();
|
||||
organizationJoinRequest.setInvitation(ACCEPT_TOKEN);
|
||||
mockMvc.perform(post("/user/membership")
|
||||
.contentType("application/json")
|
||||
.content(objectMapper.writeValueAsString(organizationJoinRequest))
|
||||
.header("Authorization", "Bearer " + jwtToken)
|
||||
.header("X-Request-ID", "testRequestId")
|
||||
).andExpect(status().isOk()).andReturn();
|
||||
|
||||
ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
|
||||
verify(organizationService, atMostOnce()).joinOrganization(anyString(), argumentCaptor.capture(), anyString());
|
||||
String userId = argumentCaptor.getValue();
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(delete("/user/membership/{orgId}", ORGANIZATION_ID)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.header("Authorization", "Bearer " + jwtToken)
|
||||
.header("X-Request-ID", "testRequestId")
|
||||
).andExpect(status().isOk()).andReturn();
|
||||
|
||||
ResponseEntity<InlineResponse2001> response = organizationService.listMembers(ORGANIZATION_ID);
|
||||
final boolean isMemberFounded = response.getBody().getResults()
|
||||
.stream().anyMatch(member -> member.getId().equals(userId));
|
||||
Assert.assertFalse(isMemberFounded);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inquireOrgMembershipTest() throws Exception {
|
||||
String jwtToken = generateRBKadminJwt();
|
||||
|
||||
// Join organization
|
||||
OrganizationJoinRequest organizationJoinRequest = new OrganizationJoinRequest();
|
||||
organizationJoinRequest.setInvitation(ACCEPT_TOKEN);
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(post("/user/membership")
|
||||
.contentType("application/json")
|
||||
.content(objectMapper.writeValueAsString(organizationJoinRequest))
|
||||
.header("Authorization", "Bearer " + generateRBKadminJwt())
|
||||
.header("X-Request-ID", "testRequestId")
|
||||
).andExpect(status().isOk()).andReturn();
|
||||
|
||||
// get membership
|
||||
mockMvc.perform(get("/user/membership/{orgId}", ORGANIZATION_ID)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.header("Authorization", "Bearer " + jwtToken)
|
||||
.header("X-Request-ID", "testRequestId")
|
||||
)
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.org").exists())
|
||||
.andExpect(jsonPath("$.member").exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listOrgMembershipTest() throws Exception {
|
||||
String jwtToken = generateRBKadminJwt();
|
||||
for (int i = 0; i < 8; i++) {
|
||||
OrganizationEntity organizationEntity = buildOrganization();
|
||||
organizationEntity.setId(UUID.randomUUID().toString());
|
||||
Set<MemberEntity> memberEntities = organizationEntity.getMembers().stream()
|
||||
.peek(memberEntity -> memberEntity.setId(UUID.randomUUID().toString()))
|
||||
.collect(Collectors.toSet());
|
||||
organizationEntity.setMembers(memberEntities);
|
||||
organizationRepository.save(organizationEntity);
|
||||
}
|
||||
|
||||
MvcResult mvcResultFirst = mockMvc.perform(get("/user/membership")
|
||||
.queryParam("limit", "5")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.header("Authorization", "Bearer " + jwtToken)
|
||||
.header("X-Request-ID", "testRequestId")
|
||||
).andExpect(status().isOk()).andReturn();
|
||||
|
||||
OrganizationSearchResult organizationSearchResultFirst = objectMapper.readValue(
|
||||
mvcResultFirst.getResponse().getContentAsString(), OrganizationSearchResult.class);
|
||||
Assert.assertEquals(5, organizationSearchResultFirst.getResults().size());
|
||||
|
||||
MvcResult mvcResultSecond = mockMvc.perform(get("/user/membership")
|
||||
.queryParam("limit", "5")
|
||||
.queryParam("continuationToken", organizationSearchResultFirst.getContinuationToken())
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.header("Authorization", "Bearer " + jwtToken)
|
||||
.header("X-Request-ID", "testRequestId")
|
||||
).andExpect(status().isOk()).andReturn();
|
||||
|
||||
OrganizationSearchResult organizationSearchResultSecond = objectMapper.readValue(
|
||||
mvcResultSecond.getResponse().getContentAsString(), OrganizationSearchResult.class);
|
||||
|
||||
Assert.assertEquals(4, organizationSearchResultSecond.getResults().size());
|
||||
Assert.assertNull(organizationSearchResultSecond.getContinuationToken());
|
||||
}
|
||||
|
||||
private InvitationEntity buildInvitation() {
|
||||
return InvitationEntity.builder()
|
||||
.id(INVITATION_ID)
|
||||
.acceptToken(ACCEPT_TOKEN)
|
||||
.createdAt(LocalDateTime.now())
|
||||
.expiresAt(LocalDateTime.now())
|
||||
.inviteeContactEmail("contactEmail")
|
||||
.inviteeContactType("contactType")
|
||||
.metadata("metadata")
|
||||
.organizationId(ORGANIZATION_ID)
|
||||
.status("Pending")
|
||||
.inviteeRoles(Set.of(
|
||||
MemberRoleEntity.builder()
|
||||
.id("role1")
|
||||
.roleId("role1")
|
||||
.resourceId("resource1")
|
||||
.scopeId("scope1")
|
||||
.organizationId(ORGANIZATION_ID)
|
||||
.build(),
|
||||
MemberRoleEntity.builder()
|
||||
.id("role2")
|
||||
.roleId("role2")
|
||||
.resourceId("resource2")
|
||||
.scopeId("scope2")
|
||||
.organizationId(ORGANIZATION_ID)
|
||||
.build()))
|
||||
.build();
|
||||
}
|
||||
|
||||
private OrganizationEntity buildOrganization() {
|
||||
MemberEntity member = MemberEntity.builder()
|
||||
.id(MEMBER_ID)
|
||||
.email("email")
|
||||
.build();
|
||||
|
||||
return OrganizationEntity.builder()
|
||||
.id(ORGANIZATION_ID)
|
||||
.createdAt(LocalDateTime.now())
|
||||
.name("name")
|
||||
.owner("owner")
|
||||
.members(Set.of(member))
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
@ -7,6 +7,7 @@ import com.rbkmoney.orgmanager.util.JsonMapper;
|
||||
import com.rbkmoney.swag.organizations.model.*;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.openapitools.jackson.nullable.JsonNullable;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
@ -48,7 +49,7 @@ public class InvitationConverterTest {
|
||||
.roles(Set.of(new MemberRole())))
|
||||
.expiresAt(OffsetDateTime.parse("2019-08-24T14:15:22Z"))
|
||||
.metadata(Map.of("a", "b"));
|
||||
invitation.setStatus("Pending");
|
||||
invitation.setStatus(JsonNullable.of("Pending"));
|
||||
|
||||
// When
|
||||
InvitationEntity entity = converter.toEntity(invitation, "org");
|
||||
@ -101,7 +102,7 @@ public class InvitationConverterTest {
|
||||
.roles(Set.of(new MemberRole())))
|
||||
.acceptToken("token")
|
||||
.metadata(Map.of("a", "b"));
|
||||
expected.setStatus("Pending");
|
||||
expected.setStatus(JsonNullable.of("Pending"));
|
||||
|
||||
assertThat(invitation).isEqualToComparingFieldByField(expected);
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ public abstract class AbstractRepositoryTest {
|
||||
public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
|
||||
@Override
|
||||
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
|
||||
postgres.start();
|
||||
TestPropertyValues.of(
|
||||
"spring.datasource.url=" + postgres.getJdbcUrl(),
|
||||
"spring.datasource.username=" + postgres.getUsername(),
|
||||
|
@ -5,10 +5,13 @@ import com.rbkmoney.orgmanager.entity.MemberEntity;
|
||||
import com.rbkmoney.orgmanager.entity.OrganizationEntity;
|
||||
import com.rbkmoney.orgmanager.entity.OrganizationRoleEntity;
|
||||
import com.rbkmoney.orgmanager.entity.ScopeEntity;
|
||||
import com.rbkmoney.orgmanager.service.OrganizationService;
|
||||
import com.rbkmoney.swag.organizations.model.Organization;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
@ -18,6 +21,7 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@DirtiesContext
|
||||
@ -31,6 +35,9 @@ public class OrganizationRepositoryTest extends AbstractRepositoryTest {
|
||||
@Autowired
|
||||
private OrganizationRepository organizationRepository;
|
||||
|
||||
@Autowired
|
||||
private OrganizationService organizationService;
|
||||
|
||||
@Autowired
|
||||
private MemberRepository memberRepository;
|
||||
|
||||
@ -47,7 +54,6 @@ public class OrganizationRepositoryTest extends AbstractRepositoryTest {
|
||||
.id("memberId")
|
||||
.email("email")
|
||||
.build();
|
||||
|
||||
OrganizationEntity organization = OrganizationEntity.builder()
|
||||
.id(ORGANIZATION_ID)
|
||||
.createdAt(LocalDateTime.now())
|
||||
@ -60,7 +66,7 @@ public class OrganizationRepositoryTest extends AbstractRepositoryTest {
|
||||
organizationRepository.save(organization);
|
||||
|
||||
// Then
|
||||
Optional<OrganizationEntity> savedOrganization = organizationRepository.findById(ORGANIZATION_ID);
|
||||
Optional<OrganizationEntity> savedOrganization = organizationService.findById(ORGANIZATION_ID);
|
||||
assertTrue(savedOrganization.isPresent());
|
||||
assertThat(savedOrganization.get().getMembers()).hasSize(1);
|
||||
|
||||
@ -95,10 +101,10 @@ public class OrganizationRepositoryTest extends AbstractRepositoryTest {
|
||||
organizationRepository.save(organization);
|
||||
|
||||
// Then
|
||||
Optional<OrganizationEntity> savedOrganization = organizationRepository.findById(ORGANIZATION_ID);
|
||||
assertTrue(savedOrganization.isPresent());
|
||||
assertThat(savedOrganization.get().getRoles()).hasSize(1);
|
||||
savedOrganization.get().getRoles().forEach(
|
||||
Optional<OrganizationEntity> savedOrganizationOptional = organizationService.findById(ORGANIZATION_ID);
|
||||
assertTrue(savedOrganizationOptional.isPresent());
|
||||
assertThat(savedOrganizationOptional.get().getRoles()).hasSize(1);
|
||||
savedOrganizationOptional.get().getRoles().forEach(
|
||||
r -> assertThat(r.getPossibleScopes()).hasSize(1));
|
||||
|
||||
Optional<OrganizationRoleEntity> savedMember = organizationRoleRepository.findById("roleId");
|
||||
|
@ -5,7 +5,7 @@ import com.rbkmoney.orgmanager.entity.InvitationEntity;
|
||||
import com.rbkmoney.orgmanager.repository.InvitationRepository;
|
||||
import com.rbkmoney.orgmanager.repository.OrganizationRepository;
|
||||
import com.rbkmoney.swag.organizations.model.InlineObject;
|
||||
import com.rbkmoney.swag.organizations.model.InlineResponse2003;
|
||||
import com.rbkmoney.swag.organizations.model.InlineResponse2002;
|
||||
import com.rbkmoney.swag.organizations.model.Invitation;
|
||||
import com.rbkmoney.swag.organizations.model.InvitationStatusName;
|
||||
import org.junit.Test;
|
||||
@ -115,7 +115,7 @@ public class InvitationServiceTest {
|
||||
.thenReturn(invitation);
|
||||
|
||||
// When
|
||||
ResponseEntity<InlineResponse2003> response = service.list(orgId, InvitationStatusName.PENDING);
|
||||
ResponseEntity<InlineResponse2002> response = service.list(orgId, InvitationStatusName.PENDING);
|
||||
|
||||
// Then
|
||||
assertThat(response.getStatusCode())
|
||||
@ -134,7 +134,7 @@ public class InvitationServiceTest {
|
||||
.thenReturn(false);
|
||||
|
||||
// When
|
||||
ResponseEntity<InlineResponse2003> response = service.list(orgId, InvitationStatusName.ACCEPTED);
|
||||
ResponseEntity<InlineResponse2002> response = service.list(orgId, InvitationStatusName.ACCEPTED);
|
||||
|
||||
// Then
|
||||
assertThat(response.getStatusCode())
|
||||
@ -146,6 +146,7 @@ public class InvitationServiceTest {
|
||||
@Test
|
||||
public void shouldRevoke() {
|
||||
// Given
|
||||
String orgId = "orgId";
|
||||
String invitationId = "invitationId";
|
||||
InvitationEntity entity = new InvitationEntity();
|
||||
|
||||
@ -153,7 +154,7 @@ public class InvitationServiceTest {
|
||||
.thenReturn(Optional.of(entity));
|
||||
|
||||
// When
|
||||
ResponseEntity<Void> response = service.revoke(invitationId, new InlineObject()
|
||||
ResponseEntity<Void> response = service.revoke(orgId, invitationId, new InlineObject()
|
||||
.reason("reason")
|
||||
.status(InlineObject.StatusEnum.REVOKED));
|
||||
|
||||
@ -171,13 +172,14 @@ public class InvitationServiceTest {
|
||||
@Test
|
||||
public void shouldReturnNotFoundIfInvitationDoesNotExist() {
|
||||
// Given
|
||||
String orgId = "orgId";
|
||||
String invitationId = "invitationId";
|
||||
|
||||
when(invitationRepository.findById(invitationId))
|
||||
.thenReturn(Optional.empty());
|
||||
|
||||
// When
|
||||
ResponseEntity<Void> response = service.revoke(invitationId, new InlineObject());
|
||||
ResponseEntity<Void> response = service.revoke(orgId, invitationId, new InlineObject());
|
||||
|
||||
// Then
|
||||
assertThat(response.getStatusCode())
|
||||
|
@ -5,6 +5,7 @@ import com.rbkmoney.orgmanager.entity.OrganizationEntity;
|
||||
import com.rbkmoney.orgmanager.entity.OrganizationRoleEntity;
|
||||
import com.rbkmoney.orgmanager.repository.OrganizationRepository;
|
||||
import com.rbkmoney.orgmanager.repository.OrganizationRoleRepository;
|
||||
import com.rbkmoney.swag.organizations.model.InlineResponse200;
|
||||
import com.rbkmoney.swag.organizations.model.InlineResponse2001;
|
||||
import com.rbkmoney.swag.organizations.model.Role;
|
||||
import com.rbkmoney.swag.organizations.model.RoleId;
|
||||
@ -49,7 +50,7 @@ public class OrganizationRoleServiceTest {
|
||||
.thenReturn(role);
|
||||
|
||||
// When
|
||||
ResponseEntity<InlineResponse2001> response = service.list(orgId);
|
||||
ResponseEntity<InlineResponse200> response = service.list(orgId);
|
||||
|
||||
// Then
|
||||
assertThat(response.getStatusCode())
|
||||
@ -69,7 +70,7 @@ public class OrganizationRoleServiceTest {
|
||||
.thenReturn(Optional.empty());
|
||||
|
||||
// When
|
||||
ResponseEntity<InlineResponse2001> response = service.list(orgId);
|
||||
ResponseEntity<InlineResponse200> response = service.list(orgId);
|
||||
|
||||
// Then
|
||||
assertThat(response.getStatusCode())
|
||||
|
@ -6,6 +6,7 @@ import com.rbkmoney.orgmanager.entity.MemberEntity;
|
||||
import com.rbkmoney.orgmanager.entity.OrganizationEntity;
|
||||
import com.rbkmoney.orgmanager.repository.MemberRepository;
|
||||
import com.rbkmoney.orgmanager.repository.OrganizationRepository;
|
||||
import com.rbkmoney.swag.organizations.model.InlineResponse2001;
|
||||
import com.rbkmoney.swag.organizations.model.InlineResponse2002;
|
||||
import com.rbkmoney.swag.organizations.model.Member;
|
||||
import com.rbkmoney.swag.organizations.model.Organization;
|
||||
@ -118,7 +119,7 @@ public class OrganizationServiceTest {
|
||||
.thenReturn(member);
|
||||
|
||||
// When
|
||||
ResponseEntity<InlineResponse2002> response = service.listMembers(orgId);
|
||||
ResponseEntity<InlineResponse2001> response = service.listMembers(orgId);
|
||||
|
||||
// Then
|
||||
assertThat(response.getStatusCode())
|
||||
@ -138,7 +139,7 @@ public class OrganizationServiceTest {
|
||||
.thenReturn(Optional.empty());
|
||||
|
||||
// When
|
||||
ResponseEntity<InlineResponse2002> response = service.listMembers(orgId);
|
||||
ResponseEntity<InlineResponse2001> response = service.listMembers(orgId);
|
||||
|
||||
// Then
|
||||
assertThat(response.getStatusCode())
|
||||
|
2
src/test/resources/wiremock.properties
Normal file
2
src/test/resources/wiremock.properties
Normal file
@ -0,0 +1,2 @@
|
||||
wiremock.server.baseUrl=http://localhost:${wiremock.server.port}
|
||||
keycloak.auth-server-url=${wiremock.server.baseUrl}/auth
|
Loading…
Reference in New Issue
Block a user