From 671c3ee05a735d67968c20bd7fdf35542d61cf50 Mon Sep 17 00:00:00 2001 From: Stoyan Tzenkov Date: Mon, 17 Dec 2018 12:29:18 +0200 Subject: [PATCH 1/4] NY-6152: Accesspoints' endpoints deleted. Signed-off-by: Stoyan Tzenkov --- pom.xml | 5 + .../nynja/account/StartupScriptsListener.java | 6 +- .../account/accesspoints/AccessPoint.java | 155 ++++++++++++++++++ .../accesspoints/AccessPointRepository.java | 16 ++ .../accesspoints/AccessPointService.java | 32 ++++ .../components/PreparedStatementsCache.java | 6 +- .../CassandraAccessPointConfig.java | 91 ++++++++++ .../configuration/CassandraAccountConfig.java | 103 ++++++++++++ ...raConfig.java => CassandraBaseConfig.java} | 143 ++++++++-------- .../account/services/AccountServiceImpl.java | 62 +++---- src/main/resources/application-dev.yml | 5 +- .../configurations/CassandraTestsConfig.java | 2 + 12 files changed, 512 insertions(+), 114 deletions(-) create mode 100644 src/main/java/biz/nynja/account/accesspoints/AccessPoint.java create mode 100644 src/main/java/biz/nynja/account/accesspoints/AccessPointRepository.java create mode 100644 src/main/java/biz/nynja/account/accesspoints/AccessPointService.java create mode 100644 src/main/java/biz/nynja/account/configuration/CassandraAccessPointConfig.java create mode 100644 src/main/java/biz/nynja/account/configuration/CassandraAccountConfig.java rename src/main/java/biz/nynja/account/configuration/{CassandraConfig.java => CassandraBaseConfig.java} (52%) diff --git a/pom.xml b/pom.xml index 931932d..7a41f5d 100644 --- a/pom.xml +++ b/pom.xml @@ -165,6 +165,11 @@ 3.4.0 + + org.springframework.boot + spring-boot-configuration-processor + true + diff --git a/src/main/java/biz/nynja/account/StartupScriptsListener.java b/src/main/java/biz/nynja/account/StartupScriptsListener.java index 4dcf578..ca66b87 100644 --- a/src/main/java/biz/nynja/account/StartupScriptsListener.java +++ b/src/main/java/biz/nynja/account/StartupScriptsListener.java @@ -9,6 +9,7 @@ import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @@ -16,11 +17,9 @@ import org.springframework.stereotype.Component; import com.datastax.driver.core.Session; import com.datastax.driver.core.exceptions.InvalidQueryException; -import biz.nynja.account.configuration.CassandraConfig; import biz.nynja.account.repositories.AccountRepositoryAdditional; - /** - * This acts as {@link CassandraConfig} startupScripts executor but activated after the spring has setup the needed + * This acts as {@link CassandraAccountConfig} startupScripts executor but activated after the spring has setup the needed * tables though JPA * * @author dragomir.todorov @@ -33,6 +32,7 @@ public class StartupScriptsListener { private String keyspace; @Autowired + @Qualifier("accountSession") private Session session; @Autowired diff --git a/src/main/java/biz/nynja/account/accesspoints/AccessPoint.java b/src/main/java/biz/nynja/account/accesspoints/AccessPoint.java new file mode 100644 index 0000000..9f33f05 --- /dev/null +++ b/src/main/java/biz/nynja/account/accesspoints/AccessPoint.java @@ -0,0 +1,155 @@ +/** + * Copyright (C) 2018 Nynja Inc. All rights reserved. + */ +package biz.nynja.account.accesspoints; + + +import java.io.Serializable; +import java.nio.ByteBuffer; +import java.time.LocalDate; +import java.util.Set; +import java.util.UUID; + +import org.springframework.data.cassandra.core.cql.PrimaryKeyType; +import org.springframework.data.cassandra.core.mapping.PrimaryKey; +import org.springframework.data.cassandra.core.mapping.PrimaryKeyColumn; +import org.springframework.data.cassandra.core.mapping.Table; + +import biz.nynja.account.grpc.AccessPointDetails; +import biz.nynja.account.grpc.AccessPointDetails.Builder; + +@Table +public class AccessPoint implements Serializable { + + @PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED) + private UUID accountId; + @PrimaryKeyColumn(ordinal = 1, type = PrimaryKeyType.CLUSTERED) + private String deviceId; + private String accessToken; + private Long creationTimestamp; + private Long expirationTimestamp; + + public String getDeviceId() { + return deviceId; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } + + public UUID getAccountId() { + return accountId; + } + + public void setAccountId(UUID accountId) { + this.accountId = accountId; + } + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public Long getCreationTimestamp() { + return creationTimestamp; + } + + public void setCreationTimestamp(Long creationTimestamp) { + this.creationTimestamp = creationTimestamp; + } + + public Long getExpirationTimestamp() { + return expirationTimestamp; + } + + public void setExpirationTimestamp(Long expirationTimestamp) { + this.expirationTimestamp = expirationTimestamp; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((deviceId == null) ? 0 : deviceId.hashCode()); + result = prime * result + ((accountId == null) ? 0 : accountId.hashCode()); + result = prime * result + ((accessToken == null) ? 0 : accessToken.hashCode()); + result = prime * result + ((creationTimestamp == null) ? 0 : creationTimestamp.hashCode()); + result = prime * result + ((expirationTimestamp == null) ? 0 : expirationTimestamp.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + AccessPoint other = (AccessPoint) obj; + if (deviceId == null) { + if (other.deviceId != null) + return false; + } else if (!deviceId.equals(other.deviceId)) + return false; + if (accountId == null) { + if (other.accountId != null) + return false; + } else if (!accountId.equals(other.accountId)) + return false; + if (accessToken == null) { + if (other.accessToken != null) + return false; + } else if (!accessToken.equals(other.accessToken)) + return false; + if (creationTimestamp == null) { + if (other.creationTimestamp != null) + return false; + } else if (!creationTimestamp.equals(other.creationTimestamp)) + return false; + if (expirationTimestamp == null) { + if (other.expirationTimestamp != null) + return false; + } else if (!expirationTimestamp.equals(other.expirationTimestamp)) + return false; + return true; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("AccessPoint [deviceId=").append(deviceId) + .append(", accountId=").append(accountId) + .append(", accessToken=").append(accessToken) + .append(", creationTimestamp=").append(creationTimestamp) + .append(", expirationTimestamp=").append(expirationTimestamp) + .append("]"); + return builder.toString(); + } + + public AccessPointDetails toProto() { + + Builder builder = AccessPointDetails.newBuilder(); + + if (getAccountId() != null) { + builder.setAccountId(getAccountId().toString()); + } + if (getDeviceId() != null) { + builder.setDeviceId(getDeviceId().toString()); + } + if (getCreationTimestamp() != null) { + builder.setCreationTimestamp(getCreationTimestamp()); + } + if (getExpirationTimestamp() != null) { + builder.setExpirationTimestamp(getExpirationTimestamp()); + } + + return builder.build(); + + } + + +} diff --git a/src/main/java/biz/nynja/account/accesspoints/AccessPointRepository.java b/src/main/java/biz/nynja/account/accesspoints/AccessPointRepository.java new file mode 100644 index 0000000..45a32d4 --- /dev/null +++ b/src/main/java/biz/nynja/account/accesspoints/AccessPointRepository.java @@ -0,0 +1,16 @@ +/** + * Copyright (C) 2018 Nynja Inc. All rights reserved. + */ +package biz.nynja.account.accesspoints; + +import java.util.UUID; +import org.springframework.data.cassandra.repository.CassandraRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface AccessPointRepository + extends CassandraRepository { + + AccessPoint findByAccountIdAndDeviceId(UUID accountId, String deviceId); + +} diff --git a/src/main/java/biz/nynja/account/accesspoints/AccessPointService.java b/src/main/java/biz/nynja/account/accesspoints/AccessPointService.java new file mode 100644 index 0000000..93ff2b5 --- /dev/null +++ b/src/main/java/biz/nynja/account/accesspoints/AccessPointService.java @@ -0,0 +1,32 @@ +/** + * Copyright (C) 2018 Nynja Inc. All rights reserved. + */ +package biz.nynja.account.accesspoints; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +@Service +public class AccessPointService { + private final Logger logger = LoggerFactory.getLogger(AccessPointService.class); + private AccessPointRepository accessPointRepository; + + public AccessPointService(AccessPointRepository accessPointRepository) { + this.accessPointRepository = accessPointRepository; + } + + public Optional getAccessPoint(UUID accountId, String deviceId) { + AccessPoint accessPoint = accessPointRepository.findByAccountIdAndDeviceId(accountId, deviceId); + if (accessPoint != null) { + return Optional.of(accessPoint); + } + return Optional.empty(); + } + + +} diff --git a/src/main/java/biz/nynja/account/components/PreparedStatementsCache.java b/src/main/java/biz/nynja/account/components/PreparedStatementsCache.java index 91b9b32..20be301 100644 --- a/src/main/java/biz/nynja/account/components/PreparedStatementsCache.java +++ b/src/main/java/biz/nynja/account/components/PreparedStatementsCache.java @@ -18,20 +18,20 @@ import com.datastax.driver.core.UDTValue; import com.datastax.driver.core.UserType; import biz.nynja.account.codecs.AuthenticationProviderCodec; -import biz.nynja.account.configuration.CassandraConfig; +import biz.nynja.account.configuration.CassandraAccountConfig; import biz.nynja.account.models.AuthenticationProvider; @Configuration public class PreparedStatementsCache { - private final CassandraConfig cassandraConfig; + private final CassandraAccountConfig cassandraConfig; private final Session session; private static Map statementsCache; @Autowired - public PreparedStatementsCache(Session session, CassandraConfig cassandraConfig) { + public PreparedStatementsCache(Session session, CassandraAccountConfig cassandraConfig) { this.session = session; this.cassandraConfig = cassandraConfig; } diff --git a/src/main/java/biz/nynja/account/configuration/CassandraAccessPointConfig.java b/src/main/java/biz/nynja/account/configuration/CassandraAccessPointConfig.java new file mode 100644 index 0000000..7fd37b6 --- /dev/null +++ b/src/main/java/biz/nynja/account/configuration/CassandraAccessPointConfig.java @@ -0,0 +1,91 @@ +package biz.nynja.account.configuration; + +import java.util.Arrays; +import java.util.List; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.data.cassandra.config.CassandraClusterFactoryBean; +import org.springframework.data.cassandra.config.CassandraSessionFactoryBean; +import org.springframework.data.cassandra.core.CassandraAdminOperations; +import org.springframework.data.cassandra.core.CassandraAdminTemplate; +import org.springframework.data.cassandra.core.cql.keyspace.CreateKeyspaceSpecification; +import org.springframework.data.cassandra.core.mapping.CassandraMappingContext; +import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories; + +import biz.nynja.account.StartupScriptsListener; + +@Configuration +@ConfigurationProperties("spring.data.cassandra.accesspoint") +@EnableCassandraRepositories(basePackages = { "biz.nynja.account.accesspoints" }, + cassandraTemplateRef = "CassandraAccessPointTemplate") +@ConditionalOnMissingClass("org.springframework.test.context.junit4.SpringRunner") +public class CassandraAccessPointConfig extends CassandraBaseConfig { + + @Value("${spring.data.cassandra.accesspoint.keyspace-name}") + protected String keyspaceName; + + @Override + protected String getKeyspaceName() { + return keyspaceName; + } + + public void setKeyspaceName(String keyspaceName) { + this.keyspaceName = keyspaceName; + } + + @Bean + public CassandraMappingContext mappingContext() { + return new CassandraMappingContext(); + } + + @Override + public String[] getEntityBasePackages() { + return new String[] { "biz.nynja.account.accesspoints" }; + } + + @Override + @Primary + @Bean(name = "CassandraAccessPointTemplate") + public CassandraAdminOperations cassandraTemplate() throws Exception { + return new CassandraAdminTemplate(session().getObject(), cassandraConverter()); + } + + @Override + @Bean(name = "accessPointSession") + public CassandraSessionFactoryBean session() { + + CassandraSessionFactoryBean session = new CassandraSessionFactoryBean(); + + session.setCluster(cluster().getObject()); + session.setConverter(cassandraConverter()); + session.setKeyspaceName(getKeyspaceName()); + session.setSchemaAction(getSchemaAction()); + session.setStartupScripts(getStartupScripts()); + session.setShutdownScripts(getShutdownScripts()); + + return session; + } + + @Override + protected List getKeyspaceCreations() { + CreateKeyspaceSpecification specification = CreateKeyspaceSpecification.createKeyspace(getKeyspaceName()) + .ifNotExists().withSimpleReplication(); + return Arrays.asList(specification); + } + + @Bean + public CassandraClusterFactoryBean cluster() { + CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean(); + cluster.setContactPoints(getContactPoints()); + cluster.setPort(getPort()); + cluster.setKeyspaceCreations(getKeyspaceCreations()); + + return cluster; + } + +} \ No newline at end of file diff --git a/src/main/java/biz/nynja/account/configuration/CassandraAccountConfig.java b/src/main/java/biz/nynja/account/configuration/CassandraAccountConfig.java new file mode 100644 index 0000000..0b00cd7 --- /dev/null +++ b/src/main/java/biz/nynja/account/configuration/CassandraAccountConfig.java @@ -0,0 +1,103 @@ +package biz.nynja.account.configuration; + + +import java.util.Arrays; +import java.util.List; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.cassandra.config.CassandraClusterFactoryBean; +import org.springframework.data.cassandra.config.CassandraSessionFactoryBean; +import org.springframework.data.cassandra.core.CassandraAdminOperations; +import org.springframework.data.cassandra.core.CassandraAdminTemplate; +import org.springframework.data.cassandra.core.cql.keyspace.CreateKeyspaceSpecification; +import org.springframework.data.cassandra.core.mapping.CassandraMappingContext; +import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories; + +import biz.nynja.account.StartupScriptsListener; + +@Configuration +@ConfigurationProperties("spring.data.cassandra.account") +@EnableCassandraRepositories( + basePackages = { "biz.nynja.account.models", "biz.nynja.account.repositories"}, + cassandraTemplateRef = "CassandraAccountTemplate") +@ConditionalOnMissingClass("org.springframework.test.context.junit4.SpringRunner") +public class CassandraAccountConfig extends CassandraBaseConfig { + + @Value("${spring.data.cassandra.account.keyspace-name}") + protected String keyspaceName; + + @Override + protected String getKeyspaceName() { + return keyspaceName; + } + + public void setKeyspaceName(String keyspaceName) { + this.keyspaceName = keyspaceName; + } + + @Bean + public CassandraMappingContext mappingContext() { + return new CassandraMappingContext(); + } + + @Override + public String[] getEntityBasePackages() { + return new String[] { "biz.nynja.account.models", "biz.nynja.account.repositories" }; + } + + @Override + @Bean(name = "CassandraAccountTemplate") + public CassandraAdminOperations cassandraTemplate( + @Qualifier("accountSession") final CassandraSessionFactoryBean session) throws Exception { + return new CassandraAdminTemplate(session().getObject(), cassandraConverter()); + } + + @Override + @Bean(name = "accountSession") + public CassandraSessionFactoryBean session() { + + CassandraSessionFactoryBean session = new CassandraSessionFactoryBean(); + + session.setCluster(cluster().getObject()); + session.setConverter(cassandraConverter()); + session.setKeyspaceName(getKeyspaceName()); + session.setSchemaAction(getSchemaAction()); + session.setStartupScripts(getStartupScripts()); + session.setShutdownScripts(getShutdownScripts()); + + return session; + } + + @Override + protected List getKeyspaceCreations() { + CreateKeyspaceSpecification specification = CreateKeyspaceSpecification.createKeyspace(getKeyspaceName()) + .ifNotExists().withSimpleReplication(); + return Arrays.asList(specification); + } + + @Bean + public CassandraClusterFactoryBean cluster() { + CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean(); + cluster.setContactPoints(getContactPoints()); +// cluster.setContactPoints(InetAddress.getLocalHost().getHostName()); + cluster.setPort(getPort()); + cluster.setKeyspaceCreations(getKeyspaceCreations()); + + return cluster; + } + + /** + * See {@link StartupScriptsListener} for scripts + * that require JPA annotated tables + */ + @Override + protected List getStartupScripts() { + return super.getStartupScripts(); + } + +} \ No newline at end of file diff --git a/src/main/java/biz/nynja/account/configuration/CassandraConfig.java b/src/main/java/biz/nynja/account/configuration/CassandraBaseConfig.java similarity index 52% rename from src/main/java/biz/nynja/account/configuration/CassandraConfig.java rename to src/main/java/biz/nynja/account/configuration/CassandraBaseConfig.java index 739d506..873dae4 100644 --- a/src/main/java/biz/nynja/account/configuration/CassandraConfig.java +++ b/src/main/java/biz/nynja/account/configuration/CassandraBaseConfig.java @@ -1,77 +1,66 @@ -/** - * Copyright (C) 2018 Nynja Inc. All rights reserved. - */ -package biz.nynja.account.configuration; - -import java.util.Arrays; -import java.util.List; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.cassandra.config.AbstractCassandraConfiguration; -import org.springframework.data.cassandra.config.SchemaAction; -import org.springframework.data.cassandra.core.cql.keyspace.CreateKeyspaceSpecification; -import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories; - -import biz.nynja.account.StartupScriptsListener; - -@Configuration -@EnableCassandraRepositories -@ConditionalOnMissingClass("org.springframework.test.context.junit4.SpringRunner") -public class CassandraConfig extends AbstractCassandraConfiguration { - - @Value("${spring.data.cassandra.keyspace-name}") - private String keyspace; - - @Override - protected String getKeyspaceName() { - return keyspace; - } - - @Value("${spring.data.cassandra.contact-points}") - private String contactPoints; - - @Override - protected String getContactPoints() { - return contactPoints; - } - - @Value("${spring.data.cassandra.port}") - private int port; - - @Override - protected int getPort() { - return port; - } - - @Override - public SchemaAction getSchemaAction() { - return SchemaAction.CREATE_IF_NOT_EXISTS; - } - - @Override - protected List getKeyspaceCreations() { - CreateKeyspaceSpecification specification = CreateKeyspaceSpecification.createKeyspace(getKeyspaceName()) - .ifNotExists().withSimpleReplication(); - return Arrays.asList(specification); - } - - @Override - public String[] getEntityBasePackages() { - return new String[] { "biz.nynja.account.models" }; - } - - /** - * See {@link StartupScriptsListener} for scripts - * that require JPA annotated tables - */ - @Override - protected List getStartupScripts() { - return super.getStartupScripts(); - } - - public String getConfiguredKeyspaceName() { - return getKeyspaceName(); - } -} +package biz.nynja.account.configuration; + + + +import java.util.List; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.cassandra.config.AbstractCassandraConfiguration; +import org.springframework.data.cassandra.config.CassandraClusterFactoryBean; +import org.springframework.data.cassandra.config.CassandraSessionFactoryBean; +import org.springframework.data.cassandra.config.SchemaAction; +import org.springframework.data.cassandra.core.CassandraAdminOperations; +import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories; + +@Configuration +@EnableCassandraRepositories +@ConditionalOnMissingClass("org.springframework.test.context.junit4.SpringRunner") +public abstract class CassandraBaseConfig extends AbstractCassandraConfiguration { + + @Value("${spring.data.cassandra.contact-points}") + protected String contactPoints; + + @Value("${spring.data.cassandra.port}") + protected int port; + + @Override + protected String getContactPoints() { + return contactPoints; + } + + public void setContactPoints(String contactPoints) { + this.contactPoints = contactPoints; + } + + @Override + protected int getPort() { + return port; + } + + protected int setPort() { + return port; + } + + @Override + public SchemaAction getSchemaAction() { + return SchemaAction.CREATE_IF_NOT_EXISTS; + } + + @Override + protected List getStartupScripts() { + return super.getStartupScripts(); + } + + public String getConfiguredKeyspaceName() { + return getKeyspaceName(); + } + + public CassandraAdminOperations cassandraTemplate(CassandraSessionFactoryBean session) throws Exception { + return null; + } + + +} diff --git a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java index 636d301..eb7c03b 100644 --- a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java +++ b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java @@ -11,6 +11,7 @@ import static biz.nynja.account.validation.Validators.util; import java.util.List; import java.util.Optional; import java.util.UUID; +import java.util.stream.Collectors; import org.apache.commons.lang3.tuple.ImmutablePair; import org.lognet.springboot.grpc.GRpcService; @@ -105,7 +106,8 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas AccountByQrCodeRepository accountByQrCodeRepository, AccountByUsernameRepository accountByUsernameRepository, AccountProvider accountProvider, AccountByProfileIdRepository accountByProfileIdRepository, PhoneNumberNormalizer phoneNumberNormalizer, - AccountCreator accountCreator, ProfileProvider profileProvider, PermissionsValidator permissionsValidator) { + AccountCreator accountCreator, ProfileProvider profileProvider, + PermissionsValidator permissionsValidator) { this.accountRepositoryAdditional = accountRepositoryAdditional; this.profileRepository = profileRepository; this.profileByAutheticationProviderRepository = profileByAutheticationProviderRepository; @@ -1067,35 +1069,6 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas return; } - private static void logAndBuildGrpcAccountResponse(StreamObserver responseObserver, - AccountResponse.Builder newBuilder, String logMessage, String logValue, Cause cause) { - - logger.error(logMessage, logValue); - responseObserver.onNext(newBuilder.setError(ErrorResponse.newBuilder().setCause(cause)).build()); - responseObserver.onCompleted(); - } - - private static void logAndBuildGrpcAccountsResponse(StreamObserver responseObserver, - AccountsResponse.Builder newBuilder, String logMessage, String logValue, Cause cause) { - logger.error(logMessage, logValue); - responseObserver.onNext(newBuilder.setError(ErrorResponse.newBuilder().setCause(cause)).build()); - responseObserver.onCompleted(); - } - - private static void logAndBuildGrpcProfileResponse(StreamObserver responseObserver, - ProfileResponse.Builder newBuilder, String logMessage, String logValue, Cause cause) { - logger.error(logMessage, logValue); - responseObserver.onNext(newBuilder.setError(ErrorResponse.newBuilder().setCause(cause)).build()); - responseObserver.onCompleted(); - } - - private static void logAndBuildGrpcStatusResponse(StreamObserver responseObserver, - StatusResponse.Builder newBuilder, String logMessage, String logValue, Cause cause) { - logger.error(logMessage, logValue); - responseObserver.onNext(newBuilder.setError(ErrorResponse.newBuilder().setCause(cause)).build()); - responseObserver.onCompleted(); - } - @Override @PerformPermissionCheck @Permitted(role = RoleConstants.ADMIN) @@ -1182,4 +1155,33 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas responseObserver.onCompleted(); } + private static void logAndBuildGrpcAccountResponse(StreamObserver responseObserver, + AccountResponse.Builder newBuilder, String logMessage, String logValue, Cause cause) { + + logger.error(logMessage, logValue); + responseObserver.onNext(newBuilder.setError(ErrorResponse.newBuilder().setCause(cause)).build()); + responseObserver.onCompleted(); + } + + private static void logAndBuildGrpcAccountsResponse(StreamObserver responseObserver, + AccountsResponse.Builder newBuilder, String logMessage, String logValue, Cause cause) { + logger.error(logMessage, logValue); + responseObserver.onNext(newBuilder.setError(ErrorResponse.newBuilder().setCause(cause)).build()); + responseObserver.onCompleted(); + } + + private static void logAndBuildGrpcProfileResponse(StreamObserver responseObserver, + ProfileResponse.Builder newBuilder, String logMessage, String logValue, Cause cause) { + logger.error(logMessage, logValue); + responseObserver.onNext(newBuilder.setError(ErrorResponse.newBuilder().setCause(cause)).build()); + responseObserver.onCompleted(); + } + + private static void logAndBuildGrpcStatusResponse(StreamObserver responseObserver, + StatusResponse.Builder newBuilder, String logMessage, String logValue, Cause cause) { + logger.error(logMessage, logValue); + responseObserver.onNext(newBuilder.setError(ErrorResponse.newBuilder().setCause(cause)).build()); + responseObserver.onCompleted(); + } + } diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 5a241bc..5de0eb4 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -10,9 +10,12 @@ grpc: spring: data: cassandra: - keyspace-name: account contact-points: localhost port: 9042 + account: + keyspace-name: account + accesspoint: + keyspace-name: accesspoint # To enable colors in Eclipse: # spring.output.ansi.enabled=ALWAYS and in eclipse # Help -> Install New Software... and click "Add..." to add the following URL: diff --git a/src/test/java/biz/nynja/account/configurations/CassandraTestsConfig.java b/src/test/java/biz/nynja/account/configurations/CassandraTestsConfig.java index f57d3f5..9a599b0 100644 --- a/src/test/java/biz/nynja/account/configurations/CassandraTestsConfig.java +++ b/src/test/java/biz/nynja/account/configurations/CassandraTestsConfig.java @@ -1,5 +1,6 @@ package biz.nynja.account.configurations; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Bean; @@ -17,6 +18,7 @@ import com.datastax.driver.core.Session; public class CassandraTestsConfig { @MockBean + @Qualifier("accountSession") private Session session; @Bean -- GitLab From ae850a0b4b290d2c7aa49a44b1ee8f11318760bd Mon Sep 17 00:00:00 2001 From: Stoyan Tzenkov Date: Mon, 17 Dec 2018 12:41:40 +0200 Subject: [PATCH 2/4] NY-6152: AccessPointDetails deleted. Signed-off-by: Stoyan Tzenkov --- .../account/accesspoints/AccessPoint.java | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/src/main/java/biz/nynja/account/accesspoints/AccessPoint.java b/src/main/java/biz/nynja/account/accesspoints/AccessPoint.java index 9f33f05..613b04c 100644 --- a/src/main/java/biz/nynja/account/accesspoints/AccessPoint.java +++ b/src/main/java/biz/nynja/account/accesspoints/AccessPoint.java @@ -15,9 +15,6 @@ import org.springframework.data.cassandra.core.mapping.PrimaryKey; import org.springframework.data.cassandra.core.mapping.PrimaryKeyColumn; import org.springframework.data.cassandra.core.mapping.Table; -import biz.nynja.account.grpc.AccessPointDetails; -import biz.nynja.account.grpc.AccessPointDetails.Builder; - @Table public class AccessPoint implements Serializable { @@ -130,26 +127,6 @@ public class AccessPoint implements Serializable { return builder.toString(); } - public AccessPointDetails toProto() { - - Builder builder = AccessPointDetails.newBuilder(); - - if (getAccountId() != null) { - builder.setAccountId(getAccountId().toString()); - } - if (getDeviceId() != null) { - builder.setDeviceId(getDeviceId().toString()); - } - if (getCreationTimestamp() != null) { - builder.setCreationTimestamp(getCreationTimestamp()); - } - if (getExpirationTimestamp() != null) { - builder.setExpirationTimestamp(getExpirationTimestamp()); - } - - return builder.build(); - - } } -- GitLab From 9adefc67a15427fdc67919bdc0c7c52fd969e3c3 Mon Sep 17 00:00:00 2001 From: Stoyan Tzenkov Date: Thu, 20 Dec 2018 09:53:54 +0200 Subject: [PATCH 3/4] NY-6152: Accesspoint check in interceptor. ADMIN to ACCOUNT_ADMIN. Signed-off-by: Stoyan Tzenkov --- .../account/accesspoints/AccessPoint.java | 12 +- .../accesspoints/AccessPointRepository.java | 3 +- .../accesspoints/AccessPointService.java | 17 ++- .../CassandraAccessPointConfig.java | 3 +- .../configuration/CassandraAccountConfig.java | 2 +- .../permissions/PermissionsInterceptor.java | 106 +++++++++------ .../permissions/PermissionsValidator.java | 2 +- .../account/permissions/RoleConstants.java | 2 +- .../account/services/AccountServiceImpl.java | 34 ++--- .../account/services/AccountServiceTests.java | 125 ++++++++++++------ 10 files changed, 190 insertions(+), 116 deletions(-) diff --git a/src/main/java/biz/nynja/account/accesspoints/AccessPoint.java b/src/main/java/biz/nynja/account/accesspoints/AccessPoint.java index 613b04c..978d6e1 100644 --- a/src/main/java/biz/nynja/account/accesspoints/AccessPoint.java +++ b/src/main/java/biz/nynja/account/accesspoints/AccessPoint.java @@ -5,13 +5,9 @@ package biz.nynja.account.accesspoints; import java.io.Serializable; -import java.nio.ByteBuffer; -import java.time.LocalDate; -import java.util.Set; import java.util.UUID; import org.springframework.data.cassandra.core.cql.PrimaryKeyType; -import org.springframework.data.cassandra.core.mapping.PrimaryKey; import org.springframework.data.cassandra.core.mapping.PrimaryKeyColumn; import org.springframework.data.cassandra.core.mapping.Table; @@ -21,8 +17,8 @@ public class AccessPoint implements Serializable { @PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED) private UUID accountId; @PrimaryKeyColumn(ordinal = 1, type = PrimaryKeyType.CLUSTERED) - private String deviceId; private String accessToken; + private String deviceId; private Long creationTimestamp; private Long expirationTimestamp; @@ -118,8 +114,8 @@ public class AccessPoint implements Serializable { @Override public String toString() { StringBuilder builder = new StringBuilder(); - builder.append("AccessPoint [deviceId=").append(deviceId) - .append(", accountId=").append(accountId) + builder.append("AccessPoint [accountId=").append(accountId) + .append(", deviceId=").append(deviceId) .append(", accessToken=").append(accessToken) .append(", creationTimestamp=").append(creationTimestamp) .append(", expirationTimestamp=").append(expirationTimestamp) @@ -127,6 +123,4 @@ public class AccessPoint implements Serializable { return builder.toString(); } - - } diff --git a/src/main/java/biz/nynja/account/accesspoints/AccessPointRepository.java b/src/main/java/biz/nynja/account/accesspoints/AccessPointRepository.java index 45a32d4..6888c6d 100644 --- a/src/main/java/biz/nynja/account/accesspoints/AccessPointRepository.java +++ b/src/main/java/biz/nynja/account/accesspoints/AccessPointRepository.java @@ -4,6 +4,7 @@ package biz.nynja.account.accesspoints; import java.util.UUID; + import org.springframework.data.cassandra.repository.CassandraRepository; import org.springframework.stereotype.Repository; @@ -11,6 +12,6 @@ import org.springframework.stereotype.Repository; public interface AccessPointRepository extends CassandraRepository { - AccessPoint findByAccountIdAndDeviceId(UUID accountId, String deviceId); + AccessPoint findByAccountIdAndAccessToken(UUID accountId, String accessToken); } diff --git a/src/main/java/biz/nynja/account/accesspoints/AccessPointService.java b/src/main/java/biz/nynja/account/accesspoints/AccessPointService.java index 93ff2b5..ca24bd2 100644 --- a/src/main/java/biz/nynja/account/accesspoints/AccessPointService.java +++ b/src/main/java/biz/nynja/account/accesspoints/AccessPointService.java @@ -3,7 +3,7 @@ */ package biz.nynja.account.accesspoints; -import java.util.List; +import java.util.Date; import java.util.Optional; import java.util.UUID; @@ -20,13 +20,22 @@ public class AccessPointService { this.accessPointRepository = accessPointRepository; } - public Optional getAccessPoint(UUID accountId, String deviceId) { - AccessPoint accessPoint = accessPointRepository.findByAccountIdAndDeviceId(accountId, deviceId); + public Optional getAccessPoint(UUID accountId, String accessToken) { + AccessPoint accessPoint = accessPointRepository.findByAccountIdAndAccessToken(accountId, accessToken); if (accessPoint != null) { return Optional.of(accessPoint); } return Optional.empty(); } - + public AccessPoint buildAccessPoint(String deviceId, String accessToken, String accountId, long expiresIn) { + AccessPoint accessPoint = new AccessPoint(); + accessPoint.setDeviceId(deviceId); + accessPoint.setAccountId(UUID.fromString(accountId)); + accessPoint.setAccessToken(accessToken); + accessPoint.setCreationTimestamp(new Date().getTime()); + accessPoint.setExpirationTimestamp(new Date().getTime() + expiresIn); + return accessPoint; + } + } diff --git a/src/main/java/biz/nynja/account/configuration/CassandraAccessPointConfig.java b/src/main/java/biz/nynja/account/configuration/CassandraAccessPointConfig.java index 7fd37b6..1b5472a 100644 --- a/src/main/java/biz/nynja/account/configuration/CassandraAccessPointConfig.java +++ b/src/main/java/biz/nynja/account/configuration/CassandraAccessPointConfig.java @@ -21,7 +21,8 @@ import biz.nynja.account.StartupScriptsListener; @Configuration @ConfigurationProperties("spring.data.cassandra.accesspoint") -@EnableCassandraRepositories(basePackages = { "biz.nynja.account.accesspoints" }, +@EnableCassandraRepositories( + basePackages = { "biz.nynja.account.accesspoints" }, cassandraTemplateRef = "CassandraAccessPointTemplate") @ConditionalOnMissingClass("org.springframework.test.context.junit4.SpringRunner") public class CassandraAccessPointConfig extends CassandraBaseConfig { diff --git a/src/main/java/biz/nynja/account/configuration/CassandraAccountConfig.java b/src/main/java/biz/nynja/account/configuration/CassandraAccountConfig.java index 0b00cd7..311fa8d 100644 --- a/src/main/java/biz/nynja/account/configuration/CassandraAccountConfig.java +++ b/src/main/java/biz/nynja/account/configuration/CassandraAccountConfig.java @@ -57,7 +57,7 @@ public class CassandraAccountConfig extends CassandraBaseConfig { return new CassandraAdminTemplate(session().getObject(), cassandraConverter()); } - @Override + @Override @Bean(name = "accountSession") public CassandraSessionFactoryBean session() { diff --git a/src/main/java/biz/nynja/account/permissions/PermissionsInterceptor.java b/src/main/java/biz/nynja/account/permissions/PermissionsInterceptor.java index 1fc1d13..ea6b484 100644 --- a/src/main/java/biz/nynja/account/permissions/PermissionsInterceptor.java +++ b/src/main/java/biz/nynja/account/permissions/PermissionsInterceptor.java @@ -7,27 +7,35 @@ import static io.grpc.Metadata.ASCII_STRING_MARSHALLER; import java.lang.reflect.Method; import java.util.Base64; +import java.util.Optional; +import java.util.UUID; import org.lognet.springboot.grpc.GRpcGlobalInterceptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import com.auth0.jwt.JWT; import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.DecodedJWT; import biz.nynja.account.services.AccountServiceImpl; +import biz.nynja.account.accesspoints.AccessPointService; +import biz.nynja.account.accesspoints.AccessPoint; import io.grpc.Context; +import io.grpc.Contexts; import io.grpc.Metadata; import io.grpc.ServerCall; import io.grpc.ServerCallHandler; import io.grpc.ServerInterceptor; +import io.grpc.Status; /** - * @author Stoyan.Tzenkov - account-service ServerInterceptor. Validates roles for granting permissions to - * account-service endpoints(rpcs). - * General rules: + * @author Stoyan.Tzenkov - account-service ServerInterceptor. + * Validates roles for granting permissions to account-service endpoints(rpcs). + * General rules: * - if access token is not present - PERMISSION DENIED; + * - if no accesspoint found for the requesting account ID and access token - PERMISSION DENIED; * - if no roles found in the access token - PERMISSION DENIED; * - if rpc not found in the account-service class - PERMISSION DENIED; * - if no Permitted annotation found for the rpc method - PERMISSION DENIED; @@ -49,6 +57,9 @@ public class PermissionsInterceptor implements ServerInterceptor { private static final ServerCall.Listener NOOP_LISTENER = new ServerCall.Listener() { }; + @Autowired + private AccessPointService accessPointService; + @Override public ServerCall.Listener interceptCall(ServerCall call, Metadata headers, ServerCallHandler next) { @@ -61,36 +72,40 @@ public class PermissionsInterceptor implements ServerInterceptor { * Expected metadata is "Authorization" : "Bearer --accessTokenValue--" so we can skip validation as istio won't * allow this request through */ - // String accessToken = (headers.get(ACCESS_TOKEN_METADATA).split(" "))[1]; - // String rpc = getRpcName(call); - // - // boolean permitted = false; - // Context ctx = null; - // String[] requestingRoles = null; - // - // if (accessToken != null) { - // ctx = Context.current().withValue(ACCESS_TOKEN_CTX, accessToken); - // requestingRoles = getRolesFromAccessToken(accessToken, rpc); - // - // if (requestingRoles != null) { - // Method method = getMethod(rpc); - // - // if (method != null) { - // Permitted[] permittedRoles = method.getAnnotationsByType(Permitted.class); - // permitted = checkPermissions(requestingRoles, permittedRoles); - // } - // } - // } - // - // if (permitted) { - // logger.info("Permission granted to rpc {}.", rpc); - // return Contexts.interceptCall(ctx, call, headers, next); - // } else { - // logger.error("Permission denied for rpc {}, roles {}.", rpc, requestingRoles); - // call.close(Status.PERMISSION_DENIED.withDescription("An unauthorized call was made to " + rpc + "."), - // headers); - // return NOOP_LISTENER; - // } +// String accessToken = (headers.get(ACCESS_TOKEN_METADATA).split(" "))[1]; +// String rpc = getRpcName(call); +// +// boolean permitted = false; +// Context ctx = null; +// String[] requestingRoles = null; +// +// if (accessToken != null && !accessToken.isEmpty()) { +// ctx = Context.current().withValue(ACCESS_TOKEN_CTX, accessToken); +// DecodedJWT decodedToken = JWT.decode(accessToken); +// +// if (accessPointAvailable(accessToken, decodedToken, rpc)) { +// requestingRoles = getRolesFromAccessToken(decodedToken); +// +// if (requestingRoles != null) { +// Method method = getMethod(rpc); +// +// if (method != null) { +// Permitted[] permittedRoles = method.getAnnotationsByType(Permitted.class); +// permitted = checkPermissions(requestingRoles, permittedRoles); +// } +// } +// } +// } +// +// if (permitted) { +// logger.info("Permission granted to rpc {}.", rpc); +// return Contexts.interceptCall(ctx, call, headers, next); +// } else { +// logger.error("Permission denied for rpc {}, roles {}.", rpc, requestingRoles); +// call.close(Status.PERMISSION_DENIED.withDescription("An unauthorized call was made to " + rpc + "."), +// headers); +// return NOOP_LISTENER; +// } } private String getRpcName(ServerCall call) { @@ -99,19 +114,22 @@ public class PermissionsInterceptor implements ServerInterceptor { return callName.substring(callName.lastIndexOf('/') + 1); } - private String[] getRolesFromAccessToken(String accessToken, String rpc) { + private boolean accessPointAvailable(String accessToken, DecodedJWT decodedToken, String rpc) { + + String accountId = new String(Base64.getDecoder().decode(decodedToken.getSubject())); + logger.info("Verifying permissions for rpc {} for user with account id {}.", rpc, accountId); + + Optional accessPoint = accessPointService.getAccessPoint(UUID.fromString(accountId), accessToken); + return accessPoint.isPresent(); + } + + private String[] getRolesFromAccessToken(DecodedJWT decodedToken) { // Get roles from access token String[] requestingRoles = null; - if (accessToken != null && !accessToken.isEmpty()) { - DecodedJWT decodedToken = JWT.decode(accessToken); - String requestingAccountId = new String(Base64.getDecoder().decode(decodedToken.getSubject())); - logger.info("Verifying permissions for rpc {} for user with account id {}.", rpc, requestingAccountId); - - Claim claim = decodedToken.getClaim("roles"); - if (claim != null) { - requestingRoles = claim.asArray(String.class); - } + Claim claim = decodedToken.getClaim("roles"); + if (claim != null) { + requestingRoles = claim.asArray(String.class); } return requestingRoles; } @@ -135,7 +153,7 @@ public class PermissionsInterceptor implements ServerInterceptor { return true; } for (String role : requestingRoles) { - if (role.equals(permitted.role()) || role.equals(RoleConstants.ADMIN) + if (role.equals(permitted.role()) || role.equals(RoleConstants.ACCOUNT_ADMIN) || role.equals(RoleConstants.AUTH_SERVICE)) { return true; } diff --git a/src/main/java/biz/nynja/account/permissions/PermissionsValidator.java b/src/main/java/biz/nynja/account/permissions/PermissionsValidator.java index 10144e4..c213cab 100644 --- a/src/main/java/biz/nynja/account/permissions/PermissionsValidator.java +++ b/src/main/java/biz/nynja/account/permissions/PermissionsValidator.java @@ -68,7 +68,7 @@ public class PermissionsValidator { private static boolean isAuthorized(String[] requestingRoles) { for (String role : requestingRoles) { switch (role) { - case RoleConstants.ADMIN: + case RoleConstants.ACCOUNT_ADMIN: case RoleConstants.AUTH_SERVICE: return true; } diff --git a/src/main/java/biz/nynja/account/permissions/RoleConstants.java b/src/main/java/biz/nynja/account/permissions/RoleConstants.java index 4a9b8d4..ff0185c 100644 --- a/src/main/java/biz/nynja/account/permissions/RoleConstants.java +++ b/src/main/java/biz/nynja/account/permissions/RoleConstants.java @@ -8,7 +8,7 @@ package biz.nynja.account.permissions; */ public class RoleConstants { - public static final String ADMIN = "ADMIN"; + public static final String ACCOUNT_ADMIN = "ACCOUNT_ADMIN"; public static final String USER = "USER"; public static final String ANY = "ANY"; public static final String AUTH_SERVICE = "AUTH_SERVICE"; diff --git a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java index eb7c03b..ae63d02 100644 --- a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java +++ b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java @@ -123,7 +123,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas @Override @PerformPermissionCheck - @Permitted(role = RoleConstants.ADMIN) + @Permitted(role = RoleConstants.ACCOUNT_ADMIN) @Permitted(role = RoleConstants.AUTH_SERVICE) @Permitted(role = RoleConstants.USER) public void getAccountByCreationProvider(AuthenticationProviderRequest request, @@ -242,7 +242,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas @Override @PerformPermissionCheck - @Permitted(role = RoleConstants.ADMIN) + @Permitted(role = RoleConstants.ACCOUNT_ADMIN) @Permitted(role = RoleConstants.USER) public void getAccountByUsername(GetByUsernameRequest request, StreamObserver responseObserver) { logger.info("Getting account by username: {}", request.getUsername()); @@ -327,7 +327,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas @Override @PerformPermissionCheck - @Permitted(role = RoleConstants.ADMIN) + @Permitted(role = RoleConstants.ACCOUNT_ADMIN) @Permitted(role = RoleConstants.USER) public void getAccountByQrCode(GetByQrCodeRequest request, StreamObserver responseObserver) { logger.info("Search account by QR code: {}", request.getQrCode()); @@ -385,7 +385,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas } @Override - @Permitted(role = RoleConstants.ADMIN) + @Permitted(role = RoleConstants.ACCOUNT_ADMIN) public void getAllAccountsByProfileId(AccountsByProfileIdRequest request, StreamObserver responseObserver) { logger.info("Getting accounts by profile id: {}", request.getProfileId()); @@ -415,7 +415,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas @Override @PerformPermissionCheck - @Permitted(role = RoleConstants.ADMIN) + @Permitted(role = RoleConstants.ACCOUNT_ADMIN) @Permitted(role = RoleConstants.AUTH_SERVICE) @Permitted(role = RoleConstants.USER) public void getAccountByAccountId(AccountByAccountIdRequest request, @@ -451,7 +451,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas } @Override - @Permitted(role = RoleConstants.ADMIN) + @Permitted(role = RoleConstants.ACCOUNT_ADMIN) @Permitted(role = RoleConstants.AUTH_SERVICE) @Permitted(role = RoleConstants.USER) public void createPendingAccount(CreatePendingAccountRequest request, @@ -481,7 +481,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas @Override @PerformPermissionCheck - @Permitted(role = RoleConstants.ADMIN) + @Permitted(role = RoleConstants.ACCOUNT_ADMIN) @Permitted(role = RoleConstants.USER) public void updateAccount(UpdateAccountRequest request, StreamObserver responseObserver) { logger.info("Updating account..."); @@ -528,7 +528,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas @Override @PerformPermissionCheck - @Permitted(role = RoleConstants.ADMIN) + @Permitted(role = RoleConstants.ACCOUNT_ADMIN) @Permitted(role = RoleConstants.USER) public void deleteAccount(DeleteAccountRequest request, StreamObserver responseObserver) { logger.debug("Deleting account...: {}", request); @@ -565,7 +565,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas @Override @PerformPermissionCheck - @Permitted(role = RoleConstants.ADMIN) + @Permitted(role = RoleConstants.ACCOUNT_ADMIN) @Permitted(role = RoleConstants.USER) public void deleteProfile(DeleteProfileRequest request, StreamObserver responseObserver) { logger.debug("Deleting profile: {}", request); @@ -595,7 +595,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas @Override @PerformPermissionCheck - @Permitted(role = RoleConstants.ADMIN) + @Permitted(role = RoleConstants.ACCOUNT_ADMIN) @Permitted(role = RoleConstants.AUTH_SERVICE) @Permitted(role = RoleConstants.USER) public void addAuthenticationProviderToProfile(AddAuthenticationProviderRequest request, @@ -676,7 +676,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas @Override @PerformPermissionCheck - @Permitted(role = RoleConstants.ADMIN) + @Permitted(role = RoleConstants.ACCOUNT_ADMIN) @Permitted(role = RoleConstants.USER) public void addContactInfoToAccount(AddContactInfoRequest request, StreamObserver responseObserver) { @@ -729,7 +729,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas @Override @PerformPermissionCheck - @Permitted(role = RoleConstants.ADMIN) + @Permitted(role = RoleConstants.ACCOUNT_ADMIN) @Permitted(role = RoleConstants.USER) public void deleteContactInfoFromAccount(DeleteContactInfoRequest request, StreamObserver responseObserver) { @@ -772,7 +772,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas @Override @PerformPermissionCheck - @Permitted(role = RoleConstants.ADMIN) + @Permitted(role = RoleConstants.ACCOUNT_ADMIN) @Permitted(role = RoleConstants.USER) public void deleteAuthenticationProviderFromProfile(DeleteAuthenticationProviderRequest request, StreamObserver responseObserver) { @@ -879,7 +879,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas @Override @PerformPermissionCheck - @Permitted(role = RoleConstants.ADMIN) + @Permitted(role = RoleConstants.ACCOUNT_ADMIN) @Permitted(role = RoleConstants.USER) public void getProfileByProfileId(ProfileByProfileIdRequest request, StreamObserver responseObserver) { @@ -920,7 +920,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas @Override @PerformPermissionCheck - @Permitted(role = RoleConstants.ADMIN) + @Permitted(role = RoleConstants.ACCOUNT_ADMIN) @Permitted(role = RoleConstants.USER) public void editContactInfoForAccount(EditContactInfoRequest request, StreamObserver responseObserver) { @@ -1000,7 +1000,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas @Override @PerformPermissionCheck - @Permitted(role = RoleConstants.ADMIN) + @Permitted(role = RoleConstants.ACCOUNT_ADMIN) @Permitted(role = RoleConstants.AUTH_SERVICE) @Permitted(role = RoleConstants.USER) public void updateAuthenticationProviderForProfile(UpdateAuthenticationProviderRequest request, @@ -1071,7 +1071,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas @Override @PerformPermissionCheck - @Permitted(role = RoleConstants.ADMIN) + @Permitted(role = RoleConstants.ACCOUNT_ADMIN) @Permitted(role = RoleConstants.USER) @Permitted(role = RoleConstants.AUTH_SERVICE) public void getAccountByLoginOption(AuthenticationProviderRequest request, diff --git a/src/test/java/biz/nynja/account/services/AccountServiceTests.java b/src/test/java/biz/nynja/account/services/AccountServiceTests.java index 8c06861..fce0d7d 100644 --- a/src/test/java/biz/nynja/account/services/AccountServiceTests.java +++ b/src/test/java/biz/nynja/account/services/AccountServiceTests.java @@ -3,15 +3,20 @@ */ package biz.nynja.account.services; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.verify; -import java.util.*; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; -import org.apache.commons.lang3.tuple.ImmutablePair; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -25,21 +30,78 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; +import biz.nynja.account.accesspoints.AccessPoint; +import biz.nynja.account.accesspoints.AccessPointService; import biz.nynja.account.components.AccountServiceHelper; import biz.nynja.account.components.PreparedStatementsCache; import biz.nynja.account.configurations.CassandraTestsConfig; -import biz.nynja.account.grpc.*; +import biz.nynja.account.grpc.AccountByAccountIdRequest; +import biz.nynja.account.grpc.AccountDetails; +import biz.nynja.account.grpc.AccountResponse; +import biz.nynja.account.grpc.AccountServiceGrpc; +import biz.nynja.account.grpc.AccountsByProfileIdRequest; +import biz.nynja.account.grpc.AccountsList; +import biz.nynja.account.grpc.AccountsResponse; +import biz.nynja.account.grpc.AddAuthenticationProviderRequest; +import biz.nynja.account.grpc.AddContactInfoRequest; +import biz.nynja.account.grpc.AuthProviderDetails; +import biz.nynja.account.grpc.AuthenticationProviderRequest; +import biz.nynja.account.grpc.AuthenticationType; +import biz.nynja.account.grpc.CompletePendingAccountCreationRequest; +import biz.nynja.account.grpc.ContactDetails; +import biz.nynja.account.grpc.ContactType; +import biz.nynja.account.grpc.CreatePendingAccountRequest; +import biz.nynja.account.grpc.CreatePendingAccountResponse; import biz.nynja.account.grpc.Date; +import biz.nynja.account.grpc.DeleteAccountRequest; +import biz.nynja.account.grpc.DeleteAuthenticationProviderRequest; +import biz.nynja.account.grpc.DeleteContactInfoRequest; +import biz.nynja.account.grpc.DeleteProfileRequest; +import biz.nynja.account.grpc.EditContactInfoRequest; import biz.nynja.account.grpc.ErrorResponse.Cause; -import biz.nynja.account.models.*; +import biz.nynja.account.grpc.GetByEmailRequest; +import biz.nynja.account.grpc.GetByPhoneNumberRequest; +import biz.nynja.account.grpc.GetByQrCodeRequest; +import biz.nynja.account.grpc.GetByUsernameRequest; +import biz.nynja.account.grpc.ProfileByProfileIdRequest; +import biz.nynja.account.grpc.ProfileResponse; +import biz.nynja.account.grpc.Role; +import biz.nynja.account.grpc.SearchResponse; +import biz.nynja.account.grpc.StatusResponse; +import biz.nynja.account.grpc.UpdateAccountRequest; +import biz.nynja.account.grpc.UpdateAuthenticationProviderRequest; import biz.nynja.account.models.Account; -import biz.nynja.account.repositories.*; +import biz.nynja.account.models.AccountByAuthenticationProvider; +import biz.nynja.account.models.AccountByProfileId; +import biz.nynja.account.models.AccountByQrCode; +import biz.nynja.account.models.AccountByUsername; +import biz.nynja.account.models.AuthenticationProvider; +import biz.nynja.account.models.ContactInfo; +import biz.nynja.account.models.PendingAccount; +import biz.nynja.account.models.PendingAccountByAuthenticationProvider; +import biz.nynja.account.models.Profile; +import biz.nynja.account.models.ProfileByAuthenticationProvider; +import biz.nynja.account.permissions.PermissionsInterceptor; +import biz.nynja.account.repositories.AccountByAuthenticationProviderRepository; +import biz.nynja.account.repositories.AccountByProfileIdRepository; +import biz.nynja.account.repositories.AccountByQrCodeRepository; +import biz.nynja.account.repositories.AccountByUsernameRepository; +import biz.nynja.account.repositories.AccountRepository; +import biz.nynja.account.repositories.AccountRepositoryAdditional; +import biz.nynja.account.repositories.PendingAccountRepository; +import biz.nynja.account.repositories.ProfileByAuthenticationProviderRepository; +import biz.nynja.account.repositories.ProfileRepository; import biz.nynja.account.services.decomposition.AccountProvider; import biz.nynja.account.services.decomposition.IncorrectAccountCountException; import biz.nynja.account.services.decomposition.ProfileProvider; import biz.nynja.account.utils.GrpcServerTestBase; import biz.nynja.account.utils.Util; +import io.grpc.Context; +import io.grpc.Contexts; import io.grpc.Metadata; +import io.grpc.ServerCall; +import io.grpc.ServerCallHandler; +import io.grpc.ServerInterceptor; import io.grpc.stub.MetadataUtils; /** @@ -174,23 +236,31 @@ public class AccountServiceTests extends GrpcServerTestBase { @MockBean private ProfileProvider profileProvider; + @MockBean + private AccessPointService accessPointService; + private AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub; private AccountServiceGrpc.AccountServiceBlockingStub searchServiceBlockingStub; @Before public void setupTest() { - String adminAccessToken = "eyJraWQiOiIyMDE4MDYwOCIsInR5cCI6IkpXVCIsImFsZyI6IkVTMjU2In0.eyJzdWIiOiJZemt4T0dOalpqWXRPRFl3WkMwME1EVmtMV0l5WVdFdE9USmhZV0pqTURKa1ltUXgiLCJhdWQiOiJibmx1YW1FPTpueW5qYTpueW5qYSIsInNjb3BlIjoiYWNjZXNzIiwicm9sZXMiOlsiQURNSU4iLCJVU0VSIl0sImlzcyI6Imh0dHBzOi8vYXV0aC5ueW5qYS5iaXovIiwiZXhwIjoxNTQzMzEwMTI4LCJpYXQiOjE1NDMzMDY1Mjh9.IdfUiOx_cPdp3lUIVbTKx51L9BrTigzWh3-yUc9-sLNMonO1GFaM2lJrpus4-Wi5G7D1lsX5PLWxt85pRJ0AnQ"; + AccessPoint accessPoint = new AccessPoint(); + String accountId = "0994566e-ac7b-45b2-b6ef-36440e44a15a"; + String adminAccessToken = "eyJraWQiOiIyMDE4MTEzMCIsInR5cCI6IkpXVCIsImFsZyI6IkVTMjU2In0.eyJzdWIiOiJNRGs1TkRVMk5tVXRZV00zWWkwME5XSXlMV0kyWldZdE16WTBOREJsTkRSaE1UVmgiLCJhdWQiOiJibmx1YW1FPTpueW5qYTpueW5qYSIsInNjb3BlIjoiYWNjZXNzIiwicm9sZXMiOlsiQURNSU4iLCJVU0VSIl0sImlzcyI6Imh0dHBzOi8vYXV0aC5ueW5qYS5iaXovIiwiZXhwIjoxNTQ1MTQzNTY0LCJpYXQiOjE1NDUxMzk5NjR9.w9LZEKB8GLRHDRpa80Lp2EFlGOjmJA4mWP6__Fk0JDu8HlJPk5GyXAm7081s6BqH99ixsKXsGGea6CuT0NHKqQ"; - accountServiceBlockingStub = AccountServiceGrpc.newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); - searchServiceBlockingStub = AccountServiceGrpc.newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + accountServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + searchServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); Metadata headers = new Metadata(); - Metadata.Key key = Metadata.Key.of("accessToken", Metadata.ASCII_STRING_MARSHALLER); - headers.put(key, adminAccessToken); + Metadata.Key key = Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER); + headers.put(key, "Bearer " + adminAccessToken); accountServiceBlockingStub = MetadataUtils.attachHeaders(accountServiceBlockingStub, headers); searchServiceBlockingStub = MetadataUtils.attachHeaders(searchServiceBlockingStub, headers); - + given(accessPointService.getAccessPoint(UUID.fromString(accountId), adminAccessToken)) + .willReturn(Optional.of(accessPoint)); } @Test @@ -204,7 +274,7 @@ public class AccountServiceTests extends GrpcServerTestBase { Optional accountResponse = Optional.of(response); given(accountProvider.getAccountByAccountId(request)).willReturn(accountResponse); - final AccountResponse reply = accountServiceBlockingStub.getAccountByAccountId(request); + final AccountResponse reply = accountServiceBlockingStub.getAccountByAccountId(request); assertNotNull("Reply should not be null", reply); assertTrue(String.format("Reply should contain profile ID '%s'", Util.ACCOUNT_ID.toString()), @@ -432,8 +502,6 @@ public class AccountServiceTests extends GrpcServerTestBase { .authenticationProviderAlreadyUsedInProfile(Mockito.any(AuthenticationProvider.class))) .willReturn(true); - final AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc - .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); final CreatePendingAccountResponse reply = accountServiceBlockingStub.createPendingAccount(request); assertNotNull("Reply should not be null", reply); assertTrue(String.format("Reply should contain account id '%s'", Cause.AUTH_PROVIDER_ALREADY_USED), @@ -606,9 +674,6 @@ public class AccountServiceTests extends GrpcServerTestBase { .completePendingAccountCreation(Mockito.any(CompletePendingAccountCreationRequest.class))) .willReturn(null); - final AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc - .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); - final AccountResponse respose = accountServiceBlockingStub.completePendingAccountCreation(request); assertNotNull("Reply should not be null", respose); assertTrue(String.format("Reply should contain cause '%s'", Cause.ERROR_CREATING_ACCOUNT), @@ -688,7 +753,8 @@ public class AccountServiceTests extends GrpcServerTestBase { final DeleteProfileRequest request = DeleteProfileRequest.newBuilder() .setProfileId(Util.PROFILE_ID_NOT_FOUND.toString()).build(); - given(accountRepositoryAdditional.deleteProfile(Util.PROFILE_ID_NOT_FOUND)).willReturn(Optional.of(Cause.ERROR_DELETING_PROFILE)); + given(accountRepositoryAdditional.deleteProfile(Util.PROFILE_ID_NOT_FOUND)) + .willReturn(Optional.of(Cause.ERROR_DELETING_PROFILE)); final StatusResponse reply = accountServiceBlockingStub.deleteProfile(request); assertNotNull("Reply should not be null", reply); @@ -735,7 +801,7 @@ public class AccountServiceTests extends GrpcServerTestBase { Util.PHONE_NUMBER_STREIGHT, AuthenticationType.PHONE.name())) .willReturn(profileByAuthenticationProvider); - final StatusResponse reply = accountServiceBlockingStub.addAuthenticationProviderToProfile(request); + final StatusResponse reply = accountServiceBlockingStub.addAuthenticationProviderToProfile(request); assertNotNull("Reply should not be null", reply); assertTrue(String.format("Reply should contain cause '%s'", Cause.AUTH_PROVIDER_ALREADY_USED), reply.getError().getCause().equals(Cause.AUTH_PROVIDER_ALREADY_USED)); @@ -745,8 +811,7 @@ public class AccountServiceTests extends GrpcServerTestBase { public void testAddAuthenticationProviderToProfileAuthProviderIdMissing() { final AddAuthenticationProviderRequest request = AddAuthenticationProviderRequest.newBuilder() .setAuthenticationProvider(AuthProviderDetails.newBuilder() - .setAuthenticationProvider(Util.PHONE_PROVIDER) - .setAuthenticationType(AuthenticationType.PHONE)) + .setAuthenticationProvider(Util.PHONE_PROVIDER).setAuthenticationType(AuthenticationType.PHONE)) .build(); given(accountRepositoryAdditional.addAuthenticationProvider(Mockito.any(UUID.class), @@ -780,7 +845,7 @@ public class AccountServiceTests extends GrpcServerTestBase { .findByAuthenticationProviderAndAuthenticationProviderType(Util.PHONE_PROVIDER, "PHONE")) .willReturn(null); - final StatusResponse reply = accountServiceBlockingStub.addAuthenticationProviderToProfile(request); + final StatusResponse reply = accountServiceBlockingStub.addAuthenticationProviderToProfile(request); assertNotNull("Reply should not be null", reply); assertTrue(String.format("Reply should contain cause '%s'", Cause.MISSING_AUTH_PROVIDER_ID), reply.getError().getCause().equals(Cause.MISSING_AUTH_PROVIDER_ID)); @@ -1872,8 +1937,6 @@ public class AccountServiceTests extends GrpcServerTestBase { given(accountProvider.getAccountResponseByLoginOption(AuthenticationType.PHONE, Util.PHONE_PROVIDER)) .willReturn(accountResponse); - final AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc - .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); final AccountResponse reply = accountServiceBlockingStub.getAccountByLoginOption(request); assertNotNull("Reply should not be null", reply); @@ -1891,8 +1954,6 @@ public class AccountServiceTests extends GrpcServerTestBase { given(accountProvider.getAccountResponseByLoginOption(AuthenticationType.EMAIL, Util.EMAIL)) .willReturn(accountResponse); - final AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc - .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); final AccountResponse reply = accountServiceBlockingStub.getAccountByLoginOption(request); assertNotNull("Reply should not be null", reply); @@ -1908,8 +1969,6 @@ public class AccountServiceTests extends GrpcServerTestBase { given(accountProvider.getAccountResponseByLoginOption(AuthenticationType.EMAIL, Util.EMAIL_NOT_USED)) .willReturn(Optional.empty()); - final AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc - .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); final AccountResponse reply = accountServiceBlockingStub.getAccountByLoginOption(request); assertNotNull("Reply should not be null", reply); @@ -1921,8 +1980,6 @@ public class AccountServiceTests extends GrpcServerTestBase { final AuthenticationProviderRequest request = AuthenticationProviderRequest.newBuilder() .setAuthenticationIdentifier(Util.PHONE_PROVIDER).build(); - final AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc - .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); final AccountResponse reply = accountServiceBlockingStub.getAccountByLoginOption(request); assertNotNull("Reply should not be null", reply); @@ -1934,8 +1991,6 @@ public class AccountServiceTests extends GrpcServerTestBase { final AuthenticationProviderRequest request = AuthenticationProviderRequest.newBuilder() .setAuthenticationType(AuthenticationType.PHONE).build(); - final AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc - .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); final AccountResponse reply = accountServiceBlockingStub.getAccountByLoginOption(request); assertNotNull("Reply should not be null", reply); @@ -1948,8 +2003,6 @@ public class AccountServiceTests extends GrpcServerTestBase { .setAuthenticationIdentifier(Util.INVALID_PHONE_PROVIDER) .setAuthenticationType(AuthenticationType.PHONE).build(); - final AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc - .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); final AccountResponse reply = accountServiceBlockingStub.getAccountByLoginOption(request); assertNotNull("Reply should not be null", reply); @@ -1962,8 +2015,6 @@ public class AccountServiceTests extends GrpcServerTestBase { .setAuthenticationIdentifier(Util.INVALID_EMAIL).setAuthenticationType(AuthenticationType.EMAIL) .build(); - final AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc - .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); final AccountResponse reply = accountServiceBlockingStub.getAccountByLoginOption(request); assertNotNull("Reply should not be null", reply); -- GitLab From ba1ebe3d857cc2adb0d1f95ec341661dc1080504 Mon Sep 17 00:00:00 2001 From: Stoyan Tzenkov Date: Thu, 20 Dec 2018 11:57:26 +0200 Subject: [PATCH 4/4] NY-6152: PermissionsInterceptor restructured. Signed-off-by: Stoyan Tzenkov --- .../permissions/PermissionsInterceptor.java | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/main/java/biz/nynja/account/permissions/PermissionsInterceptor.java b/src/main/java/biz/nynja/account/permissions/PermissionsInterceptor.java index ea6b484..7a37de8 100644 --- a/src/main/java/biz/nynja/account/permissions/PermissionsInterceptor.java +++ b/src/main/java/biz/nynja/account/permissions/PermissionsInterceptor.java @@ -26,6 +26,7 @@ import io.grpc.Context; import io.grpc.Contexts; import io.grpc.Metadata; import io.grpc.ServerCall; +import io.grpc.ServerCall.Listener; import io.grpc.ServerCallHandler; import io.grpc.ServerInterceptor; import io.grpc.Status; @@ -66,7 +67,7 @@ public class PermissionsInterceptor implements ServerInterceptor { // WARNING: THe line bellow is to be removed and code following uncommented // when Istio starts sending an access token with each and every request - return next.startCall(call, headers); + return next.startCall(call, headers); /* * Expected metadata is "Authorization" : "Bearer --accessTokenValue--" so we can skip validation as istio won't @@ -79,24 +80,28 @@ public class PermissionsInterceptor implements ServerInterceptor { // Context ctx = null; // String[] requestingRoles = null; // -// if (accessToken != null && !accessToken.isEmpty()) { -// ctx = Context.current().withValue(ACCESS_TOKEN_CTX, accessToken); -// DecodedJWT decodedToken = JWT.decode(accessToken); +// if (accessToken == null && accessToken.isEmpty()) { +// permissionDenied(call, headers, "Permission denied for rpc {}. Access token not in headers", rpc ); +// } +// ctx = Context.current().withValue(ACCESS_TOKEN_CTX, accessToken); +// DecodedJWT decodedToken = JWT.decode(accessToken); // -// if (accessPointAvailable(accessToken, decodedToken, rpc)) { -// requestingRoles = getRolesFromAccessToken(decodedToken); +// if (!accessPointAvailable(accessToken, decodedToken, rpc)) { +// permissionDenied(call, headers, "Permission denied for rpc {}. No access point available for this account and access token.", rpc ); +// } // -// if (requestingRoles != null) { -// Method method = getMethod(rpc); +// requestingRoles = getRolesFromAccessToken(decodedToken); +// if (requestingRoles == null) { +// permissionDenied(call, headers, "Permission denied for rpc {}. No roles found for requesting account in access token.", rpc ); +// } // -// if (method != null) { -// Permitted[] permittedRoles = method.getAnnotationsByType(Permitted.class); -// permitted = checkPermissions(requestingRoles, permittedRoles); -// } -// } -// } +// Method method = getMethod(rpc); +// if (method == null) { +// permissionDenied(call, headers, "Permission denied for rpc {}. Could not identify the method implementing this rpc.", rpc ); // } // +// Permitted[] permittedRoles = method.getAnnotationsByType(Permitted.class); +// permitted = checkPermissions(requestingRoles, permittedRoles); // if (permitted) { // logger.info("Permission granted to rpc {}.", rpc); // return Contexts.interceptCall(ctx, call, headers, next); @@ -162,4 +167,11 @@ public class PermissionsInterceptor implements ServerInterceptor { return false; } + private ServerCall.Listener permissionDenied(ServerCall call, Metadata headers, String message, String rpc ) { + logger.error(message, rpc); + call.close(Status.PERMISSION_DENIED.withDescription("An unauthorized call was made to " + rpc + "."), + headers); + return NOOP_LISTENER; + } + } -- GitLab