Skip to content

Commit d21e007

Browse files
authored
Merge branch 'datahub-project:master' into master
2 parents fa26c82 + 30719ac commit d21e007

File tree

524 files changed

+22593
-4295
lines changed

Some content is hidden

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

524 files changed

+22593
-4295
lines changed

.github/workflows/pr-labeler.yml

+4-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ jobs:
5252
"chakru-r",
5353
"brock-acryl",
5454
"mminichino",
55-
"jayacryl"
55+
"jayacryl",
56+
"v-tarasevich-blitz-brain",
57+
"ryota-cloud",
58+
"annadoesdesign"
5659
]'),
5760
github.actor
5861
)

.github/workflows/python-build-pages.yml

+3-13
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88
- "metadata-ingestion/**"
99
- "metadata-ingestion-modules/**"
1010
- "metadata-models/**"
11-
pull_request_target:
11+
pull_request:
1212
branches:
1313
- "**"
1414
paths:
@@ -38,11 +38,7 @@ jobs:
3838
distribution: "zulu"
3939
java-version: 17
4040
- uses: gradle/actions/setup-gradle@v4
41-
- uses: actions/checkout@v4
42-
# Note: not using acryldata/sane-checkout-action because this is a
43-
# pull_request_target event, and hence requires `ref`.
44-
with:
45-
ref: ${{ github.event.pull_request.head.sha }}
41+
- uses: acryldata/sane-checkout-action@v3
4642
- uses: actions/setup-python@v5
4743
with:
4844
python-version: "3.10"
@@ -58,17 +54,11 @@ jobs:
5854
env:
5955
GITHUB_TOKEN: ${{ github.token }}
6056
- name: Publish
61-
# Cloudflare's pages-action does not support PRs from forks.
62-
# See https://developers.cloudflare.com/pages/platform/known-issues/
63-
# Based on the discussion here https://github.com/json-schema-org/website/issues/330
64-
# we can use a direct upload to work around this limitation.
65-
# See https://github.com/AdrianGonz97/refined-cf-pages-action#enabling-pr-previews-from-forks
66-
uses: AdrianGonz97/refined-cf-pages-action@v1
57+
uses: cloudflare/pages-action@v1
6758
with:
6859
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
6960
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
7061
projectName: ${{ vars.CLOUDFLARE_WHEELS_PROJECT_NAME }}
71-
deploymentName: ${{ vars.CLOUDFLARE_WHEELS_PROJECT_NAME }}
7262
workingDirectory: python-build
7363
directory: site
7464
gitHubToken: ${{ github.token }}

build.gradle

