diff options
author | Jon Marius Venstad <venstad@gmail.com> | 2019-10-02 17:46:33 +0200 |
---|---|---|
committer | Jon Marius Venstad <venstad@gmail.com> | 2019-10-02 17:46:33 +0200 |
commit | 816cf75a092b426f671799c645d04845758181eb (patch) | |
tree | 42f85cc0ff589e38eca05138c45b253385e1c849 /controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/SignatureFilter.java | |
parent | 70290819f83da07f76c2e5d70513a09ef6fd4f52 (diff) |
Differentiate between developer and headeless keys in signature filter
Diffstat (limited to 'controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/SignatureFilter.java')
-rw-r--r-- | controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/SignatureFilter.java | 77 |
1 files changed, 61 insertions, 16 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/SignatureFilter.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/SignatureFilter.java index 6755110bb49..fc9fd8ae235 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/SignatureFilter.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/SignatureFilter.java @@ -10,19 +10,27 @@ import com.yahoo.config.provision.TenantName; import com.yahoo.jdisc.http.filter.DiscFilterRequest; import com.yahoo.jdisc.http.filter.security.base.JsonSecurityRequestFilterBase; import com.yahoo.log.LogLevel; +import com.yahoo.security.KeyUtils; import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.Controller; import com.yahoo.vespa.hosted.controller.api.role.Role; import com.yahoo.vespa.hosted.controller.api.role.SecurityContext; import com.yahoo.vespa.hosted.controller.api.role.SimplePrincipal; import com.yahoo.vespa.hosted.controller.application.TenantAndApplicationId; +import com.yahoo.vespa.hosted.controller.tenant.CloudTenant; import com.yahoo.yolean.Exceptions; import java.security.Principal; +import java.security.PublicKey; +import java.util.Base64; +import java.util.HashSet; import java.util.Optional; import java.util.Set; +import java.util.function.Function; import java.util.logging.Logger; +import static java.nio.charset.StandardCharsets.UTF_8; + /** * Assigns the {@link Role#buildService(TenantName, ApplicationName)} role to requests with a * Authorization header signature matching the public key of the indicated application. @@ -47,23 +55,40 @@ public class SignatureFilter extends JsonSecurityRequestFilterBase { && request.getHeader("X-Authorization") != null) try { ApplicationId id = ApplicationId.fromSerializedForm(request.getHeader("X-Key-Id")); - boolean verified = controller.applications().getApplication(TenantAndApplicationId.from(id)).stream() - .flatMap(application -> application.pemDeployKeys().stream()) - .map(key -> new RequestVerifier(key, controller.clock())) - .anyMatch(verifier -> verifier.verify(Method.valueOf(request.getMethod()), - request.getUri(), - request.getHeader("X-Timestamp"), - request.getHeader("X-Content-Hash"), - request.getHeader("X-Authorization"))); + SecurityContext securityContext = null; + if (request.getHeader("X-Key") != null) { + PublicKey key = KeyUtils.fromPemEncodedPublicKey(new String(Base64.getDecoder().decode(request.getHeader("X-Key")), UTF_8)); + if (keyVerifies(key, request)) { + Principal principal = null; + Set<Role> roles = new HashSet<>(); + Optional <Application> application = controller.applications().getApplication(TenantAndApplicationId.from(id)); + if (application.isPresent() && application.get().deployKeys().contains(key)) { + principal = new SimplePrincipal("headless@" + id.tenant() + "." + id.application()); + roles.add(Role.reader(id.tenant())); + roles.add(Role.headless(id.tenant(), id.application())); + } + + Optional<CloudTenant> tenant = controller.tenants().get(id.tenant()) + .filter(CloudTenant.class::isInstance) + .map(CloudTenant.class::cast); + if (tenant.isPresent() && tenant.get().developerKeys().containsKey(key)) { + principal = tenant.get().developerKeys().get(key); // Precedence over headless user. + roles.add(Role.reader(id.tenant())); + roles.add(Role.developer(id.tenant())); + } + + if (principal != null) + securityContext = new SecurityContext(principal, roles); + } + } + else if (anyDeployKeyMatches(TenantAndApplicationId.from(id), request)) + securityContext = new SecurityContext(new SimplePrincipal("buildService@" + id.tenant() + "." + id.application()), + Set.of(Role.buildService(id.tenant(), id.application()))); - if (verified) { - Principal principal = new SimplePrincipal("buildService@" + id.tenant() + "." + id.application()); - request.setUserPrincipal(principal); - request.setRemoteUser(principal.getName()); - request.setAttribute(SecurityContext.ATTRIBUTE_NAME, - new SecurityContext(principal, - Set.of(Role.buildService(id.tenant(), id.application()), - Role.applicationDeveloper(id.tenant(), id.application())))); + if (securityContext != null) { + request.setUserPrincipal(securityContext.principal()); + request.setRemoteUser(securityContext.principal().getName()); + request.setAttribute(SecurityContext.ATTRIBUTE_NAME, securityContext); } } catch (Exception e) { @@ -72,4 +97,24 @@ public class SignatureFilter extends JsonSecurityRequestFilterBase { return Optional.empty(); } + // TODO jonmv: Remove after October 2019. + private boolean anyDeployKeyMatches(TenantAndApplicationId id, DiscFilterRequest request) { + return controller.applications().getApplication(id).stream() + .map(Application::deployKeys) + .flatMap(Set::stream) + .anyMatch(key -> keyVerifies(key, request)); + } + + private boolean keyVerifies(PublicKey key, DiscFilterRequest request) { + return new RequestVerifier(key, controller.clock()).verify(Method.valueOf(request.getMethod()), + request.getUri(), + request.getHeader("X-Timestamp"), + request.getHeader("X-Content-Hash"), + request.getHeader("X-Authorization")); + } + + private Optional<Principal> getPrincipal(CloudTenant tenant, PublicKey key) { + return Optional.empty(); + } + } |