From 4e7586ecaf3cc63cd39d8e53d50ba2452b41a5b0 Mon Sep 17 00:00:00 2001 From: John Joyce Date: Thu, 1 Jul 2021 13:59:44 -0700 Subject: [PATCH 1/3] Adding file-based authentication to datahub-frontend --- build.gradle | 1 + datahub-frontend/README.md | 2 +- .../controllers/AuthenticationController.java | 9 ++- .../app/security/AuthenticationManager.java | 4 +- datahub-frontend/conf/jaas.conf | 6 +- datahub-frontend/conf/user.props | 1 + datahub-frontend/play.gradle | 1 + datahub-frontend/run/frontend.env | 2 + datahub-frontend/run/jaas.conf | 8 ++ datahub-frontend/run/run-local-frontend | 2 +- datahub-frontend/run/run-local-frontend-debug | 2 +- docs-website/sidebars.js | 7 +- docs/how/auth/jaas.md | 71 ++++++++++++++++++ .../sso/configure-oidc-react-google.md | 4 +- .../sso/configure-oidc-react-okta.md | 4 +- .../{ => auth/sso}/configure-oidc-react.md | 6 +- .../how/{ => auth}/sso/img/google-setup-1.png | Bin .../how/{ => auth}/sso/img/google-setup-2.png | Bin docs/how/{ => auth}/sso/img/okta-setup-1.png | Bin docs/how/{ => auth}/sso/img/okta-setup-2.png | Bin 20 files changed, 110 insertions(+), 20 deletions(-) create mode 100644 datahub-frontend/conf/user.props create mode 100644 datahub-frontend/run/jaas.conf create mode 100644 docs/how/auth/jaas.md rename docs/how/{ => auth}/sso/configure-oidc-react-google.md (97%) rename docs/how/{ => auth}/sso/configure-oidc-react-okta.md (96%) rename docs/how/{ => auth/sso}/configure-oidc-react.md (97%) rename docs/how/{ => auth}/sso/img/google-setup-1.png (100%) rename docs/how/{ => auth}/sso/img/google-setup-2.png (100%) rename docs/how/{ => auth}/sso/img/okta-setup-1.png (100%) rename docs/how/{ => auth}/sso/img/okta-setup-2.png (100%) diff --git a/build.gradle b/build.gradle index 9affce7dab994a..90c3afc85c71e2 100644 --- a/build.gradle +++ b/build.gradle @@ -72,6 +72,7 @@ project.ext.externalDependency = [ 'javaxInject' : 'javax.inject:javax.inject:1', 'jerseyCore': 'org.glassfish.jersey.core:jersey-client:2.25.1', 'jerseyGuava': 'org.glassfish.jersey.bundles.repackaged:jersey-guava:2.25.1', + 'jettyJaas': 'org.eclipse.jetty:jetty-jaas:9.4.28.v20200408', 'jsonSimple': 'com.googlecode.json-simple:json-simple:1.1.1', 'junitJupiterApi': "org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion", 'junitJupiterParams': "org.junit.jupiter:junit-jupiter-params:$junitJupiterVersion", diff --git a/datahub-frontend/README.md b/datahub-frontend/README.md index 96b6234e9c05ae..be54eea3855cdb 100644 --- a/datahub-frontend/README.md +++ b/datahub-frontend/README.md @@ -321,7 +321,7 @@ WHZ-Authentication { ### Authentication in React The React app supports both JAAS as described above and separately OIDC authentication. To learn about configuring OIDC for React, -see the [OIDC in React](../docs/how/configure-oidc-react.md) document. +see the [OIDC in React](../docs/how/auth/sso/configure-oidc-react.md) document. ### API Debugging diff --git a/datahub-frontend/app/react/controllers/AuthenticationController.java b/datahub-frontend/app/react/controllers/AuthenticationController.java index a04c5ca02f50f4..e544a7f3b666c5 100644 --- a/datahub-frontend/app/react/controllers/AuthenticationController.java +++ b/datahub-frontend/app/react/controllers/AuthenticationController.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.linkedin.common.urn.CorpuserUrn; -import com.linkedin.datahub.graphql.exception.ValidationException; import com.typesafe.config.Config; import org.apache.commons.lang3.StringUtils; import org.pac4j.core.client.Client; @@ -101,7 +100,9 @@ public Result logIn() { final String password = json.findPath(PASSWORD).textValue(); if (StringUtils.isBlank(username)) { - throw new ValidationException("username must not be empty"); + JsonNode invalidCredsJson = Json.newObject() + .put("message", "User name must not be empty."); + return badRequest(invalidCredsJson); } ctx().session().clear(); @@ -110,7 +111,9 @@ public Result logIn() { AuthenticationManager.authenticateUser(username, password); } catch (NamingException e) { _logger.error("Authentication error", e); - return badRequest("Invalid Credential"); + JsonNode invalidCredsJson = Json.newObject() + .put("message", "Invalid Credentials"); + return badRequest(invalidCredsJson); } final String actorUrn = new CorpuserUrn(username).toString(); diff --git a/datahub-frontend/app/security/AuthenticationManager.java b/datahub-frontend/app/security/AuthenticationManager.java index 00dfe5e18098eb..1fb755564999dd 100644 --- a/datahub-frontend/app/security/AuthenticationManager.java +++ b/datahub-frontend/app/security/AuthenticationManager.java @@ -31,8 +31,8 @@ public static void authenticateUser(@Nonnull String userName, @Nonnull String pa } private static class WHZCallbackHandler implements CallbackHandler { - private String password = null; - private String username = null; + private String password; + private String username; private WHZCallbackHandler(@Nonnull String username, @Nonnull String password) { this.username = username; diff --git a/datahub-frontend/conf/jaas.conf b/datahub-frontend/conf/jaas.conf index f18003238efac1..40e62dd8d3a03b 100644 --- a/datahub-frontend/conf/jaas.conf +++ b/datahub-frontend/conf/jaas.conf @@ -2,5 +2,7 @@ // DummyLoginModule -- this module can work with a username (that is in user table) and any password WHZ-Authentication { - security.DummyLoginModule sufficient; -}; + org.eclipse.jetty.jaas.spi.PropertyFileLoginModule sufficient + debug="true" + file="/datahub-frontend/conf/user.props"; +}; \ No newline at end of file diff --git a/datahub-frontend/conf/user.props b/datahub-frontend/conf/user.props new file mode 100644 index 00000000000000..c4dab3889ad4c3 --- /dev/null +++ b/datahub-frontend/conf/user.props @@ -0,0 +1 @@ +admin:mypass \ No newline at end of file diff --git a/datahub-frontend/play.gradle b/datahub-frontend/play.gradle index 87e363134be8d4..086d2434843e31 100644 --- a/datahub-frontend/play.gradle +++ b/datahub-frontend/play.gradle @@ -30,6 +30,7 @@ dependencies { play project(":datahub-dao") play project(":datahub-graphql-core") + play externalDependency.jettyJaas play externalDependency.graphqlJava play externalDependency.antlr4Runtime play externalDependency.antlr4 diff --git a/datahub-frontend/run/frontend.env b/datahub-frontend/run/frontend.env index 3714011d6d63e2..91532e0c4e4af6 100644 --- a/datahub-frontend/run/frontend.env +++ b/datahub-frontend/run/frontend.env @@ -28,3 +28,5 @@ DATAHUB_TRACKING_TOPIC=DataHubUsageEvent_v1 # Required Elastic Client Configuration (Analytics) ELASTIC_CLIENT_HOST=localhost ELASTIC_CLIENT_PORT=9200 + +# AUTH_JAAS_ENABLED=false diff --git a/datahub-frontend/run/jaas.conf b/datahub-frontend/run/jaas.conf new file mode 100644 index 00000000000000..f444c27c57f32c --- /dev/null +++ b/datahub-frontend/run/jaas.conf @@ -0,0 +1,8 @@ +// This is a sample JAAS config that uses the following login module +// DummyLoginModule -- this module can work with a username (that is in user table) and any password + +WHZ-Authentication { + org.eclipse.jetty.jaas.spi.PropertyFileLoginModule sufficient + debug="true" + file="../conf/user.props"; +}; \ No newline at end of file diff --git a/datahub-frontend/run/run-local-frontend b/datahub-frontend/run/run-local-frontend index 40201be05091b9..77041e91a1278a 100755 --- a/datahub-frontend/run/run-local-frontend +++ b/datahub-frontend/run/run-local-frontend @@ -13,7 +13,7 @@ export JAVA_OPTS=" -Xmx1024m -Dhttp.port=$PORT -Dconfig.file=$CONF_DIR/application.conf - -Djava.security.auth.login.config=$CONF_DIR/jaas.conf + -Djava.security.auth.login.config=$CURRENT_DIR/jaas.conf -Dlogback.configurationFile=$CURRENT_DIR/logback.xml -Dlogback.debug=true" diff --git a/datahub-frontend/run/run-local-frontend-debug b/datahub-frontend/run/run-local-frontend-debug index a8ea43abfec20a..8a5ab4455bf51e 100755 --- a/datahub-frontend/run/run-local-frontend-debug +++ b/datahub-frontend/run/run-local-frontend-debug @@ -13,7 +13,7 @@ export JAVA_OPTS=" -Xmx1024m -Dhttp.port=$PORT -Dconfig.file=$CONF_DIR/application.conf - -Djava.security.auth.login.config=$CONF_DIR/jaas.conf + -Djava.security.auth.login.config=$CURRENT_DIR/jaas.conf -Dlogback.configurationFile=$CURRENT_DIR/logback.xml -Dlogback.debug=true -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005" diff --git a/docs-website/sidebars.js b/docs-website/sidebars.js index bf5b7316283a2f..6ce8bc8aeca204 100644 --- a/docs-website/sidebars.js +++ b/docs-website/sidebars.js @@ -84,9 +84,10 @@ module.exports = { //"docs/demo/graph-onboarding", //"docs/how/search-onboarding", //"docs/how/search-over-new-field", - "docs/how/configure-oidc-react", - "docs/how/sso/configure-oidc-react-google", - "docs/how/sso/configure-oidc-react-okta", + "docs/how/auth/jaas", + "docs/how/auth/sso/configure-oidc-react", + "docs/how/auth/sso/configure-oidc-react-google", + "docs/how/auth/sso/configure-oidc-react-okta", "docs/how/restore-indices", "datahub-web-react/src/app/analytics/README", ], diff --git a/docs/how/auth/jaas.md b/docs/how/auth/jaas.md new file mode 100644 index 00000000000000..6268d608f49260 --- /dev/null +++ b/docs/how/auth/jaas.md @@ -0,0 +1,71 @@ +# JaaS Authentication + +## Overview + +The DataHub frontend server comes with support for plugging in [JaaS](https://docs.oracle.com/javase/7/docs/technotes/guides/security/jaas/JAASRefGuide.html) modules. +This allows you to use a custom authentication protocol to log your users into DataHub. + +By default, we in include sample configuration of a file-based username / password authentication module ([PropertyFileLoginModule](http://archive.eclipse.org/jetty/8.0.0.M3/apidocs/org/eclipse/jetty/plus/jaas/spi/PropertyFileLoginModule.html)) +that is configured with a single username / password combination: datahub - datahub. + +To change or extend the default behavior, you have multiple options, each dependent on which deployment environment you're operating in. + +### Modify user.props file directly (Local Testing) + +The first option for customizing file-based users is to modify the file `datahub-frontend/app/conf/user.props` directly. +Once you've added your desired users, you can simply run `./dev.sh` or `./datahub-frontend/run-local-frontend` to validate your +new users can log in. + +### Mount a custom user.props file (Docker Compose) + +By default, the `datahub-frontend` container will look for a file called `user.props` mounted at the container path +`/datahub-frontend/conf/user.props`. If you wish to launch this container with a custom set of users, you'll need to override the default +file mounting when running using `docker-compose`. + +To do so, change the `datahub-frontend-react` service in the docker-compose.yml file containing it to include the custom file: + +``` +datahub-frontend-react: + build: + context: ../ + dockerfile: docker/datahub-frontend/Dockerfile + image: linkedin/datahub-frontend-react:${DATAHUB_VERSION:-head} + env_file: datahub-frontend/env/docker.env + hostname: datahub-frontend-react + container_name: datahub-frontend-react + ports: + - "9002:9002" + depends_on: + - datahub-gms + volumes: + - ./my-custom-dir/user.props:/datahub-frontend/conf/user.props +``` + +And then run `docker-compose up` against your compose file. + + +## Custom JaaS Configuration + +In order to change the default JaaS module configuration, you will have to launch the `datahub-frontend-react` container with the custom `jaas.conf` file mounted as a volume +at the location `/datahub-frontend/conf/jaas.conf`. + +To do so, change the `datahub-frontend-react` service in the docker-compose.yml file containing it to include the custom file: + +``` +datahub-frontend-react: + build: + context: ../ + dockerfile: docker/datahub-frontend/Dockerfile + image: linkedin/datahub-frontend-react:${DATAHUB_VERSION:-head} + env_file: datahub-frontend/env/docker.env + hostname: datahub-frontend-react + container_name: datahub-frontend-react + ports: + - "9002:9002" + depends_on: + - datahub-gms + volumes: + - ./my-custom-dir/jaas.conf:/datahub-frontend/conf/jaas.conf +``` + +And then run `docker-compose up` against your compose file. diff --git a/docs/how/sso/configure-oidc-react-google.md b/docs/how/auth/sso/configure-oidc-react-google.md similarity index 97% rename from docs/how/sso/configure-oidc-react-google.md rename to docs/how/auth/sso/configure-oidc-react-google.md index 41d16392ea8483..c3aa82f5a967a4 100644 --- a/docs/how/sso/configure-oidc-react-google.md +++ b/docs/how/auth/sso/configure-oidc-react-google.md @@ -24,7 +24,7 @@ Note that in order to complete this step you should be logged into a Google acco c. Fill out the details in the App Information & Domain sections. Make sure the 'Application Home Page' provided matches where DataHub is deployed at your organization. -![google-setup-1](./img/google-setup-1.png) +![google-setup-1](img/google-setup-1.png) Once you've completed this, **Save & Continue**. @@ -63,7 +63,7 @@ f. You will now receive a pair of values, a client id and a client secret. Bookm At this point, you should be looking at a screen like the following: -![google-setup-2](./img/google-setup-2.png) +![google-setup-2](img/google-setup-2.png) Success! diff --git a/docs/how/sso/configure-oidc-react-okta.md b/docs/how/auth/sso/configure-oidc-react-okta.md similarity index 96% rename from docs/how/sso/configure-oidc-react-okta.md rename to docs/how/auth/sso/configure-oidc-react-okta.md index 733bb7aa3746fd..796a36e2ba7b2b 100644 --- a/docs/how/sso/configure-oidc-react-okta.md +++ b/docs/how/auth/sso/configure-oidc-react-okta.md @@ -47,8 +47,8 @@ for example, `https://dev-33231928.okta.com/.well-known/openid-configuration`. At this point, you should be looking at a screen like the following: -![okta-setup-1](./img/okta-setup-1.png) -![okta-setup-2](./img/okta-setup-2.png) +![okta-setup-1](img/okta-setup-1.png) +![okta-setup-2](img/okta-setup-2.png) Success! diff --git a/docs/how/configure-oidc-react.md b/docs/how/auth/sso/configure-oidc-react.md similarity index 97% rename from docs/how/configure-oidc-react.md rename to docs/how/auth/sso/configure-oidc-react.md index 0dafca9623d503..1495086c75a8d6 100644 --- a/docs/how/configure-oidc-react.md +++ b/docs/how/auth/sso/configure-oidc-react.md @@ -8,8 +8,8 @@ to be a secure environment and as such authentication is validated & enforced on ## Provider-Specific Guides -1. [Configuring OIDC using Google](./sso/configure-oidc-react-google.md) -2. [Configuring OIDC using Okta](./sso/configure-oidc-react-okta.md) +1. [Configuring OIDC using Google](configure-oidc-react-google.md) +2. [Configuring OIDC using Okta](configure-oidc-react-okta.md) ## Configuring OIDC in React @@ -47,7 +47,7 @@ this endpoint *will* exist as per the OIDC specification. For more info see http The second step to enabling OIDC involves configuring `datahub-frontend` to enable OIDC authentication with your Identity Provider. -To do so, you must update the `datahub-frontend` [docker.env](../../docker/datahub-frontend/env/docker.env) file with the +To do so, you must update the `datahub-frontend` [docker.env](../../../../docker/datahub-frontend/env/docker.env) file with the values received from your identity provider: ``` diff --git a/docs/how/sso/img/google-setup-1.png b/docs/how/auth/sso/img/google-setup-1.png similarity index 100% rename from docs/how/sso/img/google-setup-1.png rename to docs/how/auth/sso/img/google-setup-1.png diff --git a/docs/how/sso/img/google-setup-2.png b/docs/how/auth/sso/img/google-setup-2.png similarity index 100% rename from docs/how/sso/img/google-setup-2.png rename to docs/how/auth/sso/img/google-setup-2.png diff --git a/docs/how/sso/img/okta-setup-1.png b/docs/how/auth/sso/img/okta-setup-1.png similarity index 100% rename from docs/how/sso/img/okta-setup-1.png rename to docs/how/auth/sso/img/okta-setup-1.png diff --git a/docs/how/sso/img/okta-setup-2.png b/docs/how/auth/sso/img/okta-setup-2.png similarity index 100% rename from docs/how/sso/img/okta-setup-2.png rename to docs/how/auth/sso/img/okta-setup-2.png From 7581127ca299f9a1da7075102a11a416bf227819 Mon Sep 17 00:00:00 2001 From: John Joyce Date: Thu, 1 Jul 2021 14:03:06 -0700 Subject: [PATCH 2/3] Add datahub:datahub --- datahub-frontend/conf/user.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datahub-frontend/conf/user.props b/datahub-frontend/conf/user.props index c4dab3889ad4c3..fde693e0c3097f 100644 --- a/datahub-frontend/conf/user.props +++ b/datahub-frontend/conf/user.props @@ -1 +1 @@ -admin:mypass \ No newline at end of file +datahub:datahub \ No newline at end of file From d8a8810d36bd56aaf9f65c0802ee5c07afff1cea Mon Sep 17 00:00:00 2001 From: John Joyce Date: Fri, 2 Jul 2021 05:57:58 -0700 Subject: [PATCH 3/3] Addressing Fredriks comments --- datahub-frontend/conf/jaas.conf | 4 ++-- datahub-frontend/run/jaas.conf | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/datahub-frontend/conf/jaas.conf b/datahub-frontend/conf/jaas.conf index 40e62dd8d3a03b..64b7735609c260 100644 --- a/datahub-frontend/conf/jaas.conf +++ b/datahub-frontend/conf/jaas.conf @@ -1,8 +1,8 @@ // This is a sample JAAS config that uses the following login module -// DummyLoginModule -- this module can work with a username (that is in user table) and any password +// org.eclipse.jetty.jaas.spi.PropertyFileLoginModule -- this module can work with a username and any password defined in the `../conf/user.props` file WHZ-Authentication { org.eclipse.jetty.jaas.spi.PropertyFileLoginModule sufficient debug="true" file="/datahub-frontend/conf/user.props"; -}; \ No newline at end of file +}; diff --git a/datahub-frontend/run/jaas.conf b/datahub-frontend/run/jaas.conf index f444c27c57f32c..7e552b14a83e78 100644 --- a/datahub-frontend/run/jaas.conf +++ b/datahub-frontend/run/jaas.conf @@ -1,8 +1,9 @@ // This is a sample JAAS config that uses the following login module -// DummyLoginModule -- this module can work with a username (that is in user table) and any password +// This is a sample JAAS config that uses the following login module +// org.eclipse.jetty.jaas.spi.PropertyFileLoginModule -- this module can work with a username and any password defined in the `../conf/user.props` file WHZ-Authentication { org.eclipse.jetty.jaas.spi.PropertyFileLoginModule sufficient debug="true" file="../conf/user.props"; -}; \ No newline at end of file +};