Skip to content

Commit 4993206

Browse files
committed
feat(auth): user.props authentication
* document breaking change to user.props * add flag for legacy behavior
1 parent 7f64ffd commit 4993206

File tree

11 files changed

+85
-16
lines changed

11 files changed

+85
-16
lines changed

datahub-frontend/app/auth/AuthModule.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,12 @@ protected OperationContext provideOperationContext(
181181
final Authentication systemAuthentication,
182182
final ConfigurationProvider configurationProvider) {
183183
ActorContext systemActorContext =
184-
ActorContext.builder().systemAuth(true).authentication(systemAuthentication).build();
184+
ActorContext.builder()
185+
.systemAuth(true)
186+
.authentication(systemAuthentication)
187+
.enforceExistenceEnabled(
188+
configurationProvider.getAuthentication().isEnforceExistenceEnabled())
189+
.build();
185190
OperationContextConfig systemConfig =
186191
OperationContextConfig.builder()
187192
.viewAuthorizationConfiguration(configurationProvider.getAuthorization().getView())

datahub-frontend/app/config/ConfigurationProvider.java

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package config;
22

3+
import com.datahub.authentication.AuthenticationConfiguration;
34
import com.datahub.authorization.AuthorizationConfiguration;
45
import com.linkedin.metadata.config.VisualConfiguration;
56
import com.linkedin.metadata.config.cache.CacheConfiguration;
@@ -30,4 +31,7 @@ public class ConfigurationProvider {
3031

3132
/** Configuration for authorization */
3233
private AuthorizationConfiguration authorization;
34+
35+
/** Configuration for authentication */
36+
private AuthenticationConfiguration authentication;
3337
}

datahub-upgrade/src/main/java/com/linkedin/datahub/upgrade/config/SystemUpdateConfig.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,8 @@ protected OperationContext javaSystemOperationContext(
194194
ValidationContext.builder()
195195
.alternateValidation(
196196
configurationProvider.getFeatureFlags().isAlternateMCPValidation())
197-
.build());
197+
.build(),
198+
true);
198199

199200
entityServiceAspectRetriever.setSystemOperationContext(systemOperationContext);
200201
systemGraphRetriever.setSystemOperationContext(systemOperationContext);

docs/authentication/guides/add-users.md

+30
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import Tabs from '@theme/Tabs';
2+
import TabItem from '@theme/TabItem';
3+
14
# Onboarding Users to DataHub
25

36
New user accounts can be provisioned on DataHub in 3 ways:
@@ -94,6 +97,11 @@ using this mechanism. It is highly recommended that admins change or remove the
9497

9598
## Adding new users using a user.props file
9699

100+
:::NOTE
101+
Adding users via the `user.props` will require disabling existence checks on GMS using the `METADATA_SERVICE_AUTH_ENFORCE_EXISTENCE_ENABLED=false` environment variable or using the API to enable the user prior to login.
102+
The directions below include demonstrate using the API to enable the user.
103+
:::
104+
97105
To define a set of username / password combinations that should be allowed to log in to DataHub (in addition to the root 'datahub' user),
98106
create a new file called `user.props` at the file path `${HOME}/.datahub/plugins/frontend/auth/user.props` within the `datahub-frontend-react` container
99107
or pod.
@@ -107,6 +115,28 @@ janesmith:janespassword
107115
johndoe:johnspassword
108116
```
109117

118+
In order to enable the user access with the credential defined in `user.props`, set the `status` aspect on the user with an Admin user. This can be done using an API call or via the [OpenAPI UI interface](../../api/openapi/openapi-usage-guide).
119+
120+
<Tabs>
121+
<TabItem value="openapi" label="OpenAPI" default>
122+
123+
Example enabling login for the `janesmith` user from the example above. Make sure to update the example with your access token.
124+
125+
```shell
126+
curl -X 'POST' \
127+
'http://localhost:9002/openapi/v3/entity/corpuser/urn%3Ali%3Acorpuser%3Ajanesmith/status?async=false&systemMetadata=false&createIfEntityNotExists=false&createIfNotExists=true' \
128+
-H 'accept: application/json' \
129+
-H 'Content-Type: application/json' \
130+
-H 'Authorization: Bearer <access token>' \
131+
-d '{
132+
"value": {
133+
"removed": false
134+
}
135+
}'
136+
```
137+
</TabItem>
138+
</Tabs>
139+
110140
Once you've saved the file, simply start the DataHub containers & navigate to `http://localhost:9002/login`
111141
to verify that your new credentials work.
112142

