From c6a5fc7210188f60c9bc1a4986fdd10c33deb79e Mon Sep 17 00:00:00 2001 From: sergeyPensov Date: Tue, 18 Dec 2018 16:24:25 +0200 Subject: [PATCH 01/27] Implement gRpc bridge --- pom.xml | 12 ++ .../services/erlang/ErlangAccountBridge.java | 6 +- .../erlang/ErlangAccountHttpBridge.java | 3 +- .../erlang/ErlangAccountMqttBridge.java | 144 ++++++++++++++++++ .../erlang/interceptor/TokenInterceptor.java | 19 +++ .../TokenInterceptorConstants.java | 11 ++ src/main/resources/application-dev.yml | 2 +- 7 files changed, 192 insertions(+), 5 deletions(-) create mode 100644 src/main/java/biz/nynja/account/services/erlang/ErlangAccountMqttBridge.java create mode 100644 src/main/java/biz/nynja/account/services/erlang/interceptor/TokenInterceptor.java create mode 100644 src/main/java/biz/nynja/account/services/erlang/interceptor/TokenInterceptorConstants.java diff --git a/pom.xml b/pom.xml index 931932d..d9d421a 100644 --- a/pom.xml +++ b/pom.xml @@ -111,6 +111,18 @@ + + libs-snapshot-local.biz.nynja.protos + bridge-service-ny-5863-bridge-service + 1.0-SNAPSHOT + + + com.google.protobuf + protobuf-java + + + + com.googlecode.libphonenumber libphonenumber diff --git a/src/main/java/biz/nynja/account/services/erlang/ErlangAccountBridge.java b/src/main/java/biz/nynja/account/services/erlang/ErlangAccountBridge.java index 803db0e..f30b96d 100644 --- a/src/main/java/biz/nynja/account/services/erlang/ErlangAccountBridge.java +++ b/src/main/java/biz/nynja/account/services/erlang/ErlangAccountBridge.java @@ -6,18 +6,18 @@ package biz.nynja.account.services.erlang; import biz.nynja.account.models.Account; import biz.nynja.account.models.Profile; +import java.util.List; import java.util.UUID; - public interface ErlangAccountBridge { boolean createProfile(Profile profile, Account defaultAccount); - boolean deleteProfile(UUID profileId); + boolean deleteProfile(UUID profileId, List accountsIds); boolean createAccount(Account account); boolean updateAccount(Account account); - boolean deleteAccount(UUID accountId); + boolean deleteAccount(UUID profileId, UUID accountId); } diff --git a/src/main/java/biz/nynja/account/services/erlang/ErlangAccountHttpBridge.java b/src/main/java/biz/nynja/account/services/erlang/ErlangAccountHttpBridge.java index aa88d2f..8382eb1 100644 --- a/src/main/java/biz/nynja/account/services/erlang/ErlangAccountHttpBridge.java +++ b/src/main/java/biz/nynja/account/services/erlang/ErlangAccountHttpBridge.java @@ -6,6 +6,7 @@ package biz.nynja.account.services.erlang; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.util.List; import java.util.UUID; import org.slf4j.Logger; @@ -99,7 +100,7 @@ public class ErlangAccountHttpBridge implements ErlangAccountBridge { } @Override - public boolean deleteAccount(UUID accountId) { + public boolean deleteAccount(UUID accountId, List accountsIds) { if (!erlangBridgeConfiguration.isEnabled()) return true; JsonObject accountObject = new JsonObject(); diff --git a/src/main/java/biz/nynja/account/services/erlang/ErlangAccountMqttBridge.java b/src/main/java/biz/nynja/account/services/erlang/ErlangAccountMqttBridge.java new file mode 100644 index 0000000..cfaaad4 --- /dev/null +++ b/src/main/java/biz/nynja/account/services/erlang/ErlangAccountMqttBridge.java @@ -0,0 +1,144 @@ +/** + * Copyright (C) 2018 Nynja Inc. All rights reserved. + */ +package biz.nynja.account.services.erlang; + +import java.net.MalformedURLException; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.springframework.stereotype.Component; + +import biz.nynja.account.configuration.ErlangBridgeConfiguration; +import biz.nynja.account.models.Account; +import biz.nynja.account.models.Profile; +import biz.nynja.account.services.erlang.interceptor.TokenInterceptorConstants; +import biz.nynja.bridge.grpc.AccountBridgeGrpc; +import biz.nynja.bridge.grpc.AccountData; +import biz.nynja.bridge.grpc.BridgeSuccessResponse; +import biz.nynja.bridge.grpc.ProfileData; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.Metadata; +import io.grpc.stub.MetadataUtils; + +@Component +public class ErlangAccountMqttBridge implements ErlangAccountBridge { + + private final ErlangBridgeConfiguration erlangBridgeConfiguration; + + public ErlangAccountMqttBridge(ErlangBridgeConfiguration erlangBridgeConfiguration) throws MalformedURLException { + this.erlangBridgeConfiguration = erlangBridgeConfiguration; + } + + @Override + public boolean createProfile(Profile profile, Account account) { + + if (!erlangBridgeConfiguration.isEnabled()) + return true; + ProfileData profileData = buildProfileData(profile, account); + // todo update after testing with real connection + BridgeSuccessResponse response = buildGrpcConnection().createProfile(profileData); + return true; + } + + @Override + public boolean deleteProfile(UUID profileId, List accountsIds) { + if (!erlangBridgeConfiguration.isEnabled()) + return true; + BridgeSuccessResponse response = buildGrpcConnection() + .deleteProfile(buildDeleteProfileData(profileId, (UUID[]) accountsIds.toArray())); + return true; + } + + @Override + public boolean createAccount(Account account) { + if (!erlangBridgeConfiguration.isEnabled()) + return true; + BridgeSuccessResponse response = buildGrpcConnection().createAccount(buildAccountData(account)); + + return true; + } + + @Override + public boolean updateAccount(Account account) { + if (!erlangBridgeConfiguration.isEnabled()) + return true; + + return true; + } + + @Override + public boolean deleteAccount(UUID profileId, UUID accountId) { + if (!erlangBridgeConfiguration.isEnabled()) + return true; + BridgeSuccessResponse response = buildGrpcConnection() + .deleteAccount(buildDeleteProfileData(profileId, accountId)); + return true; + } + + private ProfileData buildProfileData(Profile profile, Account account) { + return ProfileData.newBuilder().setProfileId(profile.getProfileId().toString()) + .setDefaultAccount(buildAccountData(account)) + .setLastUpdateTimestamp(profile.getCreationTimestamp().toString()).build(); + } + + private AccountData buildAccountData(Account account) { + return AccountData.newBuilder().setAccountId(account.getAccountId().toString()) + .setFirstName(account.getFirstName()).setLastName(account.getLastName()) + .setUsername(account.getUsername()).setAvatar(account.getAvatar()) + .setLastUpdateTimestamp(account.getLastUpdateTimestamp().toString()).build(); + } + + // Erlang protocol + private ProfileData buildDeleteProfileData(UUID profileId, UUID... accountsId) { + return ProfileData.newBuilder().setProfileId(profileId.toString()) + .addAllAccountsIds(Arrays.stream(accountsId).map(UUID::toString).collect(Collectors.toList())).build(); + } + + private AccountBridgeGrpc.AccountBridgeBlockingStub buildGrpcConnection() { + ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(erlangBridgeConfiguration.getHost(), + Integer.getInteger(erlangBridgeConfiguration.getPort())).usePlaintext().build(); + AccountBridgeGrpc.AccountBridgeBlockingStub bridgeServiceBlockingStub = AccountBridgeGrpc + .newBlockingStub(managedChannel); + return MetadataUtils.attachHeaders(bridgeServiceBlockingStub, getHeaders()); + } + + /* + * public StatusResponse updateAuthProvider(String profileId, AuthProviderDetails details, SidType sidTypeToRemove, + * String sidToRemove) { + * + * UpdateAuthenticationProviderRequest request = UpdateAuthenticationProviderRequest.newBuilder() + * .setProfileId(profileId) + * .setOldAuthProvider(AuthProviderDetails.newBuilder().setAuthenticationProvider(sidToRemove) + * .setAuthenticationType(AuthenticationType.valueOf(sidTypeToRemove.name()))) .setUpdatedAuthProvider( + * AuthProviderDetails.newBuilder().setAuthenticationProvider(details.getAuthenticationProvider()) + * .setAuthenticationType(details.getAuthenticationType())) .build(); ManagedChannel managedChannel = + * ManagedChannelBuilder.forAddress(accountServiceAddress, accountServicePort) .usePlaintext().build(); + * + * AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc + * .newBlockingStub(managedChannel); + * + * Metadata headers = getHeaders(); accountServiceBlockingStub = + * MetadataUtils.attachHeaders(accountServiceBlockingStub, headers); + * + * StatusResponse response = accountServiceBlockingStub.updateAuthenticationProviderForProfile(request); return + * response; } + * + */ + + /** + * Attaches the access token to the rpc header + * + * @return + * @throws InternalError + */ + private Metadata getHeaders() throws InternalError { + Metadata headers = new Metadata(); + Metadata.Key key = Metadata.Key.of("accessToken", Metadata.ASCII_STRING_MARSHALLER); + headers.put(key, "Bearer " + TokenInterceptorConstants.ACCESS_TOKEN_CTX.get()); + return headers; + } +} diff --git a/src/main/java/biz/nynja/account/services/erlang/interceptor/TokenInterceptor.java b/src/main/java/biz/nynja/account/services/erlang/interceptor/TokenInterceptor.java new file mode 100644 index 0000000..67de571 --- /dev/null +++ b/src/main/java/biz/nynja/account/services/erlang/interceptor/TokenInterceptor.java @@ -0,0 +1,19 @@ +/** + * Copyright (C) 2018 Nynja Inc. All rights reserved. + */ +package biz.nynja.account.services.erlang.interceptor; + +import io.grpc.*; +import org.lognet.springboot.grpc.GRpcGlobalInterceptor; + +@GRpcGlobalInterceptor +public class TokenInterceptor implements ServerInterceptor { + + @Override + public ServerCall.Listener interceptCall(ServerCall serverCall, Metadata metadata, + ServerCallHandler serverCallHandler) { + String accessToken = metadata.get(TokenInterceptorConstants.ACCESS_TOKEN_METADATA); + Context ctx = Context.current().withValue(TokenInterceptorConstants.ACCESS_TOKEN_CTX, accessToken); + return Contexts.interceptCall(ctx, serverCall, metadata, serverCallHandler); + } +} diff --git a/src/main/java/biz/nynja/account/services/erlang/interceptor/TokenInterceptorConstants.java b/src/main/java/biz/nynja/account/services/erlang/interceptor/TokenInterceptorConstants.java new file mode 100644 index 0000000..5df55f1 --- /dev/null +++ b/src/main/java/biz/nynja/account/services/erlang/interceptor/TokenInterceptorConstants.java @@ -0,0 +1,11 @@ +package biz.nynja.account.services.erlang.interceptor; + +import io.grpc.Context; +import io.grpc.Metadata; + +import static io.grpc.Metadata.ASCII_STRING_MARSHALLER; + +public class TokenInterceptorConstants { + public static final Metadata.Key ACCESS_TOKEN_METADATA = Metadata.Key.of("accessToken", ASCII_STRING_MARSHALLER); + public static final Context.Key ACCESS_TOKEN_CTX = Context.key("accessToken"); +} diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 5a241bc..b604e12 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -36,7 +36,7 @@ account-data: erlang-bridge: enable: false; - ip: + host: port: #Metrics related configurations -- GitLab From e6c7d5d0798a760ebbaddd8f5a2452865efdf8a1 Mon Sep 17 00:00:00 2001 From: sergeyPensov Date: Wed, 26 Dec 2018 15:58:13 +0200 Subject: [PATCH 02/27] Add saga to account --- .../AccountRepositoryAdditionalImpl.java | 48 +++++++++++++------ .../erlang/ErlangAccountHttpBridge.java | 10 ++-- 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java index 2a9c034..361f53d 100644 --- a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java +++ b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java @@ -15,6 +15,8 @@ import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; +import biz.nynja.account.repositories.batch.SagaTransaction; +import biz.nynja.account.repositories.batch.Transaction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.cassandra.core.CassandraBatchOperations; @@ -102,7 +104,7 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio } public Account completePendingAccountCreation(CompletePendingAccountCreationRequest request) { - CassandraBatchOperations batchOperations = cassandraTemplate.batchOps(); + Transaction sagaTransaction = new SagaTransaction(cassandraTemplate); PendingAccount pendingAccount = pendingAccountRepository .findByAccountId(UUID.fromString(request.getAccountId())); if (pendingAccount == null) { @@ -122,10 +124,15 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio Long timeCreated = Instant.now().toEpochMilli(); WriteResult wr; try { - newAccountInsert(batchOperations, request, pendingAccount, timeCreated); - newProfileByAuthenticationProviderInsert(batchOperations, pendingAccount); - newProfileInsert(batchOperations, request, pendingAccount, timeCreated); - wr = batchOperations.execute(); + Account account = newAccountInsert(sagaTransaction, request, pendingAccount, timeCreated); + newProfileByAuthenticationProviderInsert(sagaTransaction, pendingAccount); + Profile profile = newProfileInsert(sagaTransaction, request, pendingAccount, timeCreated); + wr = sagaTransaction.execute(); + if (!erlangAccountBridge.createProfile(profile, account)) { + logger.error("Internal error with erlang"); + sagaTransaction.rollBack(); + return null; + } } catch (IllegalArgumentException | IllegalStateException e) { logger.info("Exception while completing pending account creation."); logger.debug("Exception while completing pending account creation: {} ...", e.getMessage()); @@ -169,7 +176,7 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio } public Account updateAccount(UpdateAccountRequest request) { - CassandraBatchOperations batchOperations = cassandraTemplate.batchOps(); + Transaction sagaTransaction = new SagaTransaction(cassandraTemplate); Account existingAccount = accountRepository.findByAccountId(UUID.fromString(request.getAccountId())); if (existingAccount == null) { logger.error("Existing account with the provided id {} was not found.", request.getAccountId()); @@ -180,12 +187,17 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio WriteResult wr = null; try { try { - updateAccountData(batchOperations, request, existingAccount, timeUpdated); + updateAccountData(sagaTransaction, request, existingAccount, timeUpdated); } catch (DateTimeException e) { logger.error("Exception with birthday date while updating account with id {}", request.getAccountId()); return null; } - wr = batchOperations.execute(); + wr = sagaTransaction.execute(); + if (!erlangAccountBridge.updateAccount(existingAccount)) { + logger.error("Internal error with erlang"); + sagaTransaction.rollBack(); + return null; + } } catch (IllegalArgumentException | IllegalStateException e) { logger.error("Exception while updating account with id {}.", request.getAccountId()); logger.debug("Exception while updating account: {}.", e.getMessage()); @@ -203,7 +215,7 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio } public boolean deleteAccount(UUID accountId) { - CassandraBatchOperations batchOperations = cassandraTemplate.batchOps(); + Transaction sagaTransaction = new SagaTransaction(cassandraTemplate); Account existingAccount = accountRepository.findByAccountId(accountId); if (!doExistAccountAndProfileToDelete(accountId)) { return false; @@ -219,23 +231,29 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio boolean alsoDeleteProfile = existingAccountsForProfile.size() == 1; WriteResult wr = null; try { - deleteAccountData(batchOperations, existingAccount); - deleteProfileByAuthenticationProvider(batchOperations, existingAccount.getProfileId(), + deleteAccountData(sagaTransaction, existingAccount); + deleteProfileByAuthenticationProvider(sagaTransaction, existingAccount.getProfileId(), AuthenticationProvider.createAuthenticationProviderFromStrings( existingAccount.getAuthenticationProviderType(), existingAccount.getAuthenticationProvider())); if (alsoDeleteProfile) { if (existingProfile.getAuthenticationProviders() != null) { - deleteAuthenticationProvidersFromProfile(batchOperations, existingProfile.getProfileId(), + deleteAuthenticationProvidersFromProfile(sagaTransaction, existingProfile.getProfileId(), existingProfile.getAuthenticationProviders()); } - deleteProfileData(batchOperations, existingProfile); + deleteProfileData(sagaTransaction, existingProfile); } else { - if (!removeCreationProvider(batchOperations, existingAccount, existingProfile)) { + if (!removeCreationProvider(sagaTransaction, existingAccount, existingProfile)) { return false; } } - wr = batchOperations.execute(); + wr = sagaTransaction.execute(); + + if (!erlangAccountBridge.deleteAccount(existingProfile.getProfileId(), accountId)) { + logger.error("Internal error with erlang"); + sagaTransaction.rollBack(); + return false; + } } catch (IllegalArgumentException | IllegalStateException e) { logger.error("Exception while deleting account: {}.", e.getMessage()); return false; diff --git a/src/main/java/biz/nynja/account/services/erlang/ErlangAccountHttpBridge.java b/src/main/java/biz/nynja/account/services/erlang/ErlangAccountHttpBridge.java index 8382eb1..918a66c 100644 --- a/src/main/java/biz/nynja/account/services/erlang/ErlangAccountHttpBridge.java +++ b/src/main/java/biz/nynja/account/services/erlang/ErlangAccountHttpBridge.java @@ -23,8 +23,6 @@ import biz.nynja.account.models.Account; import biz.nynja.account.models.Profile; import biz.nynja.account.services.erlang.connector.HttpClient; - - @Service // TODO: 11/19/2018 change boolean response when ENC will implement return error part public class ErlangAccountHttpBridge implements ErlangAccountBridge { @@ -67,7 +65,7 @@ public class ErlangAccountHttpBridge implements ErlangAccountBridge { } @Override - public boolean deleteProfile(UUID profileId) { + public boolean deleteProfile(UUID profileId, List accountsIds) { if (!erlangBridgeConfiguration.isEnabled()) return true; JsonObject profileObject = new JsonObject(); @@ -78,7 +76,7 @@ public class ErlangAccountHttpBridge implements ErlangAccountBridge { return false; } - return false; + return true; } @Override @@ -100,7 +98,7 @@ public class ErlangAccountHttpBridge implements ErlangAccountBridge { } @Override - public boolean deleteAccount(UUID accountId, List accountsIds) { + public boolean deleteAccount(UUID profileId, UUID accountId) { if (!erlangBridgeConfiguration.isEnabled()) return true; JsonObject accountObject = new JsonObject(); @@ -110,7 +108,7 @@ public class ErlangAccountHttpBridge implements ErlangAccountBridge { } catch (IOException e) { return false; } - return false; + return true; } private JsonObject prepareProfileJsonObject(Profile profile, Account account) { -- GitLab From 5f3e5fc261ae3f2b35d5e684846c6c2e7d45ed5d Mon Sep 17 00:00:00 2001 From: Stanimir Penkov Date: Thu, 20 Dec 2018 11:55:38 +0200 Subject: [PATCH 03/27] =?UTF-8?q?NY-6215:=20Add=20endpoint=20for=20updatin?= =?UTF-8?q?g=20login=20option=E2=80=99s=20searchable=20state?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stanimir Penkov --- .../AccountRepositoryAdditional.java | 3 + .../AccountRepositoryAdditionalImpl.java | 71 ++++++++++++++++--- .../account/services/AccountServiceImpl.java | 52 ++++++++++++++ 3 files changed, 116 insertions(+), 10 deletions(-) diff --git a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditional.java b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditional.java index c6f039d..dd43e40 100644 --- a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditional.java +++ b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditional.java @@ -12,6 +12,7 @@ import org.springframework.stereotype.Repository; import biz.nynja.account.grpc.CompletePendingAccountCreationRequest; import biz.nynja.account.grpc.UpdateAccountRequest; import biz.nynja.account.grpc.ErrorResponse.Cause; +import biz.nynja.account.grpc.SearchableOption; import biz.nynja.account.models.Account; import biz.nynja.account.models.AccountByProfileId; import biz.nynja.account.models.AuthenticationProvider; @@ -58,4 +59,6 @@ public interface AccountRepositoryAdditional { Optional searchAccountByLoginOption(AuthenticationProvider loginOption) throws IncorrectAccountCountException; void removeNullsForSearchableOption(); + + boolean updateSearchableOption(UUID profileId, String authProviderType, String authProvider, SearchableOption searchableOption); } diff --git a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java index f0e92ca..c3d61c1 100644 --- a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java +++ b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java @@ -36,6 +36,7 @@ import biz.nynja.account.grpc.CompletePendingAccountCreationRequest; import biz.nynja.account.grpc.ContactType; import biz.nynja.account.grpc.ErrorResponse.Cause; import biz.nynja.account.grpc.Role; +import biz.nynja.account.grpc.SearchableOption; import biz.nynja.account.grpc.UpdateAccountRequest; import biz.nynja.account.models.Account; import biz.nynja.account.models.AccountBuilder; @@ -747,6 +748,54 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio return false; } + @Override + public boolean updateSearchableOption(UUID profileId, String authProviderType, String authProvider, + SearchableOption searchableOption) { + if (authProviderType == null || authProvider == null || authProviderType.isEmpty() || authProvider.isEmpty()) { + logger.error( + "Error updating searchable option in profile {}. Auth provider info (type and/or identifier) is missing.", + profileId); + return false; + } + + Profile existingProfile = profileRepository.findByProfileId(profileId); + if (existingProfile == null) { + logger.error( + "Error updating searchable option in profile {}. Existing profile with the provided id {} was not found.", + profileId); + return false; + } + + ProfileByAuthenticationProvider existingProfileByAuthenticationProvider = profileByAuthenticationProviderRepository + .findByAuthenticationProviderAndAuthenticationProviderType(authProvider, authProviderType); + if (existingProfileByAuthenticationProvider == null) { + logger.error( + "Error updating searchable option in profileByAuthenticationProvider. Existing profileByAuthenticationProvider for {}:{} was not found.", + authProviderType, authProvider); + return false; + } + + CassandraBatchOperations batchOperations = cassandraTemplate.batchOps(); + WriteResult wr = null; + try { + updateSearchableInProfileByAuthenticationProvider(batchOperations, existingProfileByAuthenticationProvider, + searchableOption); + if (!updateSearchableInProfile(batchOperations, existingProfile, authProviderType, authProvider, + searchableOption)) { + return false; + } + wr = batchOperations.execute(); + } catch (IllegalArgumentException | IllegalStateException e) { + logger.debug("Exception while updating searchable option for auth provider {}:{} in profile{}: {}.", + authProviderType, authProvider, profileId, e.getMessage()); + } + if (wr != null && wr.wasApplied()) { + logger.info("Successfully updated searchable option in profile {}.", profileId); + return true; + } + return false; + } + @Override public Optional getAccountByLoginOption(AuthenticationProvider loginOption) throws IncorrectAccountCountException { @@ -887,11 +936,12 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio CassandraBatchOperations batchOperations = cassandraTemplate.batchOps(); WriteResult wr; try { - setDefaultSearchableInProfileByAuthenticationProvider(batchOperations, - profilesByAuthenticationProvider.get(i)); - if (!setDefaultSearchableInProfile(batchOperations, profileToUpdate, + updateSearchableInProfileByAuthenticationProvider(batchOperations, + profilesByAuthenticationProvider.get(i), SearchableOption.SEARCH_ENABLED); + if (!updateSearchableInProfile(batchOperations, profileToUpdate, profilesByAuthenticationProvider.get(i).getAuthenticationProviderType(), - profilesByAuthenticationProvider.get(i).getAuthenticationProvider())) { + profilesByAuthenticationProvider.get(i).getAuthenticationProvider(), + SearchableOption.SEARCH_ENABLED)) { logger.error( "Error replacing null with default searchable option for profile {}: auth provider {}:{}.", profilesByAuthenticationProvider.get(i).getProfileId(), @@ -915,14 +965,14 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio } } - private void setDefaultSearchableInProfileByAuthenticationProvider(CassandraBatchOperations batchOps, - ProfileByAuthenticationProvider profileByAuthenticationProvider) { - profileByAuthenticationProvider.setSearchable(Boolean.TRUE); + private void updateSearchableInProfileByAuthenticationProvider(CassandraBatchOperations batchOps, + ProfileByAuthenticationProvider profileByAuthenticationProvider, SearchableOption searchableOption) { + profileByAuthenticationProvider.setSearchable(AuthenticationProvider.isSearchDisabled(searchableOption)); batchOps.update(profileByAuthenticationProvider); } - private boolean setDefaultSearchableInProfile(CassandraBatchOperations batchOps, Profile profileToUpdate, - String authProviderType, String authProvider) { + private boolean updateSearchableInProfile(CassandraBatchOperations batchOps, Profile profileToUpdate, + String authProviderType, String authProvider, SearchableOption searchableOption) { Set authProviderSet = profileToUpdate.getAuthenticationProviders(); if (authProviderSet == null) { logger.error("No existing auth providers found for profile {}.", profileToUpdate.getProfileId()); @@ -930,7 +980,8 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio } AuthenticationProvider authProviderToUpdate = AuthenticationProvider - .createAuthenticationProviderWithSearchableOption(authProviderType, authProvider, Boolean.TRUE); + .createAuthenticationProviderWithSearchableOption(authProviderType, authProvider, + AuthenticationProvider.isSearchDisabled(searchableOption)); Optional currentAuthProvider = AuthenticationProvider .foundExistingAuthenticationProviderByTypeAndValue(authProviderType, authProvider, authProviderSet); if (!currentAuthProvider.isPresent()) { diff --git a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java index ae63d02..9511276 100644 --- a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java +++ b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java @@ -50,6 +50,7 @@ import biz.nynja.account.grpc.SearchResultDetails; import biz.nynja.account.grpc.StatusResponse; import biz.nynja.account.grpc.UpdateAccountRequest; import biz.nynja.account.grpc.UpdateAuthenticationProviderRequest; +import biz.nynja.account.grpc.UpdateSearchableOptionRequest; import biz.nynja.account.models.Account; import biz.nynja.account.models.AccountByProfileId; import biz.nynja.account.models.AccountByQrCode; @@ -1184,4 +1185,55 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas responseObserver.onCompleted(); } + @Override + @PerformPermissionCheck + @Permitted(role = RoleConstants.ADMIN) + @Permitted(role = RoleConstants.USER) + public void updateSearchableOption(UpdateSearchableOptionRequest request, + StreamObserver responseObserver) { + if (request.getAuthenticationType() == null || request.getAuthenticationType().isEmpty()) { + logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), + "Missing authentication provider type", "", Cause.MISSING_AUTH_PROVIDER_TYPE); + return; + } + if (request.getAuthenticationIdentifier() == null || request.getAuthenticationIdentifier().isEmpty()) { + logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), + "Missing authentication provider identifier", "", Cause.MISSING_AUTH_PROVIDER_ID); + return; + } + if (request.getProfileId() == null || request.getProfileId().isEmpty()) { + logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), "Missing profile id", "", + Cause.MISSING_PROFILE_ID); + return; + } + if (!util.isValidUuid(request.getProfileId())) { + logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), "Invalid profile id", "", + Cause.INVALID_PROFILE_ID); + return; + } + + List existingAccountsForProfile = accountByProfileIdRepository + .findAllByProfileId(UUID.fromString(request.getProfileId())); + + if (!permissionsValidator.isRpcAllowed(existingAccountsForProfile)) { + logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), + "Can not update searchable option for authentication provider in profile {}.", + request.getProfileId(), Cause.ERROR_PERMISSION_DENIED); + return; + } + + if (!accountRepositoryAdditional.updateSearchableOption(UUID.fromString(request.getProfileId()), + request.getAuthenticationType(), request.getAuthenticationIdentifier(), request.getSearchOption())) { + logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), + "Can not update searchable option for authentication provider in profile {}.", + request.getProfileId(), Cause.ERROR_UPDATING_SEARCHABLE_OPTION); + return; + } + + logger.info("Successfully updated authentication provider {}:{} with searchable option {} in profile {}", + request.getAuthenticationType(), request.getAuthenticationIdentifier(), request.getSearchOption(), + request.getProfileId()); + responseObserver.onNext(StatusResponse.newBuilder().setStatus("SUCCESS").build()); + responseObserver.onCompleted(); + } } -- GitLab From 4b78f5e80aa53ffc1167c31bf37b22bf6265a947 Mon Sep 17 00:00:00 2001 From: Stanimir Penkov Date: Thu, 20 Dec 2018 12:02:46 +0200 Subject: [PATCH 04/27] NY-6215: Additional check added. Signed-off-by: Stanimir Penkov --- .../repositories/AccountRepositoryAdditionalImpl.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java index c3d61c1..16aed3b 100644 --- a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java +++ b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java @@ -757,6 +757,11 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio profileId); return false; } + if (searchableOption == null) { + logger.error("Error updating searchable option {}:{} in profile {}. Can not use null for searchableOption.", + authProviderType, authProvider, profileId); + return false; + } Profile existingProfile = profileRepository.findByProfileId(profileId); if (existingProfile == null) { -- GitLab From c5b80966c7fd10ea630f450e2f07e8e924e9a09f Mon Sep 17 00:00:00 2001 From: Stanimir Penkov Date: Thu, 20 Dec 2018 17:56:13 +0200 Subject: [PATCH 05/27] NY-6215: Code Review Changes - extracted validation method; - additional check added. Signed-off-by: Stanimir Penkov --- .../account/services/AccountServiceImpl.java | 58 +++++++++++++------ 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java index 9511276..07c0e57 100644 --- a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java +++ b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java @@ -1191,24 +1191,11 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas @Permitted(role = RoleConstants.USER) public void updateSearchableOption(UpdateSearchableOptionRequest request, StreamObserver responseObserver) { - if (request.getAuthenticationType() == null || request.getAuthenticationType().isEmpty()) { - logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), - "Missing authentication provider type", "", Cause.MISSING_AUTH_PROVIDER_TYPE); - return; - } - if (request.getAuthenticationIdentifier() == null || request.getAuthenticationIdentifier().isEmpty()) { - logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), - "Missing authentication provider identifier", "", Cause.MISSING_AUTH_PROVIDER_ID); - return; - } - if (request.getProfileId() == null || request.getProfileId().isEmpty()) { - logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), "Missing profile id", "", - Cause.MISSING_PROFILE_ID); - return; - } - if (!util.isValidUuid(request.getProfileId())) { - logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), "Invalid profile id", "", - Cause.INVALID_PROFILE_ID); + + Validation validation = validateUpdateSearchableOptionRequest(request); + if (validation.hasErrors()) { + logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), validation.getErrorMessage(), + "", validation.getCause().get()); return; } @@ -1236,4 +1223,39 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas responseObserver.onNext(StatusResponse.newBuilder().setStatus("SUCCESS").build()); responseObserver.onCompleted(); } + + private Validation validateUpdateSearchableOptionRequest(UpdateSearchableOptionRequest request) { + Validation validation = new Validation(); + + if (request.getAuthenticationType() == null || request.getAuthenticationType().isEmpty()) { + validation.addError( + new ValidationError("Missing authentication provider type", Cause.MISSING_AUTH_PROVIDER_TYPE)); + return validation; + } + + if (!request.getAuthenticationType().equals(AuthenticationType.EMAIL.toString()) + && !request.getAuthenticationType().equals(AuthenticationType.PHONE.toString())) { + validation.addError( + new ValidationError("Missing authentication provider type", Cause.INVALID_AUTH_PROVIDER_TYPE)); + return validation; + } + + if (request.getAuthenticationIdentifier() == null || request.getAuthenticationIdentifier().isEmpty()) { + validation.addError( + new ValidationError("Missing authentication provider identifier", Cause.MISSING_AUTH_PROVIDER_ID)); + return validation; + } + + if (request.getProfileId() == null || request.getProfileId().isEmpty()) { + validation.addError(new ValidationError("Missing profile id", Cause.MISSING_PROFILE_ID)); + return validation; + } + + if (!util.isValidUuid(request.getProfileId())) { + validation.addError(new ValidationError("Invalid profile id", Cause.INVALID_PROFILE_ID)); + return validation; + } + + return validation; + } } -- GitLab From 56f5323843485a4ea03a15a00ce7e7793d9cadcb Mon Sep 17 00:00:00 2001 From: Stanimir Penkov Date: Thu, 3 Jan 2019 11:56:32 +0200 Subject: [PATCH 06/27] NY-6215: Change error message Signed-off-by: Stanimir Penkov --- .../java/biz/nynja/account/services/AccountServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java index 07c0e57..fef7825 100644 --- a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java +++ b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java @@ -1236,7 +1236,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas if (!request.getAuthenticationType().equals(AuthenticationType.EMAIL.toString()) && !request.getAuthenticationType().equals(AuthenticationType.PHONE.toString())) { validation.addError( - new ValidationError("Missing authentication provider type", Cause.INVALID_AUTH_PROVIDER_TYPE)); + new ValidationError("Invalid authentication provider type", Cause.INVALID_AUTH_PROVIDER_TYPE)); return validation; } -- GitLab From 7b72be7686a0fd4919f90deb97bc460354d7a8ac Mon Sep 17 00:00:00 2001 From: Stanimir Penkov Date: Thu, 3 Jan 2019 16:36:38 +0200 Subject: [PATCH 07/27] NY-6215: Code Review Changes - extracted method; Signed-off-by: Stanimir Penkov --- .../AccountRepositoryAdditionalImpl.java | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java index 16aed3b..bcfdf04 100644 --- a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java +++ b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java @@ -751,15 +751,8 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio @Override public boolean updateSearchableOption(UUID profileId, String authProviderType, String authProvider, SearchableOption searchableOption) { - if (authProviderType == null || authProvider == null || authProviderType.isEmpty() || authProvider.isEmpty()) { - logger.error( - "Error updating searchable option in profile {}. Auth provider info (type and/or identifier) is missing.", - profileId); - return false; - } - if (searchableOption == null) { - logger.error("Error updating searchable option {}:{} in profile {}. Can not use null for searchableOption.", - authProviderType, authProvider, profileId); + + if (!haveNeededSearchableOptionData(profileId, authProviderType, authProvider, searchableOption)) { return false; } @@ -801,6 +794,22 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio return false; } + private boolean haveNeededSearchableOptionData(UUID profileId, String authProviderType, String authProvider, + SearchableOption searchableOption) { + if (authProviderType == null || authProvider == null || authProviderType.isEmpty() || authProvider.isEmpty()) { + logger.error( + "Error updating searchable option in profile {}. Auth provider info (type and/or identifier) is missing.", + profileId); + return false; + } + if (searchableOption == null) { + logger.error("Error updating searchable option {}:{} in profile {}. Can not use null for searchableOption.", + authProviderType, authProvider, profileId); + return false; + } + return true; + } + @Override public Optional getAccountByLoginOption(AuthenticationProvider loginOption) throws IncorrectAccountCountException { -- GitLab From 6ce8f5c74c3bcc7b12e9e1ef92cd68aba8197b91 Mon Sep 17 00:00:00 2001 From: Stanimir Penkov Date: Thu, 3 Jan 2019 18:22:56 +0200 Subject: [PATCH 08/27] NY-6215: Code Review Changes - moved validation method; Signed-off-by: Stanimir Penkov --- .../account/services/AccountServiceImpl.java | 38 +------------------ .../nynja/account/validation/Validators.java | 35 +++++++++++++++++ 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java index fef7825..15c6145 100644 --- a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java +++ b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java @@ -1192,7 +1192,8 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas public void updateSearchableOption(UpdateSearchableOptionRequest request, StreamObserver responseObserver) { - Validation validation = validateUpdateSearchableOptionRequest(request); + Validation validation = authenticationProvider.validateUpdateSearchableOptionRequest(request.getProfileId(), + request.getAuthenticationType(), request.getAuthenticationIdentifier()); if (validation.hasErrors()) { logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), validation.getErrorMessage(), "", validation.getCause().get()); @@ -1223,39 +1224,4 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas responseObserver.onNext(StatusResponse.newBuilder().setStatus("SUCCESS").build()); responseObserver.onCompleted(); } - - private Validation validateUpdateSearchableOptionRequest(UpdateSearchableOptionRequest request) { - Validation validation = new Validation(); - - if (request.getAuthenticationType() == null || request.getAuthenticationType().isEmpty()) { - validation.addError( - new ValidationError("Missing authentication provider type", Cause.MISSING_AUTH_PROVIDER_TYPE)); - return validation; - } - - if (!request.getAuthenticationType().equals(AuthenticationType.EMAIL.toString()) - && !request.getAuthenticationType().equals(AuthenticationType.PHONE.toString())) { - validation.addError( - new ValidationError("Invalid authentication provider type", Cause.INVALID_AUTH_PROVIDER_TYPE)); - return validation; - } - - if (request.getAuthenticationIdentifier() == null || request.getAuthenticationIdentifier().isEmpty()) { - validation.addError( - new ValidationError("Missing authentication provider identifier", Cause.MISSING_AUTH_PROVIDER_ID)); - return validation; - } - - if (request.getProfileId() == null || request.getProfileId().isEmpty()) { - validation.addError(new ValidationError("Missing profile id", Cause.MISSING_PROFILE_ID)); - return validation; - } - - if (!util.isValidUuid(request.getProfileId())) { - validation.addError(new ValidationError("Invalid profile id", Cause.INVALID_PROFILE_ID)); - return validation; - } - - return validation; - } } diff --git a/src/main/java/biz/nynja/account/validation/Validators.java b/src/main/java/biz/nynja/account/validation/Validators.java index 930b836..f1f1689 100644 --- a/src/main/java/biz/nynja/account/validation/Validators.java +++ b/src/main/java/biz/nynja/account/validation/Validators.java @@ -346,6 +346,41 @@ public class Validators { } } + public Validation validateUpdateSearchableOptionRequest(String profileId, String authenticationType, + String authenticationIdentifier) { + Validation validation = new Validation(); + if (authenticationType == null || authenticationType.isEmpty()) { + validation.addError( + new ValidationError("Missing authentication provider type", Cause.MISSING_AUTH_PROVIDER_TYPE)); + return validation; + } + + if (!authenticationType.equals(AuthenticationType.EMAIL.toString()) + && !authenticationType.equals(AuthenticationType.PHONE.toString())) { + validation.addError( + new ValidationError("Invalid authentication provider type", Cause.INVALID_AUTH_PROVIDER_TYPE)); + return validation; + } + + if (authenticationIdentifier == null || authenticationIdentifier.isEmpty()) { + validation.addError( + new ValidationError("Missing authentication provider identifier", Cause.MISSING_AUTH_PROVIDER_ID)); + return validation; + } + + if (profileId == null || profileId.isEmpty()) { + validation.addError(new ValidationError("Missing profile id", Cause.MISSING_PROFILE_ID)); + return validation; + } + + if (!isValidUuid(profileId)) { + validation.addError(new ValidationError("Invalid profile id", Cause.INVALID_PROFILE_ID)); + return validation; + } + + return validation; + } + private boolean isValidUuid(String id) { return id.matches("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"); } -- GitLab From 9f46b35be91a7549994e9adc6abe5588904c2a06 Mon Sep 17 00:00:00 2001 From: Stanimir Penkov Date: Fri, 4 Jan 2019 17:30:27 +0200 Subject: [PATCH 09/27] NY-6215: Updated role Signed-off-by: Stanimir Penkov --- .../java/biz/nynja/account/services/AccountServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java index 15c6145..a300fb8 100644 --- a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java +++ b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java @@ -1187,7 +1187,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas @Override @PerformPermissionCheck - @Permitted(role = RoleConstants.ADMIN) + @Permitted(role = RoleConstants.ACCOUNT_ADMIN) @Permitted(role = RoleConstants.USER) public void updateSearchableOption(UpdateSearchableOptionRequest request, StreamObserver responseObserver) { -- GitLab From 0cc7cc3fc8a301adfd2d70c7d3675d7361bf0fda Mon Sep 17 00:00:00 2001 From: Stanimir Penkov Date: Thu, 3 Jan 2019 14:22:20 +0200 Subject: [PATCH 10/27] =?UTF-8?q?NY-6216:=20Add=20unit=20tests=20for=20upd?= =?UTF-8?q?ating=20login=20option=E2=80=99s=20searchable=20state?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stanimir Penkov --- .../account/services/AccountServiceTests.java | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/src/test/java/biz/nynja/account/services/AccountServiceTests.java b/src/test/java/biz/nynja/account/services/AccountServiceTests.java index 116a083..7313213 100644 --- a/src/test/java/biz/nynja/account/services/AccountServiceTests.java +++ b/src/test/java/biz/nynja/account/services/AccountServiceTests.java @@ -2019,4 +2019,119 @@ public class AccountServiceTests extends GrpcServerTestBase { assertNotNull("Reply should not be null", reply); assertEquals(reply.getError().getCause(), Cause.INVALID_EMAIL); } + + @Test + public void testUpdateSearchableOptionPhoneOK() { + final UpdateSearchableOptionRequest request = UpdateSearchableOptionRequest.newBuilder() + .setProfileId(Util.PROFILE_ID.toString()).setAuthenticationIdentifier(Util.PHONE_PROVIDER) + .setAuthenticationType(AuthenticationType.PHONE.toString()) + .setSearchOption(SearchableOption.SEARCH_DISABLED).build(); + + given(accountRepositoryAdditional.updateSearchableOption(Mockito.any(UUID.class), Mockito.any(String.class), + Mockito.any(String.class), Mockito.any(SearchableOption.class))).willReturn(true); + + given(profileRepository.findByProfileId(Util.PROFILE_ID)).willReturn(profile2AuthProviders); + + given(profileByAutheticationProviderRepository + .findByAuthenticationProviderAndAuthenticationProviderType(Util.PHONE_PROVIDER, "PHONE")) + .willReturn(profileByAuthenticationProvider); + + final StatusResponse reply = accountServiceBlockingStub.updateSearchableOption(request); + assertNotNull("Reply should not be null", reply); + assertEquals("SUCCESS", reply.getStatus()); + } + + @Test + public void testUpdateSearchableOptionEmailOK() { + final UpdateSearchableOptionRequest request = UpdateSearchableOptionRequest.newBuilder() + .setProfileId(Util.PROFILE_ID.toString()).setAuthenticationIdentifier(Util.EMAIL) + .setAuthenticationType(AuthenticationType.EMAIL.toString()) + .setSearchOption(SearchableOption.SEARCH_DISABLED).build(); + + given(accountRepositoryAdditional.updateSearchableOption(Mockito.any(UUID.class), Mockito.any(String.class), + Mockito.any(String.class), Mockito.any(SearchableOption.class))).willReturn(true); + + given(profileRepository.findByProfileId(Util.PROFILE_ID)).willReturn(profile2AuthProviders); + + given(profileByAutheticationProviderRepository + .findByAuthenticationProviderAndAuthenticationProviderType(Util.EMAIL, "EMAIL")) + .willReturn(profileByAuthenticationProvider); + + final StatusResponse reply = accountServiceBlockingStub.updateSearchableOption(request); + assertNotNull("Reply should not be null", reply); + assertEquals("SUCCESS", reply.getStatus()); + } + + @Test + public void testUpdateSearchableOptionErrorUpdatingSearchableOption() { + final UpdateSearchableOptionRequest request = UpdateSearchableOptionRequest.newBuilder() + .setProfileId(Util.PROFILE_ID.toString()).setAuthenticationIdentifier(Util.PHONE_PROVIDER) + .setAuthenticationType(AuthenticationType.PHONE.toString()) + .setSearchOption(SearchableOption.SEARCH_DISABLED).build(); + + given(accountRepositoryAdditional.updateSearchableOption(Mockito.any(UUID.class), Mockito.any(String.class), + Mockito.any(String.class), Mockito.any(SearchableOption.class))).willReturn(false); + + final StatusResponse reply = accountServiceBlockingStub.updateSearchableOption(request); + assertNotNull("Reply should not be null", reply); + assertEquals(reply.getError().getCause(), Cause.ERROR_UPDATING_SEARCHABLE_OPTION); + } + + @Test + public void testUpdateSearchableOptionMissingAuthenticationProviderType() { + final UpdateSearchableOptionRequest request = UpdateSearchableOptionRequest.newBuilder() + .setProfileId(Util.PROFILE_ID.toString()).setAuthenticationIdentifier(Util.PHONE_PROVIDER) + .setSearchOption(SearchableOption.SEARCH_DISABLED).build(); + + final StatusResponse reply = accountServiceBlockingStub.updateSearchableOption(request); + assertNotNull("Reply should not be null", reply); + assertEquals(reply.getError().getCause(), Cause.MISSING_AUTH_PROVIDER_TYPE); + } + + @Test + public void testUpdateSearchableOptionMissingAuthenticationProviderIdentifier() { + final UpdateSearchableOptionRequest request = UpdateSearchableOptionRequest.newBuilder() + .setProfileId(Util.PROFILE_ID.toString()).setAuthenticationType(AuthenticationType.PHONE.toString()) + .setSearchOption(SearchableOption.SEARCH_DISABLED).build(); + + final StatusResponse reply = accountServiceBlockingStub.updateSearchableOption(request); + assertNotNull("Reply should not be null", reply); + assertEquals(reply.getError().getCause(), Cause.MISSING_AUTH_PROVIDER_ID); + } + + @Test + public void testUpdateSearchableOptionMissingProfileId() { + final UpdateSearchableOptionRequest request = UpdateSearchableOptionRequest.newBuilder() + .setAuthenticationIdentifier(Util.PHONE_PROVIDER) + .setAuthenticationType(AuthenticationType.PHONE.toString()) + .setSearchOption(SearchableOption.SEARCH_DISABLED).build(); + + final StatusResponse reply = accountServiceBlockingStub.updateSearchableOption(request); + assertNotNull("Reply should not be null", reply); + assertEquals(reply.getError().getCause(), Cause.MISSING_PROFILE_ID); + } + + @Test + public void testUpdateSearchableOptionInvalidProfileId() { + final UpdateSearchableOptionRequest request = UpdateSearchableOptionRequest.newBuilder() + .setProfileId(Util.INVALID_PROFILE_ID).setAuthenticationIdentifier(Util.PHONE_PROVIDER) + .setAuthenticationType(AuthenticationType.PHONE.toString()) + .setSearchOption(SearchableOption.SEARCH_DISABLED).build(); + + final StatusResponse reply = accountServiceBlockingStub.updateSearchableOption(request); + assertNotNull("Reply should not be null", reply); + assertEquals(reply.getError().getCause(), Cause.INVALID_PROFILE_ID); + } + + @Test + public void testUpdateSearchableOptionInvalidAuthenticationProviderType() { + final UpdateSearchableOptionRequest request = UpdateSearchableOptionRequest.newBuilder() + .setProfileId(Util.PROFILE_ID.toString()).setAuthenticationIdentifier("Facebook_provider") + .setAuthenticationType(AuthenticationType.FACEBOOK.toString()) + .setSearchOption(SearchableOption.SEARCH_DISABLED).build(); + + final StatusResponse reply = accountServiceBlockingStub.updateSearchableOption(request); + assertNotNull("Reply should not be null", reply); + assertEquals(reply.getError().getCause(), Cause.INVALID_AUTH_PROVIDER_TYPE); + } } -- GitLab From 2dce7d589f8543a4adb68d318ba37aaad8f0dc66 Mon Sep 17 00:00:00 2001 From: Stanimir Penkov Date: Fri, 4 Jan 2019 18:32:09 +0200 Subject: [PATCH 11/27] NY-6216: Added needed imports Signed-off-by: Stanimir Penkov --- .../java/biz/nynja/account/services/AccountServiceTests.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/java/biz/nynja/account/services/AccountServiceTests.java b/src/test/java/biz/nynja/account/services/AccountServiceTests.java index 7313213..2a1940d 100644 --- a/src/test/java/biz/nynja/account/services/AccountServiceTests.java +++ b/src/test/java/biz/nynja/account/services/AccountServiceTests.java @@ -67,9 +67,11 @@ 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.SearchableOption; import biz.nynja.account.grpc.StatusResponse; import biz.nynja.account.grpc.UpdateAccountRequest; import biz.nynja.account.grpc.UpdateAuthenticationProviderRequest; +import biz.nynja.account.grpc.UpdateSearchableOptionRequest; import biz.nynja.account.models.Account; import biz.nynja.account.models.AccountByAuthenticationProvider; import biz.nynja.account.models.AccountByProfileId; -- GitLab From e9380059338de21030aac00cfd8adab9724eeef4 Mon Sep 17 00:00:00 2001 From: Filip Nikolov Date: Mon, 7 Jan 2019 10:19:43 +0200 Subject: [PATCH 12/27] Change comment wording. --- releases/staging/account-service.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/releases/staging/account-service.yaml b/releases/staging/account-service.yaml index 28b8dfb..6adc18a 100644 --- a/releases/staging/account-service.yaml +++ b/releases/staging/account-service.yaml @@ -31,6 +31,7 @@ spec: http: 8080 grpc: 6565 + ## CORS policy needs clean up!!! This is temporary solution to allow UI team and others that depend on stable environment to work on staging. ## # CORS policy corsPolicy: allowOrigin: -- GitLab From c15e7b389cde7c42e9cfbf7177269ecbecc3f5e6 Mon Sep 17 00:00:00 2001 From: Stanimir Penkov Date: Mon, 7 Jan 2019 11:16:16 +0200 Subject: [PATCH 13/27] NY-6036: Remove duplication in logs - removed duplication in logs; - updated message. Signed-off-by: Stanimir Penkov --- .../java/biz/nynja/account/services/AccountServiceImpl.java | 2 +- .../nynja/account/services/decomposition/AccountProvider.java | 1 - .../nynja/account/services/decomposition/ProfileProvider.java | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java index a300fb8..a3cd2a7 100644 --- a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java +++ b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java @@ -421,7 +421,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas @Permitted(role = RoleConstants.USER) public void getAccountByAccountId(AccountByAccountIdRequest request, StreamObserver responseObserver) { - logger.info("Getting accounts by account id: {}", request.getAccountId()); + logger.info("Getting account by account id: {}", request.getAccountId()); if ((request.getAccountId() == null) || (request.getAccountId().isEmpty())) { logAndBuildGrpcAccountResponse(responseObserver, AccountResponse.newBuilder(), "Missing account id", "", diff --git a/src/main/java/biz/nynja/account/services/decomposition/AccountProvider.java b/src/main/java/biz/nynja/account/services/decomposition/AccountProvider.java index e912b9c..0e5bd08 100644 --- a/src/main/java/biz/nynja/account/services/decomposition/AccountProvider.java +++ b/src/main/java/biz/nynja/account/services/decomposition/AccountProvider.java @@ -164,7 +164,6 @@ public class AccountProvider { } public Optional getAccountByAccountId(AccountByAccountIdRequest request) { - logger.info("Getting accounts by account id: {}", request.getAccountId()); Account account = accountRepository.findByAccountId(UUID.fromString(request.getAccountId())); if (account == null || account.getAccountId() == null) { return Optional.empty(); diff --git a/src/main/java/biz/nynja/account/services/decomposition/ProfileProvider.java b/src/main/java/biz/nynja/account/services/decomposition/ProfileProvider.java index 9c138bf..a4436e3 100644 --- a/src/main/java/biz/nynja/account/services/decomposition/ProfileProvider.java +++ b/src/main/java/biz/nynja/account/services/decomposition/ProfileProvider.java @@ -24,7 +24,6 @@ public class ProfileProvider { } public Optional getProfileByProfileId(ProfileByProfileIdRequest request) { - logger.info("Getting profile by profile id: {}", request.getProfileId()); Profile profile = profileRepository.findByProfileId(UUID.fromString(request.getProfileId())); if (profile == null || profile.getProfileId() == null) { return Optional.empty(); -- GitLab From 1845c77b333e24881c4cf97afee6303bc799fce9 Mon Sep 17 00:00:00 2001 From: Stanimir Penkov Date: Mon, 7 Jan 2019 12:12:49 +0200 Subject: [PATCH 14/27] NY-6216: Code Review Feedback - use .name() Signed-off-by: Stanimir Penkov --- .../biz/nynja/account/validation/Validators.java | 4 ++-- .../account/services/AccountServiceTests.java | 15 +++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/main/java/biz/nynja/account/validation/Validators.java b/src/main/java/biz/nynja/account/validation/Validators.java index f1f1689..179d49a 100644 --- a/src/main/java/biz/nynja/account/validation/Validators.java +++ b/src/main/java/biz/nynja/account/validation/Validators.java @@ -355,8 +355,8 @@ public class Validators { return validation; } - if (!authenticationType.equals(AuthenticationType.EMAIL.toString()) - && !authenticationType.equals(AuthenticationType.PHONE.toString())) { + if (!authenticationType.equals(AuthenticationType.EMAIL.name()) + && !authenticationType.equals(AuthenticationType.PHONE.name())) { validation.addError( new ValidationError("Invalid authentication provider type", Cause.INVALID_AUTH_PROVIDER_TYPE)); return validation; diff --git a/src/test/java/biz/nynja/account/services/AccountServiceTests.java b/src/test/java/biz/nynja/account/services/AccountServiceTests.java index 2a1940d..0f0386d 100644 --- a/src/test/java/biz/nynja/account/services/AccountServiceTests.java +++ b/src/test/java/biz/nynja/account/services/AccountServiceTests.java @@ -2026,7 +2026,7 @@ public class AccountServiceTests extends GrpcServerTestBase { public void testUpdateSearchableOptionPhoneOK() { final UpdateSearchableOptionRequest request = UpdateSearchableOptionRequest.newBuilder() .setProfileId(Util.PROFILE_ID.toString()).setAuthenticationIdentifier(Util.PHONE_PROVIDER) - .setAuthenticationType(AuthenticationType.PHONE.toString()) + .setAuthenticationType(AuthenticationType.PHONE.name()) .setSearchOption(SearchableOption.SEARCH_DISABLED).build(); given(accountRepositoryAdditional.updateSearchableOption(Mockito.any(UUID.class), Mockito.any(String.class), @@ -2047,7 +2047,7 @@ public class AccountServiceTests extends GrpcServerTestBase { public void testUpdateSearchableOptionEmailOK() { final UpdateSearchableOptionRequest request = UpdateSearchableOptionRequest.newBuilder() .setProfileId(Util.PROFILE_ID.toString()).setAuthenticationIdentifier(Util.EMAIL) - .setAuthenticationType(AuthenticationType.EMAIL.toString()) + .setAuthenticationType(AuthenticationType.EMAIL.name()) .setSearchOption(SearchableOption.SEARCH_DISABLED).build(); given(accountRepositoryAdditional.updateSearchableOption(Mockito.any(UUID.class), Mockito.any(String.class), @@ -2068,7 +2068,7 @@ public class AccountServiceTests extends GrpcServerTestBase { public void testUpdateSearchableOptionErrorUpdatingSearchableOption() { final UpdateSearchableOptionRequest request = UpdateSearchableOptionRequest.newBuilder() .setProfileId(Util.PROFILE_ID.toString()).setAuthenticationIdentifier(Util.PHONE_PROVIDER) - .setAuthenticationType(AuthenticationType.PHONE.toString()) + .setAuthenticationType(AuthenticationType.PHONE.name()) .setSearchOption(SearchableOption.SEARCH_DISABLED).build(); given(accountRepositoryAdditional.updateSearchableOption(Mockito.any(UUID.class), Mockito.any(String.class), @@ -2093,7 +2093,7 @@ public class AccountServiceTests extends GrpcServerTestBase { @Test public void testUpdateSearchableOptionMissingAuthenticationProviderIdentifier() { final UpdateSearchableOptionRequest request = UpdateSearchableOptionRequest.newBuilder() - .setProfileId(Util.PROFILE_ID.toString()).setAuthenticationType(AuthenticationType.PHONE.toString()) + .setProfileId(Util.PROFILE_ID.toString()).setAuthenticationType(AuthenticationType.PHONE.name()) .setSearchOption(SearchableOption.SEARCH_DISABLED).build(); final StatusResponse reply = accountServiceBlockingStub.updateSearchableOption(request); @@ -2104,8 +2104,7 @@ public class AccountServiceTests extends GrpcServerTestBase { @Test public void testUpdateSearchableOptionMissingProfileId() { final UpdateSearchableOptionRequest request = UpdateSearchableOptionRequest.newBuilder() - .setAuthenticationIdentifier(Util.PHONE_PROVIDER) - .setAuthenticationType(AuthenticationType.PHONE.toString()) + .setAuthenticationIdentifier(Util.PHONE_PROVIDER).setAuthenticationType(AuthenticationType.PHONE.name()) .setSearchOption(SearchableOption.SEARCH_DISABLED).build(); final StatusResponse reply = accountServiceBlockingStub.updateSearchableOption(request); @@ -2117,7 +2116,7 @@ public class AccountServiceTests extends GrpcServerTestBase { public void testUpdateSearchableOptionInvalidProfileId() { final UpdateSearchableOptionRequest request = UpdateSearchableOptionRequest.newBuilder() .setProfileId(Util.INVALID_PROFILE_ID).setAuthenticationIdentifier(Util.PHONE_PROVIDER) - .setAuthenticationType(AuthenticationType.PHONE.toString()) + .setAuthenticationType(AuthenticationType.PHONE.name()) .setSearchOption(SearchableOption.SEARCH_DISABLED).build(); final StatusResponse reply = accountServiceBlockingStub.updateSearchableOption(request); @@ -2129,7 +2128,7 @@ public class AccountServiceTests extends GrpcServerTestBase { public void testUpdateSearchableOptionInvalidAuthenticationProviderType() { final UpdateSearchableOptionRequest request = UpdateSearchableOptionRequest.newBuilder() .setProfileId(Util.PROFILE_ID.toString()).setAuthenticationIdentifier("Facebook_provider") - .setAuthenticationType(AuthenticationType.FACEBOOK.toString()) + .setAuthenticationType(AuthenticationType.FACEBOOK.name()) .setSearchOption(SearchableOption.SEARCH_DISABLED).build(); final StatusResponse reply = accountServiceBlockingStub.updateSearchableOption(request); -- GitLab From b0600ee86170cbf62d8dd9b043c7b44a4cc0ca31 Mon Sep 17 00:00:00 2001 From: Stoyan Tzenkov Date: Mon, 7 Jan 2019 16:34:57 +0200 Subject: [PATCH 15/27] NY-5138: Authentication providers per profile limited to max-authenticationproviders-per-profile. Signed-off-by: Stoyan Tzenkov --- .../ProfileDataConfiguration.java | 21 +++++++++++++++++++ .../account/services/AccountServiceImpl.java | 13 +++++++++++- src/main/resources/application-dev.yml | 3 +++ src/main/resources/application-production.yml | 3 +++ 4 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/main/java/biz/nynja/account/configuration/ProfileDataConfiguration.java diff --git a/src/main/java/biz/nynja/account/configuration/ProfileDataConfiguration.java b/src/main/java/biz/nynja/account/configuration/ProfileDataConfiguration.java new file mode 100644 index 0000000..0d37511 --- /dev/null +++ b/src/main/java/biz/nynja/account/configuration/ProfileDataConfiguration.java @@ -0,0 +1,21 @@ +/** + * Copyright (C) 2018 Nynja Inc. All rights reserved. + */ +package biz.nynja.account.configuration; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties(prefix = "profile-data") +public class ProfileDataConfiguration { + private int maxProvidersPerProfile; + + public int getMaxProvidersPerProfile() { + return maxProvidersPerProfile; + } + + public void setMaxProvidersPerProfile(int maxProvidersPerProfile) { + this.maxProvidersPerProfile = maxProvidersPerProfile; + } +} diff --git a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java index a3cd2a7..f625656 100644 --- a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java +++ b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java @@ -18,6 +18,8 @@ import org.lognet.springboot.grpc.GRpcService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import biz.nynja.account.configuration.AccountDataConfiguration; +import biz.nynja.account.configuration.ProfileDataConfiguration; import biz.nynja.account.grpc.AccountByAccountIdRequest; import biz.nynja.account.grpc.AccountResponse; import biz.nynja.account.grpc.AccountServiceGrpc; @@ -100,6 +102,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas private final AccountCreator accountCreator; private final ProfileProvider profileProvider; private final PermissionsValidator permissionsValidator; + private final ProfileDataConfiguration profileDataConfiguration; public AccountServiceImpl(AccountRepositoryAdditional accountRepositoryAdditional, ProfileRepository profileRepository, @@ -108,7 +111,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas AccountByUsernameRepository accountByUsernameRepository, AccountProvider accountProvider, AccountByProfileIdRepository accountByProfileIdRepository, PhoneNumberNormalizer phoneNumberNormalizer, AccountCreator accountCreator, ProfileProvider profileProvider, - PermissionsValidator permissionsValidator) { + PermissionsValidator permissionsValidator, ProfileDataConfiguration profileDataConfiguration) { this.accountRepositoryAdditional = accountRepositoryAdditional; this.profileRepository = profileRepository; this.profileByAutheticationProviderRepository = profileByAutheticationProviderRepository; @@ -120,6 +123,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas this.accountCreator = accountCreator; this.profileProvider = profileProvider; this.permissionsValidator = permissionsValidator; + this.profileDataConfiguration = profileDataConfiguration; } @Override @@ -647,6 +651,13 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas return; } + // Make sure there will be no more than providers in this profile + if(profile.getAuthenticationProviders().size() >= profileDataConfiguration.getMaxProvidersPerProfile()) { + logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), + "Max number of authentication providers reached for profile id {}.", request.getProfileId(), Cause.MAX_PROVIDERS_PER_PROFILE_REACHED); + return; + } + // Make sure that the requested authentication provider is not already used in the system. ProfileByAuthenticationProvider profileByAuthProvider = profileByAutheticationProviderRepository .findByAuthenticationProviderAndAuthenticationProviderType( diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 5de0eb4..3492976 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -37,6 +37,9 @@ pending-account: account-data: max-contact-info-of-type: 10 +profile-data: + max-authenticationproviders-per-profile: 3 + erlang-bridge: enable: false; ip: diff --git a/src/main/resources/application-production.yml b/src/main/resources/application-production.yml index e42ba70..f6221bf 100644 --- a/src/main/resources/application-production.yml +++ b/src/main/resources/application-production.yml @@ -31,6 +31,9 @@ pending-account: account-data: max-contact-info-of-type: ${MAX_CONTACT_INFO_OF_TYPE:10} +profile-data: +max-authenticationproviders-per-profile: 3 + erlang-bridge: enable: false; ip: ${ERLANG_IP} -- GitLab From ec6173cb5244d175589e9be4e503ddefed820218 Mon Sep 17 00:00:00 2001 From: Stanimir Penkov Date: Mon, 7 Jan 2019 18:43:44 +0200 Subject: [PATCH 16/27] NY-6473: Fix: Error deleting profile/account after deleting the account's creation provider Signed-off-by: Stanimir Penkov --- .../AccountRepositoryAdditionalImpl.java | 40 +++++++++++++------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java index bcfdf04..77a6745 100644 --- a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java +++ b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java @@ -226,18 +226,23 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio WriteResult wr = null; try { deleteAccountData(batchOperations, existingAccount); - deleteProfileByAuthenticationProvider(batchOperations, existingAccount.getProfileId(), - AuthenticationProvider.createAuthenticationProviderFromStringsWithDefaultSearchableOption( - existingAccount.getAuthenticationProviderType(), - existingAccount.getAuthenticationProvider())); if (alsoDeleteProfile) { - if (existingProfile.getAuthenticationProviders() != null) { + if (existingProfile.getAuthenticationProviders() != null + && existingProfile.getAuthenticationProviders().size() > 0) { deleteAuthenticationProvidersFromProfile(batchOperations, existingProfile.getProfileId(), existingProfile.getAuthenticationProviders()); } deleteProfileData(batchOperations, existingProfile); } else { + if (existingAccount.getAuthenticationProviderType() != null + && existingAccount.getAuthenticationProvider() != null) { + deleteProfileByAuthenticationProvider(batchOperations, existingAccount.getProfileId(), + AuthenticationProvider.createAuthenticationProviderFromStringsWithDefaultSearchableOption( + existingAccount.getAuthenticationProviderType(), + existingAccount.getAuthenticationProvider())); + } if (!removeCreationProvider(batchOperations, existingAccount, existingProfile)) { + logger.error("Error deleting account {}", existingAccount.getAccountId()); return false; } } @@ -266,14 +271,22 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio // update authentication providers of the profile by removing the one of the deleted account (if not // already manually removed by the user) Long timeUpdated = Instant.now().toEpochMilli(); - if (existingProfile.getAuthenticationProviders() != null) { + if (existingProfile.getAuthenticationProviders() != null + && existingProfile.getAuthenticationProviders().size() > 0) { Set existingAuthenticationProvidersSet = new HashSet( existingProfile.getAuthenticationProviders()); + if (existingAccount.getAuthenticationProviderType() == null + && existingAccount.getAuthenticationProvider() == null) { + // The creation provider is already deleted + return true; + } Optional existingCreationProviderToDelete = AuthenticationProvider .foundExistingAuthenticationProviderByTypeAndValue(existingAccount.getAuthenticationProviderType(), existingAccount.getAuthenticationProvider(), existingAuthenticationProvidersSet); if (!existingCreationProviderToDelete.isPresent()) { - logger.error("Error removing creation provider from account {}.", existingAccount.getAccountId()); + logger.error( + "The creation provider for account {} was not found in the list of the profile's authentication providers.", + existingAccount.getAccountId()); return false; } @@ -284,6 +297,7 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio if (existingAuthenticationProvidersSet.size() > 0) { updateAuthProvidersInProfileWhenDeletingAccount(batchOperations, existingProfile, existingAuthenticationProvidersSet, timeUpdated); + return true; } else { logger.error( "Error deleting account. At least one authentication provider should exist in profile: {}.", @@ -291,8 +305,11 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio return false; } } + logger.error("Error removing creation provider from account {}.", existingAccount.getAccountId()); + return false; } - return true; + logger.error("No authentication providers found for profile {}", existingProfile.getProfileId()); + return false; } private void updateAccountData(CassandraBatchOperations batchOps, UpdateAccountRequest request, @@ -416,7 +433,8 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio WriteResult wr = null; try { deleteProfileAccountsWhenDeletingProfile(profileId, batchOperations, existingAccountsForProfile); - if (existingProfile.getAuthenticationProviders() != null) { + if (existingProfile.getAuthenticationProviders() != null + && existingProfile.getAuthenticationProviders().size() > 0) { deleteAuthenticationProvidersFromProfile(batchOperations, existingProfile.getProfileId(), existingProfile.getAuthenticationProviders()); } @@ -438,10 +456,6 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio for (AccountByProfileId accountByProfileId : existingAccountsForProfile) { Account existingAccount = accountRepository.findByAccountId(accountByProfileId.getAccountId()); deleteAccountData(batchOperations, existingAccount); - deleteProfileByAuthenticationProvider(batchOperations, profileId, - AuthenticationProvider.createAuthenticationProviderFromStringsWithDefaultSearchableOption( - existingAccount.getAuthenticationProviderType(), - existingAccount.getAuthenticationProvider())); } } -- GitLab From 6abbabae98be8b3e17d74b558d9410cfd518e6b3 Mon Sep 17 00:00:00 2001 From: Stanimir Penkov Date: Tue, 8 Jan 2019 11:08:30 +0200 Subject: [PATCH 17/27] NY-6057: Added info in log file Signed-off-by: Stanimir Penkov --- src/main/java/biz/nynja/account/services/AccountServiceImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java index a3cd2a7..b6bec90 100644 --- a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java +++ b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java @@ -546,6 +546,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas } if (!util.isValidUuid(request.getAccountId())) { + logger.info("Can not delete account. Invalid account id: {}", request.getAccountId()); logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), "Invalid account id: {}", request.getAccountId(), Cause.INVALID_ACCOUNT_ID); return; -- GitLab From e53a31457d3c632368554b0ac92dc3850c0b84f1 Mon Sep 17 00:00:00 2001 From: Stoyan Tzenkov Date: Tue, 8 Jan 2019 17:06:26 +0200 Subject: [PATCH 18/27] NY-5138: authenticationproviders per profile increased to 20. Signed-off-by: Stoyan Tzenkov --- src/main/resources/application-dev.yml | 2 +- src/main/resources/application-production.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 3492976..a958a6a 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -38,7 +38,7 @@ account-data: max-contact-info-of-type: 10 profile-data: - max-authenticationproviders-per-profile: 3 + max-authenticationproviders-per-profile: 20 erlang-bridge: enable: false; diff --git a/src/main/resources/application-production.yml b/src/main/resources/application-production.yml index f6221bf..fb7c565 100644 --- a/src/main/resources/application-production.yml +++ b/src/main/resources/application-production.yml @@ -32,7 +32,7 @@ account-data: max-contact-info-of-type: ${MAX_CONTACT_INFO_OF_TYPE:10} profile-data: -max-authenticationproviders-per-profile: 3 +max-authenticationproviders-per-profile: 20 erlang-bridge: enable: false; -- GitLab From e249df8f6a414fda294906bbd0812ec0d4fe7733 Mon Sep 17 00:00:00 2001 From: Stoyan Tzenkov Date: Tue, 8 Jan 2019 18:02:07 +0200 Subject: [PATCH 19/27] NY-5138: ProfileCOnfig fixed. Signed-off-by: Stoyan Tzenkov --- .../configuration/ProfileDataConfiguration.java | 10 +++++----- .../biz/nynja/account/services/AccountServiceImpl.java | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/biz/nynja/account/configuration/ProfileDataConfiguration.java b/src/main/java/biz/nynja/account/configuration/ProfileDataConfiguration.java index 0d37511..bcb6ad9 100644 --- a/src/main/java/biz/nynja/account/configuration/ProfileDataConfiguration.java +++ b/src/main/java/biz/nynja/account/configuration/ProfileDataConfiguration.java @@ -9,13 +9,13 @@ import org.springframework.context.annotation.Configuration; @Configuration @ConfigurationProperties(prefix = "profile-data") public class ProfileDataConfiguration { - private int maxProvidersPerProfile; + private int maxAuthenticationprovidersPerProfile; - public int getMaxProvidersPerProfile() { - return maxProvidersPerProfile; + public int getMaxAuthenticationprovidersPerProfile() { + return maxAuthenticationprovidersPerProfile; } - public void setMaxProvidersPerProfile(int maxProvidersPerProfile) { - this.maxProvidersPerProfile = maxProvidersPerProfile; + public void setMaxAuthenticationprovidersPerProfile(int maxAuthenticationprovidersPerProfile) { + this.maxAuthenticationprovidersPerProfile = maxAuthenticationprovidersPerProfile; } } diff --git a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java index f625656..7545533 100644 --- a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java +++ b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java @@ -652,7 +652,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas } // Make sure there will be no more than providers in this profile - if(profile.getAuthenticationProviders().size() >= profileDataConfiguration.getMaxProvidersPerProfile()) { + if(profile.getAuthenticationProviders().size() >= profileDataConfiguration.getMaxAuthenticationprovidersPerProfile()) { logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), "Max number of authentication providers reached for profile id {}.", request.getProfileId(), Cause.MAX_PROVIDERS_PER_PROFILE_REACHED); return; -- GitLab From 8a6165e05bbdfbb682b156b385aad04971aebdf1 Mon Sep 17 00:00:00 2001 From: Stanimir Penkov Date: Wed, 9 Jan 2019 11:52:23 +0200 Subject: [PATCH 20/27] NY-4867: Fix errors with accountId/profileId - updated existing checks for accountId/profileId; - updated log messages; - added check for used accountId/profileId. Signed-off-by: Stanimir Penkov --- .../AccountRepositoryAdditional.java | 4 ++ .../AccountRepositoryAdditionalImpl.java | 24 ++++++++ .../account/services/AccountServiceImpl.java | 60 ++++++++++++++++--- .../decomposition/AccountCreator.java | 11 ++++ 4 files changed, 90 insertions(+), 9 deletions(-) diff --git a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditional.java b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditional.java index dd43e40..800a1cd 100644 --- a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditional.java +++ b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditional.java @@ -37,6 +37,10 @@ public interface AccountRepositoryAdditional { PendingAccountByAuthenticationProvider findSameAuthenticationProviderInPendingAccount(AuthenticationProvider authProvider); + boolean accountIdAlreadyUsed(UUID accountId); + + boolean profileIdAlreadyUsed(UUID profileId); + boolean authenticationProviderAlreadyUsedInProfile(AuthenticationProvider authProvider); boolean addAuthenticationProvider(UUID profileId, AuthenticationProvider authProvider); diff --git a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java index 77a6745..c09021f 100644 --- a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java +++ b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java @@ -120,6 +120,16 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio pendingAccount.getAuthenticationProviderType(), pendingAccount.getAuthenticationProvider()); return null; } + if (accountRepository.findByAccountId(pendingAccount.getAccountId()) != null) { + logger.error("The account id {} is already used.", pendingAccount.getAccountId()); + pendingAccountRepository.deleteById(pendingAccount.getAccountId()); + return null; + } + if (profileRepository.findByProfileId(pendingAccount.getProfileId()) != null) { + logger.error("The profile id {} is already used.", pendingAccount.getProfileId()); + pendingAccountRepository.deleteById(pendingAccount.getAccountId()); + return null; + } Long timeCreated = Instant.now().toEpochMilli(); WriteResult wr; @@ -469,6 +479,20 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio return false; } + public boolean accountIdAlreadyUsed(UUID accountId) { + if (accountRepository.findByAccountId(accountId) != null) { + return true; + } + return false; + } + + public boolean profileIdAlreadyUsed(UUID profileId) { + if (profileRepository.findByProfileId(profileId) != null) { + return true; + } + return false; + } + @Override public boolean addAuthenticationProvider(UUID profileId, AuthenticationProvider authProvider) { BatchStatement batch = new BatchStatement(); diff --git a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java index 4d68518..72542ac 100644 --- a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java +++ b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java @@ -476,7 +476,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas public void completePendingAccountCreation(CompletePendingAccountCreationRequest request, StreamObserver responseObserver) { - logger.info("Complete pending account creation..."); + logger.info("Complete pending account creation for account id {} ...", request.getAccountId()); logger.debug("Complete pending account creation...: {} ...", request); AccountResponse response = accountCreator.retrieveCompletePendingAccountResponse(request); @@ -497,6 +497,12 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas Cause.MISSING_ACCOUNT_ID); return; } + if (!util.isValidUuid(request.getAccountId())) { + logAndBuildGrpcAccountResponse(responseObserver, AccountResponse.newBuilder(), "Invalid account id: {}", + request.getAccountId(), Cause.INVALID_ACCOUNT_ID); + return; + } + if (!permissionsValidator.isRpcAllowed(request.getAccountId())) { logAndBuildGrpcAccountResponse(responseObserver, AccountResponse.newBuilder(), "Can not update account {}.", request.getAccountId(), Cause.ERROR_PERMISSION_DENIED); @@ -543,18 +549,17 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas Cause.MISSING_ACCOUNT_ID); return; } - if (!permissionsValidator.isRpcAllowed(request.getAccountId())) { - logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), "Can not delete account {}.", - request.getAccountId(), Cause.ERROR_PERMISSION_DENIED); - return; - } - if (!util.isValidUuid(request.getAccountId())) { logger.info("Can not delete account. Invalid account id: {}", request.getAccountId()); logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), "Invalid account id: {}", request.getAccountId(), Cause.INVALID_ACCOUNT_ID); return; } + if (!permissionsValidator.isRpcAllowed(request.getAccountId())) { + logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), "Can not delete account {}.", + request.getAccountId(), Cause.ERROR_PERMISSION_DENIED); + return; + } boolean wasAccountDeleted = accountRepositoryAdditional.deleteAccount(UUID.fromString(request.getAccountId())); if (wasAccountDeleted) { @@ -614,6 +619,11 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas Cause.MISSING_PROFILE_ID); return; } + if (!util.isValidUuid(request.getProfileId())) { + logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), "Invalid profile id: {}", + request.getProfileId(), Cause.INVALID_PROFILE_ID); + return; + } List existingAccountsForProfile = accountByProfileIdRepository .findAllByProfileId(UUID.fromString(request.getProfileId())); @@ -703,6 +713,11 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas validationResult.get().getValue(), "", validationResult.get().getKey()); return; } + if (!util.isValidUuid(request.getAccountId())) { + logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), "Invalid account id: {}", + request.getAccountId(), Cause.INVALID_ACCOUNT_ID); + return; + } if (!permissionsValidator.isRpcAllowed(request.getAccountId())) { logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), @@ -756,6 +771,11 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas validationResult.get().getRight(), validationResult.get().getLeft()); return; } + if (!util.isValidUuid(request.getAccountId())) { + logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), "Invalid account id: {}", + request.getAccountId(), Cause.INVALID_ACCOUNT_ID); + return; + } if (!permissionsValidator.isRpcAllowed(request.getAccountId())) { logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), @@ -796,6 +816,11 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas Cause.MISSING_PROFILE_ID); return; } + if (!util.isValidUuid(request.getProfileId())) { + logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), "Invalid profile id: {}", + request.getProfileId(), Cause.INVALID_PROFILE_ID); + return; + } if (request.getAuthenticationProvider().getAuthenticationTypeValue() == 0) { logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), "Missing auth provider type.", @@ -937,8 +962,8 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas @Permitted(role = RoleConstants.USER) public void editContactInfoForAccount(EditContactInfoRequest request, StreamObserver responseObserver) { - logger.info("Removing contact info from account requested."); - logger.debug("Removing contact info from account requested: {}", request); + logger.info("Editing contact info for account requested."); + logger.debug("Editing contact info for account requested: {}", request); Optional> validationResultEditContactInfo = account.validateEditContactInfoRequest( request.getAccountId(), request.getOldContactInfo(), request.getEditedContactInfo()); @@ -948,6 +973,11 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas validationResultEditContactInfo.get().getKey()); return; } + if (!util.isValidUuid(request.getAccountId())) { + logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), "Invalid account id: {}", + request.getAccountId(), Cause.INVALID_ACCOUNT_ID); + return; + } if (!permissionsValidator.isRpcAllowed(request.getAccountId())) { logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), @@ -1030,6 +1060,11 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas validationResultUpdateAuthProvider.get().getKey()); return; } + if (!util.isValidUuid(request.getProfileId())) { + logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), "Invalid profile id: {}.", + request.getProfileId(), validationResultUpdateAuthProvider.get().getKey()); + return; + } List existingAccountsForProfile = accountByProfileIdRepository .findAllByProfileId(UUID.fromString(request.getProfileId())); @@ -1203,6 +1238,8 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas @Permitted(role = RoleConstants.USER) public void updateSearchableOption(UpdateSearchableOptionRequest request, StreamObserver responseObserver) { + logger.info("Updating searchable option for profile {} requested.", request.getProfileId()); + logger.debug("Updating searchable option for profile requested: {}", request); Validation validation = authenticationProvider.validateUpdateSearchableOptionRequest(request.getProfileId(), request.getAuthenticationType(), request.getAuthenticationIdentifier()); @@ -1211,6 +1248,11 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas "", validation.getCause().get()); return; } + if (!util.isValidUuid(request.getProfileId())) { + logAndBuildGrpcStatusResponse(responseObserver, StatusResponse.newBuilder(), "Invalid profile id: {}", + request.getProfileId(), Cause.INVALID_PROFILE_ID); + return; + } List existingAccountsForProfile = accountByProfileIdRepository .findAllByProfileId(UUID.fromString(request.getProfileId())); diff --git a/src/main/java/biz/nynja/account/services/decomposition/AccountCreator.java b/src/main/java/biz/nynja/account/services/decomposition/AccountCreator.java index d4d507d..9123af3 100644 --- a/src/main/java/biz/nynja/account/services/decomposition/AccountCreator.java +++ b/src/main/java/biz/nynja/account/services/decomposition/AccountCreator.java @@ -80,6 +80,17 @@ public class AccountCreator { pendingAccount.setAccountId(UUID.randomUUID()); pendingAccount.setProfileId(UUID.randomUUID()); + if (pendingAccountRepository.findByAccountId(pendingAccount.getAccountId()) != null + || accountRepositoryAdditional.accountIdAlreadyUsed(pendingAccount.getAccountId())) { + logger.error("Can not create pending account. The account id {} is already used.", pendingAccount.getAccountId()); + return CreatePendingAccountResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.INTERNAL_SERVER_ERROR)).build(); + } + if (accountRepositoryAdditional.profileIdAlreadyUsed(pendingAccount.getProfileId())) { + logger.error("Can not create pending account. The profile id {} is already used.", pendingAccount.getProfileId()); + return CreatePendingAccountResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.INTERNAL_SERVER_ERROR)).build(); + } pendingAccount.setCreationTimestamp(Instant.now().toEpochMilli()); try { -- GitLab From 257c116ccc1a5fb08c2d61386deed355230a22d3 Mon Sep 17 00:00:00 2001 From: Stanimir Penkov Date: Wed, 9 Jan 2019 12:19:39 +0200 Subject: [PATCH 21/27] NY-4867: Remove unused method's parameter Signed-off-by: Stanimir Penkov --- .../account/repositories/AccountRepositoryAdditionalImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java index c09021f..79ca704 100644 --- a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java +++ b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java @@ -442,7 +442,7 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio WriteResult wr = null; try { - deleteProfileAccountsWhenDeletingProfile(profileId, batchOperations, existingAccountsForProfile); + deleteProfileAccountsWhenDeletingProfile(batchOperations, existingAccountsForProfile); if (existingProfile.getAuthenticationProviders() != null && existingProfile.getAuthenticationProviders().size() > 0) { deleteAuthenticationProvidersFromProfile(batchOperations, existingProfile.getProfileId(), @@ -461,7 +461,7 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio return Optional.of(Cause.ERROR_DELETING_PROFILE); } - private void deleteProfileAccountsWhenDeletingProfile(UUID profileId, CassandraBatchOperations batchOperations, + private void deleteProfileAccountsWhenDeletingProfile(CassandraBatchOperations batchOperations, List existingAccountsForProfile) { for (AccountByProfileId accountByProfileId : existingAccountsForProfile) { Account existingAccount = accountRepository.findByAccountId(accountByProfileId.getAccountId()); -- GitLab From a142f5bea7260e5974dce510dcb04c81290460b0 Mon Sep 17 00:00:00 2001 From: sergeyPensov Date: Wed, 9 Jan 2019 16:21:17 +0200 Subject: [PATCH 22/27] Fix bridge connection --- .../repositories/AccountRepositoryAdditionalImpl.java | 5 +++-- .../services/erlang/ErlangAccountHttpBridge.java | 4 ++-- .../services/erlang/ErlangAccountMqttBridge.java | 11 +++++++++-- src/main/resources/application-dev.yml | 6 +++--- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java index 1f63209..a8dadef 100644 --- a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java +++ b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java @@ -17,6 +17,7 @@ import java.util.stream.Collectors; import biz.nynja.account.repositories.batch.SagaTransaction; import biz.nynja.account.repositories.batch.Transaction; +import biz.nynja.account.services.erlang.ErlangAccountBridge; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.cassandra.core.CassandraBatchOperations; @@ -72,7 +73,7 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio private final PendingAccountRepository pendingAccountRepository; private final AccountServiceHelper accountServiceHelper; private final Session session; - private final ErlangAccountHttpBridge erlangAccountBridge; + private final ErlangAccountBridge erlangAccountBridge; private final PermissionsValidator permissionsValidator; public AccountRepositoryAdditionalImpl(PendingAccountConfiguration pendingAccountConfiguration, @@ -83,7 +84,7 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio ProfileByAuthenticationProviderRepository profileByAuthenticationProviderRepository, PendingAccountByAuthenticationProviderRepository pendingAccountByAuthenticationProviderRepository, PendingAccountRepository pendingAccountRepository, AccountServiceHelper accountServiceHelper, - Session session, ErlangAccountHttpBridge erlangAccountBridge, PermissionsValidator permissionsValidator, + Session session, ErlangAccountBridge erlangAccountBridge, PermissionsValidator permissionsValidator, AccountDataConfiguration accountDataConfiguration) { this.pendingAccountConfiguration = pendingAccountConfiguration; this.cassandraTemplate = cassandraTemplate; diff --git a/src/main/java/biz/nynja/account/services/erlang/ErlangAccountHttpBridge.java b/src/main/java/biz/nynja/account/services/erlang/ErlangAccountHttpBridge.java index 918a66c..84f6e7e 100644 --- a/src/main/java/biz/nynja/account/services/erlang/ErlangAccountHttpBridge.java +++ b/src/main/java/biz/nynja/account/services/erlang/ErlangAccountHttpBridge.java @@ -45,9 +45,9 @@ public class ErlangAccountHttpBridge implements ErlangAccountBridge { profileURL = null; return; } - accountURL = new URL( + accountURL = new URL("http://" + erlangBridgeConfiguration.getHost() + ":" + erlangBridgeConfiguration.getPort() + "/swm/account"); - profileURL = new URL( + profileURL = new URL("http://" + erlangBridgeConfiguration.getHost() + ":" + erlangBridgeConfiguration.getPort() + "/swm/profile"); } diff --git a/src/main/java/biz/nynja/account/services/erlang/ErlangAccountMqttBridge.java b/src/main/java/biz/nynja/account/services/erlang/ErlangAccountMqttBridge.java index cfaaad4..0bd0d70 100644 --- a/src/main/java/biz/nynja/account/services/erlang/ErlangAccountMqttBridge.java +++ b/src/main/java/biz/nynja/account/services/erlang/ErlangAccountMqttBridge.java @@ -6,9 +6,11 @@ package biz.nynja.account.services.erlang; import java.net.MalformedURLException; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.UUID; import java.util.stream.Collectors; +import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; import biz.nynja.account.configuration.ErlangBridgeConfiguration; @@ -25,6 +27,7 @@ import io.grpc.Metadata; import io.grpc.stub.MetadataUtils; @Component +@Primary public class ErlangAccountMqttBridge implements ErlangAccountBridge { private final ErlangBridgeConfiguration erlangBridgeConfiguration; @@ -88,8 +91,12 @@ public class ErlangAccountMqttBridge implements ErlangAccountBridge { private AccountData buildAccountData(Account account) { return AccountData.newBuilder().setAccountId(account.getAccountId().toString()) .setFirstName(account.getFirstName()).setLastName(account.getLastName()) + .setProfileId(account.getProfileId().toString()) .setUsername(account.getUsername()).setAvatar(account.getAvatar()) - .setLastUpdateTimestamp(account.getLastUpdateTimestamp().toString()).build(); + .setLastUpdateTimestamp( + Objects.isNull(account.getLastUpdateTimestamp()) ? Long.toString(System.currentTimeMillis()) + : account.getLastUpdateTimestamp().toString()) + .build(); } // Erlang protocol @@ -100,7 +107,7 @@ public class ErlangAccountMqttBridge implements ErlangAccountBridge { private AccountBridgeGrpc.AccountBridgeBlockingStub buildGrpcConnection() { ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(erlangBridgeConfiguration.getHost(), - Integer.getInteger(erlangBridgeConfiguration.getPort())).usePlaintext().build(); + Integer.parseInt(erlangBridgeConfiguration.getPort())).usePlaintext().build(); AccountBridgeGrpc.AccountBridgeBlockingStub bridgeServiceBlockingStub = AccountBridgeGrpc .newBlockingStub(managedChannel); return MetadataUtils.attachHeaders(bridgeServiceBlockingStub, getHeaders()); diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 397d75c..aced73b 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -38,9 +38,9 @@ account-data: max-contact-info-of-type: 10 erlang-bridge: - enable: false; - host: - port: + enabled: true + host: localhost + port: 6580 #Metrics related configurations management: -- GitLab From 1569aa7da3d69eca31783adb0ada457e3642c670 Mon Sep 17 00:00:00 2001 From: Dragomir Todorov Date: Wed, 9 Jan 2019 16:42:30 +0200 Subject: [PATCH 23/27] NY-6550, NY-6560: Added validation, fixed small bug --- .../account/grid/ag/AdminServiceImpl.java | 58 +++++++++++++++---- .../nynja/account/grid/ag/AgGridService.java | 2 +- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/src/main/java/biz/nynja/account/grid/ag/AdminServiceImpl.java b/src/main/java/biz/nynja/account/grid/ag/AdminServiceImpl.java index 1c9272e..87fb0fa 100644 --- a/src/main/java/biz/nynja/account/grid/ag/AdminServiceImpl.java +++ b/src/main/java/biz/nynja/account/grid/ag/AdminServiceImpl.java @@ -3,6 +3,7 @@ */ package biz.nynja.account.grid.ag; +import org.apache.commons.lang3.StringUtils; import org.lognet.springboot.grpc.GRpcService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,6 +14,8 @@ import biz.nynja.account.admin.grpc.AccountsCount; import biz.nynja.account.admin.grpc.AdminAccountServiceGrpc; import biz.nynja.account.admin.grpc.CreateAccountRequest; import biz.nynja.account.admin.grpc.EmptyRequest; +import biz.nynja.account.admin.grpc.FilterModel; +import biz.nynja.account.admin.grpc.FilterModel.FilterType; import biz.nynja.account.admin.grpc.GetAllAccountsRequest; import biz.nynja.account.grpc.AccountResponse; import biz.nynja.account.grpc.CompletePendingAccountCreationRequest; @@ -52,10 +55,11 @@ public class AdminServiceImpl extends AdminAccountServiceGrpc.AdminAccountServic logger.info("Getting accounts ..."); logger.debug("Getting accounts: {} ...", request); - Validation validation = validateRowInput(request.getStartRow(), request.getEndRow()); + Validation validation = validateInput(request); if (validation.hasErrors()) { responseObserver.onNext(AccountsAdminResponse.newBuilder().setError(ErrorResponse.newBuilder() - .setCause(validation.getCause().get()).setMessage(validation.getErrorMessage())).build()); + .setCause(validation.getCause().get()).setMessage(validation.getErrors().get(0).getMessage())) + .build()); responseObserver.onCompleted(); return; } @@ -67,18 +71,50 @@ public class AdminServiceImpl extends AdminAccountServiceGrpc.AdminAccountServic responseObserver.onCompleted(); } - private Validation validateRowInput(int startRow, int endRow) { + private Validation validateInput(GetAllAccountsRequest request) { Validation validation = new Validation(); - if (startRow < 1) { - validation.addError(new ValidationError( - "startRow parameter (" + startRow - + ") should be more than 1 and less or equal to endRow parameter (" + endRow + ").", + if (request.getStartRow() < 1) { + validation.addError(new ValidationError("startRow parameter (" + request.getStartRow() + + ") should be more than 1 and less or equal to endRow parameter (" + request.getStartRow() + ").", Cause.ADMIN_INVALID_START_ROW)); - } else if (endRow < startRow || (endRow > accountRepository.count() + 100)) { - validation.addError(new ValidationError("endRow parameter (" + endRow + ") should be more than start row (" - + startRow + ") and less than all users plus maximum pagination of 100." - + (accountRepository.count() + 100), Cause.ADMIN_INVALID_END_ROW)); } + if (request.getEndRow() < request.getStartRow() || (request.getEndRow() > accountRepository.count() + 100)) { + validation.addError( + new ValidationError("endRow parameter (" + request.getEndRow() + ") should be more than start row (" + + request.getStartRow() + ") and less than all users plus maximum pagination of 100." + + (accountRepository.count() + 100), Cause.ADMIN_INVALID_END_ROW)); + } + + for (FilterModel model : request.getFilterModelList()) { + if ("creationTimestamp".equals(model.getColId()) || "lastUpdateTimestamp".equals(model.getColId())) { + try { + Long.valueOf(model.getFilterValue()); + if (!StringUtils.isEmpty(model.getAdditionalFilterValue())) { + Long.valueOf(model.getAdditionalFilterValue()); + + if (Long.valueOf(model.getFilterValue()) > Long.valueOf(model.getAdditionalFilterValue())) { + validation.addError(new ValidationError( + "When filtering by creationTimestamp and lastUpdateTimestamp filter value should be lower than additional filter value.", + Cause.ADMIN_INVALID_FILTER_CRITERIA)); + } + } + } catch (NumberFormatException e) { + validation.addError(new ValidationError( + "When filtering by creationTimestamp and lastUpdateTimestamp filter values should be valid long numbers.", + Cause.ADMIN_INVALID_FILTER_CRITERIA)); + } + + if ((FilterType.EQUALS.equals(model.getFilterType()) + || FilterType.NOTEQUAL.equals(model.getFilterType())) + && (StringUtils.isEmpty(model.getFilterValue()) + || StringUtils.isEmpty(model.getAdditionalFilterValue()))) { + validation.addError(new ValidationError( + "When filtering by creationTimestamp and lastUpdateTimestamp with type of equals or nonequal both values should be present.", + Cause.ADMIN_INVALID_FILTER_CRITERIA)); + } + } + } + return validation; } diff --git a/src/main/java/biz/nynja/account/grid/ag/AgGridService.java b/src/main/java/biz/nynja/account/grid/ag/AgGridService.java index 4d70652..88f2419 100644 --- a/src/main/java/biz/nynja/account/grid/ag/AgGridService.java +++ b/src/main/java/biz/nynja/account/grid/ag/AgGridService.java @@ -167,7 +167,7 @@ public class AgGridService { } else { helper = getFilteredResults(pageable, filterModel); accounts.retainAll(helper.getAccounts().getContent()); - if (count < helper.getCount()) { + if (helper.getCount() < count) { count = helper.getCount(); } } -- GitLab From c095a212bf6b4df2b4aded75a0ead847e8f4e5a0 Mon Sep 17 00:00:00 2001 From: sergeyPensov Date: Thu, 10 Jan 2019 12:22:54 +0200 Subject: [PATCH 24/27] Fix dependencies and properties for dev brunch --- pom.xml | 2 +- src/main/resources/application-dev.yml | 2 +- src/main/resources/application-production.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 4dff9bb..fa3ba37 100644 --- a/pom.xml +++ b/pom.xml @@ -113,7 +113,7 @@ libs-snapshot-local.biz.nynja.protos - bridge-service-ny-5863-bridge-service + bridge-service-intracoldev 1.0-SNAPSHOT diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 86f0ed5..4956ef2 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -41,7 +41,7 @@ profile-data: max-authenticationproviders-per-profile: 20 erlang-bridge: - enabled: true + enabled: false host: localhost port: 6580 diff --git a/src/main/resources/application-production.yml b/src/main/resources/application-production.yml index fb7c565..178b0ec 100644 --- a/src/main/resources/application-production.yml +++ b/src/main/resources/application-production.yml @@ -35,7 +35,7 @@ profile-data: max-authenticationproviders-per-profile: 20 erlang-bridge: - enable: false; + enabled: ${ERLANG_ENABLED:false} ip: ${ERLANG_IP} port: ${ERLANG_PORT} -- GitLab From d791ca07a311d5fe73b9c5b4fb0cbbe1a2315b1a Mon Sep 17 00:00:00 2001 From: sergeyPensov Date: Thu, 10 Jan 2019 12:35:06 +0200 Subject: [PATCH 25/27] delete not important comments --- .../erlang/ErlangAccountMqttBridge.java | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/src/main/java/biz/nynja/account/services/erlang/ErlangAccountMqttBridge.java b/src/main/java/biz/nynja/account/services/erlang/ErlangAccountMqttBridge.java index 0bd0d70..3d0832c 100644 --- a/src/main/java/biz/nynja/account/services/erlang/ErlangAccountMqttBridge.java +++ b/src/main/java/biz/nynja/account/services/erlang/ErlangAccountMqttBridge.java @@ -113,29 +113,6 @@ public class ErlangAccountMqttBridge implements ErlangAccountBridge { return MetadataUtils.attachHeaders(bridgeServiceBlockingStub, getHeaders()); } - /* - * public StatusResponse updateAuthProvider(String profileId, AuthProviderDetails details, SidType sidTypeToRemove, - * String sidToRemove) { - * - * UpdateAuthenticationProviderRequest request = UpdateAuthenticationProviderRequest.newBuilder() - * .setProfileId(profileId) - * .setOldAuthProvider(AuthProviderDetails.newBuilder().setAuthenticationProvider(sidToRemove) - * .setAuthenticationType(AuthenticationType.valueOf(sidTypeToRemove.name()))) .setUpdatedAuthProvider( - * AuthProviderDetails.newBuilder().setAuthenticationProvider(details.getAuthenticationProvider()) - * .setAuthenticationType(details.getAuthenticationType())) .build(); ManagedChannel managedChannel = - * ManagedChannelBuilder.forAddress(accountServiceAddress, accountServicePort) .usePlaintext().build(); - * - * AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc - * .newBlockingStub(managedChannel); - * - * Metadata headers = getHeaders(); accountServiceBlockingStub = - * MetadataUtils.attachHeaders(accountServiceBlockingStub, headers); - * - * StatusResponse response = accountServiceBlockingStub.updateAuthenticationProviderForProfile(request); return - * response; } - * - */ - /** * Attaches the access token to the rpc header * -- GitLab From e7d7ebc41a37725dec91620de2e03854ba19c9b0 Mon Sep 17 00:00:00 2001 From: sergeyPensov Date: Thu, 10 Jan 2019 13:55:10 +0200 Subject: [PATCH 26/27] Change protocol --- .../account/services/erlang/ErlangAccountHttpBridge.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/biz/nynja/account/services/erlang/ErlangAccountHttpBridge.java b/src/main/java/biz/nynja/account/services/erlang/ErlangAccountHttpBridge.java index 84f6e7e..24574f3 100644 --- a/src/main/java/biz/nynja/account/services/erlang/ErlangAccountHttpBridge.java +++ b/src/main/java/biz/nynja/account/services/erlang/ErlangAccountHttpBridge.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2018 Nynja Inc. All rights reserved. + * Copyright (C) 2018 Nynja Inc. All rights reserved. */ package biz.nynja.account.services.erlang; @@ -27,7 +27,7 @@ import biz.nynja.account.services.erlang.connector.HttpClient; // TODO: 11/19/2018 change boolean response when ENC will implement return error part public class ErlangAccountHttpBridge implements ErlangAccountBridge { private static final Logger logger = LoggerFactory.getLogger(ErlangAccountHttpBridge.class); - + private static String PROTOCOL = "https://"; private final JsonParser parser = new JsonParser(); private final ObjectMapper mapper = new ObjectMapper(); @@ -38,6 +38,7 @@ public class ErlangAccountHttpBridge implements ErlangAccountBridge { public ErlangAccountHttpBridge(HttpClient httpClient, ErlangBridgeConfiguration erlangBridgeConfiguration) throws MalformedURLException { + this.httpClient = httpClient; this.erlangBridgeConfiguration = erlangBridgeConfiguration; if (!erlangBridgeConfiguration.isEnabled()) { @@ -45,9 +46,9 @@ public class ErlangAccountHttpBridge implements ErlangAccountBridge { profileURL = null; return; } - accountURL = new URL("http://" + + accountURL = new URL(PROTOCOL + erlangBridgeConfiguration.getHost() + ":" + erlangBridgeConfiguration.getPort() + "/swm/account"); - profileURL = new URL("http://" + + profileURL = new URL(PROTOCOL + erlangBridgeConfiguration.getHost() + ":" + erlangBridgeConfiguration.getPort() + "/swm/profile"); } -- GitLab From 7232b0ebef39d62e4556dad86d51b0b538019c9d Mon Sep 17 00:00:00 2001 From: Filip Nikolov Date: Thu, 10 Jan 2019 17:14:59 +0200 Subject: [PATCH 27/27] Implement JWT token validation. --- .../templates/authentication-policy.yaml | 19 +++++++++++++++++++ .../account-service/templates/deployment.yaml | 8 +++++--- 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 charts/account-service/templates/authentication-policy.yaml diff --git a/charts/account-service/templates/authentication-policy.yaml b/charts/account-service/templates/authentication-policy.yaml new file mode 100644 index 0000000..8fdcf60 --- /dev/null +++ b/charts/account-service/templates/authentication-policy.yaml @@ -0,0 +1,19 @@ +apiVersion: "authentication.istio.io/v1alpha1" +kind: "Policy" +metadata: + name: {{ template "account-service.fullname" . }} + labels: + app: {{ template "account-service.name" . }} + chart: {{ template "account-service.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + targets: + - name: {{ template "account-service.name" . }} + origins: + - jwt: + issuer: https://auth.nynja.biz/ + jwksUri: http://auth-service.auth.svc.cluster.local:8008/keys/public + audiences: + - dGVzdEluc3RhbmNl:NynjaApp:NynjaOrg + principalBinding: USE_ORIGIN diff --git a/charts/account-service/templates/deployment.yaml b/charts/account-service/templates/deployment.yaml index 8a286f6..05a885c 100644 --- a/charts/account-service/templates/deployment.yaml +++ b/charts/account-service/templates/deployment.yaml @@ -42,9 +42,11 @@ spec: periodSeconds: 5 timeoutSeconds: 5 livenessProbe: - httpGet: - path: /actuator/info - port: {{ .Values.ports.containerPort.http }} + exec: + command: + - /bin/sh + - -c + - curl --silent http://localhost:{{ .Values.ports.containerPort.http }}/actuator/info successThreshold: 1 failureThreshold: 10 initialDelaySeconds: 60 -- GitLab