diff --git a/gradle.properties b/gradle.properties index 8da49da0b..11742e03c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,6 +14,6 @@ # limitations under the License. # -version=0.27.0 +version=0.28.0-RC1 groupId=com.nike.cerberus artifactId=cms diff --git a/src/main/java/com/nike/cerberus/CerberusHttpHeaders.java b/src/main/java/com/nike/cerberus/CerberusHttpHeaders.java index 77baa1c40..a7f96395a 100644 --- a/src/main/java/com/nike/cerberus/CerberusHttpHeaders.java +++ b/src/main/java/com/nike/cerberus/CerberusHttpHeaders.java @@ -1,7 +1,43 @@ package com.nike.cerberus; +import com.nike.riposte.server.http.RequestInfo; +import io.netty.handler.codec.http.HttpHeaders; +import org.apache.commons.lang3.StringUtils; + public final class CerberusHttpHeaders { public static final String HEADER_X_CERBERUS_CLIENT = "X-Cerberus-Client"; public static final String HEADER_X_REFRESH_TOKEN = "X-Refresh-Token"; + public static final String HEADER_X_FORWARDED_FOR = "X-Forwarded-For"; + private static final String UNKNOWN = "Unknown"; + + /** + * Get the value of the X-Cerberus-Client header or "Unknown" if not found. + */ + public static String getClientVersion(RequestInfo request) { + final HttpHeaders headers = request.getHeaders(); + if (headers != null) { + String value = headers.get(HEADER_X_CERBERUS_CLIENT); + if (value != null) { + return value; + } + } + return UNKNOWN; + } + + /** + * Get the first IP address from the Http header "X-Forwarded-For" + * + * E.g. "X-Forwarded-For: ip1, ip2, ip3" would return "ip1" + */ + public static String getXForwardedClientIp(RequestInfo request) { + final HttpHeaders headers = request.getHeaders(); + if (headers != null) { + String value = headers.get(HEADER_X_FORWARDED_FOR); + if (value != null) { + return StringUtils.substringBefore(value, ",").trim(); + } + } + return null; + } } diff --git a/src/main/java/com/nike/cerberus/endpoints/AdminStandardEndpoint.java b/src/main/java/com/nike/cerberus/endpoints/AdminStandardEndpoint.java index e2757bd6d..51de92224 100644 --- a/src/main/java/com/nike/cerberus/endpoints/AdminStandardEndpoint.java +++ b/src/main/java/com/nike/cerberus/endpoints/AdminStandardEndpoint.java @@ -32,6 +32,8 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import static com.nike.cerberus.CerberusHttpHeaders.getXForwardedClientIp; + /** * Extension endpoint class for validating caller is admin before executing. */ @@ -51,9 +53,9 @@ public final CompletableFuture> execute(final RequestInfo req securityContext.get().getUserPrincipal().getName() : "( Principal is not a Vault auth principal. )" : "( Principal name is empty. )"; - log.info("Admin Endpoint Event: the principal {} is attempting to access admin endpoint: {}", principal, this.getClass().getName()); + log.info("Admin Endpoint Event: the principal {} from ip: {} is attempting to access admin endpoint: {}", principal, getXForwardedClientIp(request), this.getClass().getName()); if (!securityContext.isPresent() || !securityContext.get().isUserInRole(VaultAuthPrincipal.ROLE_ADMIN)) { - log.error("Admin Endpoint Event: the principal {} is attempted to access {}, an admin endpoint but was not an admin", principal, + log.error("Admin Endpoint Event: the principal {} from ip: {} attempted to access {}, an admin endpoint but was not an admin", principal, getXForwardedClientIp(request), this.getClass().getName()); throw new ApiException(DefaultApiError.ACCESS_DENIED); } diff --git a/src/main/java/com/nike/cerberus/endpoints/authentication/AuthenticateIamPrincipal.java b/src/main/java/com/nike/cerberus/endpoints/authentication/AuthenticateIamPrincipal.java index 520242b12..c8ee9ac98 100644 --- a/src/main/java/com/nike/cerberus/endpoints/authentication/AuthenticateIamPrincipal.java +++ b/src/main/java/com/nike/cerberus/endpoints/authentication/AuthenticateIamPrincipal.java @@ -26,7 +26,6 @@ import com.nike.riposte.util.AsyncNettyHelper; import com.nike.riposte.util.Matcher; import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,6 +35,8 @@ import java.util.concurrent.Executor; import static com.nike.cerberus.CerberusHttpHeaders.HEADER_X_CERBERUS_CLIENT; +import static com.nike.cerberus.CerberusHttpHeaders.getClientVersion; +import static com.nike.cerberus.CerberusHttpHeaders.getXForwardedClientIp; /** * Authentication endpoint for IAM roles. If valid, a client token that is encrypted via KMS is returned. The @@ -64,14 +65,12 @@ public CompletableFuture> execute(final Reques private ResponseInfo authenticate(RequestInfo request) { final IamPrincipalCredentials credentials = request.getContent(); - final HttpHeaders headers = request.getHeaders(); - final boolean clientHeaderExists = headers != null && headers.get(HEADER_X_CERBERUS_CLIENT) != null; - final String clientHeader = clientHeaderExists ? headers.get(HEADER_X_CERBERUS_CLIENT) : "Unknown"; - log.info("{}: {}, IAM Auth Event: the IAM principal {} in attempting to authenticate in region {}", + log.info("{}: {}, IAM Auth Event: the IAM principal {} with ip: {} in attempting to authenticate in region {}", HEADER_X_CERBERUS_CLIENT, - clientHeader, + getClientVersion(request), credentials.getIamPrincipalArn(), + getXForwardedClientIp(request), credentials.getRegion()); return ResponseInfo.newBuilder(authenticationService.authenticate(request.getContent())).build(); diff --git a/src/main/java/com/nike/cerberus/endpoints/authentication/AuthenticateIamRole.java b/src/main/java/com/nike/cerberus/endpoints/authentication/AuthenticateIamRole.java index 266f7e26e..c7e2a9618 100644 --- a/src/main/java/com/nike/cerberus/endpoints/authentication/AuthenticateIamRole.java +++ b/src/main/java/com/nike/cerberus/endpoints/authentication/AuthenticateIamRole.java @@ -26,7 +26,6 @@ import com.nike.riposte.util.AsyncNettyHelper; import com.nike.riposte.util.Matcher; import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,6 +35,8 @@ import java.util.concurrent.Executor; import static com.nike.cerberus.CerberusHttpHeaders.HEADER_X_CERBERUS_CLIENT; +import static com.nike.cerberus.CerberusHttpHeaders.getClientVersion; +import static com.nike.cerberus.CerberusHttpHeaders.getXForwardedClientIp; /** * Authentication endpoint for IAM roles. If valid, a client token that is encrypted via KMS is returned. The @@ -66,16 +67,14 @@ public CompletableFuture> execute(final Reques private ResponseInfo authenticate(RequestInfo request) { final IamRoleCredentials credentials = request.getContent(); - final HttpHeaders headers = request.getHeaders(); - final boolean clientHeaderExists = headers != null && headers.get(HEADER_X_CERBERUS_CLIENT) != null; - final String clientHeader = clientHeaderExists ? headers.get(HEADER_X_CERBERUS_CLIENT) : "Unknown"; - log.info("{}: {}, IAM Auth Event: the IAM principal {} in attempting to authenticate in region {}", + log.info("{}: {}, IAM Auth Event: the IAM principal {} with ip: {} is attempting to authenticate in region {}", HEADER_X_CERBERUS_CLIENT, - clientHeader, + getClientVersion(request), String.format(AwsIamRoleArnParser.AWS_IAM_ROLE_ARN_TEMPLATE, credentials.getAccountId(), credentials.getRoleName()), + getXForwardedClientIp(request), credentials.getRegion()); return ResponseInfo.newBuilder(authenticationService.authenticate(request.getContent())).build(); diff --git a/src/main/java/com/nike/cerberus/endpoints/authentication/AuthenticateUser.java b/src/main/java/com/nike/cerberus/endpoints/authentication/AuthenticateUser.java index 7a31d8562..568ac7d4e 100644 --- a/src/main/java/com/nike/cerberus/endpoints/authentication/AuthenticateUser.java +++ b/src/main/java/com/nike/cerberus/endpoints/authentication/AuthenticateUser.java @@ -40,6 +40,8 @@ import java.util.concurrent.Executor; import static com.nike.cerberus.CerberusHttpHeaders.HEADER_X_CERBERUS_CLIENT; +import static com.nike.cerberus.CerberusHttpHeaders.getClientVersion; +import static com.nike.cerberus.CerberusHttpHeaders.getXForwardedClientIp; /** * Authentication endpoint for user credentials. If valid, a client token will be returned. @@ -67,14 +69,12 @@ public CompletableFuture> execute(final RequestInfo authenticate(RequestInfo request) { final UserCredentials credentials = extractCredentials(request.getHeaders().get(HttpHeaders.AUTHORIZATION)); - final io.netty.handler.codec.http.HttpHeaders headers = request.getHeaders(); - final boolean clientHeaderExists = headers != null && headers.get(HEADER_X_CERBERUS_CLIENT) != null; - final String clientHeader = clientHeaderExists ? headers.get(HEADER_X_CERBERUS_CLIENT) : "Unknown"; - log.info("{}: {}, User Auth Event: the principal: {} is attempting to authenticate", + log.info("{}: {}, User Auth Event: the principal: {} with ip: {} is attempting to authenticate", HEADER_X_CERBERUS_CLIENT, - clientHeader, - credentials.getUsername()); + getClientVersion(request), + credentials.getUsername(), + getXForwardedClientIp(request)); return ResponseInfo.newBuilder(authenticationService.authenticate(credentials)).build(); } diff --git a/src/main/java/com/nike/cerberus/endpoints/authentication/RefreshUserToken.java b/src/main/java/com/nike/cerberus/endpoints/authentication/RefreshUserToken.java index ab9e46270..a1e054763 100644 --- a/src/main/java/com/nike/cerberus/endpoints/authentication/RefreshUserToken.java +++ b/src/main/java/com/nike/cerberus/endpoints/authentication/RefreshUserToken.java @@ -28,7 +28,6 @@ import com.nike.riposte.util.AsyncNettyHelper; import com.nike.riposte.util.Matcher; import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,6 +39,8 @@ import java.util.concurrent.Executor; import static com.nike.cerberus.CerberusHttpHeaders.HEADER_X_CERBERUS_CLIENT; +import static com.nike.cerberus.CerberusHttpHeaders.getClientVersion; +import static com.nike.cerberus.CerberusHttpHeaders.getXForwardedClientIp; /** * Authentication endpoint that allows refreshing the user token to pickup any permission changes. @@ -72,14 +73,12 @@ public ResponseInfo getRefreshedUserToken(final RequestInfo if (securityContext.isPresent()) { final VaultAuthPrincipal vaultAuthPrincipal = (VaultAuthPrincipal) securityContext.get().getUserPrincipal(); - final HttpHeaders headers = request.getHeaders(); - final boolean clientHeaderExists = headers != null && headers.get(HEADER_X_CERBERUS_CLIENT) != null; - final String clientHeader = clientHeaderExists ? headers.get(HEADER_X_CERBERUS_CLIENT) : "Unknown"; - log.info("{}: {}, Refresh User Token Auth Event: the principal: {} is attempting to refresh its token", + log.info("{}: {}, Refresh User Token Auth Event: the principal: {} with ip: {} is attempting to refresh its token", HEADER_X_CERBERUS_CLIENT, - clientHeader, - vaultAuthPrincipal.getName()); + getClientVersion(request), + vaultAuthPrincipal.getName(), + getXForwardedClientIp(request)); return ResponseInfo.newBuilder( authenticationService.refreshUserToken( diff --git a/src/main/java/com/nike/cerberus/endpoints/authentication/RevokeToken.java b/src/main/java/com/nike/cerberus/endpoints/authentication/RevokeToken.java index 28a1e08a4..a4055b074 100644 --- a/src/main/java/com/nike/cerberus/endpoints/authentication/RevokeToken.java +++ b/src/main/java/com/nike/cerberus/endpoints/authentication/RevokeToken.java @@ -27,7 +27,6 @@ import com.nike.riposte.util.AsyncNettyHelper; import com.nike.riposte.util.Matcher; import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpResponseStatus; import org.slf4j.Logger; @@ -40,6 +39,8 @@ import java.util.concurrent.Executor; import static com.nike.cerberus.CerberusHttpHeaders.HEADER_X_CERBERUS_CLIENT; +import static com.nike.cerberus.CerberusHttpHeaders.getClientVersion; +import static com.nike.cerberus.CerberusHttpHeaders.getXForwardedClientIp; /** * Revokes the token supplied in the Vault token header. @@ -72,14 +73,12 @@ public ResponseInfo revokeToken(RequestInfo request) { if (securityContext.isPresent()) { final VaultAuthPrincipal vaultAuthPrincipal = (VaultAuthPrincipal) securityContext.get().getUserPrincipal(); - final HttpHeaders headers = request.getHeaders(); - final boolean clientHeaderExists = headers != null && headers.get(HEADER_X_CERBERUS_CLIENT) != null; - final String clientHeader = clientHeaderExists ? headers.get(HEADER_X_CERBERUS_CLIENT) : "Unknown"; - log.info("{}: {}, Delete Token Auth Event: the principal: {} is attempting to delete a token", + log.info("{}: {}, Delete Token Auth Event: the principal: {} with ip: {} is attempting to delete a token", HEADER_X_CERBERUS_CLIENT, - clientHeader, - vaultAuthPrincipal.getName()); + getClientVersion(request), + vaultAuthPrincipal.getName(), + getXForwardedClientIp(request)); authenticationService.revoke(vaultAuthPrincipal.getClientToken().getId()); return ResponseInfo.newBuilder().withHttpStatusCode(HttpResponseStatus.NO_CONTENT.code()).build(); diff --git a/src/main/java/com/nike/cerberus/endpoints/sdb/CreateSafeDepositBoxV1.java b/src/main/java/com/nike/cerberus/endpoints/sdb/CreateSafeDepositBoxV1.java index a5e18ba1a..8709a5bf8 100644 --- a/src/main/java/com/nike/cerberus/endpoints/sdb/CreateSafeDepositBoxV1.java +++ b/src/main/java/com/nike/cerberus/endpoints/sdb/CreateSafeDepositBoxV1.java @@ -30,7 +30,6 @@ import com.nike.riposte.util.Matcher; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.DefaultHttpHeaders; -import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpResponseStatus; import org.slf4j.Logger; @@ -43,8 +42,12 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; + +import static com.nike.cerberus.CerberusHttpHeaders.getClientVersion; +import static com.nike.cerberus.CerberusHttpHeaders.getXForwardedClientIp; import static com.nike.cerberus.CerberusHttpHeaders.HEADER_X_CERBERUS_CLIENT; import static com.nike.cerberus.CerberusHttpHeaders.HEADER_X_REFRESH_TOKEN; + import static io.netty.handler.codec.http.HttpHeaders.Names.LOCATION; /** @@ -81,14 +84,12 @@ private ResponseInfo> createSafeDepositBox(final RequestInfo if (securityContext.isPresent()) { final VaultAuthPrincipal vaultAuthPrincipal = (VaultAuthPrincipal) securityContext.get().getUserPrincipal(); - final HttpHeaders headers = request.getHeaders(); - final boolean clientHeaderExists = headers != null && headers.get(HEADER_X_CERBERUS_CLIENT) != null; - final String clientHeader = clientHeaderExists ? headers.get(HEADER_X_CERBERUS_CLIENT) : "Unknown"; - log.info("{}: {}, Create SDB Event: the principal: {} is attempting to create sdb name: '{}'", + log.info("{}: {}, Create SDB Event: the principal: {} from ip; {} is attempting to create sdb name: '{}'", HEADER_X_CERBERUS_CLIENT, - clientHeader, + getClientVersion(request), vaultAuthPrincipal.getName(), + getXForwardedClientIp(request), request.getContent().getName()); final String id = diff --git a/src/main/java/com/nike/cerberus/endpoints/sdb/CreateSafeDepositBoxV2.java b/src/main/java/com/nike/cerberus/endpoints/sdb/CreateSafeDepositBoxV2.java index 0fa4aded2..a1d782df4 100644 --- a/src/main/java/com/nike/cerberus/endpoints/sdb/CreateSafeDepositBoxV2.java +++ b/src/main/java/com/nike/cerberus/endpoints/sdb/CreateSafeDepositBoxV2.java @@ -30,7 +30,6 @@ import com.nike.riposte.util.Matcher; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.DefaultHttpHeaders; -import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpResponseStatus; import org.slf4j.Logger; @@ -42,8 +41,11 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import static com.nike.cerberus.CerberusHttpHeaders.getClientVersion; +import static com.nike.cerberus.CerberusHttpHeaders.getXForwardedClientIp; import static com.nike.cerberus.CerberusHttpHeaders.HEADER_X_CERBERUS_CLIENT; import static com.nike.cerberus.CerberusHttpHeaders.HEADER_X_REFRESH_TOKEN; + import static io.netty.handler.codec.http.HttpHeaders.Names.LOCATION; /** @@ -79,14 +81,12 @@ private ResponseInfo createSafeDepositBox(final RequestInfo deleteSafeDepositBox(final RequestInfo request) if (securityContext.isPresent()) { final VaultAuthPrincipal vaultAuthPrincipal = (VaultAuthPrincipal) securityContext.get().getUserPrincipal(); - final HttpHeaders headers = request.getHeaders(); - final boolean clientHeaderExists = headers != null && headers.get(HEADER_X_CERBERUS_CLIENT) != null; - final String clientHeader = clientHeaderExists ? headers.get(HEADER_X_CERBERUS_CLIENT) : "Unknown"; String sdbId = request.getPathParam("id"); Optional sdbNameOptional = safeDepositBoxService.getSafeDepositBoxNameById(sdbId); String sdbName = sdbNameOptional.orElse(String.format("(Failed to lookup name from id: %s)", sdbId)); - log.info("{}: {}, Delete SDB Event: the principal: {} is attempting to delete sdb name: '{}' and id: '{}'", + log.info("{}: {}, Delete SDB Event: the principal: {} from ip: {} is attempting to delete sdb name: '{}' and id: '{}'", HEADER_X_CERBERUS_CLIENT, - clientHeader, + getClientVersion(request), vaultAuthPrincipal.getName(), + getXForwardedClientIp(request), sdbName, sdbId); diff --git a/src/main/java/com/nike/cerberus/endpoints/sdb/GetSafeDepositBoxV1.java b/src/main/java/com/nike/cerberus/endpoints/sdb/GetSafeDepositBoxV1.java index f906cf4a5..d17ab2d5f 100644 --- a/src/main/java/com/nike/cerberus/endpoints/sdb/GetSafeDepositBoxV1.java +++ b/src/main/java/com/nike/cerberus/endpoints/sdb/GetSafeDepositBoxV1.java @@ -28,7 +28,6 @@ import com.nike.riposte.util.AsyncNettyHelper; import com.nike.riposte.util.Matcher; import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,6 +39,8 @@ import java.util.concurrent.Executor; import static com.nike.cerberus.CerberusHttpHeaders.HEADER_X_CERBERUS_CLIENT; +import static com.nike.cerberus.CerberusHttpHeaders.getClientVersion; +import static com.nike.cerberus.CerberusHttpHeaders.getXForwardedClientIp; /** * Extracts the user groups from the security context for the request and attempts to get details about the safe @@ -73,17 +74,15 @@ public ResponseInfo getSafeDepositBox(final RequestInfo if (securityContext.isPresent()) { final VaultAuthPrincipal vaultAuthPrincipal = (VaultAuthPrincipal) securityContext.get().getUserPrincipal(); - final HttpHeaders headers = request.getHeaders(); - final boolean clientHeaderExists = headers != null && headers.get(HEADER_X_CERBERUS_CLIENT) != null; - final String clientHeader = clientHeaderExists ? headers.get(HEADER_X_CERBERUS_CLIENT) : "Unknown"; String sdbId = request.getPathParam("id"); Optional sdbNameOptional = safeDepositBoxService.getSafeDepositBoxNameById(sdbId); String sdbName = sdbNameOptional.orElse(String.format("(Failed to lookup name from id: %s)", sdbId)); - log.info("{}: {}, Read SDB Event: the principal: {} is attempting to read sdb name: '{}' and id: '{}'", + log.info("{}: {}, Read SDB Event: the principal: {} from ip: {} is attempting to read sdb name: '{}' and id: '{}'", HEADER_X_CERBERUS_CLIENT, - clientHeader, + getClientVersion(request), vaultAuthPrincipal.getName(), + getXForwardedClientIp(request), sdbName, sdbId); diff --git a/src/main/java/com/nike/cerberus/endpoints/sdb/GetSafeDepositBoxV2.java b/src/main/java/com/nike/cerberus/endpoints/sdb/GetSafeDepositBoxV2.java index 1504c11fc..c2b56df21 100644 --- a/src/main/java/com/nike/cerberus/endpoints/sdb/GetSafeDepositBoxV2.java +++ b/src/main/java/com/nike/cerberus/endpoints/sdb/GetSafeDepositBoxV2.java @@ -29,7 +29,6 @@ import com.nike.riposte.util.AsyncNettyHelper; import com.nike.riposte.util.Matcher; import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,6 +40,8 @@ import java.util.concurrent.Executor; import static com.nike.cerberus.CerberusHttpHeaders.HEADER_X_CERBERUS_CLIENT; +import static com.nike.cerberus.CerberusHttpHeaders.getClientVersion; +import static com.nike.cerberus.CerberusHttpHeaders.getXForwardedClientIp; /** * Extracts the user groups from the security context for the request and attempts to get details about the safe @@ -73,17 +74,15 @@ public ResponseInfo getSafeDepositBox(final RequestInfo if (securityContext.isPresent()) { final VaultAuthPrincipal vaultAuthPrincipal = (VaultAuthPrincipal) securityContext.get().getUserPrincipal(); - final HttpHeaders headers = request.getHeaders(); - final boolean clientHeaderExists = headers != null && headers.get(HEADER_X_CERBERUS_CLIENT) != null; - final String clientHeader = clientHeaderExists ? headers.get(HEADER_X_CERBERUS_CLIENT) : "Unknown"; String sdbId = request.getPathParam("id"); Optional sdbNameOptional = safeDepositBoxService.getSafeDepositBoxNameById(sdbId); String sdbName = sdbNameOptional.orElse(String.format("(Failed to lookup name from id: %s)", sdbId)); - log.info("{}: {}, Read SDB Event: the principal: {} is attempting to read sdb name: '{}' and id: '{}'", + log.info("{}: {}, Read SDB Event: the principal: {} from ip: {} is attempting to read sdb name: '{}' and id: '{}'", HEADER_X_CERBERUS_CLIENT, - clientHeader, + getClientVersion(request), vaultAuthPrincipal.getName(), + getXForwardedClientIp(request), sdbName, sdbId); diff --git a/src/main/java/com/nike/cerberus/endpoints/sdb/GetSafeDepositBoxes.java b/src/main/java/com/nike/cerberus/endpoints/sdb/GetSafeDepositBoxes.java index 027760bdb..ac09486d5 100644 --- a/src/main/java/com/nike/cerberus/endpoints/sdb/GetSafeDepositBoxes.java +++ b/src/main/java/com/nike/cerberus/endpoints/sdb/GetSafeDepositBoxes.java @@ -30,7 +30,6 @@ import com.nike.riposte.util.Matcher; import com.nike.riposte.util.MultiMatcher; import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,6 +42,8 @@ import java.util.concurrent.Executor; import static com.nike.cerberus.CerberusHttpHeaders.HEADER_X_CERBERUS_CLIENT; +import static com.nike.cerberus.CerberusHttpHeaders.getClientVersion; +import static com.nike.cerberus.CerberusHttpHeaders.getXForwardedClientIp; /** * Extracts the user groups from the security context for the request and returns any safe deposit boxes @@ -75,14 +76,12 @@ public ResponseInfo> getSafeDepositBoxes(final Reque if (securityContext.isPresent()) { final VaultAuthPrincipal vaultAuthPrincipal = (VaultAuthPrincipal) securityContext.get().getUserPrincipal(); - final HttpHeaders headers = request.getHeaders(); - final boolean clientHeaderExists = headers != null && headers.get(HEADER_X_CERBERUS_CLIENT) != null; - final String clientHeader = clientHeaderExists ? headers.get(HEADER_X_CERBERUS_CLIENT) : "Unknown"; - log.info("{}: {}, List SDB Event: the principal: {} is attempting to list the SDBs that it has access to", + log.info("{}: {}, List SDB Event: the principal: {} from ip: {} is attempting to list the SDBs that it has access to", HEADER_X_CERBERUS_CLIENT, - clientHeader, - vaultAuthPrincipal.getName()); + getClientVersion(request), + vaultAuthPrincipal.getName(), + getXForwardedClientIp(request)); return ResponseInfo.newBuilder( safeDepositBoxService.getAssociatedSafeDepositBoxes(vaultAuthPrincipal)).build(); diff --git a/src/main/java/com/nike/cerberus/endpoints/sdb/UpdateSafeDepositBoxV1.java b/src/main/java/com/nike/cerberus/endpoints/sdb/UpdateSafeDepositBoxV1.java index 5572abffd..c76001c88 100644 --- a/src/main/java/com/nike/cerberus/endpoints/sdb/UpdateSafeDepositBoxV1.java +++ b/src/main/java/com/nike/cerberus/endpoints/sdb/UpdateSafeDepositBoxV1.java @@ -30,7 +30,6 @@ import com.nike.riposte.util.Matcher; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.DefaultHttpHeaders; -import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpResponseStatus; import org.slf4j.Logger; @@ -42,6 +41,8 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import static com.nike.cerberus.CerberusHttpHeaders.getClientVersion; +import static com.nike.cerberus.CerberusHttpHeaders.getXForwardedClientIp; import static com.nike.cerberus.CerberusHttpHeaders.HEADER_X_CERBERUS_CLIENT; import static com.nike.cerberus.CerberusHttpHeaders.HEADER_X_REFRESH_TOKEN; @@ -76,18 +77,16 @@ private ResponseInfo updateSafeDepositBox(final RequestInfo sdbNameOptional = safeDepositBoxService.getSafeDepositBoxNameById(sdbId); String sdbName = sdbNameOptional.orElseGet(() -> String.format("(Failed to lookup name from id: %s)", sdbId)); - log.info("{}: {}, Update SDB Event: the principal: {} is attempting to update sdb name: '{}' and id: '{}'", + log.info("{}: {}, Update SDB Event: the principal: {} from ip: {} is attempting to update sdb name: '{}' and id: '{}'", HEADER_X_CERBERUS_CLIENT, - clientHeader, + getClientVersion(request), vaultAuthPrincipal.getName(), + getXForwardedClientIp(request), sdbName, sdbId); diff --git a/src/main/java/com/nike/cerberus/endpoints/sdb/UpdateSafeDepositBoxV2.java b/src/main/java/com/nike/cerberus/endpoints/sdb/UpdateSafeDepositBoxV2.java index 457f66d85..0ed0963f1 100644 --- a/src/main/java/com/nike/cerberus/endpoints/sdb/UpdateSafeDepositBoxV2.java +++ b/src/main/java/com/nike/cerberus/endpoints/sdb/UpdateSafeDepositBoxV2.java @@ -31,7 +31,6 @@ import com.nike.riposte.util.Matcher; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.DefaultHttpHeaders; -import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpResponseStatus; import org.slf4j.Logger; @@ -43,6 +42,8 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import static com.nike.cerberus.CerberusHttpHeaders.getClientVersion; +import static com.nike.cerberus.CerberusHttpHeaders.getXForwardedClientIp; import static com.nike.cerberus.CerberusHttpHeaders.HEADER_X_CERBERUS_CLIENT; import static com.nike.cerberus.CerberusHttpHeaders.HEADER_X_REFRESH_TOKEN; @@ -76,17 +77,15 @@ private ResponseInfo updateSafeDepositBox(final RequestInfo sdbNameOptional = safeDepositBoxService.getSafeDepositBoxNameById(sdbId); String sdbName = sdbNameOptional.orElseGet(() -> String.format("(Failed to lookup name from id: %s)", sdbId)); - log.info("{}: {}, Update SDB Event: the principal: {} is attempting to update sdb name: '{}' and id: '{}'", + log.info("{}: {}, Update SDB Event: the principal: {} from ip: {} is attempting to update sdb name: '{}' and id: '{}'", HEADER_X_CERBERUS_CLIENT, - clientHeader, + getClientVersion(request), vaultAuthPrincipal.getName(), + getXForwardedClientIp(request), sdbName, sdbId); SafeDepositBoxV2 safeDepositBoxV2 = safeDepositBoxService.updateSafeDepositBoxV2(request.getContent(), diff --git a/src/test/java/com/nike/cerberus/CerberusHttpHeadersTest.java b/src/test/java/com/nike/cerberus/CerberusHttpHeadersTest.java new file mode 100644 index 000000000..b2901146b --- /dev/null +++ b/src/test/java/com/nike/cerberus/CerberusHttpHeadersTest.java @@ -0,0 +1,60 @@ +package com.nike.cerberus; + +import com.nike.riposte.server.http.RequestInfo; +import io.netty.handler.codec.http.DefaultHttpHeaders; +import io.netty.handler.codec.http.HttpHeaders; +import org.junit.Assert; +import org.junit.Test; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class CerberusHttpHeadersTest { + + @Test + public void test_getClientVersion() { + String fakeVersion = "fake/1.2.3"; + HttpHeaders headers = new DefaultHttpHeaders(); + headers.add(CerberusHttpHeaders.HEADER_X_CERBERUS_CLIENT, fakeVersion); + RequestInfo request = mock(RequestInfo.class); + when(request.getHeaders()).thenReturn(headers); + + Assert.assertEquals(fakeVersion, CerberusHttpHeaders.getClientVersion(request)); + } + + @Test + public void test_getClientVersion_when_null() { + RequestInfo request = mock(RequestInfo.class); + + Assert.assertEquals("Unknown", CerberusHttpHeaders.getClientVersion(request)); + } + + @Test + public void test_getXForwardedClientIp_with_three() { + String value = "ip1, ip2, ip3"; + HttpHeaders headers = new DefaultHttpHeaders(); + headers.add(CerberusHttpHeaders.HEADER_X_FORWARDED_FOR, value); + RequestInfo request = mock(RequestInfo.class); + when(request.getHeaders()).thenReturn(headers); + + Assert.assertEquals("ip1", CerberusHttpHeaders.getXForwardedClientIp(request)); + } + + @Test + public void test_getXForwardedClientIp_with_one() { + String value = "ip1"; + HttpHeaders headers = new DefaultHttpHeaders(); + headers.add(CerberusHttpHeaders.HEADER_X_FORWARDED_FOR, value); + RequestInfo request = mock(RequestInfo.class); + when(request.getHeaders()).thenReturn(headers); + + Assert.assertEquals("ip1", CerberusHttpHeaders.getXForwardedClientIp(request)); + } + + @Test + public void test_getXForwardedClientIp_with_null() { + RequestInfo request = mock(RequestInfo.class); + + Assert.assertNull(CerberusHttpHeaders.getXForwardedClientIp(request)); + } +} \ No newline at end of file