summaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@oath.com>2017-11-20 13:38:00 +0100
committerBjørn Christian Seime <bjorncs@oath.com>2017-11-20 15:48:58 +0100
commit67383d77a96f0d6ff1c653bf49f9d0dfa2c6fbee (patch)
tree82a08623190e9a541bba3eabb1e9df0b0ba1d810 /controller-server
parent2dd374a7899775ba613384580ea32c076578e873 (diff)
Add filter combining Athenz with user authentication filter
Diffstat (limited to 'controller-server')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/filter/AthenzPrincipalFilter.java3
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/filter/UserAuthWithAthenzPrincipalFilter.java75
-rw-r--r--controller-server/src/main/resources/configdefinitions/athenz.def4
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