docs/how/updating-datahub.md

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ This file documents any backwards-incompatible changes in DataHub and assists pe
6666
changed to NOT fill out `created` and `lastModified` auditstamps by default
6767
for input and output dataset edges. This should not have any user-observable
6868
impact (time-based lineage viz will still continue working based on observed time), but could break assumptions previously being made by clients.
69+
- #12158 - Users provisioned with `user.props` will need to be enabled before login in order to be granted access to DataHub.
6970

7071
### Potential Downtime
7172

metadata-operation-context/src/main/java/io/datahubproject/metadata/context/ActorContext.java

+12-4
Original file line numberDiff line numberDiff line change
@@ -29,23 +29,31 @@
2929
@EqualsAndHashCode
3030
public class ActorContext implements ContextInterface {
3131

32-
public static ActorContext asSystem(Authentication systemAuthentication) {
33-
return ActorContext.builder().systemAuth(true).authentication(systemAuthentication).build();
32+
public static ActorContext asSystem(
33+
Authentication systemAuthentication, boolean enforceExistenceEnabled) {
34+
return ActorContext.builder()
35+
.systemAuth(true)
36+
.authentication(systemAuthentication)
37+
.enforceExistenceEnabled(enforceExistenceEnabled)
38+
.build();
3439
}
3540

3641
public static ActorContext asSessionRestricted(
3742
Authentication authentication,
3843
Set<DataHubPolicyInfo> dataHubPolicySet,
39-
Collection<Urn> groupMembership) {
44+
Collection<Urn> groupMembership,
45+
boolean enforceExistenceEnabled) {
4046
return ActorContext.builder()
4147
.systemAuth(false)
4248
.authentication(authentication)
4349
.policyInfoSet(dataHubPolicySet)
4450
.groupMembership(groupMembership)
51+
.enforceExistenceEnabled(enforceExistenceEnabled)
4552
.build();
4653
}
4754

4855
private final Authentication authentication;
56+
private final boolean enforceExistenceEnabled;
4957

5058
@EqualsAndHashCode.Exclude @Builder.Default
5159
private final Set<DataHubPolicyInfo> policyInfoSet = Collections.emptySet();
@@ -79,7 +87,7 @@ public boolean isActive(AspectRetriever aspectRetriever) {
7987

8088
Map<String, Aspect> aspectMap = urnAspectMap.getOrDefault(selfUrn, Map.of());
8189

82-
if (!aspectMap.containsKey(CORP_USER_KEY_ASPECT_NAME)) {
90+
if (enforceExistenceEnabled && !aspectMap.containsKey(CORP_USER_KEY_ASPECT_NAME)) {
8391
// user is hard deleted
8492
return false;
8593
}

metadata-operation-context/src/main/java/io/datahubproject/metadata/context/OperationContext.java

+18-7
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,8 @@ public static OperationContext asSystem(
152152
@Nullable ServicesRegistryContext servicesRegistryContext,
153153
@Nullable IndexConvention indexConvention,
154154
@Nullable RetrieverContext retrieverContext,
155-
@Nonnull ValidationContext validationContext) {
155+
@Nonnull ValidationContext validationContext,
156+
boolean enforceExistenceEnabled) {
156157
return asSystem(
157158
config,
158159
systemAuthentication,
@@ -161,7 +162,8 @@ public static OperationContext asSystem(
161162
indexConvention,
162163
retrieverContext,
163164
validationContext,
164-
ObjectMapperContext.DEFAULT);
165+
ObjectMapperContext.DEFAULT,
166+
enforceExistenceEnabled);
165167
}
166168

167169
public static OperationContext asSystem(
@@ -172,10 +174,15 @@ public static OperationContext asSystem(
172174
@Nullable IndexConvention indexConvention,
173175
@Nullable RetrieverContext retrieverContext,
174176
@Nonnull ValidationContext validationContext,
175-
@Nonnull ObjectMapperContext objectMapperContext) {
177+
@Nonnull ObjectMapperContext objectMapperContext,
178+
boolean enforceExistenceEnabled) {
176179

177180
ActorContext systemActorContext =
178-
ActorContext.builder().systemAuth(true).authentication(systemAuthentication).build();
181+
ActorContext.builder()
182+
.systemAuth(true)
183+
.authentication(systemAuthentication)
184+
.enforceExistenceEnabled(enforceExistenceEnabled)
185+
.build();
179186
OperationContextConfig systemConfig =
180187
config.toBuilder().allowSystemAuthentication(true).build();
181188
SearchContext systemSearchContext =
@@ -457,13 +464,16 @@ public int hashCode() {
457464
public static class OperationContextBuilder {
458465

459466
@Nonnull
460-
public OperationContext build(@Nonnull Authentication sessionAuthentication) {
461-
return build(sessionAuthentication, false);
467+
public OperationContext build(
468+
@Nonnull Authentication sessionAuthentication, boolean enforceExistenceEnabled) {
469+
return build(sessionAuthentication, false, enforceExistenceEnabled);
462470
}
463471

464472
@Nonnull
465473
public OperationContext build(
466-
@Nonnull Authentication sessionAuthentication, boolean skipCache) {
474+
@Nonnull Authentication sessionAuthentication,
475+
boolean skipCache,
476+
boolean enforceExistenceEnabled) {
467477
final Urn actorUrn = UrnUtils.getUrn(sessionAuthentication.getActor().toUrnStr());
468478
final ActorContext sessionActor =
469479
ActorContext.builder()
@@ -476,6 +486,7 @@ public OperationContext build(
476486
.equals(sessionAuthentication.getActor()))
477487
.policyInfoSet(this.authorizationContext.getAuthorizer().getActorPolicies(actorUrn))
478488
.groupMembership(this.authorizationContext.getAuthorizer().getActorGroups(actorUrn))
489+
.enforceExistenceEnabled(enforceExistenceEnabled)
479490
.build();
480491
return build(sessionActor, skipCache);
481492
}

metadata-operation-context/src/main/java/io/datahubproject/test/metadata/context/TestOperationContexts.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,8 @@ public static OperationContext systemContext(
260260
servicesRegistryContext,
261261
indexConvention,
262262
retrieverContext,
263-
validationContext);
263+
validationContext,
264+
true);
264265

265266
if (postConstruct != null) {
266267
postConstruct.accept(operationContext);

metadata-service/auth-config/src/main/java/com/datahub/authentication/AuthenticationConfiguration.java

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ public class AuthenticationConfiguration {
99
/** Whether authentication is enabled */
1010
private boolean enabled;
1111

12+
/** Whether user existence is enforced */
13+
private boolean enforceExistenceEnabled;
14+
1215
/**
1316
* List of configurations for {@link com.datahub.plugins.auth.authentication.Authenticator}s to be
1417
* registered

metadata-service/configuration/src/main/resources/application.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ authentication:
66
# Enable if you want all requests to the Metadata Service to be authenticated.
77
enabled: ${METADATA_SERVICE_AUTH_ENABLED:true}
88

9+
# Disable if you want to skip validation of deleted user's tokens
10+
enforceExistenceEnabled: ${METADATA_SERVICE_AUTH_ENFORCE_EXISTENCE_ENABLED:true}
11+
912
# Required if enabled is true! A configurable chain of Authenticators
1013
authenticators:
1114
# Required for authenticating requests with DataHub-issued Access Tokens - best not to remove.

metadata-service/factories/src/main/java/com/linkedin/gms/factory/context/SystemOperationContextFactory.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ protected OperationContext javaSystemOperationContext(
7979
ValidationContext.builder()
8080
.alternateValidation(
8181
configurationProvider.getFeatureFlags().isAlternateMCPValidation())
82-
.build());
82+
.build(),
83+
configurationProvider.getAuthentication().isEnforceExistenceEnabled());
8384

8485
entityClientAspectRetriever.setSystemOperationContext(systemOperationContext);
8586
entityServiceAspectRetriever.setSystemOperationContext(systemOperationContext);
@@ -134,7 +135,8 @@ protected OperationContext restliSystemOperationContext(
134135
ValidationContext.builder()
135136
.alternateValidation(
136137
configurationProvider.getFeatureFlags().isAlternateMCPValidation())
137-
.build());
138+
.build(),
139+
configurationProvider.getAuthentication().isEnforceExistenceEnabled());
138140

139141
entityClientAspectRetriever.setSystemOperationContext(systemOperationContext);
140142
systemGraphRetriever.setSystemOperationContext(systemOperationContext);

0 commit comments

Comments
 (0)