diff options
author | Bjørn Christian Seime <bjorncs@oath.com> | 2017-11-20 13:38:00 +0100 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@oath.com> | 2017-11-20 15:48:58 +0100 |
commit | 67383d77a96f0d6ff1c653bf49f9d0dfa2c6fbee (patch) | |
tree | 82a08623190e9a541bba3eabb1e9df0b0ba1d810 /controller-server | |
parent | 2dd374a7899775ba613384580ea32c076578e873 (diff) |
Add filter combining Athenz with user authentication filter
Diffstat (limited to 'controller-server')
3 files changed, 81 insertions, 1 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/filter/AthenzPrincipalFilter.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/filter/AthenzPrincipalFilter.java index de771ff2e17..da5136817df 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/filter/AthenzPrincipalFilter.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/filter/AthenzPrincipalFilter.java @@ -23,6 +23,7 @@ import java.util.concurrent.Executor; * * @author bjorncs */ +// TODO bjorncs: Move this class into separate container-security bundle public class AthenzPrincipalFilter implements SecurityRequestFilter { private final ErrorResponseContentCreator responseCreator = new ErrorResponseContentCreator(); @@ -59,7 +60,7 @@ public class AthenzPrincipalFilter implements SecurityRequestFilter { } } - private void sendUnauthorized(DiscFilterRequest request, ResponseHandler responseHandler, String message) { + protected void sendUnauthorized(DiscFilterRequest request, ResponseHandler responseHandler, String message) { try (FastContentWriter writer = ResponseDispatch.newInstance(Response.Status.UNAUTHORIZED) .connectFastWriter(responseHandler)) { writer.write( diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/filter/UserAuthWithAthenzPrincipalFilter.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/filter/UserAuthWithAthenzPrincipalFilter.java new file mode 100644 index 00000000000..f20490db910 --- /dev/null +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/filter/UserAuthWithAthenzPrincipalFilter.java @@ -0,0 +1,75 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.athenz.filter; + +import com.google.inject.Inject; +import com.yahoo.jdisc.handler.ResponseHandler; +import com.yahoo.jdisc.http.filter.DiscFilterRequest; +import com.yahoo.vespa.hosted.controller.athenz.ZmsKeystore; +import com.yahoo.vespa.hosted.controller.athenz.config.AthenzConfig; +import com.yahoo.yolean.chain.Provides; + +import java.util.concurrent.Executor; + +/** + * A variant of the {@link AthenzPrincipalFilter} to be used in combination with a cookie-based + * security filter for user authentication + * Assumes that the user authentication filter configured in the same filter chain and is configured to run before this filter. + * + * @author bjorncs + */ +@Provides("UserAuthWithAthenzPrincipalFilter") +// TODO Remove this filter once migrated to Okta +public class UserAuthWithAthenzPrincipalFilter extends AthenzPrincipalFilter { + + private final String userAuthenticationPassThruAttribute; + + @Inject + public UserAuthWithAthenzPrincipalFilter(ZmsKeystore zmsKeystore, Executor executor, AthenzConfig config) { + super(zmsKeystore, executor, config); + this.userAuthenticationPassThruAttribute = config.userAuthenticationPassThruAttribute(); + } + + @Override + public void filter(DiscFilterRequest request, ResponseHandler responseHandler) { + if (request.getMethod().equals("OPTIONS")) return; // Skip authentication on OPTIONS - required for Javascript CORS + + switch (fromHttpRequest(request)) { + case USER_COOKIE_MISSING: + case USER_COOKIE_ALTERNATIVE_MISSING: + super.filter(request, responseHandler); // Cookie-based authentication failed, delegate to Athenz + break; + case USER_COOKIE_OK: + return; // Authenticated using user cookie + case USER_COOKIE_INVALID: + sendUnauthorized(request, responseHandler, "Your user cookie is invalid (either expired or tampered)"); + break; + } + } + + private UserAuthenticationResult fromHttpRequest(DiscFilterRequest request) { + if (!request.containsAttribute(userAuthenticationPassThruAttribute)) { + throw new IllegalStateException("User authentication filter passthru attribute missing"); + } + Integer statusCode = (Integer) request.getAttribute(userAuthenticationPassThruAttribute); + for (UserAuthenticationResult result : UserAuthenticationResult.values()) { + if (result.statusCode == statusCode) { + return result; + } + } + throw new IllegalStateException("Invalid status code: " + statusCode); + } + + private enum UserAuthenticationResult { + USER_COOKIE_MISSING(0), + USER_COOKIE_OK(1), + USER_COOKIE_INVALID(-1), + USER_COOKIE_ALTERNATIVE_MISSING(-2); + + final int statusCode; + + UserAuthenticationResult(int statusCode) { + this.statusCode = statusCode; + } + + } +} diff --git a/controller-server/src/main/resources/configdefinitions/athenz.def b/controller-server/src/main/resources/configdefinitions/athenz.def index 4e27e3ebd07..6d10f3dee28 100644 --- a/controller-server/src/main/resources/configdefinitions/athenz.def +++ b/controller-server/src/main/resources/configdefinitions/athenz.def @@ -13,6 +13,10 @@ ztsUrl string # Athenz domain for controller identity. The domain is also used for Athenz tenancy integration. domain string +# Name of the internal user authentication passthru attribute +userAuthenticationPassThruAttribute string +# TODO Remove once migrated to Okta + # Athenz service name for controller identity service.name string |