Skip to content

Commit

Permalink
Authentication and Authorization
Browse files Browse the repository at this point in the history
Client sdk authentication, Server Authentication and authorization.
  • Loading branch information
jmelinav authored Jun 15, 2020
1 parent 639c607 commit 392b4d2
Show file tree
Hide file tree
Showing 33 changed files with 710 additions and 233 deletions.
84 changes: 70 additions & 14 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,36 @@
<artifactId>feast-core</artifactId>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<skip>false</skip>
</configuration>
</plugin>
</plugins>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<release>11</release>
</configuration>
</plugin>

<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
</plugin>

<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<skip>false</skip>
</configuration>
<executions>
<execution>
<id>build-info</id>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

<dependencies>
Expand All @@ -56,6 +77,19 @@
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value-annotations</artifactId>
<version>1.6.6</version>
</dependency>

<dependency>
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value</artifactId>
<version>1.6.6</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>javax.inject</groupId>
Expand Down Expand Up @@ -127,6 +161,10 @@
<version>5.3.0.RELEASE</version>
</dependency>

<dependency>
<groupId>io.github.lognet</groupId>
<artifactId>grpc-spring-boot-starter</artifactId>
</dependency>
<!--compile "org.springframework.boot:spring-boot-starter-data-jpa:${springBootVersion}"-->
<dependency>
<groupId>org.springframework.boot</groupId>
Expand Down Expand Up @@ -186,7 +224,6 @@
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.3.6.Final</version>
</dependency>

<!--compile 'org.postgresql:postgresql:42.2.5'-->
Expand Down Expand Up @@ -245,6 +282,28 @@
<artifactId>keto-client</artifactId>
<version>0.4.4-alpha.1</version>
</dependency>


<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>

<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.2.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>6.1.2.Final</version>
</dependency>

<!--testCompile 'com.jayway.jsonpath:json-path-assert:2.2.0'-->
<dependency>
Expand All @@ -271,10 +330,7 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package feast.core.auth.authentication.GoogleOID;
package feast.core.auth.authentication;

