diff options
author | Morten Tokle <mortent@verizonmedia.com> | 2021-04-16 14:23:33 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-16 14:23:33 +0200 |
commit | b5ef9172e7ba9a4dc4429918e1ae2fc26444ce33 (patch) | |
tree | 16d88702fe9fde02d5005cbd1f0ce8ecce5d18e8 /container-core | |
parent | 95162715532714931a379f35f29fba6836e57daa (diff) | |
parent | 852ae37871cc7db3447dbfc8ddea5157b6a81d4d (diff) |
Merge pull request #17440 from vespa-engine/mortent/custom-acl-mapping
Custom acl mapping
Diffstat (limited to 'container-core')
9 files changed, 291 insertions, 2 deletions
diff --git a/container-core/abi-spec.json b/container-core/abi-spec.json index 970f7d19eb5..43e0cab967e 100644 --- a/container-core/abi-spec.json +++ b/container-core/abi-spec.json @@ -478,6 +478,37 @@ "public static final java.lang.String FULL_COVERAGE" ] }, + "com.yahoo.container.jdisc.AclMapping$Action": { + "superClass": "java.lang.Object", + "interfaces": [], + "attributes": [ + "public" + ], + "methods": [ + "public static com.yahoo.container.jdisc.AclMapping$Action custom(java.lang.String)", + "public java.lang.String name()", + "public boolean equals(java.lang.Object)", + "public int hashCode()", + "public java.lang.String toString()" + ], + "fields": [ + "public static final com.yahoo.container.jdisc.AclMapping$Action READ", + "public static final com.yahoo.container.jdisc.AclMapping$Action WRITE" + ] + }, + "com.yahoo.container.jdisc.AclMapping": { + "superClass": "java.lang.Object", + "interfaces": [], + "attributes": [ + "public", + "interface", + "abstract" + ], + "methods": [ + "public abstract com.yahoo.container.jdisc.AclMapping$Action get(com.yahoo.container.jdisc.RequestView)" + ], + "fields": [] + }, "com.yahoo.container.jdisc.AsyncHttpResponse": { "superClass": "com.yahoo.container.jdisc.HttpResponse", "interfaces": [], @@ -515,6 +546,20 @@ ], "fields": [] }, + "com.yahoo.container.jdisc.DefaultAclMapping": { + "superClass": "java.lang.Object", + "interfaces": [ + "com.yahoo.container.jdisc.AclMapping" + ], + "attributes": [ + "public" + ], + "methods": [ + "public void <init>()", + "public com.yahoo.container.jdisc.AclMapping$Action get(com.yahoo.container.jdisc.RequestView)" + ], + "fields": [] + }, "com.yahoo.container.jdisc.EmptyResponse": { "superClass": "com.yahoo.container.jdisc.HttpResponse", "interfaces": [], @@ -596,6 +641,21 @@ ], "fields": [] }, + "com.yahoo.container.jdisc.HttpRequestHandler": { + "superClass": "java.lang.Object", + "interfaces": [ + "com.yahoo.jdisc.handler.RequestHandler" + ], + "attributes": [ + "public", + "interface", + "abstract" + ], + "methods": [ + "public com.yahoo.container.jdisc.RequestHandlerSpec requestHandlerSpec()" + ], + "fields": [] + }, "com.yahoo.container.jdisc.HttpResponse": { "superClass": "java.lang.Object", "interfaces": [], @@ -689,6 +749,34 @@ ], "fields": [] }, + "com.yahoo.container.jdisc.RequestHandlerSpec$Builder": { + "superClass": "java.lang.Object", + "interfaces": [], + "attributes": [ + "public" + ], + "methods": [ + "public void <init>()", + "public com.yahoo.container.jdisc.RequestHandlerSpec$Builder withAclMapping(com.yahoo.container.jdisc.AclMapping)", + "public com.yahoo.container.jdisc.RequestHandlerSpec build()" + ], + "fields": [] + }, + "com.yahoo.container.jdisc.RequestHandlerSpec": { + "superClass": "java.lang.Object", + "interfaces": [], + "attributes": [ + "public" + ], + "methods": [ + "public com.yahoo.container.jdisc.AclMapping aclMapping()", + "public static com.yahoo.container.jdisc.RequestHandlerSpec$Builder builder()" + ], + "fields": [ + "public static final java.lang.String ATTRIBUTE_NAME", + "public static final com.yahoo.container.jdisc.RequestHandlerSpec DEFAULT_INSTANCE" + ] + }, "com.yahoo.container.jdisc.RequestHandlerTestDriver$MockResponseHandler": { "superClass": "java.lang.Object", "interfaces": [ @@ -734,6 +822,20 @@ ], "fields": [] }, + "com.yahoo.container.jdisc.RequestView": { + "superClass": "java.lang.Object", + "interfaces": [], + "attributes": [ + "public", + "interface", + "abstract" + ], + "methods": [ + "public abstract com.yahoo.jdisc.http.HttpRequest$Method method()", + "public abstract java.net.URI uri()" + ], + "fields": [] + }, "com.yahoo.container.jdisc.ThreadedHttpRequestHandler$LazyContentChannel": { "superClass": "java.lang.Object", "interfaces": [ @@ -752,7 +854,9 @@ }, "com.yahoo.container.jdisc.ThreadedHttpRequestHandler": { "superClass": "com.yahoo.container.jdisc.ThreadedRequestHandler", - "interfaces": [], + "interfaces": [ + "com.yahoo.container.jdisc.HttpRequestHandler" + ], "attributes": [ "public", "abstract" @@ -2019,6 +2123,7 @@ "public abstract void setHeaders(java.lang.String, java.lang.String)", "public abstract void setHeaders(java.lang.String, java.util.List)", "public int getIntHeader(java.lang.String)", + "public com.yahoo.container.jdisc.RequestView asRequestView()", "public java.util.List getCookies()", "public void setCookies(java.util.List)", "public long getConnectedAt(java.util.concurrent.TimeUnit)", diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/AclMapping.java b/container-core/src/main/java/com/yahoo/container/jdisc/AclMapping.java new file mode 100644 index 00000000000..e7c3d71ba44 --- /dev/null +++ b/container-core/src/main/java/com/yahoo/container/jdisc/AclMapping.java @@ -0,0 +1,50 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +package com.yahoo.container.jdisc; + +import java.util.Objects; + +/** + * Mapping from request to action + * + * @author mortent + */ +public interface AclMapping { + class Action { + public static final Action READ = new Action("read"); + public static final Action WRITE = new Action("write"); + private final String name; + public static Action custom(String name) { + return new Action(name); + } + private Action(String name) { + if(Objects.requireNonNull(name).isBlank()) { + throw new IllegalArgumentException("Name cannot be blank"); + } + this.name = Objects.requireNonNull(name); + } + public String name() { return name; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Action action = (Action) o; + return Objects.equals(name, action.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + @Override + public String toString() { + return "Action{" + + "name='" + name + '\'' + + '}'; + } + } + + Action get(RequestView requestView); +} diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/DefaultAclMapping.java b/container-core/src/main/java/com/yahoo/container/jdisc/DefaultAclMapping.java new file mode 100644 index 00000000000..93639029128 --- /dev/null +++ b/container-core/src/main/java/com/yahoo/container/jdisc/DefaultAclMapping.java @@ -0,0 +1,29 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +package com.yahoo.container.jdisc; + +/** + * Default ACL mapping + * @author mortent + */ +public class DefaultAclMapping implements AclMapping { + + @Override + public Action get(RequestView requestMeta) { + switch (requestMeta.method()) { + case GET: + case HEAD: + case OPTIONS: + return Action.READ; + case POST: + case DELETE: + case PUT: + case PATCH: + case CONNECT: + case TRACE: + return Action.WRITE; + default: + throw new IllegalArgumentException("Illegal request method: " + requestMeta.method()); + } + } +} diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/HttpRequestHandler.java b/container-core/src/main/java/com/yahoo/container/jdisc/HttpRequestHandler.java new file mode 100644 index 00000000000..f322c9c5b6f --- /dev/null +++ b/container-core/src/main/java/com/yahoo/container/jdisc/HttpRequestHandler.java @@ -0,0 +1,20 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +package com.yahoo.container.jdisc; + +import com.yahoo.jdisc.handler.RequestHandler; + +/** + * Extends a request handler with a http specific + * + * @author mortent + */ +public interface HttpRequestHandler extends RequestHandler { + + /** + * @return handler specification + */ + default RequestHandlerSpec requestHandlerSpec() { + return RequestHandlerSpec.DEFAULT_INSTANCE; + } +} diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/RequestHandlerSpec.java b/container-core/src/main/java/com/yahoo/container/jdisc/RequestHandlerSpec.java new file mode 100644 index 00000000000..91fac9ac448 --- /dev/null +++ b/container-core/src/main/java/com/yahoo/container/jdisc/RequestHandlerSpec.java @@ -0,0 +1,46 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +package com.yahoo.container.jdisc; + +import java.util.Objects; + +/** + * A specification provided by a request handler. + * Available through request context attribute + * + * @author mortent + */ +public class RequestHandlerSpec { + + public static final String ATTRIBUTE_NAME = RequestHandlerSpec.class.getName(); + public static final RequestHandlerSpec DEFAULT_INSTANCE = RequestHandlerSpec.builder().build(); + + private final AclMapping aclMapping; + + private RequestHandlerSpec(AclMapping aclMapping) { + this.aclMapping = aclMapping; + } + + public AclMapping aclMapping() { + return aclMapping; + } + + public static Builder builder(){ + return new Builder(); + } + + public static class Builder { + + private AclMapping aclMapping = new DefaultAclMapping(); + + public Builder withAclMapping(AclMapping aclMapping) { + this.aclMapping = Objects.requireNonNull(aclMapping); + return this; + } + + public RequestHandlerSpec build() { + return new RequestHandlerSpec(aclMapping); + } + } +} + diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/RequestView.java b/container-core/src/main/java/com/yahoo/container/jdisc/RequestView.java new file mode 100644 index 00000000000..51a5fdc8959 --- /dev/null +++ b/container-core/src/main/java/com/yahoo/container/jdisc/RequestView.java @@ -0,0 +1,18 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +package com.yahoo.container.jdisc; + +import com.yahoo.jdisc.http.HttpRequest; + +import java.net.URI; + +/** + * Read-only view of the request + * + * @author mortent + */ +public interface RequestView { + HttpRequest.Method method(); + + URI uri(); +} diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/ThreadedHttpRequestHandler.java b/container-core/src/main/java/com/yahoo/container/jdisc/ThreadedHttpRequestHandler.java index 5b8fe907293..be708f2fc94 100644 --- a/container-core/src/main/java/com/yahoo/container/jdisc/ThreadedHttpRequestHandler.java +++ b/container-core/src/main/java/com/yahoo/container/jdisc/ThreadedHttpRequestHandler.java @@ -32,7 +32,7 @@ import java.util.logging.Logger; * @author Steinar Knutsen * @author bratseth */ -public abstract class ThreadedHttpRequestHandler extends ThreadedRequestHandler { +public abstract class ThreadedHttpRequestHandler extends ThreadedRequestHandler implements HttpRequestHandler { public static final String CONTENT_TYPE = "Content-Type"; private static final String RENDERING_ERRORS = "rendering_errors"; diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/filter/DiscFilterRequest.java b/container-core/src/main/java/com/yahoo/jdisc/http/filter/DiscFilterRequest.java index f7ab399574c..72068bd2dd5 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/filter/DiscFilterRequest.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/filter/DiscFilterRequest.java @@ -1,6 +1,7 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.jdisc.http.filter; +import com.yahoo.container.jdisc.RequestView; import com.yahoo.jdisc.HeaderFields; import com.yahoo.jdisc.http.Cookie; import com.yahoo.jdisc.http.HttpHeaders; @@ -254,6 +255,19 @@ public abstract class DiscFilterRequest { } } + public RequestView asRequestView() { + return new RequestView() { + @Override + public HttpRequest.Method method() { + return HttpRequest.Method.valueOf(getMethod()); + } + + @Override + public URI uri() { + return getUri(); + } + }; + } public List<Cookie> getCookies() { return parent.decodeCookieHeader(); diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/FilteringRequestHandler.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/FilteringRequestHandler.java index a487b63ef10..27d122bcaa2 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/FilteringRequestHandler.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/FilteringRequestHandler.java @@ -2,6 +2,8 @@ package com.yahoo.jdisc.http.server.jetty; import com.google.common.base.Preconditions; +import com.yahoo.container.jdisc.RequestHandlerSpec; +import com.yahoo.container.jdisc.HttpRequestHandler; import com.yahoo.jdisc.Request; import com.yahoo.jdisc.Response; import com.yahoo.jdisc.handler.AbstractRequestHandler; @@ -65,6 +67,11 @@ class FilteringRequestHandler extends AbstractRequestHandler { throw new BindingNotFoundException(request.getUri()); } + if (resolvedRequestHandler instanceof HttpRequestHandler) { + RequestHandlerSpec requestHandlerSpec = ((HttpRequestHandler) resolvedRequestHandler).requestHandlerSpec(); + request.context().put(RequestHandlerSpec.ATTRIBUTE_NAME, requestHandlerSpec); + } + RequestHandler requestHandler = new ReferenceCountingRequestHandler(resolvedRequestHandler); ResponseHandler responseHandler; |