From 921ce10d70c089687745cf3783be8ebabd29421c Mon Sep 17 00:00:00 2001 From: abotev-intracol Date: Wed, 7 Nov 2018 13:51:14 +0200 Subject: [PATCH 01/15] NY-5110 [BE] Fix refresh token responses - add a fix; Signed-off-by: abotev-intracol --- .../nynja/auth/grpc/token/TokenResponse.java | 9 +++++++++ .../token/refresh/RefreshTokenController.java | 10 ++++++++-- .../grpc/token/refresh/RefreshTokenService.java | 17 ++++++++--------- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/main/java/biz/nynja/auth/grpc/token/TokenResponse.java b/src/main/java/biz/nynja/auth/grpc/token/TokenResponse.java index 0bbef97..b8d8bcb 100644 --- a/src/main/java/biz/nynja/auth/grpc/token/TokenResponse.java +++ b/src/main/java/biz/nynja/auth/grpc/token/TokenResponse.java @@ -27,6 +27,7 @@ public class TokenResponse { private String accountId; + private String message; public TokenResponse() { } @@ -79,4 +80,12 @@ public class TokenResponse { this.accountId = accountId; } + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + } diff --git a/src/main/java/biz/nynja/auth/grpc/token/refresh/RefreshTokenController.java b/src/main/java/biz/nynja/auth/grpc/token/refresh/RefreshTokenController.java index d451219..79d04a3 100644 --- a/src/main/java/biz/nynja/auth/grpc/token/refresh/RefreshTokenController.java +++ b/src/main/java/biz/nynja/auth/grpc/token/refresh/RefreshTokenController.java @@ -51,7 +51,11 @@ public class RefreshTokenController { logger.debug("Exchange refresh token for new access token request recieved: {}", refreshToken); Optional decodedToken = refreshTokenService.decodeRefreshToken(refreshToken); - if (decodedToken.isPresent() && refreshTokenService.validateRefreshToken(decodedToken.get())) { + if (!decodedToken.isPresent()) { + throw new IllegalArgumentException("Refresh token is not valid!"); + } + Optional isValid = refreshTokenService.validateRefreshToken(decodedToken.get()); + if (!isValid.isPresent()) { String token = accessTokenService.createAccessToken(decodedToken.get()); TokenResponse tokenResponse = new TokenResponse(); @@ -60,7 +64,9 @@ public class RefreshTokenController { tokenResponse.setExpires_in(tokenConfig.getAccessExpiresIn()); return ResponseEntity.ok(tokenResponse); } else { - throw new IllegalArgumentException("Refresh token is not valid!"); + TokenResponse tokenResponse = new TokenResponse(); + tokenResponse.setMessage(isValid.get()); + return ResponseEntity.ok(tokenResponse); } } } diff --git a/src/main/java/biz/nynja/auth/grpc/token/refresh/RefreshTokenService.java b/src/main/java/biz/nynja/auth/grpc/token/refresh/RefreshTokenService.java index 2347cc8..f38615d 100644 --- a/src/main/java/biz/nynja/auth/grpc/token/refresh/RefreshTokenService.java +++ b/src/main/java/biz/nynja/auth/grpc/token/refresh/RefreshTokenService.java @@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import biz.nynja.account.grpc.AccessStatus; import biz.nynja.account.grpc.AccountResponse; import biz.nynja.auth.grpc.integrations.AccountServiceCommunicator; import biz.nynja.auth.grpc.token.Encryptor; @@ -111,9 +112,7 @@ public class RefreshTokenService { byte[] decryptedData = cipher.doFinal(Base64.getDecoder().decode(encodedData[0])); decryptedToken = new String(decryptedData); - } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException - | InvalidAlgorithmParameterException | UnsupportedEncodingException | IllegalBlockSizeException - | BadPaddingException e) { + } catch (Exception e) { logger.error("Error when decoding refresh token {}.", e.getMessage()); logger.debug("Error when decoding refresh token {}.", e.getCause()); return Optional.empty(); @@ -122,16 +121,16 @@ public class RefreshTokenService { return Optional.of(new JSONObject(decryptedToken)); } - public boolean validateRefreshToken(JSONObject tokenDetails) { + public Optional validateRefreshToken(JSONObject tokenDetails) { logger.debug("Validating refreshToken details: {}", tokenDetails); String accountId = new String(Base64.getDecoder().decode(tokenDetails.getString("sub"))); AccountResponse accountResponse = accountServiceCommunicator.getAccountById(accountId); // TODO Account status is not clear enough. Account should be validated because it could be disabled or deleted. - if (accountResponse.getAccountDetails().getAccessStatus().equals("DISABLED") - || accountResponse.getAccountDetails().getAccessStatus().equals("SUSPENDED")) { + if (accountResponse.getAccountDetails().getAccessStatus().equals(AccessStatus.DISABLED) + || accountResponse.getAccountDetails().getAccessStatus().equals(AccessStatus.SUSPENDED)) { logger.debug("Account by id: {} is disabled", accountId); - return false; + return Optional.of("Account is disabled!"); } if (tokenDetails.getLong("exp") != 0) { @@ -139,9 +138,9 @@ public class RefreshTokenService { Date refreshTokenExpiration = new Date(tokenDetails.getLong("exp")); if (currentTime.after(refreshTokenExpiration)) { logger.debug("Refresh token: {} is expired!", tokenDetails.toString()); - return false; + return Optional.of("Refresh token is expired!"); } } - return true; + return Optional.empty(); } } -- GitLab From bac6b0dddfdf365288dd2755dd2071aea209091e Mon Sep 17 00:00:00 2001 From: Stoyan Tzenkov Date: Wed, 7 Nov 2018 16:15:04 +0200 Subject: [PATCH 02/15] NY-5110 fixed Signed-off-by: Stoyan Tzenkov --- .../services/AuthenticationServiceImpl.java | 39 +++++++++++-------- .../token/refresh/RefreshTokenController.java | 6 ++- .../token/refresh/RefreshTokenService.java | 14 ++++--- 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/main/java/biz/nynja/auth/grpc/services/AuthenticationServiceImpl.java b/src/main/java/biz/nynja/auth/grpc/services/AuthenticationServiceImpl.java index b1332e0..e91b78a 100644 --- a/src/main/java/biz/nynja/auth/grpc/services/AuthenticationServiceImpl.java +++ b/src/main/java/biz/nynja/auth/grpc/services/AuthenticationServiceImpl.java @@ -69,8 +69,9 @@ public class AuthenticationServiceImpl extends AuthenticationServiceGrpc.Authent private RefreshTokenService refreshTokenService; @Autowired - public AuthenticationServiceImpl(AuthTokenService authTokenService, Validator validator, VerifyTokenService verifyTokenService, - VerifyCodeGenerator verifyCodeGenerator, AccountServiceCommunicator accountService, AccessTokenResponseProvider accessTokenResponseProvider, + public AuthenticationServiceImpl(AuthTokenService authTokenService, Validator validator, + VerifyTokenService verifyTokenService, VerifyCodeGenerator verifyCodeGenerator, + AccountServiceCommunicator accountService, AccessTokenResponseProvider accessTokenResponseProvider, AccessTokenService accessTokenService, TokenConfig tokenConfig, RefreshTokenService refreshTokenService) { this.authTokenService = authTokenService; this.validator = validator; @@ -175,8 +176,8 @@ public class AuthenticationServiceImpl extends AuthenticationServiceGrpc.Authent responseObserver.onNext(GenerateAccessTokenResponse.newBuilder().setError(ErrorResponse.newBuilder() .setMessage(e.getMessage()).setCause(Cause.valueOf(e.getCause().getMessage()))).build()); } else { - responseObserver.onNext(GenerateAccessTokenResponse.newBuilder().setError(ErrorResponse.newBuilder() - .setMessage(e.getMessage())).build()); + responseObserver.onNext(GenerateAccessTokenResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setMessage(e.getMessage())).build()); } responseObserver.onCompleted(); return; @@ -197,17 +198,23 @@ public class AuthenticationServiceImpl extends AuthenticationServiceGrpc.Authent logger.debug("Exchange refresh token for new access token request recieved: {}", request.getRefreshToken()); Optional decodedToken = refreshTokenService.decodeRefreshToken(request.getRefreshToken()); - if (decodedToken.isPresent() && refreshTokenService.validateRefreshToken(decodedToken.get())) { - String token = accessTokenService.createAccessToken(decodedToken.get()); - - responseObserver - .onNext(GenerateTokenResponse.newBuilder() - .setTokenResponseDetails(TokenResponseDetails.newBuilder().setToken(token) - .setExp(tokenConfig.getAccessExpiresIn()) - .setResponseTokenType(ResponseTokenType.BEARER).build()) - .build()); - responseObserver.onCompleted(); - return; + Optional> isValid = refreshTokenService.validateRefreshToken(decodedToken.get()); + if (decodedToken.isPresent()) { + if (!isValid.isPresent()) { + String token = accessTokenService.createAccessToken(decodedToken.get()); + + responseObserver.onNext(GenerateTokenResponse.newBuilder() + .setTokenResponseDetails(TokenResponseDetails.newBuilder().setToken(token) + .setExp(tokenConfig.getAccessExpiresIn()).setResponseTokenType(ResponseTokenType.BEARER) + .build()) + .build()); + responseObserver.onCompleted(); + return; + } else { + responseObserver.onNext(GenerateTokenResponse.newBuilder().setError(ErrorResponse.newBuilder() + .setMessage(isValid.get().getLeft()).setCause(isValid.get().getRight())).build()); + responseObserver.onCompleted(); + } } else { responseObserver.onNext(GenerateTokenResponse.newBuilder() .setError(ErrorResponse.newBuilder().setCause(Cause.REFRESH_TOKEN_INVALID)).build()); @@ -228,7 +235,7 @@ public class AuthenticationServiceImpl extends AuthenticationServiceGrpc.Authent accessTokenService.checkFailedDeviceAttemptsCounterAndTimeout(request.getDeviceId()); } logger.debug("Couldn't generate google access token."); - if (e instanceof InternalError ) { + if (e instanceof InternalError) { throw new InternalError(e.getMessage(), new InternalError(e.getCause().getMessage())); } else { throw new InternalError("Couldn't generate google access token."); diff --git a/src/main/java/biz/nynja/auth/grpc/token/refresh/RefreshTokenController.java b/src/main/java/biz/nynja/auth/grpc/token/refresh/RefreshTokenController.java index 79d04a3..d5bc98b 100644 --- a/src/main/java/biz/nynja/auth/grpc/token/refresh/RefreshTokenController.java +++ b/src/main/java/biz/nynja/auth/grpc/token/refresh/RefreshTokenController.java @@ -7,6 +7,7 @@ import static org.springframework.web.bind.annotation.RequestMethod.GET; import java.util.Optional; +import org.apache.commons.lang3.tuple.ImmutablePair; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,6 +21,7 @@ import biz.nynja.auth.grpc.token.TokenConfig; import biz.nynja.auth.grpc.token.TokenResponse; import biz.nynja.auth.grpc.token.access.AccessTokenService; import biz.nynja.authentication.grpc.ResponseTokenType; +import biz.nynja.authentication.grpc.ErrorResponse.Cause; /** * @author Angel.Botev @@ -54,7 +56,7 @@ public class RefreshTokenController { if (!decodedToken.isPresent()) { throw new IllegalArgumentException("Refresh token is not valid!"); } - Optional isValid = refreshTokenService.validateRefreshToken(decodedToken.get()); + Optional> isValid = refreshTokenService.validateRefreshToken(decodedToken.get()); if (!isValid.isPresent()) { String token = accessTokenService.createAccessToken(decodedToken.get()); @@ -65,7 +67,7 @@ public class RefreshTokenController { return ResponseEntity.ok(tokenResponse); } else { TokenResponse tokenResponse = new TokenResponse(); - tokenResponse.setMessage(isValid.get()); + tokenResponse.setMessage(isValid.get().getLeft()); return ResponseEntity.ok(tokenResponse); } } diff --git a/src/main/java/biz/nynja/auth/grpc/token/refresh/RefreshTokenService.java b/src/main/java/biz/nynja/auth/grpc/token/refresh/RefreshTokenService.java index f38615d..bd6f360 100644 --- a/src/main/java/biz/nynja/auth/grpc/token/refresh/RefreshTokenService.java +++ b/src/main/java/biz/nynja/auth/grpc/token/refresh/RefreshTokenService.java @@ -20,6 +20,7 @@ import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; +import org.apache.commons.lang3.tuple.ImmutablePair; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,6 +29,7 @@ import org.springframework.stereotype.Service; import biz.nynja.account.grpc.AccessStatus; import biz.nynja.account.grpc.AccountResponse; +import biz.nynja.account.grpc.ErrorResponse.Cause; import biz.nynja.auth.grpc.integrations.AccountServiceCommunicator; import biz.nynja.auth.grpc.token.Encryptor; import biz.nynja.auth.grpc.token.TokenConfig; @@ -121,16 +123,18 @@ public class RefreshTokenService { return Optional.of(new JSONObject(decryptedToken)); } - public Optional validateRefreshToken(JSONObject tokenDetails) { + public Optional> validateRefreshToken(JSONObject tokenDetails) { logger.debug("Validating refreshToken details: {}", tokenDetails); String accountId = new String(Base64.getDecoder().decode(tokenDetails.getString("sub"))); AccountResponse accountResponse = accountServiceCommunicator.getAccountById(accountId); // TODO Account status is not clear enough. Account should be validated because it could be disabled or deleted. - if (accountResponse.getAccountDetails().getAccessStatus().equals(AccessStatus.DISABLED) - || accountResponse.getAccountDetails().getAccessStatus().equals(AccessStatus.SUSPENDED)) { + if (accountResponse.getAccountDetails().getAccessStatus().equals(AccessStatus.DISABLED)) { logger.debug("Account by id: {} is disabled", accountId); - return Optional.of("Account is disabled!"); + return Optional.of(new ImmutablePair("Account is disabled!", biz.nynja.authentication.grpc.ErrorResponse.Cause.ACCOUNT_DISABLED)); + } else if (accountResponse.getAccountDetails().getAccessStatus().equals(AccessStatus.SUSPENDED)) { + logger.debug("Account by id: {} is suspended", accountId); + return Optional.of(new ImmutablePair("Account is suspended!", biz.nynja.authentication.grpc.ErrorResponse.Cause.ACCOUNT_SUSPENDED)); } if (tokenDetails.getLong("exp") != 0) { @@ -138,7 +142,7 @@ public class RefreshTokenService { Date refreshTokenExpiration = new Date(tokenDetails.getLong("exp")); if (currentTime.after(refreshTokenExpiration)) { logger.debug("Refresh token: {} is expired!", tokenDetails.toString()); - return Optional.of("Refresh token is expired!"); + return Optional.of(new ImmutablePair("Refresh token has expired!", biz.nynja.authentication.grpc.ErrorResponse.Cause.EXPIRED_REFRESH_TOKEN)); } } return Optional.empty(); -- GitLab From 59ca2625ece25238aeabbde2d0bb0b681c41cc21 Mon Sep 17 00:00:00 2001 From: Stanimir Penkov Date: Tue, 6 Nov 2018 14:40:18 +0200 Subject: [PATCH 03/15] NY-4093: Unit Tests for using Email - added unit tests - updated the check for sid type phone Signed-off-by: Stanimir Penkov --- .../token/verify/VerifyTokenController.java | 2 +- .../AuthenticationServiceImplTest.java | 51 +++++++++++++++++++ .../services/VerifyTokenControllerTest.java | 38 ++++++++++++++ 3 files changed, 90 insertions(+), 1 deletion(-) diff --git a/src/main/java/biz/nynja/auth/grpc/token/verify/VerifyTokenController.java b/src/main/java/biz/nynja/auth/grpc/token/verify/VerifyTokenController.java index 88d71e7..6176843 100644 --- a/src/main/java/biz/nynja/auth/grpc/token/verify/VerifyTokenController.java +++ b/src/main/java/biz/nynja/auth/grpc/token/verify/VerifyTokenController.java @@ -70,7 +70,7 @@ public class VerifyTokenController { throw new InternalError("Verify token could not be issued."); } - if (sendVia == null || sendVia.getNumber() == 0) { + if ((sendVia == null || sendVia.getNumber() == 0) && sidType.getNumber() == SidType.PHONE_VALUE) { throw new IllegalArgumentException("send_via parameter should be one of SMS or CALL"); } diff --git a/src/test/java/biz/nynja/auth/grpc/services/AuthenticationServiceImplTest.java b/src/test/java/biz/nynja/auth/grpc/services/AuthenticationServiceImplTest.java index fb10daa..7efa008 100644 --- a/src/test/java/biz/nynja/auth/grpc/services/AuthenticationServiceImplTest.java +++ b/src/test/java/biz/nynja/auth/grpc/services/AuthenticationServiceImplTest.java @@ -62,6 +62,8 @@ public class AuthenticationServiceImplTest extends GrpcServerTestBase { private final static String PHONE = "BG:+359885555555"; private final static String SID = "BG:+359885555555"; + private final static String EMAIL = "test@mytestemail.com"; + private final static String EMAIL_INVALID = "invalidemail@"; private final static String VERIFY_CODE = "111111"; @MockBean @@ -117,6 +119,20 @@ public class AuthenticationServiceImplTest extends GrpcServerTestBase { reply.getError().getCause().equals(Cause.SID_INVALID)); } + @Test + public void testGenerateVerifyTokenSidEmailInvalid() { + final GenerateVerifyTokenRequest request = GenerateVerifyTokenRequest.newBuilder().setSid(EMAIL_INVALID) + .setSidType(SidType.EMAIL).build(); + + final AuthenticationServiceGrpc.AuthenticationServiceBlockingStub authenticationServiceBlockingStub = AuthenticationServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final GenerateTokenResponse reply = authenticationServiceBlockingStub.generateVerifyToken(request); + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.EMAIL_INVALID), + reply.getError().getCause().equals(Cause.EMAIL_INVALID)); + } + @Test public void testGenerateVerifyTokenNullInternalServerError() { final GenerateVerifyTokenRequest request = GenerateVerifyTokenRequest.newBuilder().setSid(SID) @@ -152,6 +168,24 @@ public class AuthenticationServiceImplTest extends GrpcServerTestBase { reply.getTokenResponseDetails().getResponseTokenType().equals(ResponseTokenType.CODE)); } + @Test + public void testGenerateVerifyTokenEmailOK() { + final GenerateVerifyTokenRequest request = GenerateVerifyTokenRequest.newBuilder().setSid(EMAIL) + .setSidType(SidType.EMAIL).setSendVia(SendMethod.IDLE).build(); + + given(verifyCodeGenerator.generateVerifyCode(6)).willReturn(VERIFY_CODE); + given(verifyTokenService.generateVerifyToken(EMAIL, SidType.EMAIL, VERIFY_CODE)).willReturn("VerifyToken"); + given(verifyCodeGenerator.sendVerifyCodeViaEmail(EMAIL, VERIFY_CODE)).willReturn(true); + + final AuthenticationServiceGrpc.AuthenticationServiceBlockingStub authenticationServiceBlockingStub = AuthenticationServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final GenerateTokenResponse reply = authenticationServiceBlockingStub.generateVerifyToken(request); + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain token type '%s'", ResponseTokenType.CODE), + reply.getTokenResponseDetails().getResponseTokenType().equals(ResponseTokenType.CODE)); + } + @Test public void testGenerateVerifyTokenVerifyCodeNotSent() { final GenerateVerifyTokenRequest request = GenerateVerifyTokenRequest.newBuilder().setSid(SID) @@ -205,6 +239,23 @@ public class AuthenticationServiceImplTest extends GrpcServerTestBase { assertNotNull(accessTokenResponse.getAccessTokenResponseDetails().getTokenResponseDetails().getToken()); } + public void testGenerateVerifyTokenVerifyCodeNotSentEmail() { + final GenerateVerifyTokenRequest request = GenerateVerifyTokenRequest.newBuilder().setSid(EMAIL) + .setSidType(SidType.EMAIL).build(); + + given(verifyCodeGenerator.generateVerifyCode(6)).willReturn(VERIFY_CODE); + given(verifyTokenService.generateVerifyToken(EMAIL, SidType.EMAIL, VERIFY_CODE)).willReturn("VerifyToken"); + given(verifyCodeGenerator.sendVerifyCodeViaEmail(EMAIL, VERIFY_CODE)).willReturn(false); + + final AuthenticationServiceGrpc.AuthenticationServiceBlockingStub authenticationServiceBlockingStub = AuthenticationServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final GenerateTokenResponse reply = authenticationServiceBlockingStub.generateVerifyToken(request); + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.INTERNAL_SERVER_ERROR), + reply.getError().getCause().equals(Cause.INTERNAL_SERVER_ERROR)); + } + @Test public void testAccessTokenGenerationWrongCode() { Mockito.when(accessTokenService.retrieveAuthProviderDetails(Mockito.anyString(), Mockito.anyString())) diff --git a/src/test/java/biz/nynja/auth/grpc/services/VerifyTokenControllerTest.java b/src/test/java/biz/nynja/auth/grpc/services/VerifyTokenControllerTest.java index 1a02843..df28ce8 100644 --- a/src/test/java/biz/nynja/auth/grpc/services/VerifyTokenControllerTest.java +++ b/src/test/java/biz/nynja/auth/grpc/services/VerifyTokenControllerTest.java @@ -42,6 +42,8 @@ public class VerifyTokenControllerTest { private final static String PHONE = "BG:+359885555555"; private final static String SID = "BG:+359885555555"; + public static final String EMAIL = "test@mytestemail.com"; + private final static String EMAIL_INVALID = "invalidemail@"; private final static SidType SID_TYPE_PHONE = SidType.PHONE; private final static String SID_INVALID = "incorectSid"; private final static SendMethod SEND_VIA = SendMethod.SMS; @@ -74,6 +76,18 @@ public class VerifyTokenControllerTest { .andExpect(status().isOk()).andExpect(jsonPath("$.token_type", is("CODE"))); } + @Test + public void testGenerateVerifyTokenEmailRestOK() throws Exception { + given(verifyTokenService.setSidType("EMAIL")).willReturn(SidType.EMAIL); + given(verifyTokenService.convertRequestSid(SidType.EMAIL, EMAIL)).willReturn(EMAIL); + given(verifyCodeGenerator.generateVerifyCode(6)).willReturn(VERIFY_CODE); + given(verifyTokenService.generateVerifyToken(EMAIL, SidType.EMAIL, VERIFY_CODE)).willReturn("token"); + given(verifyTokenService.verifyCodeSend(EMAIL, VERIFY_CODE, SidType.EMAIL, SendMethod.IDLE)).willReturn(null); + + mockMvc.perform(get("/tokens?sid=" + EMAIL + "&sid_type=" + SidType.EMAIL)).andExpect(status().isOk()) + .andExpect(jsonPath("$.token_type", is("CODE"))); + } + @Test public void testGenerateVerifyTokenRestVerifyCodeNotSent() throws Exception { given(verifyCodeGenerator.generateVerifyCode(6)).willReturn(VERIFY_CODE); @@ -84,6 +98,16 @@ public class VerifyTokenControllerTest { .andExpect(status().isInternalServerError()); } + @Test + public void testGenerateVerifyTokenRestVerifyCodeNotSentEmail() throws Exception { + given(verifyCodeGenerator.generateVerifyCode(6)).willReturn(VERIFY_CODE); + given(verifyTokenService.generateVerifyToken(EMAIL, SidType.EMAIL, VERIFY_CODE)).willReturn("VerifyToken"); + given(verifyCodeGenerator.sendVerifyCodeViaEmail(EMAIL, VERIFY_CODE)).willReturn(false); + + mockMvc.perform(get("/tokens?sid=" + EMAIL + "&sid_type=" + SidType.EMAIL)) + .andExpect(status().isInternalServerError()); + } + @Test public void testGenerateVerifyTokenRestSidInvalid() throws Exception { given(validator.verifyTokenRequestValidate(SidType.PHONE, SID_INVALID, SEND_VIA)) @@ -98,6 +122,20 @@ public class VerifyTokenControllerTest { .andExpect(status().isBadRequest()); } + @Test + public void testGenerateVerifyTokenRestSidEmailInvalid() throws Exception { + given(validator.verifyTokenRequestValidate(SidType.EMAIL, EMAIL_INVALID, SendMethod.IDLE)) + .willReturn(new ImmutablePair(Cause.EMAIL_INVALID, "Email is invalid!")); + given(verifyTokenService.setSidType("EMAIL")).willReturn(SidType.EMAIL); + given(verifyTokenService.setSendMethod(null)).willReturn(SendMethod.IDLE); + given(verifyTokenService.convertRequestSid(SidType.EMAIL, EMAIL_INVALID)).willReturn(EMAIL_INVALID); + given(verifyCodeGenerator.generateVerifyCode(6)).willReturn(VERIFY_CODE); + given(verifyTokenService.generateVerifyToken(EMAIL, SidType.EMAIL, VERIFY_CODE)).willReturn("token"); + + mockMvc.perform(get("/tokens?sid=" + EMAIL_INVALID + "&sid_type=" + SidType.EMAIL)) + .andExpect(status().isBadRequest()); + } + @Test public void testGenerateVerifyTokenNullInternalServerError() throws Exception { given(verifyCodeGenerator.generateVerifyCode(6)).willReturn(VERIFY_CODE); -- GitLab From 5e04ec9e9cd9b8681e8d2233ef49638ffcdf9a39 Mon Sep 17 00:00:00 2001 From: Dragomir Todorov Date: Wed, 7 Nov 2018 15:42:42 +0200 Subject: [PATCH 04/15] NY-4897: First iteration of admin access token generation --- .../biz/nynja/auth/grpc/key/FileManager.java | 7 +- .../services/AuthenticationServiceImpl.java | 21 ++++++ .../nynja/auth/grpc/token/TokenConfig.java | 12 +++ .../token/access/AccessTokenController.java | 34 +++++++-- .../grpc/token/access/AccessTokenService.java | 74 +++++++++++++++++-- .../models/AdminAccessTokenRequest.java | 23 ++++++ src/main/resources/application-dev.yml | 4 +- src/main/resources/application-production.yml | 2 + 8 files changed, 161 insertions(+), 16 deletions(-) create mode 100644 src/main/java/biz/nynja/auth/grpc/token/access/models/AdminAccessTokenRequest.java diff --git a/src/main/java/biz/nynja/auth/grpc/key/FileManager.java b/src/main/java/biz/nynja/auth/grpc/key/FileManager.java index ef0b746..fc8fddc 100644 --- a/src/main/java/biz/nynja/auth/grpc/key/FileManager.java +++ b/src/main/java/biz/nynja/auth/grpc/key/FileManager.java @@ -169,6 +169,12 @@ public class FileManager { return jwk; } + public JWK retrievePrivateKeyById(String keyId) throws IOException, ParseException { + JWKSet keysSet = loadJWKSetFromFile(new File(keyFolderLocation + "private-keys.json")); + JWK jwk = keysSet.getKeyByKeyId(keyId); + return jwk; + } + public JWK retrieveSecretKeyById(String keyId) throws IOException, ParseException { JWKSet keysSet = loadJWKSetFromFile(new File(keyFolderLocation + "secret-keys.json")); @@ -177,7 +183,6 @@ public class FileManager { return jwk; } - private JWKSet loadJWKSetFromFile(File file) throws IOException, ParseException { logger.debug("Reading keys from file: {}", file.getAbsolutePath()); diff --git a/src/main/java/biz/nynja/auth/grpc/services/AuthenticationServiceImpl.java b/src/main/java/biz/nynja/auth/grpc/services/AuthenticationServiceImpl.java index e91b78a..cdb8989 100644 --- a/src/main/java/biz/nynja/auth/grpc/services/AuthenticationServiceImpl.java +++ b/src/main/java/biz/nynja/auth/grpc/services/AuthenticationServiceImpl.java @@ -31,6 +31,7 @@ import biz.nynja.authentication.grpc.ErrorResponse.Cause; import biz.nynja.authentication.grpc.ExchangeRefreshTokenRequest; import biz.nynja.authentication.grpc.GenerateAccessTokenRequest; import biz.nynja.authentication.grpc.GenerateAccessTokenResponse; +import biz.nynja.authentication.grpc.GenerateAdminAccessTokenRequest; import biz.nynja.authentication.grpc.GenerateAuthTokenRequest; import biz.nynja.authentication.grpc.GenerateTokenResponse; import biz.nynja.authentication.grpc.GenerateVerifyTokenRequest; @@ -293,4 +294,24 @@ public class AuthenticationServiceImpl extends AuthenticationServiceGrpc.Authent } } + @Override + public void generateAdminAccessToken(GenerateAdminAccessTokenRequest request, + StreamObserver responseObserver) { + Optional token = accessTokenService.retrieveAdminAccessToken(request.getToken()); + if (token.isPresent()) { + TokenResponseDetails tokenResponseDetails = TokenResponseDetails.newBuilder().setToken(token.get()) + .setExp(tokenConfig.getAdminAccessExpiresIn()).setResponseTokenType(ResponseTokenType.BEARER) + .build(); + responseObserver + .onNext(GenerateTokenResponse.newBuilder().setTokenResponseDetails(tokenResponseDetails).build()); + responseObserver.onCompleted(); + return; + } else { + responseObserver.onNext(GenerateTokenResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.ACCESS_TOKEN_INVALID_ROLE)).build()); + responseObserver.onCompleted(); + return; + } + } + } diff --git a/src/main/java/biz/nynja/auth/grpc/token/TokenConfig.java b/src/main/java/biz/nynja/auth/grpc/token/TokenConfig.java index 78367ef..0cf9675 100644 --- a/src/main/java/biz/nynja/auth/grpc/token/TokenConfig.java +++ b/src/main/java/biz/nynja/auth/grpc/token/TokenConfig.java @@ -1,3 +1,6 @@ +/** + * Copyright (C) 2018 Nynja Inc. All rights reserved. + */ package biz.nynja.auth.grpc.token; import org.springframework.beans.factory.annotation.Autowired; @@ -29,6 +32,8 @@ public class TokenConfig { private final String accountServiceAddress; private final int accountServicePort; + private final int adminAccessExpiresIn; + private final String appIssuer; private final String appAud; private final String appSub; @@ -57,6 +62,8 @@ public class TokenConfig { .parseInt(env.getRequiredProperty("token.access.failed_device_attempts_timeslot")); this.accessScope = env.getRequiredProperty("token.access.scope"); + this.adminAccessExpiresIn = parseProperty(env, "token.admin.expires_in"); + this.maxFailedAttempts = parseProperty(env, "token.access.max_failed_attempts"); this.failedAttemptsTimeslot = Integer .parseInt(env.getRequiredProperty("token.access.failed_attempts_timeslot")); @@ -174,4 +181,9 @@ public class TokenConfig { public String getRefreshSecretKey() { return refreshSecretKey; } + + public int getAdminAccessExpiresIn() { + return adminAccessExpiresIn; + } + } diff --git a/src/main/java/biz/nynja/auth/grpc/token/access/AccessTokenController.java b/src/main/java/biz/nynja/auth/grpc/token/access/AccessTokenController.java index 27926dd..a16961a 100644 --- a/src/main/java/biz/nynja/auth/grpc/token/access/AccessTokenController.java +++ b/src/main/java/biz/nynja/auth/grpc/token/access/AccessTokenController.java @@ -4,11 +4,10 @@ package biz.nynja.auth.grpc.token.access; import java.io.IOException; +import java.util.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -17,8 +16,10 @@ import org.springframework.web.bind.annotation.RestController; import biz.nynja.account.grpc.ErrorResponse.Cause; import biz.nynja.auth.grpc.social.AccessTokenResponseProvider; +import biz.nynja.auth.grpc.token.TokenConfig; import biz.nynja.auth.grpc.token.TokenResponse; import biz.nynja.auth.grpc.token.access.models.AccessTokenRequestBean; +import biz.nynja.auth.grpc.token.access.models.AdminAccessTokenRequest; /** * @author Angel.Botev @@ -31,14 +32,17 @@ public class AccessTokenController { private final AccessTokenResponseProvider accessTokenResponseProvider; + private final TokenConfig tokenConfig; + + private final AccessTokenService accessTokenService; + public AccessTokenController(AccessTokenService accessTokenService, - AccessTokenResponseProvider accessTokenResponseProvider) { + AccessTokenResponseProvider accessTokenResponseProvider, TokenConfig tokenConfig) { this.accessTokenResponseProvider = accessTokenResponseProvider; + this.tokenConfig = tokenConfig; + this.accessTokenService = accessTokenService; } - @Value("${token.access.expires_in}") - private Integer access_expiration; - @RequestMapping(path = "/tokens/access", method = RequestMethod.POST) public ResponseEntity generateAccessToken(@RequestBody AccessTokenRequestBean request) throws InternalError { @@ -50,4 +54,22 @@ public class AccessTokenController { throw new InternalError(e.getMessage(), new InternalError(Cause.INTERNAL_SERVER_ERROR.toString())); } } + + @RequestMapping(path = "/tokens/access/admin", method = RequestMethod.POST) + public ResponseEntity generateAdminAccessToken(@RequestBody AdminAccessTokenRequest request) + throws InternalError { + + logger.info("Exchange access token for new admin access token request recieved."); + logger.debug("Exchange access token for new admin access token request recieved: {}", request.getToken()); + + Optional newAdminAccessToken = accessTokenService.retrieveAdminAccessToken(request.getToken()); + if (!newAdminAccessToken.isPresent()) { + throw new IllegalArgumentException("The account associated with this account_id doesn't have rights!"); + } + TokenResponse response = new TokenResponse(); + response.setToken(newAdminAccessToken.get()); + response.setExpires_in(tokenConfig.getAdminAccessExpiresIn()); + + return ResponseEntity.ok(response); + } } diff --git a/src/main/java/biz/nynja/auth/grpc/token/access/AccessTokenService.java b/src/main/java/biz/nynja/auth/grpc/token/access/AccessTokenService.java index 17c6cd3..36ab327 100644 --- a/src/main/java/biz/nynja/auth/grpc/token/access/AccessTokenService.java +++ b/src/main/java/biz/nynja/auth/grpc/token/access/AccessTokenService.java @@ -11,8 +11,10 @@ import java.text.ParseException; import java.util.Base64; import java.util.Calendar; import java.util.Date; +import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; @@ -30,12 +32,16 @@ import org.springframework.util.StringUtils; import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.interfaces.DecodedJWT; import com.nimbusds.jose.JOSEException; import com.nimbusds.jose.jwk.ECKey; import com.nimbusds.jose.jwk.JWK; +import biz.nynja.account.grpc.AccountResponse; import biz.nynja.account.grpc.AuthProviderDetails; import biz.nynja.account.grpc.AuthenticationType; +import biz.nynja.account.grpc.Role; +import biz.nynja.auth.grpc.integrations.AccountServiceCommunicator; import biz.nynja.auth.grpc.key.FileManager; import biz.nynja.auth.grpc.security.bruteforce.models.CountDeviceFailedAttempts; import biz.nynja.auth.grpc.security.bruteforce.models.CountPhoneFailedAttempts; @@ -61,16 +67,19 @@ public class AccessTokenService { private Encryptor encryptor; + private AccountServiceCommunicator accountServiceCommunicator; + @Autowired public AccessTokenService(TokenConfig tokenConfig, CountPhoneFailedAttempsRepository countPhoneFailedAttempsRepository, CountDeviceFailedAttempsRepository countDeviceFailedAttempsRepository, FileManager keyFileManager, - Encryptor encryptor) { + Encryptor encryptor, AccountServiceCommunicator accountServiceCommunicator) { this.tokenConfig = tokenConfig; this.countPhoneFailedAttempsRepository = countPhoneFailedAttempsRepository; this.countDeviceFailedAttempsRepository = countDeviceFailedAttempsRepository; this.keyFileManager = keyFileManager; this.encryptor = encryptor; + this.accountServiceCommunicator = accountServiceCommunicator; } /** @@ -142,8 +151,7 @@ public class AccessTokenService { * @throws InternalError */ public String createAccessToken(String instanceId, String appClass, String orgId, String accountId, - Set roles) - throws InternalError { + Set roles) throws InternalError { if (StringUtils.isEmpty(orgId)) { orgId = tokenConfig.getAccessDefaultOrgId(); @@ -170,13 +178,19 @@ public class AccessTokenService { String aud = new StringBuilder(Base64.getEncoder().encodeToString(instanceId.getBytes())).append(":") .append(appClass).append(":").append(orgId).toString(); + String token = buildAccessToken(accountId, roles, ecKey, algorithm, iat, exp, aud); + + logger.info("Access token successfully generated."); + logger.debug("Access token successfully generated: {}.", token); + return token; + } + + private String buildAccessToken(String accountId, Set roles, ECKey ecKey, Algorithm algorithm, Date iat, + Date exp, String aud) { String token = JWT.create().withSubject(Base64.getEncoder().encodeToString(accountId.getBytes())) .withAudience(aud).withClaim("scope", tokenConfig.getAccessScope()).withExpiresAt(exp).withIssuedAt(iat) .withKeyId(ecKey.getKeyID()).withIssuer(tokenConfig.getAccessIssuer()) .withArrayClaim("roles", roles.toArray(new String[0])).sign(algorithm); - - logger.info("Access token successfully generated."); - logger.debug("Access token successfully generated: {}.", token); return token; } @@ -268,7 +282,8 @@ public class AccessTokenService { if ((currentCount >= tokenConfig.getMaxPhoneFailedAttempts()) && (elapsedTime < timeslotAllowed)) { logger.debug("Failed phone attempts counter is over the limit for provider " + sid); - throw new InternalError("Error: Failed phone attempts counter is over the limit for provider " + sid, + throw new InternalError( + "Error: Failed phone attempts counter is over the limit for provider " + sid, new InternalError(Cause.MAX_PHONE_FAILED_ATTEMPTS_REACHED.toString())); } } @@ -325,7 +340,8 @@ public class AccessTokenService { if ((currentCount >= tokenConfig.getMaxDeviceFailedAttempts()) && (elapsedTime < timeslotAllowed)) { logger.debug("Failed device attempts counter is over the limit for device " + deviceId); - throw new InternalError("Error: Failed device attempts counter is over the limit for device " + deviceId, + throw new InternalError( + "Error: Failed device attempts counter is over the limit for device " + deviceId, new InternalError(Cause.MAX_DEVICE_FAILED_ATTEMPTS_REACHED.toString())); } } @@ -366,4 +382,46 @@ public class AccessTokenService { logger.debug("CountDeviceFailedAttempts \"{}\" saved into the DB", savedFailedCount.toString()); } + /** + * Reissues the original token with updated roles field + * + * @param oldToken + * @return + */ + public Optional retrieveAdminAccessToken(String oldToken) { + DecodedJWT decodedToken = JWT.decode(oldToken); + String accountId = new String(Base64.getDecoder().decode(decodedToken.getSubject())); + + AccountResponse accountResponse = accountServiceCommunicator.getAccountById(accountId); + if (accountResponse.getAccountDetails() == null || accountResponse.getAccountDetails().getRolesList().isEmpty() + || (accountResponse.getAccountDetails().getRolesList().size() == 1 + && accountResponse.getAccountDetails().getRolesList().contains(Role.USER))) { + return Optional.empty(); + } + + ECKey ecKey = null; + Algorithm algorithm = null; + + try { + JWK jwk = keyFileManager.retrievePrivateKeyById(decodedToken.getKeyId()); + ecKey = (ECKey) jwk; + algorithm = Algorithm.ECDSA256(ecKey.toECPublicKey(), ecKey.toECPrivateKey()); + } catch (IOException | ParseException | IllegalArgumentException | JOSEException e) { + logger.error("Error when generating access token {}.", e.getMessage()); + logger.debug("Error when generating access token {}.", e.getCause()); + throw new InternalError("AccessToken cannot be created due to encryption algoritm initialization."); + } + + Calendar cal = Calendar.getInstance(); + Date iat = cal.getTime(); + cal.add(Calendar.SECOND, tokenConfig.getAdminAccessExpiresIn()); + Date exp = cal.getTime(); + + String accessToken = buildAccessToken(accountId, accountResponse.getAccountDetails().getRolesList().stream() + .map(n -> n.toString()).collect(Collectors.toSet()), ecKey, algorithm, iat, exp, + decodedToken.getAudience().toString()); + + return Optional.of(accessToken); + } + } diff --git a/src/main/java/biz/nynja/auth/grpc/token/access/models/AdminAccessTokenRequest.java b/src/main/java/biz/nynja/auth/grpc/token/access/models/AdminAccessTokenRequest.java new file mode 100644 index 0000000..c2cfa07 --- /dev/null +++ b/src/main/java/biz/nynja/auth/grpc/token/access/models/AdminAccessTokenRequest.java @@ -0,0 +1,23 @@ +/** + * Copyright (C) 2018 Nynja Inc. All rights reserved. + */ +package biz.nynja.auth.grpc.token.access.models; + +/** + * + * @author dragomir.todorov + * + */ +public class AdminAccessTokenRequest { + + private String token; + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + +} diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 403d804..7dfa972 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -33,6 +33,8 @@ token: failed_device_attempts_timeslot: 1440 max_failed_attempts: 3 failed_attempts_timeslot: 1440 + admin: + expires_in: 28800 #8 hours app: issuer: "https://auth.nynja.biz/" aud: Nynja @@ -70,7 +72,7 @@ amazon: host: email-smtp.us-west-2.amazonaws.com #Amazon SES SMTP host name. For more information: https://docs.aws.amazon.com/ses/latest/DeveloperGuide/regions.html#region-endpoints port: 587 #The port you will connect to on the Amazon SES SMTP endpoint. smtp_username: - smtp_password: + smtp_password: from: noreply@nynja.net template: diff --git a/src/main/resources/application-production.yml b/src/main/resources/application-production.yml index bc72fcc..6c43fcb 100644 --- a/src/main/resources/application-production.yml +++ b/src/main/resources/application-production.yml @@ -41,6 +41,8 @@ token: # To be removed in the future. max_failed_attempts: 1000 failed_attempts_timeslot: 1440 + admin: + expires_in: 28800 #8 hours app: issuer: "https://auth.nynja.biz/" aud: Nynja -- GitLab From 4708150c90341a8b8ed95c13069b8757b1e04620 Mon Sep 17 00:00:00 2001 From: Dragomir Todorov Date: Mon, 5 Nov 2018 12:31:45 +0200 Subject: [PATCH 05/15] NY-4897: Admin access token changes --- .../biz/nynja/auth/grpc/key/FileManager.java | 6 --- .../social/AccessTokenResponseProvider.java | 5 +- .../grpc/token/access/AccessTokenService.java | 47 +++++++------------ 3 files changed, 18 insertions(+), 40 deletions(-) diff --git a/src/main/java/biz/nynja/auth/grpc/key/FileManager.java b/src/main/java/biz/nynja/auth/grpc/key/FileManager.java index fc8fddc..7d1be24 100644 --- a/src/main/java/biz/nynja/auth/grpc/key/FileManager.java +++ b/src/main/java/biz/nynja/auth/grpc/key/FileManager.java @@ -169,12 +169,6 @@ public class FileManager { return jwk; } - public JWK retrievePrivateKeyById(String keyId) throws IOException, ParseException { - JWKSet keysSet = loadJWKSetFromFile(new File(keyFolderLocation + "private-keys.json")); - JWK jwk = keysSet.getKeyByKeyId(keyId); - return jwk; - } - public JWK retrieveSecretKeyById(String keyId) throws IOException, ParseException { JWKSet keysSet = loadJWKSetFromFile(new File(keyFolderLocation + "secret-keys.json")); diff --git a/src/main/java/biz/nynja/auth/grpc/social/AccessTokenResponseProvider.java b/src/main/java/biz/nynja/auth/grpc/social/AccessTokenResponseProvider.java index 3d6baa0..41ff073 100644 --- a/src/main/java/biz/nynja/auth/grpc/social/AccessTokenResponseProvider.java +++ b/src/main/java/biz/nynja/auth/grpc/social/AccessTokenResponseProvider.java @@ -85,9 +85,8 @@ public class AccessTokenResponseProvider { if (isSocialProvider(request.getSidType())) { socialAccessTokenRepository.save(buildSocialAccessToken(detailsBean, accountProperties.getAccountId())); } - String accessToken = accessTokenService.createAccessToken(request.getInstanceId(), - request.getAppClass(), request.getOrgId(), accountProperties.getAccountId(), - accountProperties.getRoles()); + String accessToken = accessTokenService.createAccessToken(request.getInstanceId(), request.getAppClass(), + request.getOrgId(), accountProperties.getAccountId(), accountProperties.getRoles(), false); response.setToken(accessToken); response.setToken_type(ResponseTokenType.BEARER); response.setExpires_in(access_expiration); diff --git a/src/main/java/biz/nynja/auth/grpc/token/access/AccessTokenService.java b/src/main/java/biz/nynja/auth/grpc/token/access/AccessTokenService.java index 36ab327..b4dc9b9 100644 --- a/src/main/java/biz/nynja/auth/grpc/token/access/AccessTokenService.java +++ b/src/main/java/biz/nynja/auth/grpc/token/access/AccessTokenService.java @@ -151,10 +151,9 @@ public class AccessTokenService { * @throws InternalError */ public String createAccessToken(String instanceId, String appClass, String orgId, String accountId, - Set roles) throws InternalError { + Set roles, boolean isAdmin) throws InternalError { if (StringUtils.isEmpty(orgId)) { orgId = tokenConfig.getAccessDefaultOrgId(); - } ECKey ecKey = null; @@ -172,25 +171,23 @@ public class AccessTokenService { Calendar cal = Calendar.getInstance(); Date iat = cal.getTime(); - cal.add(Calendar.SECOND, tokenConfig.getAccessExpiresIn()); + if (isAdmin) { + cal.add(Calendar.SECOND, tokenConfig.getAdminAccessExpiresIn()); + } else { + cal.add(Calendar.SECOND, tokenConfig.getAccessExpiresIn()); + } Date exp = cal.getTime(); String aud = new StringBuilder(Base64.getEncoder().encodeToString(instanceId.getBytes())).append(":") .append(appClass).append(":").append(orgId).toString(); - String token = buildAccessToken(accountId, roles, ecKey, algorithm, iat, exp, aud); - - logger.info("Access token successfully generated."); - logger.debug("Access token successfully generated: {}.", token); - return token; - } - - private String buildAccessToken(String accountId, Set roles, ECKey ecKey, Algorithm algorithm, Date iat, - Date exp, String aud) { String token = JWT.create().withSubject(Base64.getEncoder().encodeToString(accountId.getBytes())) .withAudience(aud).withClaim("scope", tokenConfig.getAccessScope()).withExpiresAt(exp).withIssuedAt(iat) .withKeyId(ecKey.getKeyID()).withIssuer(tokenConfig.getAccessIssuer()) .withArrayClaim("roles", roles.toArray(new String[0])).sign(algorithm); + + logger.info("Access token successfully generated."); + logger.debug("Access token successfully generated: {}.", token); return token; } @@ -399,27 +396,15 @@ public class AccessTokenService { return Optional.empty(); } - ECKey ecKey = null; - Algorithm algorithm = null; + String[] audienceItems = decodedToken.getAudience().get(0).split(":"); - try { - JWK jwk = keyFileManager.retrievePrivateKeyById(decodedToken.getKeyId()); - ecKey = (ECKey) jwk; - algorithm = Algorithm.ECDSA256(ecKey.toECPublicKey(), ecKey.toECPrivateKey()); - } catch (IOException | ParseException | IllegalArgumentException | JOSEException e) { - logger.error("Error when generating access token {}.", e.getMessage()); - logger.debug("Error when generating access token {}.", e.getCause()); - throw new InternalError("AccessToken cannot be created due to encryption algoritm initialization."); - } - - Calendar cal = Calendar.getInstance(); - Date iat = cal.getTime(); - cal.add(Calendar.SECOND, tokenConfig.getAdminAccessExpiresIn()); - Date exp = cal.getTime(); + // Base64 encoded instanceId : appClass : orgId + String instanceId = new String(Base64.getDecoder().decode(audienceItems[0])); + String appClass = audienceItems[1]; + String orgId = audienceItems[2]; - String accessToken = buildAccessToken(accountId, accountResponse.getAccountDetails().getRolesList().stream() - .map(n -> n.toString()).collect(Collectors.toSet()), ecKey, algorithm, iat, exp, - decodedToken.getAudience().toString()); + String accessToken = createAccessToken(instanceId, appClass, orgId, accountId, accountResponse + .getAccountDetails().getRolesList().stream().map(n -> n.toString()).collect(Collectors.toSet()), true); return Optional.of(accessToken); } -- GitLab From 3db9da4663cca3c47fdd9e980aedbaa7ba848fe1 Mon Sep 17 00:00:00 2001 From: Dragomir Todorov Date: Tue, 6 Nov 2018 10:38:01 +0200 Subject: [PATCH 06/15] NY-4897: Removed object as request parameter, instead is a header --- .../token/access/AccessTokenController.java | 9 ++++---- .../models/AdminAccessTokenRequest.java | 23 ------------------- 2 files changed, 4 insertions(+), 28 deletions(-) delete mode 100644 src/main/java/biz/nynja/auth/grpc/token/access/models/AdminAccessTokenRequest.java diff --git a/src/main/java/biz/nynja/auth/grpc/token/access/AccessTokenController.java b/src/main/java/biz/nynja/auth/grpc/token/access/AccessTokenController.java index a16961a..f95f5c8 100644 --- a/src/main/java/biz/nynja/auth/grpc/token/access/AccessTokenController.java +++ b/src/main/java/biz/nynja/auth/grpc/token/access/AccessTokenController.java @@ -10,6 +10,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @@ -19,7 +20,6 @@ import biz.nynja.auth.grpc.social.AccessTokenResponseProvider; import biz.nynja.auth.grpc.token.TokenConfig; import biz.nynja.auth.grpc.token.TokenResponse; import biz.nynja.auth.grpc.token.access.models.AccessTokenRequestBean; -import biz.nynja.auth.grpc.token.access.models.AdminAccessTokenRequest; /** * @author Angel.Botev @@ -56,13 +56,12 @@ public class AccessTokenController { } @RequestMapping(path = "/tokens/access/admin", method = RequestMethod.POST) - public ResponseEntity generateAdminAccessToken(@RequestBody AdminAccessTokenRequest request) - throws InternalError { + public ResponseEntity generateAdminAccessToken(@RequestHeader String token) throws InternalError { logger.info("Exchange access token for new admin access token request recieved."); - logger.debug("Exchange access token for new admin access token request recieved: {}", request.getToken()); + logger.debug("Exchange access token for new admin access token request recieved: {}", token); - Optional newAdminAccessToken = accessTokenService.retrieveAdminAccessToken(request.getToken()); + Optional newAdminAccessToken = accessTokenService.retrieveAdminAccessToken(token); if (!newAdminAccessToken.isPresent()) { throw new IllegalArgumentException("The account associated with this account_id doesn't have rights!"); } diff --git a/src/main/java/biz/nynja/auth/grpc/token/access/models/AdminAccessTokenRequest.java b/src/main/java/biz/nynja/auth/grpc/token/access/models/AdminAccessTokenRequest.java deleted file mode 100644 index c2cfa07..0000000 --- a/src/main/java/biz/nynja/auth/grpc/token/access/models/AdminAccessTokenRequest.java +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (C) 2018 Nynja Inc. All rights reserved. - */ -package biz.nynja.auth.grpc.token.access.models; - -/** - * - * @author dragomir.todorov - * - */ -public class AdminAccessTokenRequest { - - private String token; - - public String getToken() { - return token; - } - - public void setToken(String token) { - this.token = token; - } - -} -- GitLab From 59ec5fc25063e1104aab02b2d5deb360877daec8 Mon Sep 17 00:00:00 2001 From: Dragomir Todorov Date: Tue, 6 Nov 2018 12:54:51 +0200 Subject: [PATCH 07/15] NY-4897: Added global interceptor for access token, fixed a bug --- .../services/AuthenticationServiceImpl.java | 10 ++++- .../AuthenticationServiceConstants.java | 13 +++++++ .../AuthenticationServiceInterceptor.java | 38 +++++++++++++++++++ .../token/access/AccessTokenController.java | 2 + 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 src/main/java/biz/nynja/auth/grpc/services/interceptors/AuthenticationServiceConstants.java create mode 100644 src/main/java/biz/nynja/auth/grpc/services/interceptors/AuthenticationServiceInterceptor.java diff --git a/src/main/java/biz/nynja/auth/grpc/services/AuthenticationServiceImpl.java b/src/main/java/biz/nynja/auth/grpc/services/AuthenticationServiceImpl.java index cdb8989..3ca290e 100644 --- a/src/main/java/biz/nynja/auth/grpc/services/AuthenticationServiceImpl.java +++ b/src/main/java/biz/nynja/auth/grpc/services/AuthenticationServiceImpl.java @@ -6,6 +6,7 @@ package biz.nynja.auth.grpc.services; import java.io.IOException; import java.util.Optional; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.json.JSONObject; import org.lognet.springboot.grpc.GRpcService; @@ -15,6 +16,7 @@ import org.springframework.beans.factory.annotation.Autowired; import biz.nynja.account.grpc.AuthProviderDetails; import biz.nynja.auth.grpc.integrations.AccountServiceCommunicator; +import biz.nynja.auth.grpc.services.interceptors.AuthenticationServiceConstants; import biz.nynja.auth.grpc.social.AccessTokenResponseProvider; import biz.nynja.auth.grpc.token.GrpcObjectBuilder; import biz.nynja.auth.grpc.token.TokenConfig; @@ -297,7 +299,13 @@ public class AuthenticationServiceImpl extends AuthenticationServiceGrpc.Authent @Override public void generateAdminAccessToken(GenerateAdminAccessTokenRequest request, StreamObserver responseObserver) { - Optional token = accessTokenService.retrieveAdminAccessToken(request.getToken()); + + String accessToken = AuthenticationServiceConstants.ACCESS_TOKEN_CTX.get(); + if (StringUtils.isEmpty(accessToken)) { + accessToken = request.getToken(); + } + + Optional token = accessTokenService.retrieveAdminAccessToken(accessToken); if (token.isPresent()) { TokenResponseDetails tokenResponseDetails = TokenResponseDetails.newBuilder().setToken(token.get()) .setExp(tokenConfig.getAdminAccessExpiresIn()).setResponseTokenType(ResponseTokenType.BEARER) diff --git a/src/main/java/biz/nynja/auth/grpc/services/interceptors/AuthenticationServiceConstants.java b/src/main/java/biz/nynja/auth/grpc/services/interceptors/AuthenticationServiceConstants.java new file mode 100644 index 0000000..80fa178 --- /dev/null +++ b/src/main/java/biz/nynja/auth/grpc/services/interceptors/AuthenticationServiceConstants.java @@ -0,0 +1,13 @@ +package biz.nynja.auth.grpc.services.interceptors; + +import static io.grpc.Metadata.ASCII_STRING_MARSHALLER; + +import io.grpc.Context; +import io.grpc.Metadata; + +public class AuthenticationServiceConstants { + + 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/java/biz/nynja/auth/grpc/services/interceptors/AuthenticationServiceInterceptor.java b/src/main/java/biz/nynja/auth/grpc/services/interceptors/AuthenticationServiceInterceptor.java new file mode 100644 index 0000000..7b0423e --- /dev/null +++ b/src/main/java/biz/nynja/auth/grpc/services/interceptors/AuthenticationServiceInterceptor.java @@ -0,0 +1,38 @@ +package biz.nynja.auth.grpc.services.interceptors; + +import org.lognet.springboot.grpc.GRpcGlobalInterceptor; + +import io.grpc.Context; +import io.grpc.Contexts; +import io.grpc.Metadata; +import io.grpc.ServerCall; +import io.grpc.ServerCallHandler; +import io.grpc.ServerInterceptor; + +@GRpcGlobalInterceptor +public class AuthenticationServiceInterceptor implements ServerInterceptor { + // This should be returned if there is an error in the request to stop from going in + // private static final ServerCall.Listener NOOP_LISTENER = new ServerCall.Listener() { + // }; + + @Override + public ServerCall.Listener interceptCall(ServerCall serverCall, Metadata metadata, + ServerCallHandler serverCallHandler) { + String accessToken = metadata.get(AuthenticationServiceConstants.ACCESS_TOKEN_METADATA); + Context ctx = Context.current().withValue(AuthenticationServiceConstants.ACCESS_TOKEN_CTX, accessToken); + return Contexts.interceptCall(ctx, serverCall, metadata, serverCallHandler); + } + + /* + * public void oldMethod { + * + * // if (jwt == null) { // + * serverCall.close(Status.UNAUTHENTICATED.withDescription("JWT Token is missing from Metadata"), metadata); // + * return NOOP_LISTENER; // } // // Context ctx; // try { // Map verified = verifier.verify(jwt); // + * ctx = Context.current().withValue(Constant.USER_ID_CTX_KEY, verified.getOrDefault("sub", // + * "anonymous").toString()) // .withValue(Constant.JWT_CTX_KEY, jwt); // } catch (Exception e) { // + * System.out.println("Verification failed - Unauthenticated!"); // + * serverCall.close(Status.UNAUTHENTICATED.withDescription(e.getMessage()).withCause(e), metadata); // return + * NOOP_LISTENER; // } } + */ +} diff --git a/src/main/java/biz/nynja/auth/grpc/token/access/AccessTokenController.java b/src/main/java/biz/nynja/auth/grpc/token/access/AccessTokenController.java index f95f5c8..17f3d82 100644 --- a/src/main/java/biz/nynja/auth/grpc/token/access/AccessTokenController.java +++ b/src/main/java/biz/nynja/auth/grpc/token/access/AccessTokenController.java @@ -20,6 +20,7 @@ import biz.nynja.auth.grpc.social.AccessTokenResponseProvider; import biz.nynja.auth.grpc.token.TokenConfig; import biz.nynja.auth.grpc.token.TokenResponse; import biz.nynja.auth.grpc.token.access.models.AccessTokenRequestBean; +import biz.nynja.authentication.grpc.ResponseTokenType; /** * @author Angel.Botev @@ -68,6 +69,7 @@ public class AccessTokenController { TokenResponse response = new TokenResponse(); response.setToken(newAdminAccessToken.get()); response.setExpires_in(tokenConfig.getAdminAccessExpiresIn()); + response.setToken_type(ResponseTokenType.BEARER); return ResponseEntity.ok(response); } -- GitLab From 996a0dafdfead42d4171c6f63aecdee0580b7a5a Mon Sep 17 00:00:00 2001 From: Dragomir Todorov Date: Tue, 6 Nov 2018 15:11:53 +0200 Subject: [PATCH 08/15] NY-4897: Changed the request parameter to an empty one --- .../auth/grpc/services/AuthenticationServiceImpl.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/main/java/biz/nynja/auth/grpc/services/AuthenticationServiceImpl.java b/src/main/java/biz/nynja/auth/grpc/services/AuthenticationServiceImpl.java index 3ca290e..f53914c 100644 --- a/src/main/java/biz/nynja/auth/grpc/services/AuthenticationServiceImpl.java +++ b/src/main/java/biz/nynja/auth/grpc/services/AuthenticationServiceImpl.java @@ -6,7 +6,6 @@ package biz.nynja.auth.grpc.services; import java.io.IOException; import java.util.Optional; -import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.json.JSONObject; import org.lognet.springboot.grpc.GRpcService; @@ -28,12 +27,12 @@ import biz.nynja.auth.grpc.token.refresh.RefreshTokenService; import biz.nynja.auth.grpc.token.verify.VerifyCodeGenerator; import biz.nynja.auth.grpc.token.verify.VerifyTokenService; import biz.nynja.authentication.grpc.AuthenticationServiceGrpc; +import biz.nynja.authentication.grpc.EmptyRequest; import biz.nynja.authentication.grpc.ErrorResponse; import biz.nynja.authentication.grpc.ErrorResponse.Cause; import biz.nynja.authentication.grpc.ExchangeRefreshTokenRequest; import biz.nynja.authentication.grpc.GenerateAccessTokenRequest; import biz.nynja.authentication.grpc.GenerateAccessTokenResponse; -import biz.nynja.authentication.grpc.GenerateAdminAccessTokenRequest; import biz.nynja.authentication.grpc.GenerateAuthTokenRequest; import biz.nynja.authentication.grpc.GenerateTokenResponse; import biz.nynja.authentication.grpc.GenerateVerifyTokenRequest; @@ -297,13 +296,9 @@ public class AuthenticationServiceImpl extends AuthenticationServiceGrpc.Authent } @Override - public void generateAdminAccessToken(GenerateAdminAccessTokenRequest request, - StreamObserver responseObserver) { + public void generateAdminAccessToken(EmptyRequest request, StreamObserver responseObserver) { String accessToken = AuthenticationServiceConstants.ACCESS_TOKEN_CTX.get(); - if (StringUtils.isEmpty(accessToken)) { - accessToken = request.getToken(); - } Optional token = accessTokenService.retrieveAdminAccessToken(accessToken); if (token.isPresent()) { -- GitLab From ca03ac38964df678ceaab6a1751bec8a14b2f6c8 Mon Sep 17 00:00:00 2001 From: Dragomir Todorov Date: Wed, 7 Nov 2018 15:45:53 +0200 Subject: [PATCH 09/15] NY-4897: Added a comment for interceptor --- .../interceptors/AuthenticationServiceInterceptor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/biz/nynja/auth/grpc/services/interceptors/AuthenticationServiceInterceptor.java b/src/main/java/biz/nynja/auth/grpc/services/interceptors/AuthenticationServiceInterceptor.java index 7b0423e..746a81a 100644 --- a/src/main/java/biz/nynja/auth/grpc/services/interceptors/AuthenticationServiceInterceptor.java +++ b/src/main/java/biz/nynja/auth/grpc/services/interceptors/AuthenticationServiceInterceptor.java @@ -24,7 +24,8 @@ public class AuthenticationServiceInterceptor implements ServerInterceptor { } /* - * public void oldMethod { + * We could use a method like this to read some variables from JWT token if we need to like roles and so on public + * void jwtCheckMethod() { * * // if (jwt == null) { // * serverCall.close(Status.UNAUTHENTICATED.withDescription("JWT Token is missing from Metadata"), metadata); // -- GitLab From 547c6d9d7d60858ea226757441347cf16b5f44f0 Mon Sep 17 00:00:00 2001 From: Filip Nikolov Date: Thu, 8 Nov 2018 10:13:34 +0200 Subject: [PATCH 10/15] CORS policy update --- releases/dev/auth-service.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/releases/dev/auth-service.yaml b/releases/dev/auth-service.yaml index 8f32e33..1450b23 100644 --- a/releases/dev/auth-service.yaml +++ b/releases/dev/auth-service.yaml @@ -86,6 +86,8 @@ spec: corsPolicy: allowOrigin: - http://localhost:3000 + - http://localhost + - http://localhost/grpc/ - https://localhost - https://localhost/grpc/ - http://10.191.224.180:3000 -- GitLab From 17be46dcb847e6f6cd7a5be789fcd06b6c2232b7 Mon Sep 17 00:00:00 2001 From: Filip Nikolov Date: Thu, 8 Nov 2018 11:17:47 +0200 Subject: [PATCH 11/15] NY-4391 turn on unit tests. --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 4588926..b2b219a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -64,7 +64,7 @@ pipeline { steps { container('mvn') { withCredentials([file(credentialsId: 'mavenSettings.xml', variable: 'FILE')]) { - sh 'mvn --settings $FILE clean install -DskipTests' + sh 'mvn --settings $FILE clean install' } dockerBuildAndPushToRegistry "${NAMESPACE}/${APP_NAME}", [IMAGE_BUILD_TAG] } -- GitLab From 9b2248445bc137e9e1704f0f80decbfdeb6ba187 Mon Sep 17 00:00:00 2001 From: Filip Nikolov Date: Thu, 8 Nov 2018 15:23:28 +0200 Subject: [PATCH 12/15] Dockerfile cleanup. --- Dockerfile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 189dbc5..0ec2cac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,9 +18,7 @@ ENV ACCOUNT_SERVICE_GRPC_PORT=6565 # Install curl for use with Kubernetes readiness probe. RUN apt-get update && apt-get install -y \ curl \ - #Temporay install telnet for troubleshooting purpuses. - telnet #\ -# && rm -rf /var/lib/apt/lists/* + && rm -rf /var/lib/apt/lists/* # Expose Tomcat and gRPC server ports EXPOSE $HTTP_SERVER_PORT -- GitLab From 8351a03770b8cf5dd15e2c52c4f4f07803a906d9 Mon Sep 17 00:00:00 2001 From: Filip Nikolov Date: Thu, 8 Nov 2018 15:25:20 +0200 Subject: [PATCH 13/15] Remove curl verbose mode --- charts/auth-service/templates/deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/auth-service/templates/deployment.yaml b/charts/auth-service/templates/deployment.yaml index 6328137..0eca9d5 100644 --- a/charts/auth-service/templates/deployment.yaml +++ b/charts/auth-service/templates/deployment.yaml @@ -35,7 +35,7 @@ spec: command: - /bin/sh - -c - - "curl -v --silent http://localhost:$HTTP_SERVER_PORT/actuator/health 2>&1 | grep UP || exit 1" + - "curl --silent http://localhost:$HTTP_SERVER_PORT/actuator/health 2>&1 | grep UP || exit 1" successThreshold: 1 failureThreshold: 10 initialDelaySeconds: 60 -- GitLab From c67ce954500551c6246a7f771a732da36157ffb2 Mon Sep 17 00:00:00 2001 From: Filip Nikolov Date: Thu, 8 Nov 2018 16:00:30 +0200 Subject: [PATCH 14/15] Turn off unit tests and add CORS header. --- Jenkinsfile | 6 +++--- releases/dev/auth-service.yaml | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index b2b219a..2a663dd 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -64,7 +64,7 @@ pipeline { steps { container('mvn') { withCredentials([file(credentialsId: 'mavenSettings.xml', variable: 'FILE')]) { - sh 'mvn --settings $FILE clean install' + sh 'mvn --settings $FILE clean install -DskipTests' } dockerBuildAndPushToRegistry "${NAMESPACE}/${APP_NAME}", [IMAGE_BUILD_TAG] } @@ -117,7 +117,7 @@ pipeline { stage("Approval: Deploy to staging ?") { steps { slackSend channel: SLACK_CHANNEL, message: "$APP_NAME: build #$BUILD_NUMBER ready to deploy to `STAGING`, approval required: $BUILD_URL (24h)" - + timeout(time: 24, unit: 'HOURS') { input 'Deploy to staging ?' } } post { failure { echo 'Deploy aborted for build #...' }} @@ -131,7 +131,7 @@ pipeline { stage("Approval: Deploy to production ?") { steps { slackSend channel: SLACK_CHANNEL, message: "$APP_NAME: build #$BUILD_NUMBER ready to deploy to `PRODUCTION`, approval required: $BUILD_URL (24h)" - + timeout(time: 7, unit: 'DAYS') { input 'Deploy to production ?' } } post { failure { echo 'Deploy aborted for build #...' }} diff --git a/releases/dev/auth-service.yaml b/releases/dev/auth-service.yaml index 1450b23..0b402ed 100644 --- a/releases/dev/auth-service.yaml +++ b/releases/dev/auth-service.yaml @@ -106,4 +106,5 @@ spec: - content-type - x-grpc-web - authorization + - accessToken # To delete after 15 Nov. For reference abotev. maxAge: "600s" -- GitLab From c63855c122b2376a7672ad3219f7ccce25ae8964 Mon Sep 17 00:00:00 2001 From: Stoyan Tzenkov Date: Fri, 9 Nov 2018 10:15:25 +0200 Subject: [PATCH 15/15] NY-5110: All related Causes moved to auth.proto Signed-off-by: Stoyan Tzenkov --- .../auth/grpc/token/refresh/RefreshTokenService.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/biz/nynja/auth/grpc/token/refresh/RefreshTokenService.java b/src/main/java/biz/nynja/auth/grpc/token/refresh/RefreshTokenService.java index bd6f360..d16ed73 100644 --- a/src/main/java/biz/nynja/auth/grpc/token/refresh/RefreshTokenService.java +++ b/src/main/java/biz/nynja/auth/grpc/token/refresh/RefreshTokenService.java @@ -29,7 +29,7 @@ import org.springframework.stereotype.Service; import biz.nynja.account.grpc.AccessStatus; import biz.nynja.account.grpc.AccountResponse; -import biz.nynja.account.grpc.ErrorResponse.Cause; +import biz.nynja.authentication.grpc.ErrorResponse.Cause; import biz.nynja.auth.grpc.integrations.AccountServiceCommunicator; import biz.nynja.auth.grpc.token.Encryptor; import biz.nynja.auth.grpc.token.TokenConfig; @@ -123,7 +123,7 @@ public class RefreshTokenService { return Optional.of(new JSONObject(decryptedToken)); } - public Optional> validateRefreshToken(JSONObject tokenDetails) { + public Optional> validateRefreshToken(JSONObject tokenDetails) { logger.debug("Validating refreshToken details: {}", tokenDetails); String accountId = new String(Base64.getDecoder().decode(tokenDetails.getString("sub"))); @@ -131,10 +131,10 @@ public class RefreshTokenService { // TODO Account status is not clear enough. Account should be validated because it could be disabled or deleted. if (accountResponse.getAccountDetails().getAccessStatus().equals(AccessStatus.DISABLED)) { logger.debug("Account by id: {} is disabled", accountId); - return Optional.of(new ImmutablePair("Account is disabled!", biz.nynja.authentication.grpc.ErrorResponse.Cause.ACCOUNT_DISABLED)); + return Optional.of(new ImmutablePair("Account is disabled!", Cause.ACCESS_DISABLED)); } else if (accountResponse.getAccountDetails().getAccessStatus().equals(AccessStatus.SUSPENDED)) { logger.debug("Account by id: {} is suspended", accountId); - return Optional.of(new ImmutablePair("Account is suspended!", biz.nynja.authentication.grpc.ErrorResponse.Cause.ACCOUNT_SUSPENDED)); + return Optional.of(new ImmutablePair("Account is suspended!", Cause.ACCESS_SUSPENDED)); } if (tokenDetails.getLong("exp") != 0) { @@ -142,7 +142,7 @@ public class RefreshTokenService { Date refreshTokenExpiration = new Date(tokenDetails.getLong("exp")); if (currentTime.after(refreshTokenExpiration)) { logger.debug("Refresh token: {} is expired!", tokenDetails.toString()); - return Optional.of(new ImmutablePair("Refresh token has expired!", biz.nynja.authentication.grpc.ErrorResponse.Cause.EXPIRED_REFRESH_TOKEN)); + return Optional.of(new ImmutablePair("Refresh token has expired!", Cause.EXPIRED_REFRESH_TOKEN)); } } return Optional.empty(); -- GitLab