From 13154c15dce58db53da924998cf96aea61f68ad0 Mon Sep 17 00:00:00 2001 From: Stoyan Tzenkov Date: Wed, 23 Jan 2019 19:45:26 +0200 Subject: [PATCH] NY-6797: Turned permissions on. Signed-off-by: Stoyan Tzenkov --- .../permissions/PermissionsInterceptor.java | 80 ++++++++++--------- .../permissions/PermissionsValidator.java | 43 +++++----- .../account/services/AccountServiceTests.java | 6 +- 3 files changed, 67 insertions(+), 62 deletions(-) diff --git a/src/main/java/biz/nynja/account/permissions/PermissionsInterceptor.java b/src/main/java/biz/nynja/account/permissions/PermissionsInterceptor.java index 0a6a6f5..807dd02 100644 --- a/src/main/java/biz/nynja/account/permissions/PermissionsInterceptor.java +++ b/src/main/java/biz/nynja/account/permissions/PermissionsInterceptor.java @@ -15,6 +15,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import com.auth0.jwt.JWT; import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.DecodedJWT; @@ -22,6 +23,7 @@ import biz.nynja.account.accesspoints.AccessPoint; import biz.nynja.account.accesspoints.AccessPointService; import biz.nynja.account.services.AccountServiceImpl; import io.grpc.Context; +import io.grpc.Contexts; import io.grpc.Metadata; import io.grpc.ServerCall; import io.grpc.ServerCallHandler; @@ -64,50 +66,50 @@ public class PermissionsInterceptor implements ServerInterceptor { // WARNING: THe line bellow is to be removed and code following uncommented // when Istio starts sending an access token with each and every request - return next.startCall(call, headers); + // return next.startCall(call, headers); /* * Expected metadata is "Authorization" : "Bearer --accessTokenValue--" so we can skip validation as istio won't * allow this request through */ -// String accessToken = (headers.get(ACCESS_TOKEN_METADATA).split(" "))[1]; -// String rpc = getRpcName(call); -// -// boolean permitted = false; -// Context ctx = null; -// String[] requestingRoles = null; -// -// if (accessToken == null && accessToken.isEmpty()) { -// permissionDenied(call, headers, "Permission denied for rpc {}. Access token not in headers", rpc ); -// } -// ctx = Context.current().withValue(ACCESS_TOKEN_CTX, accessToken); -// DecodedJWT decodedToken = JWT.decode(accessToken); -// -// if (!accessPointAvailable(accessToken, decodedToken, rpc)) { -// permissionDenied(call, headers, "Permission denied for rpc {}. No access point available for this account and access token.", rpc ); -// } -// -// requestingRoles = getRolesFromAccessToken(decodedToken); -// if (requestingRoles == null) { -// permissionDenied(call, headers, "Permission denied for rpc {}. No roles found for requesting account in access token.", rpc ); -// } -// -// Method method = getMethod(rpc); -// if (method == null) { -// permissionDenied(call, headers, "Permission denied for rpc {}. Could not identify the method implementing this rpc.", rpc ); -// } -// -// Permitted[] permittedRoles = method.getAnnotationsByType(Permitted.class); -// permitted = checkPermissions(requestingRoles, permittedRoles); -// if (permitted) { -// logger.info("Permission granted to rpc {}.", rpc); -// return Contexts.interceptCall(ctx, call, headers, next); -// } else { -// logger.error("Permission denied for rpc {}, roles {}.", rpc, requestingRoles); -// call.close(Status.PERMISSION_DENIED.withDescription("An unauthorized call was made to " + rpc + "."), -// headers); -// return NOOP_LISTENER; -// } + String accessToken = (headers.get(ACCESS_TOKEN_METADATA).split(" "))[1]; + String rpc = getRpcName(call); + + boolean permitted = false; + Context ctx = null; + String[] requestingRoles = null; + + if (accessToken == null && accessToken.isEmpty()) { + permissionDenied(call, headers, "Permission denied for rpc {}. Access token not in headers", rpc ); + } + ctx = Context.current().withValue(ACCESS_TOKEN_CTX, accessToken); + DecodedJWT decodedToken = JWT.decode(accessToken); + + if (!accessPointAvailable(accessToken, decodedToken, rpc)) { + permissionDenied(call, headers, "Permission denied for rpc {}. No access point available for this account and access token.", rpc ); + } + + requestingRoles = getRolesFromAccessToken(decodedToken); + if (requestingRoles == null) { + permissionDenied(call, headers, "Permission denied for rpc {}. No roles found for requesting account in access token.", rpc ); + } + + Method method = getMethod(rpc); + if (method == null) { + permissionDenied(call, headers, "Permission denied for rpc {}. Could not identify the method implementing this rpc.", rpc ); + } + + Permitted[] permittedRoles = method.getAnnotationsByType(Permitted.class); + permitted = checkPermissions(requestingRoles, permittedRoles); + if (permitted) { + logger.info("Permission granted to rpc {}.", rpc); + return Contexts.interceptCall(ctx, call, headers, next); + } else { + logger.error("Permission denied for rpc {}, roles {}.", rpc, requestingRoles); + call.close(Status.PERMISSION_DENIED.withDescription("An unauthorized call was made to " + rpc + "."), + headers); + return NOOP_LISTENER; + } } private String getRpcName(ServerCall call) { diff --git a/src/main/java/biz/nynja/account/permissions/PermissionsValidator.java b/src/main/java/biz/nynja/account/permissions/PermissionsValidator.java index 7b45164..44edf68 100644 --- a/src/main/java/biz/nynja/account/permissions/PermissionsValidator.java +++ b/src/main/java/biz/nynja/account/permissions/PermissionsValidator.java @@ -3,6 +3,7 @@ */ package biz.nynja.account.permissions; +import java.util.Base64; import java.util.List; import org.apache.commons.lang3.StringUtils; @@ -21,15 +22,15 @@ public class PermissionsValidator { // WARNING: THe line bellow is to be removed and code following uncommented // when Istio starts sending an access token with each and every request - return true; - -// DecodedJWT decodedToken = retrieveDecodedToken(); -// String requestingAccountId = new String(Base64.getDecoder().decode(decodedToken.getSubject())); -// -// if (requestingAccountId.equals(accountId)) { -// return true; -// } -// return isAuthorizedRequestingRole(decodedToken); + // return true; + + DecodedJWT decodedToken = retrieveDecodedToken(); + String requestingAccountId = new String(Base64.getDecoder().decode(decodedToken.getSubject())); + + if (requestingAccountId.equals(accountId)) { + return true; + } + return isAuthorizedRequestingRole(decodedToken); } private DecodedJWT retrieveDecodedToken() { @@ -46,18 +47,18 @@ public class PermissionsValidator { // WARNING: The line bellow is to be removed and code following uncommented // when Istio starts sending an access token with each and every request - return true; - -// String accessToken = (String) PermissionsInterceptor.ACCESS_TOKEN_CTX.get(); -// DecodedJWT decodedToken = JWT.decode(accessToken); -// String requestingAccountId = new String(Base64.getDecoder().decode(decodedToken.getSubject())); -// -// for (AccountByProfileId account : existingAccountsForProfile) { -// if (requestingAccountId.equals(account.getAccountId().toString())) { -// return true; -// } -// } -// return isAuthorizedRequestingRole(decodedToken); + // return true; + + String accessToken = (String) PermissionsInterceptor.ACCESS_TOKEN_CTX.get(); + DecodedJWT decodedToken = JWT.decode(accessToken); + String requestingAccountId = new String(Base64.getDecoder().decode(decodedToken.getSubject())); + + for (AccountByProfileId account : existingAccountsForProfile) { + if (requestingAccountId.equals(account.getAccountId().toString())) { + return true; + } + } + return isAuthorizedRequestingRole(decodedToken); } private static boolean isAuthorizedRequestingRole(DecodedJWT decodedToken) { diff --git a/src/test/java/biz/nynja/account/services/AccountServiceTests.java b/src/test/java/biz/nynja/account/services/AccountServiceTests.java index 9526411..6bd124f 100644 --- a/src/test/java/biz/nynja/account/services/AccountServiceTests.java +++ b/src/test/java/biz/nynja/account/services/AccountServiceTests.java @@ -13,6 +13,7 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; @@ -242,7 +243,7 @@ public class AccountServiceTests extends GrpcServerTestBase { public void setupTest() { AccessPoint accessPoint = new AccessPoint(); String accountId = "0994566e-ac7b-45b2-b6ef-36440e44a15a"; - String adminAccessToken = "eyJraWQiOiIyMDE4MTEzMCIsInR5cCI6IkpXVCIsImFsZyI6IkVTMjU2In0.eyJzdWIiOiJNRGs1TkRVMk5tVXRZV00zWWkwME5XSXlMV0kyWldZdE16WTBOREJsTkRSaE1UVmgiLCJhdWQiOiJibmx1YW1FPTpueW5qYTpueW5qYSIsInNjb3BlIjoiYWNjZXNzIiwicm9sZXMiOlsiQURNSU4iLCJVU0VSIl0sImlzcyI6Imh0dHBzOi8vYXV0aC5ueW5qYS5iaXovIiwiZXhwIjoxNTQ1MTQzNTY0LCJpYXQiOjE1NDUxMzk5NjR9.w9LZEKB8GLRHDRpa80Lp2EFlGOjmJA4mWP6__Fk0JDu8HlJPk5GyXAm7081s6BqH99ixsKXsGGea6CuT0NHKqQ"; + String adminAccessToken = "eyJraWQiOiIyMDE4MTEzMCIsInR5cCI6IkpXVCIsImFsZyI6IkVTMjU2In0.eyJzdWIiOiJNRGs1TkRVMk5tVXRZV00zWWkwME5XSXlMV0kyWldZdE16WTBOREJsTkRSaE1UVmgiLCJhdWQiOiJTVTVUVkVGT1EwVXdNRGM9Om55bmphOk55bmphIiwic2NvcGUiOiJhY2Nlc3MiLCJyb2xlcyI6WyJVU0VSIiwiQUNDT1VOVF9BRE1JTiJdLCJpc3MiOiJodHRwczovL2F1dGgubnluamEuYml6LyIsImV4cCI6MTU0ODI2NzExMCwiaWF0IjoxNTQ4MjYzNTEwfQ.W9JrZsCXyMCbAvGwOfLbZJNO4PPf0j_nxrUCPX-Q395l2y6SXzGbJYw8ItlpAmZrtQg4ZrY9q2jXvJEoHdi0qg"; accountServiceBlockingStub = AccountServiceGrpc .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); @@ -578,9 +579,10 @@ public class AccountServiceTests extends GrpcServerTestBase { @Test public void testCompletePendingAccountCreationOkMultipleRoles() { + Set roles = Set.of(Role.USER, Role.ACCOUNT_ADMIN); final CompletePendingAccountCreationRequest request = CompletePendingAccountCreationRequest.newBuilder() .setAccountId(Util.ACCOUNT_ID.toString()).setUsername(Util.USERNAME).setFirstName(Util.FIRST_NAME) - .addRoles(Role.USER).addRoles(Role.ACCOUNT_ADMIN).build(); + .addAllRoles(roles).build(); accountServiceBlockingStub.completePendingAccountCreation(request); -- GitLab