Skip to content

Commit c01cb37

Browse files
Merge branch 'master' into openapi-ingest
2 parents 40b5e41 + a101c27 commit c01cb37

File tree

227 files changed

+16447
-2289
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

227 files changed

+16447
-2289
lines changed

build.gradle

+8-7
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ buildscript {
6060
ext.googleJavaFormatVersion = '1.18.1'
6161
ext.openLineageVersion = '1.25.0'
6262
ext.logbackClassicJava8 = '1.2.12'
63+
ext.awsSdk2Version = '2.30.33'
6364

6465
ext.docker_registry = 'acryldata'
6566

@@ -120,12 +121,12 @@ project.ext.externalDependency = [
120121
'assertJ': 'org.assertj:assertj-core:3.11.1',
121122
'avro': 'org.apache.avro:avro:1.11.4',
122123
'avroCompiler': 'org.apache.avro:avro-compiler:1.11.4',
123-
'awsGlueSchemaRegistrySerde': 'software.amazon.glue:schema-registry-serde:1.1.17',
124-
'awsMskIamAuth': 'software.amazon.msk:aws-msk-iam-auth:2.0.3',
125-
'awsS3': 'software.amazon.awssdk:s3:2.26.21',
126-
'awsSecretsManagerJdbc': 'com.amazonaws.secretsmanager:aws-secretsmanager-jdbc:1.0.13',
127-
'awsPostgresIamAuth': 'software.amazon.jdbc:aws-advanced-jdbc-wrapper:1.0.2',
128-
'awsRds':'software.amazon.awssdk:rds:2.18.24',
124+
'awsGlueSchemaRegistrySerde': 'software.amazon.glue:schema-registry-serde:1.1.23',
125+
'awsMskIamAuth': 'software.amazon.msk:aws-msk-iam-auth:2.3.0',
126+
'awsS3': "software.amazon.awssdk:s3:$awsSdk2Version",
127+
'awsSecretsManagerJdbc': 'com.amazonaws.secretsmanager:aws-secretsmanager-jdbc:1.0.15',
128+
'awsPostgresIamAuth': 'software.amazon.jdbc:aws-advanced-jdbc-wrapper:2.5.4',
129+
'awsRds':"software.amazon.awssdk:rds:$awsSdk2Version",
129130
'cacheApi': 'javax.cache:cache-api:1.1.0',
130131
'commonsCli': 'commons-cli:commons-cli:1.5.0',
131132
'commonsIo': 'commons-io:commons-io:2.17.0',
@@ -240,7 +241,7 @@ project.ext.externalDependency = [
240241
'playFilters': "com.typesafe.play:filters-helpers_$playScalaVersion:$playVersion",
241242
'pac4j': 'org.pac4j:pac4j-oidc:6.0.6',
242243
'playPac4j': "org.pac4j:play-pac4j_$playScalaVersion:12.0.0-PLAY2.8",
243-
'postgresql': 'org.postgresql:postgresql:42.7.4',
244+
'postgresql': 'org.postgresql:postgresql:42.7.5',
244245
'protobuf': 'com.google.protobuf:protobuf-java:3.25.5',
245246
'grpcProtobuf': 'io.grpc:grpc-protobuf:1.53.0',
246247
'rangerCommons': 'org.apache.ranger:ranger-plugins-common:2.3.0',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package auth;
2+
3+
public class GuestAuthenticationConfigs {
4+
public static final String GUEST_ENABLED_CONFIG_PATH = "auth.guest.enabled";
5+
public static final String GUEST_USER_CONFIG_PATH = "auth.guest.user";
6+
public static final String GUEST_PATH_CONFIG_PATH = "auth.guest.path";
7+
public static final String DEFAULT_GUEST_USER_NAME = "guest";
8+
public static final String DEFAULT_GUEST_PATH = "/public";
9+
10+
private Boolean isEnabled = false;
11+
private String guestUser =
12+
DEFAULT_GUEST_USER_NAME; // Default if not defined but guest auth is enabled.
13+
private String guestPath =
14+
DEFAULT_GUEST_PATH; // The path for initial access to login as guest and bypass login page.
15+
16+
public GuestAuthenticationConfigs(final com.typesafe.config.Config configs) {
17+
if (configs.hasPath(GUEST_ENABLED_CONFIG_PATH)
18+
&& configs.getBoolean(GUEST_ENABLED_CONFIG_PATH)) {
19+
isEnabled = true;
20+
}
21+
if (configs.hasPath(GUEST_USER_CONFIG_PATH)) {
22+
guestUser = configs.getString(GUEST_USER_CONFIG_PATH);
23+
}
24+
if (configs.hasPath(GUEST_PATH_CONFIG_PATH)) {
25+
guestPath = configs.getString(GUEST_PATH_CONFIG_PATH);
26+
}
27+
}
28+
29+
public boolean isGuestEnabled() {
30+
return isEnabled;
31+
}
32+
33+
public String getGuestUser() {
34+
return guestUser;
35+
}
36+
37+
public String getGuestPath() {
38+
return guestPath;
39+
}
40+
}

datahub-frontend/app/controllers/AuthenticationController.java

+21
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import auth.AuthUtils;
88
import auth.CookieConfigs;
9+
import auth.GuestAuthenticationConfigs;
910
import auth.JAASConfigs;
1011
import auth.NativeAuthenticationConfigs;
1112
import auth.sso.SsoManager;
@@ -58,6 +59,8 @@ public class AuthenticationController extends Controller {
5859
private final CookieConfigs cookieConfigs;
5960
private final JAASConfigs jaasConfigs;
6061
private final NativeAuthenticationConfigs nativeAuthenticationConfigs;
62+
private final GuestAuthenticationConfigs guestAuthenticationConfigs;
63+
6164
private final boolean verbose;
6265

6366
@Inject private org.pac4j.core.config.Config ssoConfig;
@@ -73,6 +76,7 @@ public AuthenticationController(@Nonnull Config configs) {
7376
cookieConfigs = new CookieConfigs(configs);
7477
jaasConfigs = new JAASConfigs(configs);
7578
nativeAuthenticationConfigs = new NativeAuthenticationConfigs(configs);
79+
guestAuthenticationConfigs = new GuestAuthenticationConfigs(configs);
7680
verbose = configs.hasPath(AUTH_VERBOSE_LOGGING) && configs.getBoolean(AUTH_VERBOSE_LOGGING);
7781
}
7882

@@ -110,6 +114,23 @@ public Result authenticate(Http.Request request) {
110114
return Results.redirect(redirectPath);
111115
}
112116

117+
if (guestAuthenticationConfigs.isGuestEnabled()
118+
&& guestAuthenticationConfigs.getGuestPath().equals(redirectPath)) {
119+
final String accessToken =
120+
authClient.generateSessionTokenForUser(guestAuthenticationConfigs.getGuestUser());
121+
redirectPath =
122+
"/"; // We requested guest login by accessing {guestPath} URL. It is not really a target.
123+
CorpuserUrn guestUserUrn = new CorpuserUrn(guestAuthenticationConfigs.getGuestUser());
124+
return Results.redirect(redirectPath)
125+
.withSession(createSessionMap(guestUserUrn.toString(), accessToken))
126+
.withCookies(
127+
createActorCookie(
128+
guestUserUrn.toString(),
129+
cookieConfigs.getTtlInHours(),
130+
cookieConfigs.getAuthCookieSameSite(),
131+
cookieConfigs.getAuthCookieSecure()));
132+
}
133+
113134
// 1. If SSO is enabled, redirect to IdP if not authenticated.
114135
if (ssoManager.isSsoEnabled()) {
115136
return redirectToIdentityProvider(request, redirectPath)

datahub-frontend/conf/application.conf

+5
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,11 @@ auth.oidc.grantType = ${?AUTH_OIDC_GRANT_TYPE}
203203
#
204204
auth.jaas.enabled = ${?AUTH_JAAS_ENABLED}
205205
auth.native.enabled = ${?AUTH_NATIVE_ENABLED}
206+
auth.guest.enabled = ${?GUEST_AUTHENTICATION_ENABLED}
207+
# The name of the guest user id
208+
auth.guest.user = ${?GUEST_AUTHENTICATION_USER}
209+
# The path to bypass login page and get logged in as guest
210+
auth.guest.path = ${?GUEST_AUTHENTICATION_PATH}
206211

207212
# Enforces the usage of a valid email for user sign up
208213
auth.native.signUp.enforceValidEmail = true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package security;
2+
3+
import static org.junit.jupiter.api.Assertions.*;
4+
5+
import auth.GuestAuthenticationConfigs;
6+
import com.typesafe.config.Config;
7+
import com.typesafe.config.ConfigFactory;
8+
import org.junit.jupiter.api.BeforeEach;
9+
import org.junit.jupiter.api.Test;
10+
import org.junit.jupiter.api.TestInstance;
11+
import org.junitpioneer.jupiter.ClearEnvironmentVariable;
12+
import org.junitpioneer.jupiter.SetEnvironmentVariable;
13+
14+
@TestInstance(TestInstance.Lifecycle.PER_METHOD)
15+
@SetEnvironmentVariable(key = "DATAHUB_SECRET", value = "test")
16+
@SetEnvironmentVariable(key = "KAFKA_BOOTSTRAP_SERVER", value = "")
17+
@SetEnvironmentVariable(key = "DATAHUB_ANALYTICS_ENABLED", value = "false")
18+
@SetEnvironmentVariable(key = "AUTH_OIDC_ENABLED", value = "true")
19+
@SetEnvironmentVariable(key = "AUTH_OIDC_JIT_PROVISIONING_ENABLED", value = "false")
20+
@SetEnvironmentVariable(key = "AUTH_OIDC_CLIENT_ID", value = "testclient")
21+
@SetEnvironmentVariable(key = "AUTH_OIDC_CLIENT_SECRET", value = "testsecret")
22+
@SetEnvironmentVariable(key = "AUTH_VERBOSE_LOGGING", value = "true")
23+
class GuestAuthenticationConfigsTest {
24+
25+
@BeforeEach
26+
@ClearEnvironmentVariable(key = "GUEST_AUTHENTICATION_ENABLED")
27+
@ClearEnvironmentVariable(key = "GUEST_AUTHENTICATION_USER")
28+
@ClearEnvironmentVariable(key = "GUEST_AUTHENTICATION_PATH")
29+
public void clearConfigCache() {
30+
ConfigFactory.invalidateCaches();
31+
}
32+
33+
@Test
34+
public void testGuestConfigDisabled() {
35+
Config config = ConfigFactory.load();
36+
GuestAuthenticationConfigs guestAuthConfig = new GuestAuthenticationConfigs(config);
37+
assertFalse(guestAuthConfig.isGuestEnabled());
38+
}
39+
40+
@Test
41+
@SetEnvironmentVariable(key = "GUEST_AUTHENTICATION_ENABLED", value = "true")
42+
public void testGuestConfigEnabled() {
43+
Config config = ConfigFactory.load();
44+
GuestAuthenticationConfigs guestAuthConfig = new GuestAuthenticationConfigs(config);
45+
assertTrue(guestAuthConfig.isGuestEnabled());
46+
assertEquals("guest", guestAuthConfig.getGuestUser());
47+
assertEquals("/public", guestAuthConfig.getGuestPath());
48+
}
49+
50+
@Test
51+
@SetEnvironmentVariable(key = "GUEST_AUTHENTICATION_ENABLED", value = "true")
52+
@SetEnvironmentVariable(key = "GUEST_AUTHENTICATION_USER", value = "publicUser")
53+
@SetEnvironmentVariable(key = "GUEST_AUTHENTICATION_PATH", value = "/publicPath")
54+
public void testGuestConfigWithUserEnabled() {
55+
Config config = ConfigFactory.load();
56+
GuestAuthenticationConfigs guestAuthConfig = new GuestAuthenticationConfigs(config);
57+
assertTrue(guestAuthConfig.isGuestEnabled());
58+
assertEquals("publicUser", guestAuthConfig.getGuestUser());
59+
assertEquals("/publicPath", guestAuthConfig.getGuestPath());
60+
}
61+
}

datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/GmsGraphQLEngine.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -1026,7 +1026,8 @@ private void configureQueryResolvers(final RuntimeWiring.Builder builder) {
10261026
new ScrollAcrossEntitiesResolver(this.entityClient, this.viewService))
10271027
.dataFetcher(
10281028
"searchAcrossLineage",
1029-
new SearchAcrossLineageResolver(this.entityClient, this.entityRegistry))
1029+
new SearchAcrossLineageResolver(
1030+
this.entityClient, this.entityRegistry, this.viewService))
10301031
.dataFetcher(
10311032
"scrollAcrossLineage", new ScrollAcrossLineageResolver(this.entityClient))
10321033
.dataFetcher(

datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/config/AppConfigResolver.java

+2
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ public CompletableFuture<AppConfig> get(final DataFetchingEnvironment environmen
204204
.setShowNavBarRedesign(_featureFlags.isShowNavBarRedesign())
205205
.setShowAutoCompleteResults(_featureFlags.isShowAutoCompleteResults())
206206
.setEntityVersioningEnabled(_featureFlags.isEntityVersioning())
207+
.setShowSearchBarAutocompleteRedesign(
208+
_featureFlags.isShowSearchBarAutocompleteRedesign())
207209
.build();
208210

209211
appConfig.setFeatureFlags(featureFlagsConfig);

datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/search/SearchAcrossLineageResolver.java

+26-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import com.google.common.collect.ImmutableSet;
88
import com.linkedin.common.urn.Urn;
9+
import com.linkedin.common.urn.UrnUtils;
910
import com.linkedin.datahub.graphql.QueryContext;
1011
import com.linkedin.datahub.graphql.concurrency.GraphQLConcurrencyUtils;
1112
import com.linkedin.datahub.graphql.generated.AndFilterInput;
@@ -25,8 +26,12 @@
2526
import com.linkedin.metadata.query.LineageFlags;
2627
import com.linkedin.metadata.query.SearchFlags;
2728
import com.linkedin.metadata.query.filter.Filter;
29+
import com.linkedin.metadata.query.filter.SortCriterion;
2830
import com.linkedin.metadata.search.LineageSearchResult;
31+
import com.linkedin.metadata.service.ViewService;
32+
import com.linkedin.metadata.utils.elasticsearch.FilterUtils;
2933
import com.linkedin.r2.RemoteInvocationException;
34+
import com.linkedin.view.DataHubViewInfo;
3035
import graphql.VisibleForTesting;
3136
import graphql.schema.DataFetcher;
3237
import graphql.schema.DataFetchingEnvironment;
@@ -53,10 +58,13 @@ public class SearchAcrossLineageResolver
5358

5459
private final EntityRegistry _entityRegistry;
5560

61+
private final ViewService _viewService;
62+
5663
@VisibleForTesting final Set<String> _allEntities;
5764
private final List<String> _allowedEntities;
5865

59-
public SearchAcrossLineageResolver(EntityClient entityClient, EntityRegistry entityRegistry) {
66+
public SearchAcrossLineageResolver(
67+
EntityClient entityClient, EntityRegistry entityRegistry, final ViewService viewService) {
6068
this._entityClient = entityClient;
6169
this._entityRegistry = entityRegistry;
6270
this._allEntities =
@@ -68,6 +76,8 @@ public SearchAcrossLineageResolver(EntityClient entityClient, EntityRegistry ent
6876
this._allEntities.stream()
6977
.filter(e -> !TRANSIENT_ENTITIES.contains(e))
7078
.collect(Collectors.toList());
79+
80+
this._viewService = viewService;
7181
}
7282

7383
private List<String> getEntityNamesFromInput(List<EntityType> inputTypes) {
@@ -127,6 +137,13 @@ public CompletableFuture<SearchAcrossLineageResults> get(DataFetchingEnvironment
127137
com.linkedin.metadata.graph.LineageDirection.valueOf(lineageDirection.toString());
128138
return GraphQLConcurrencyUtils.supplyAsync(
129139
() -> {
140+
final DataHubViewInfo maybeResolvedView =
141+
(input.getViewUrn() != null)
142+
? resolveView(
143+
context.getOperationContext(),
144+
_viewService,
145+
UrnUtils.getUrn(input.getViewUrn()))
146+
: null;
130147
try {
131148
log.debug(
132149
"Executing search across relationships: source urn {}, direction {}, entity types {}, query {}, filters: {}, start: {}, count: {}",
@@ -138,8 +155,13 @@ public CompletableFuture<SearchAcrossLineageResults> get(DataFetchingEnvironment
138155
start,
139156
count);
140157

141-
final Filter filter =
158+
final Filter baseFilter =
142159
ResolverUtils.buildFilter(input.getFilters(), input.getOrFilters());
160+
Filter filter =
161+
maybeResolvedView != null
162+
? FilterUtils.combineFilters(
163+
baseFilter, maybeResolvedView.getDefinition().getFilter())
164+
: baseFilter;
143165
final SearchFlags searchFlags;
144166
com.linkedin.datahub.graphql.generated.SearchFlags inputFlags = input.getSearchFlags();
145167
if (inputFlags != null) {
@@ -150,6 +172,7 @@ public CompletableFuture<SearchAcrossLineageResults> get(DataFetchingEnvironment
150172
} else {
151173
searchFlags = new SearchFlags().setFulltext(true).setSkipHighlighting(true);
152174
}
175+
List<SortCriterion> sortCriteria = SearchUtils.getSortCriteria(input.getSortInput());
153176
LineageSearchResult salResults =
154177
_entityClient.searchAcrossLineage(
155178
context
@@ -162,7 +185,7 @@ public CompletableFuture<SearchAcrossLineageResults> get(DataFetchingEnvironment
162185
sanitizedQuery,
163186
maxHops,
164187
filter,
165-
null,
188+
sortCriteria,
166189
start,
167190
count);
168191

datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/domain/DomainType.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ public class DomainType
4040
Constants.OWNERSHIP_ASPECT_NAME,
4141
Constants.INSTITUTIONAL_MEMORY_ASPECT_NAME,
4242
Constants.STRUCTURED_PROPERTIES_ASPECT_NAME,
43-
Constants.FORMS_ASPECT_NAME);
43+
Constants.FORMS_ASPECT_NAME,
44+
Constants.DISPLAY_PROPERTIES_ASPECT_NAME);
4445
private final EntityClient _entityClient;
4546

4647
public DomainType(final EntityClient entityClient) {

datahub-graphql-core/src/main/resources/app.graphql

+5
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,11 @@ type FeatureFlagsConfig {
593593
If turned on, exposes the versioning feature by allowing users to link entities in the UI.
594594
"""
595595
entityVersioningEnabled: Boolean!
596+
597+
"""
598+
If turned on, show the redesigned search bar's autocomplete
599+
"""
600+
showSearchBarAutocompleteRedesign: Boolean!
596601
}
597602

598603
"""

datahub-graphql-core/src/main/resources/search.graphql

+10
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,16 @@ input SearchAcrossLineageInput {
417417
Flags controlling the lineage query
418418
"""
419419
lineageFlags: LineageFlags
420+
421+
"""
422+
Optional - A View to apply when generating results
423+
"""
424+
viewUrn: String
425+
426+
"""
427+
Optional - Information on how to sort this search result
428+
"""
429+
sortInput: SearchSortInput
420430
}
421431

422432
"""

datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/search/ScrollAcrossLineageResolverTest.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import com.linkedin.metadata.search.LineageSearchEntityArray;
3232
import com.linkedin.metadata.search.MatchedFieldArray;
3333
import com.linkedin.metadata.search.SearchResultMetadata;
34+
import com.linkedin.metadata.service.ViewService;
3435
import graphql.schema.DataFetchingEnvironment;
3536
import io.datahubproject.metadata.context.OperationContext;
3637
import java.io.InputStream;
@@ -76,7 +77,7 @@ public void testAllEntitiesInitialization() {
7677
InputStream inputStream = ClassLoader.getSystemResourceAsStream("entity-registry.yml");
7778
EntityRegistry entityRegistry = new ConfigEntityRegistry(inputStream);
7879
SearchAcrossLineageResolver resolver =
79-
new SearchAcrossLineageResolver(_entityClient, entityRegistry);
80+
new SearchAcrossLineageResolver(_entityClient, entityRegistry, mock(ViewService.class));
8081
assertTrue(resolver._allEntities.contains("dataset"));
8182
assertTrue(resolver._allEntities.contains("dataFlow"));
8283
// Test for case sensitivity

0 commit comments

Comments
 (0)