From 689cabb5fec43a6b82e72b73465182dbe9aa1a35 Mon Sep 17 00:00:00 2001 From: William Turner <william.turner@aero.bombardier.com> Date: Wed, 8 Feb 2017 20:57:18 -0500 Subject: [PATCH] Adds UI integration (needs a lot more work) --- frontend/src/metabase/auth/auth.js | 7 +++-- .../src/metabase/auth/containers/LoginApp.jsx | 28 +++++++++++++------ frontend/src/metabase/lib/settings.js | 4 +++ frontend/src/metabase/services.js | 1 + src/metabase/api/session.clj | 19 ++++++------- src/metabase/public_settings.clj | 1 + 6 files changed, 40 insertions(+), 20 deletions(-) diff --git a/frontend/src/metabase/auth/auth.js b/frontend/src/metabase/auth/auth.js index b75b5db49a1..9cbe1536515 100644 --- a/frontend/src/metabase/auth/auth.js +++ b/frontend/src/metabase/auth/auth.js @@ -6,6 +6,7 @@ import { push } from "react-router-redux"; import MetabaseCookies from "metabase/lib/cookies"; import MetabaseUtils from "metabase/lib/utils"; import MetabaseAnalytics from "metabase/lib/analytics"; +import MetabaseSettings from "metabase/lib/settings.js"; import { clearGoogleAuthCredentials } from "metabase/lib/auth"; @@ -19,12 +20,14 @@ export const LOGIN = "metabase/auth/LOGIN"; export const login = createThunkAction(LOGIN, function(credentials, redirectUrl) { return async function(dispatch, getState) { - if (!MetabaseUtils.validEmail(credentials.email)) { + if (!MetabaseSettings.ldapEnabled() && !MetabaseUtils.validEmail(credentials.email)) { return {'data': {'errors': {'email': "Please enter a valid formatted email address."}}}; } try { - let newSession = await SessionApi.create(credentials); + let newSession = MetabaseSettings.ldapEnabled() + ? await SessionApi.createWithLdap(credentials) + : await SessionApi.create(credentials); // since we succeeded, lets set the session cookie MetabaseCookies.setSessionCookie(newSession.id); diff --git a/frontend/src/metabase/auth/containers/LoginApp.jsx b/frontend/src/metabase/auth/containers/LoginApp.jsx index 229febd771c..a9d4a2435ba 100644 --- a/frontend/src/metabase/auth/containers/LoginApp.jsx +++ b/frontend/src/metabase/auth/containers/LoginApp.jsx @@ -42,9 +42,11 @@ export default class LoginApp extends Component { validateForm() { let { credentials } = this.state; - let valid = true; + let valid = Settings.ldapEnabled() + ? !!credentials.username + : !!credentials.email; - if (!credentials.email || !credentials.password) { + if (!credentials.password) { valid = false; } @@ -128,11 +130,19 @@ export default class LoginApp extends Component { <FormMessage formError={loginError && loginError.data.message ? loginError : null} ></FormMessage> - <FormField key="email" fieldName="email" formError={loginError}> - <FormLabel title={"Email address"} fieldName={"email"} formError={loginError} /> - <input className="Form-input Form-offset full py1" name="email" placeholder="youlooknicetoday@email.com" type="text" onChange={(e) => this.onChange("email", e.target.value)} autoFocus /> - <span className="Form-charm"></span> - </FormField> + { Settings.ldapEnabled() ? ( + <FormField key="username" fieldName="username" formError={loginError}> + <FormLabel title={"Username or Email address"} fieldName={"username"} formError={loginError} /> + <input className="Form-input Form-offset full py1" name="username" placeholder="youlooknicetoday@email.com" type="text" onChange={(e) => this.onChange("username", e.target.value)} autoFocus /> + <span className="Form-charm"></span> + </FormField> + ) : ( + <FormField key="email" fieldName="email" formError={loginError}> + <FormLabel title={"Email address"} fieldName={"email"} formError={loginError} /> + <input className="Form-input Form-offset full py1" name="email" placeholder="youlooknicetoday@email.com" type="text" onChange={(e) => this.onChange("email", e.target.value)} autoFocus /> + <span className="Form-charm"></span> + </FormField> + )} <FormField key="password" fieldName="password" formError={loginError}> <FormLabel title={"Password"} fieldName={"password"} formError={loginError} /> @@ -150,7 +160,9 @@ export default class LoginApp extends Component { <button className={cx("Button Grid-cell", {'Button--primary': this.state.valid})} disabled={!this.state.valid}> Sign in </button> - <Link to={"/auth/forgot_password"+(this.state.credentials.email ? "?email="+this.state.credentials.email : "")} className="Grid-cell py2 sm-py0 text-grey-3 md-text-right text-centered flex-full link" onClick={(e) => { window.OSX ? window.OSX.resetPassword() : null }}>I seem to have forgotten my password</Link> + { (!Settings.ldapEnabled()) && + <Link to={"/auth/forgot_password"+(this.state.credentials.email ? "?email="+this.state.credentials.email : "")} className="Grid-cell py2 sm-py0 text-grey-3 md-text-right text-centered flex-full link" onClick={(e) => { window.OSX ? window.OSX.resetPassword() : null }}>I seem to have forgotten my password</Link> + } </div> </form> </div> diff --git a/frontend/src/metabase/lib/settings.js b/frontend/src/metabase/lib/settings.js index 5460a7b9568..4c0fdfaefbc 100644 --- a/frontend/src/metabase/lib/settings.js +++ b/frontend/src/metabase/lib/settings.js @@ -51,6 +51,10 @@ const MetabaseSettings = { return mb_settings.google_auth_client_id != null; }, + ldapEnabled: function() { + return mb_settings.ldap_configured; + }, + newVersionAvailable: function(settings) { let versionInfo = _.findWhere(settings, {key: "version-info"}), currentVersion = MetabaseSettings.get("version").tag; diff --git a/frontend/src/metabase/services.js b/frontend/src/metabase/services.js index 7705b6c16e9..a5e37dd65a1 100644 --- a/frontend/src/metabase/services.js +++ b/frontend/src/metabase/services.js @@ -172,6 +172,7 @@ export const LabelApi = { export const SessionApi = { create: POST("/api/session"), createWithGoogleAuth: POST("/api/session/google_auth"), + createWithLdap: POST("/api/session/ldap_auth"), delete: DELETE("/api/session"), properties: GET("/api/session/properties"), forgot_password: POST("/api/session/forgot_password"), diff --git a/src/metabase/api/session.clj b/src/metabase/api/session.clj index 93893241a7a..a9ea0f0e0a2 100644 --- a/src/metabase/api/session.clj +++ b/src/metabase/api/session.clj @@ -38,6 +38,7 @@ (def ^:private login-throttlers {:email (throttle/make-throttler :email) + :username (throttle/make-throttler :username) :ip-address (throttle/make-throttler :email, :attempts-threshold 50)}) ; IP Address doesn't have an actual UI field so just show error by email (defendpoint POST "/" @@ -220,8 +221,7 @@ "The password to bind with.") (defsetting ldap-base - "Search base for users." - :default "") + "Search base for users.") (defsetting ldap-user-filter "Filter to use for looking up a specific user, the placeholder {login} will be replaced by the user supplied value." @@ -273,16 +273,15 @@ (defendpoint POST "/ldap_auth" "Login with LDAP auth." - [:as {{:keys [email password]} :body, remote-address :remote-addr}] - {email su/Email + [:as {{:keys [username password]} :body, remote-address :remote-addr}] + {username su/NonBlankString password su/NonBlankString} (throttle/check (login-throttlers :ip-address) remote-address) - (throttle/check (login-throttlers :email) email) - (let [user (ldap-auth-user-info email password)] - (when (nil? user) - (throw (ex-info "Password did not match stored password." {:status-code 400 - :errors {:password "did not match stored password"}}))) - (ldap-auth-fetch-or-create-user! (:first-name user) (:last-name user) (:email user)))) + (throttle/check (login-throttlers :username) username) + (if-let [{:keys [first-name last-name email]} (ldap-auth-user-info username password)] + (ldap-auth-fetch-or-create-user! first-name last-name email) + (throw (ex-info "Password did not match stored password." {:status-code 400 + :errors {:password "did not match stored password"}})))) (define-routes) diff --git a/src/metabase/public_settings.clj b/src/metabase/public_settings.clj index 4d9900614fa..6ed7b788eec 100644 --- a/src/metabase/public_settings.clj +++ b/src/metabase/public_settings.clj @@ -119,6 +119,7 @@ :engines ((resolve 'metabase.driver/available-drivers)) :ga_code "UA-60817802-1" :google_auth_client_id (setting/get :google-auth-client-id) + :ldap_configured ((resolve 'metabase.api.session/ldap-configured?)) :has_sample_dataset (db/exists? 'Database, :is_sample true) :map_tile_server_url (map-tile-server-url) :password_complexity password/active-password-complexity -- GitLab