import java.util.Map;
import org.springframework.security.authentication.AuthenticationProvider;
Expand All @@ -28,15 +28,15 @@
* Google Open ID Authentication Provider. This provider is used to validate incoming requests to
* Feast Core.
*/
public class GoogleOpenIDAuthenticationProvider implements AuthenticationProvider {
public class DefaultJwtAuthenticationProvider implements AuthenticationProvider {

private JwtAuthenticationProvider authProvider;

/**
* @param options String K/V pair of options to initialize the AuthenticationProvider with. Only
* one option is currently configurable, the jwkEndpointURI.
*/
public GoogleOpenIDAuthenticationProvider(Map<String, String> options) {
public DefaultJwtAuthenticationProvider(Map<String, String> options) {

// Endpoint used to retrieve certificates to validate JWT token
String jwkEndpointURI = "https://www.googleapis.com/oauth2/v3/certs";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
*/
package feast.core.auth.authorization;

import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.Authentication;

/**
Expand All @@ -26,13 +25,11 @@
public interface AuthorizationProvider {

/**
* Validates whether a user is within a project. Throws an AccessDeniedException if user is not
* within the project.
* Validates whether a user is allowed access to the project
*
* @param project Name of the Feast project
* @param authentication Spring Security Authentication object
* @throws AccessDeniedException
* @return AuthorizationResult result of authorization query
*/
void checkIfProjectMember(String project, Authentication authentication)
throws AccessDeniedException;
AuthorizationResult checkAccess(String project, Authentication authentication);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright 2018-2020 The Feast Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package feast.core.auth.authorization;

import com.google.auto.value.AutoValue;
import java.util.Optional;
import javax.annotation.Nullable;

@AutoValue
public abstract class AuthorizationResult {
public static AuthorizationResult create(
@Nullable boolean allowed, @Nullable String failureReason) {
return new AutoValue_AuthorizationResult(allowed, Optional.ofNullable(failureReason));
}

public static AuthorizationResult failed(@Nullable String failureReason) {
return new AutoValue_AuthorizationResult(false, Optional.ofNullable(failureReason));
}

public static AuthorizationResult success() {
return new AutoValue_AuthorizationResult(true, Optional.empty());
}

public abstract boolean allowed();

public abstract Optional<String> failureReason();
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
package feast.core.auth.authorization.Keto;

import feast.core.auth.authorization.AuthorizationProvider;
import feast.core.auth.authorization.AuthorizationResult;
import java.util.List;
import java.util.Map;
import org.hibernate.validator.internal.constraintvalidators.bv.EmailValidator;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.jwt.Jwt;
import sh.ory.keto.ApiClient;
Expand Down Expand Up @@ -50,15 +50,13 @@ public KetoAuthorizationProvider(Map<String, String> options) {
}

/**
* Validates whether a user is within a project. Throws an AccessDeniedException if user is not
* within the project.
* Validates whether a user has access to the project
*
* @param project Name of the Feast project
* @param authentication Spring Security Authentication object
* @throws AccessDeniedException
* @return AuthorizationResult result of authorization query
*/
public void checkIfProjectMember(String project, Authentication authentication)
throws AccessDeniedException {
public AuthorizationResult checkAccess(String project, Authentication authentication) {
String email = getEmailFromAuth(authentication);
try {
// Get all roles from Keto
Expand All @@ -70,7 +68,7 @@ public void checkIfProjectMember(String project, Authentication authentication)
// If the user has an admin or project specific role, return.
if (("roles:admin").equals(role.getId())
|| (String.format("roles:feast:%s-member", project)).equals(role.getId())) {
return;
return AuthorizationResult.success();
}
}
} catch (ApiException e) {
Expand All @@ -81,7 +79,7 @@ public void checkIfProjectMember(String project, Authentication authentication)
e.printStackTrace();
}
// Could not determine project membership, deny access.
throw new AccessDeniedException(
return AuthorizationResult.failed(
String.format("Access denied to project %s for user %s", project, email));
}

Expand Down
15 changes: 13 additions & 2 deletions core/src/main/java/feast/core/config/FeastProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,17 @@
import feast.core.validators.OneOfStrings;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.validation.*;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
Expand All @@ -31,9 +39,11 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.info.BuildProperties;
import org.springframework.stereotype.Component;

@Getter
@Setter
@Component
@ConfigurationProperties(prefix = "feast", ignoreInvalidFields = true)
public class FeastProperties {

Expand All @@ -59,6 +69,7 @@ public FeastProperties() {}
@NotNull
/* Feast Kafka stream properties */
private StreamProperties stream;

private SecurityProperties security;

/** Feast job properties. These properties are used for ingestion jobs. */
Expand Down
10 changes: 5 additions & 5 deletions core/src/main/java/feast/core/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
*/
package feast.core.config;

import feast.core.CoreServiceGrpc;
import feast.core.auth.authentication.GoogleOID.GoogleOpenIDAuthenticationProvider;
import feast.core.auth.authentication.DefaultJwtAuthenticationProvider;
import feast.core.auth.authorization.AuthorizationProvider;
import feast.core.auth.authorization.Keto.KetoAuthorizationProvider;
import feast.core.config.FeastProperties.SecurityProperties;
import feast.proto.core.CoreServiceGrpc;
import java.util.ArrayList;
import java.util.List;
import net.devh.boot.grpc.server.security.authentication.BearerAuthenticationReader;
Expand Down Expand Up @@ -61,9 +61,9 @@ AuthenticationManager authenticationManager() {

if (securityProperties.getAuthentication().isEnabled()) {
switch (securityProperties.getAuthentication().getProvider()) {
case "GoogleOpenID":
case "jwt":
providers.add(
new GoogleOpenIDAuthenticationProvider(
new DefaultJwtAuthenticationProvider(
securityProperties.getAuthentication().getOptions()));
break;
default:
Expand Down Expand Up @@ -132,7 +132,7 @@ AuthorizationProvider authorizationProvider() {
if (securityProperties.getAuthentication().isEnabled()
&& securityProperties.getAuthorization().isEnabled()) {
switch (securityProperties.getAuthorization().getProvider()) {
case "KetoAuthorization":
case "keto":
return new KetoAuthorizationProvider(securityProperties.getAuthorization().getOptions());
default:
throw new IllegalArgumentException(
Expand Down
2 changes: 2 additions & 0 deletions core/src/main/java/feast/core/grpc/CoreServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,12 @@ public class CoreServiceImpl extends CoreServiceImplBase {
@Autowired
public CoreServiceImpl(
SpecService specService,
ProjectService projectService,
StatsService statsService,
JobService jobService,
FeastProperties feastProperties) {
this.specService = specService;
this.projectService = projectService;
this.jobService = jobService;
this.feastProperties = feastProperties;
this.statsService = statsService;
Expand Down
14 changes: 7 additions & 7 deletions core/src/main/java/feast/core/grpc/HealthServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,32 @@
*/
package feast.core.grpc;

import feast.core.service.AccessManagementService;
import feast.core.service.ProjectService;
import io.grpc.Status;
import io.grpc.health.v1.HealthGrpc.HealthImplBase;
import io.grpc.health.v1.HealthProto.HealthCheckRequest;
import io.grpc.health.v1.HealthProto.HealthCheckResponse;
import io.grpc.health.v1.HealthProto.HealthCheckResponse.ServingStatus;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import org.lognet.springboot.grpc.GRpcService;
import net.devh.boot.grpc.server.service.GrpcService;
import org.springframework.beans.factory.annotation.Autowired;

@Slf4j
@GRpcService
@GrpcService
public class HealthServiceImpl extends HealthImplBase {
private final AccessManagementService accessManagementService;
private final ProjectService projectService;

@Autowired
public HealthServiceImpl(AccessManagementService accessManagementService) {
this.accessManagementService = accessManagementService;
public HealthServiceImpl(ProjectService projectService) {
this.projectService = projectService;
}

@Override
public void check(
HealthCheckRequest request, StreamObserver<HealthCheckResponse> responseObserver) {
try {
accessManagementService.listProjects();
projectService.listProjects();
responseObserver.onNext(
HealthCheckResponse.newBuilder().setStatus(ServingStatus.SERVING).build());
responseObserver.onCompleted();
Expand Down
Loading

0 comments on commit 392b4d2

Please # to comment.