Skip to content

Commit 1c85e3a

Browse files
authored
Allow unauthenticated access when Authorization is disabled and to Health Probe (feast-dev#927)
* Config Core/Serving authentication to allow unauthenticated access to health probe. * Allow unauthenticated requests when only authentication but not authorization is enabled. * Fix ServingServiceOauthAuthenticationIT * Add missing applyFeatureSet call to ServingServiceOauthAuthenticationIT
1 parent 3590339 commit 1c85e3a

File tree

5 files changed

+39
-28
lines changed

5 files changed

+39
-28
lines changed

auth/src/main/java/feast/auth/config/SecurityConfig.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,13 @@ GrpcAuthenticationReader authenticationReader() {
8383
}
8484

8585
/**
86-
* Creates an AccessDecisionManager if authentication is enabled. This object determines the
87-
* policy used to make authentication decisions.
86+
* Creates an AccessDecisionManager if authorization is enabled. This object determines the policy
87+
* used to make authorization decisions.
8888
*
8989
* @return AccessDecisionManager
9090
*/
9191
@Bean
92-
@ConditionalOnProperty(prefix = "feast.security.authentication", name = "enabled")
92+
@ConditionalOnProperty(prefix = "feast.security.authorization", name = "enabled")
9393
AccessDecisionManager accessDecisionManager() {
9494
final List<AccessDecisionVoter<?>> voters = new ArrayList<>();
9595
voters.add(new AccessPredicateVoter());

core/src/main/java/feast/core/config/CoreSecurityConfig.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package feast.core.config;
1818

1919
import feast.proto.core.CoreServiceGrpc;
20+
import io.grpc.health.v1.HealthGrpc;
2021
import lombok.extern.slf4j.Slf4j;
2122
import net.devh.boot.grpc.server.security.check.AccessPredicate;
2223
import net.devh.boot.grpc.server.security.check.GrpcSecurityMetadataSource;
@@ -48,6 +49,7 @@ GrpcSecurityMetadataSource grpcSecurityMetadataSource() {
4849
// The following endpoints allow unauthenticated access
4950
source.set(CoreServiceGrpc.getGetFeastCoreVersionMethod(), AccessPredicate.permitAll());
5051
source.set(CoreServiceGrpc.getUpdateStoreMethod(), AccessPredicate.permitAll());
52+
source.set(HealthGrpc.getCheckMethod(), AccessPredicate.permitAll());
5153
return source;
5254
}
5355
}

core/src/test/java/feast/core/auth/CoreServiceAuthenticationIT.java

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
import io.grpc.CallCredentials;
3333
import io.grpc.Channel;
3434
import io.grpc.ManagedChannelBuilder;
35-
import io.grpc.StatusRuntimeException;
3635
import java.util.*;
3736
import org.junit.ClassRule;
3837
import org.junit.Rule;
@@ -121,18 +120,24 @@ public void shouldGetVersionFromFeastCoreAlways() {
121120
assertEquals(feastProperties.getVersion(), feastCoreVersionSecure);
122121
}
123122

123+
/**
124+
* If authentication is enabled but authorization is disabled, users can still connect to Feast
125+
* Core as anonymous users. They are not forced to authenticate.
126+
*/
124127
@Test
125-
public void shouldNotAllowUnauthenticatedFeatureSetListing() {
126-
Exception exception =
127-
assertThrows(
128-
StatusRuntimeException.class,
129-
() -> {
130-
insecureApiClient.simpleListFeatureSets("*");
131-
});
132-
133-
String expectedMessage = "UNAUTHENTICATED: Authentication failed";
134-
String actualMessage = exception.getMessage();
135-
assertEquals(actualMessage, expectedMessage);
128+
public void shouldAllowUnauthenticatedFeatureSetListing() {
129+
FeatureSetProto.FeatureSet expectedFeatureSet = DataGenerator.getDefaultFeatureSet();
130+
insecureApiClient.simpleApplyFeatureSet(expectedFeatureSet);
131+
132+
List<FeatureSetProto.FeatureSet> listFeatureSetsResponse =
133+
insecureApiClient.simpleListFeatureSets("*");
134+
FeatureSetProto.FeatureSet actualFeatureSet = listFeatureSetsResponse.get(0);
135+
136+
assert listFeatureSetsResponse.size() == 1;
137+
assertEquals(
138+
actualFeatureSet.getSpec().getProject(), expectedFeatureSet.getSpec().getProject());
139+
assertEquals(
140+
actualFeatureSet.getSpec().getProject(), expectedFeatureSet.getSpec().getProject());
136141
}
137142

138143
@Test

serving/src/main/java/feast/serving/config/ServingSecurityConfig.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818

1919
import feast.auth.credentials.GoogleAuthCredentials;
2020
import feast.auth.credentials.OAuthCredentials;
21+
import feast.proto.serving.ServingServiceGrpc;
2122
import io.grpc.CallCredentials;
23+
import io.grpc.health.v1.HealthGrpc;
2224
import java.io.IOException;
2325
import net.devh.boot.grpc.server.security.check.AccessPredicate;
2426
import net.devh.boot.grpc.server.security.check.GrpcSecurityMetadataSource;
@@ -67,6 +69,10 @@ GrpcSecurityMetadataSource grpcSecurityMetadataSource() {
6769

6870
// Authentication is enabled for all gRPC endpoints
6971
source.setDefault(AccessPredicate.authenticated());
72+
73+
// The following endpoints allow unauthenticated access
74+
source.set(ServingServiceGrpc.getGetFeastServingInfoMethod(), AccessPredicate.permitAll());
75+
source.set(HealthGrpc.getCheckMethod(), AccessPredicate.permitAll());
7076
return source;
7177
}
7278

serving/src/test/java/feast/serving/it/ServingServiceOauthAuthenticationIT.java

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package feast.serving.it;
1818

1919
import static org.junit.jupiter.api.Assertions.assertEquals;
20-
import static org.junit.jupiter.api.Assertions.assertThrows;
2120
import static org.junit.jupiter.api.Assertions.assertTrue;
2221
import static org.testcontainers.containers.wait.strategy.Wait.forHttp;
2322

@@ -26,7 +25,6 @@
2625
import feast.proto.serving.ServingServiceGrpc.ServingServiceBlockingStub;
2726
import feast.proto.types.ValueProto.Value;
2827
import io.grpc.ManagedChannel;
29-
import io.grpc.StatusRuntimeException;
3028
import java.io.File;
3129
import java.io.IOException;
3230
import java.time.Duration;
@@ -87,21 +85,21 @@ static void globalSetup() throws IOException, InitializationError, InterruptedEx
8785
}
8886

8987
@Test
90-
public void shouldNotAllowUnauthenticatedGetOnlineFeatures() {
88+
public void shouldAllowUnauthenticatedGetOnlineFeatures() {
89+
// apply feature set
90+
CoreSimpleAPIClient coreClient =
91+
AuthTestUtils.getSecureApiClientForCore(FEAST_CORE_PORT, options);
92+
AuthTestUtils.applyFeatureSet(coreClient, PROJECT_NAME, ENTITY_ID, FEATURE_NAME);
9193
ServingServiceBlockingStub servingStub =
9294
AuthTestUtils.getServingServiceStub(false, FEAST_SERVING_PORT, null);
9395
GetOnlineFeaturesRequest onlineFeatureRequest =
9496
AuthTestUtils.createOnlineFeatureRequest(PROJECT_NAME, FEATURE_NAME, ENTITY_ID, 1);
95-
Exception exception =
96-
assertThrows(
97-
StatusRuntimeException.class,
98-
() -> {
99-
servingStub.getOnlineFeatures(onlineFeatureRequest);
100-
});
101-
102-
String expectedMessage = "UNAUTHENTICATED: Authentication failed";
103-
String actualMessage = exception.getMessage();
104-
assertEquals(actualMessage, expectedMessage);
97+
GetOnlineFeaturesResponse featureResponse = servingStub.getOnlineFeatures(onlineFeatureRequest);
98+
assertEquals(1, featureResponse.getFieldValuesCount());
99+
Map<String, Value> fieldsMap = featureResponse.getFieldValues(0).getFieldsMap();
100+
assertTrue(fieldsMap.containsKey(ENTITY_ID));
101+
assertTrue(fieldsMap.containsKey(FEATURE_NAME));
102+
((ManagedChannel) servingStub.getChannel()).shutdown();
105103
}
106104

107105
@Test

0 commit comments

Comments
 (0)