+50-15
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import org.apache.tools.ant.filters.ReplaceTokens
2+
3+
14
buildscript {
25
ext.jdkVersionDefault = 17
36
ext.javaClassVersionDefault = 11
@@ -60,6 +63,7 @@ buildscript {
6063
ext.googleJavaFormatVersion = '1.18.1'
6164
ext.openLineageVersion = '1.25.0'
6265
ext.logbackClassicJava8 = '1.2.12'
66+
ext.awsSdk2Version = '2.30.33'
6367

6468
ext.docker_registry = 'acryldata'
6569

@@ -120,12 +124,12 @@ project.ext.externalDependency = [
120124
'assertJ': 'org.assertj:assertj-core:3.11.1',
121125
'avro': 'org.apache.avro:avro:1.11.4',
122126
'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',
127+
'awsGlueSchemaRegistrySerde': 'software.amazon.glue:schema-registry-serde:1.1.23',
128+
'awsMskIamAuth': 'software.amazon.msk:aws-msk-iam-auth:2.3.0',
129+
'awsS3': "software.amazon.awssdk:s3:$awsSdk2Version",
130+
'awsSecretsManagerJdbc': 'com.amazonaws.secretsmanager:aws-secretsmanager-jdbc:1.0.15',
131+
'awsPostgresIamAuth': 'software.amazon.jdbc:aws-advanced-jdbc-wrapper:2.5.4',
132+
'awsRds':"software.amazon.awssdk:rds:$awsSdk2Version",
129133
'cacheApi': 'javax.cache:cache-api:1.1.0',
130134
'commonsCli': 'commons-cli:commons-cli:1.5.0',
131135
'commonsIo': 'commons-io:commons-io:2.17.0',
@@ -240,7 +244,7 @@ project.ext.externalDependency = [
240244
'playFilters': "com.typesafe.play:filters-helpers_$playScalaVersion:$playVersion",
241245
'pac4j': 'org.pac4j:pac4j-oidc:6.0.6',
242246
'playPac4j': "org.pac4j:play-pac4j_$playScalaVersion:12.0.0-PLAY2.8",
243-
'postgresql': 'org.postgresql:postgresql:42.7.4',
247+
'postgresql': 'org.postgresql:postgresql:42.7.5',
244248
'protobuf': 'com.google.protobuf:protobuf-java:3.25.5',
245249
'grpcProtobuf': 'io.grpc:grpc-protobuf:1.53.0',
246250
'rangerCommons': 'org.apache.ranger:ranger-plugins-common:2.3.0',
@@ -395,25 +399,56 @@ configure(subprojects.findAll {! it.name.startsWith('spark-lineage')}) {
395399
}
396400
}
397401

402+
apply plugin: 'com.gorylenko.gradle-git-properties'
403+
gitProperties {
404+
keys = ['git.commit.id','git.commit.id.describe','git.commit.time']
405+
// using any tags (not limited to annotated tags) for "git.commit.id.describe" property
406+
// see http://ajoberstar.org/grgit/grgit-describe.html for more info about the describe method and available parameters
407+
// 'it' is an instance of org.ajoberstar.grgit.Grgit
408+
customProperty 'git.commit.id.describe', { it.describe(tags: true) }
409+
gitPropertiesResourceDir = rootProject.buildDir
410+
failOnNoGitDirectory = false
411+
}
412+
413+
def gitPropertiesGenerated = false
414+
415+
apply from: 'gradle/versioning/versioning-global.gradle'
416+
417+
tasks.register("generateGitPropertiesGlobal", com.gorylenko.GenerateGitPropertiesTask) {
418+
doFirst {
419+
if (!gitPropertiesGenerated) {
420+
println "Generating git.properties"
421+
gitPropertiesGenerated = true
422+
} else {
423+
// Skip actual execution if already run
424+
onlyIf { false }
425+
}
426+
}
427+
}
428+
398429
subprojects {
399430

400431
apply plugin: 'maven-publish'
401-
apply plugin: 'com.gorylenko.gradle-git-properties'
402432
apply plugin: 'com.diffplug.spotless'
403433

404-
gitProperties {
405-
keys = ['git.commit.id','git.commit.id.describe','git.commit.time']
406-
// using any tags (not limited to annotated tags) for "git.commit.id.describe" property
407-
// see http://ajoberstar.org/grgit/grgit-describe.html for more info about the describe method and available parameters
408-
// 'it' is an instance of org.ajoberstar.grgit.Grgit
409-
customProperty 'git.commit.id.describe', { it.describe(tags: true) }
410-
failOnNoGitDirectory = false
434+
def gitPropertiesTask = tasks.register("copyGitProperties", Copy) {
435+
dependsOn rootProject.tasks.named("generateGitPropertiesGlobal")
436+
def sourceFile = file("${rootProject.buildDir}/git.properties")
437+
from sourceFile
438+
into "$project.buildDir/resources/main"
411439
}
412440

413441
plugins.withType(JavaPlugin).configureEach {
442+
project.tasks.named(JavaPlugin.CLASSES_TASK_NAME).configure{
443+
dependsOn gitPropertiesTask
444+
}
414445
if (project.name == 'datahub-web-react') {
415446
return
416447
}
448+
/* TODO: evaluate ignoring jar timestamps for increased caching (compares checksum instead)
449+
jar {
450+
preserveFileTimestamps = false
451+
}*/
417452

418453
dependencies {
419454
implementation externalDependency.annotationApi
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/app/security/AuthenticationManager.java

+45-11
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,65 @@
33
import com.google.common.base.Preconditions;
44
import javax.annotation.Nonnull;
55
import javax.naming.AuthenticationException;
6+
import javax.security.auth.callback.Callback;
7+
import javax.security.auth.callback.CallbackHandler;
8+
import javax.security.auth.callback.NameCallback;
9+
import javax.security.auth.callback.PasswordCallback;
10+
import javax.security.auth.login.LoginContext;
11+
import javax.security.auth.login.LoginException;
612
import org.apache.commons.lang3.StringUtils;
7-
import org.eclipse.jetty.security.UserPrincipal;
8-
import org.eclipse.jetty.util.security.Credential;
13+
import org.slf4j.Logger;
14+
import org.slf4j.LoggerFactory;
915

1016
public class AuthenticationManager {
17+
private static final Logger log = LoggerFactory.getLogger(AuthenticationManager.class);
18+
1119
private AuthenticationManager() {} // Prevent instantiation
1220

1321
public static void authenticateJaasUser(@Nonnull String userName, @Nonnull String password)
1422
throws Exception {
1523
Preconditions.checkArgument(!StringUtils.isAnyEmpty(userName), "Username cannot be empty");
1624

1725
try {
18-
// Create and configure credentials for authentication
19-
UserPrincipal userPrincipal = new UserPrincipal(userName, Credential.getCredential(password));
26+
// Create a login context with our custom callback handler
27+
LoginContext loginContext =
28+
new LoginContext("WHZ-Authentication", new WHZCallbackHandler(userName, password));
2029

21-
// Verify credentials
22-
if (!userPrincipal.authenticate(password)) {
23-
throw new AuthenticationException("Invalid credentials for user: " + userName);
24-
}
30+
// Attempt login
31+
loginContext.login();
32+
33+
// If we get here, authentication succeeded
34+
log.debug("Authentication succeeded for user: {}", userName);
2535

26-
} catch (Exception e) {
36+
} catch (LoginException le) {
37+
log.info("Authentication failed for user {}: {}", userName, le.getMessage());
2738
AuthenticationException authenticationException =
28-
new AuthenticationException("Authentication failed");
29-
authenticationException.setRootCause(e);
39+
new AuthenticationException(le.getMessage());
40+
authenticationException.setRootCause(le);
3041
throw authenticationException;
3142
}
3243
}
44+
45+
private static class WHZCallbackHandler implements CallbackHandler {
46+
private final String password;
47+
private final String username;
48+
49+
private WHZCallbackHandler(@Nonnull String username, @Nonnull String password) {
50+
this.username = username;
51+
this.password = password;
52+
}
53+
54+
@Override
55+
public void handle(@Nonnull Callback[] callbacks) {
56+
for (Callback callback : callbacks) {
57+
if (callback instanceof NameCallback) {
58+
NameCallback nc = (NameCallback) callback;
59+
nc.setName(username);
60+
} else if (callback instanceof PasswordCallback) {
61+
PasswordCallback pc = (PasswordCallback) callback;
62+
pc.setPassword(password.toCharArray());
63+
}
64+
}
65+
}
66+
}
3367
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package security;
2+
3+
import java.security.Principal;
4+
5+
public class DataHubUserPrincipal implements Principal {
6+
private final String name;
7+
8+
public DataHubUserPrincipal(String name) {
9+
this.name = name;
10+
}
11+
12+
@Override
13+
public String getName() {
14+
return name;
15+
}
16+
17+
@Override
18+
public boolean equals(Object o) {
19+
if (this == o) return true;
20+
if (o == null || getClass() != o.getClass()) return false;
21+
22+
DataHubUserPrincipal that = (DataHubUserPrincipal) o;
23+
return name.equals(that.name);
24+
}
25+
26+
@Override
27+
public int hashCode() {
28+
return name.hashCode();
29+
}
30+
31+
@Override
32+
public String toString() {
33+
return "DataHubUserPrincipal[" + name + "]";
34+
}
35+
}

0 commit comments

Comments
 (0)