diff --git a/app/assets/locales/en.json b/app/assets/locales/en.json index 2fec3e4d1ba2c654ac79668939e0d9b50523a26f..8d58b358fb08e337267d6c3c1d561bdc1341708f 100644 --- a/app/assets/locales/en.json +++ b/app/assets/locales/en.json @@ -81,6 +81,7 @@ "account_info": "Account Info", "delete_account": "Delete Account", "change_password": "Change Password", + "set_password": "Set Your New Password", "reset_password": "Reset Password", "update_account_info": "Update Account Info", "current_password": "Current Password", @@ -358,6 +359,7 @@ "user_updated": "The user has been updated.", "user_deleted": "The user has been deleted.", "avatar_updated": "The avatar has been updated.", + "password_changed": "Successfully updated your password. Please sign in again.", "password_updated": "The password has been updated.", "account_activated": "Your account has been activated.", "activation_email_sent": "An email that contains the instructions to activate your account has been sent.", diff --git a/app/controllers/api/v1/api_controller.rb b/app/controllers/api/v1/api_controller.rb index 92b27351bf055a2950028e5609f9491d0503c2ff..0ebbe53fa198c389075bfaafd7b62ac3bb5ae4c4 100644 --- a/app/controllers/api/v1/api_controller.rb +++ b/app/controllers/api/v1/api_controller.rb @@ -90,8 +90,10 @@ module Api end # Checks if external authentication is enabled (currently only OIDC is implemented) - def external_authn_enabled? - ENV['OPENID_CONNECT_ISSUER'].present? + def external_auth? + return ENV['OPENID_CONNECT_ISSUER'].present? if ENV['LOADBALANCER_ENDPOINT'].blank? + + !Tenant.exists?(name: current_provider, client_secret: 'local') end end end diff --git a/app/controllers/api/v1/env_controller.rb b/app/controllers/api/v1/env_controller.rb index 946e261c2f4510629dd09bf2a59dd0c9c32b86b4..4982b208e08f269136efceb4faf8f393f8848809 100644 --- a/app/controllers/api/v1/env_controller.rb +++ b/app/controllers/api/v1/env_controller.rb @@ -25,7 +25,7 @@ module Api # Returns basic NON-CONFIDENTIAL information on the environment variables def index render_data data: { - EXTERNAL_AUTH: ENV['OPENID_CONNECT_ISSUER'].present?, # currently only OIDC is implemented + EXTERNAL_AUTH: external_auth?, HCAPTCHA_KEY: ENV.fetch('HCAPTCHA_SITE_KEY', nil), VERSION_TAG: ENV.fetch('VERSION_TAG', ''), CURRENT_PROVIDER: current_provider, diff --git a/app/controllers/api/v1/sessions_controller.rb b/app/controllers/api/v1/sessions_controller.rb index 65a07e91255214f90cb513560989018c507307da..41eb19cbe6d249a5e6ea9d8c9cadb072f012c738 100644 --- a/app/controllers/api/v1/sessions_controller.rb +++ b/app/controllers/api/v1/sessions_controller.rb @@ -45,6 +45,12 @@ module Api # Will return an error if the user is NOT from the current provider and if the user is NOT a super admin return render_error if user.provider != current_provider && !user.super_admin? + # Password is not set (local user migrated from v2) + if user.external_id.blank? && user.password_digest.blank? + token = user.generate_reset_token! + return render_error data: token, errors: 'PasswordNotSet' + end + # TODO: Add proper error logging for non-verified token hcaptcha if user.authenticate(session_params[:password]) return render_error data: user.id, errors: Rails.configuration.custom_error_msgs[:unverified_user] unless user.verified? diff --git a/app/controllers/api/v1/users_controller.rb b/app/controllers/api/v1/users_controller.rb index f00dd0e31dd16b4f9ce85958593b9657cca9fa03..98b5202494f5dff432c68afd80689f552797d0ab 100644 --- a/app/controllers/api/v1/users_controller.rb +++ b/app/controllers/api/v1/users_controller.rb @@ -39,7 +39,7 @@ module Api # POST /api/v1/users.json # Creates and saves a new user record in the database with the provided parameters def create - return render_error status: :forbidden if external_authn_enabled? + return render_error status: :forbidden if external_auth? # Check if this is an admin creating a user admin_create = current_user && PermissionsChecker.new(current_user:, permission_names: 'ManageUsers', current_provider:).call diff --git a/app/javascript/components/users/password_management/ResetPassword.jsx b/app/javascript/components/users/password_management/ResetPassword.jsx index b3ace1a9e25ec71bf9ac857ca0f205304bf3a4d0..56c35ab543a645ebfc7ae06122c2962e39eb799f 100644 --- a/app/javascript/components/users/password_management/ResetPassword.jsx +++ b/app/javascript/components/users/password_management/ResetPassword.jsx @@ -17,11 +17,13 @@ import React, { useEffect } from 'react'; import Card from 'react-bootstrap/Card'; import { useParams } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; import useVerifyToken from '../../../hooks/mutations/users/useVerifyToken'; import ResetPwdForm from './forms/ResetPwdForm'; import Logo from '../../shared_components/Logo'; export default function ResetPassword() { + const { t } = useTranslation(); const { token } = useParams(); const verifyTokenAPI = useVerifyToken(token); @@ -37,6 +39,7 @@ export default function ResetPassword() { <Logo /> </div> <Card className="col-xl-5 col-lg-6 col-md-8 col-10 mx-auto p-4 border-0 card-shadow"> + <Card.Title className="text-center pb-2"> { t('user.account.set_password') } </Card.Title> <ResetPwdForm token={token} /> </Card> </div> diff --git a/app/javascript/hooks/mutations/sessions/useCreateSession.jsx b/app/javascript/hooks/mutations/sessions/useCreateSession.jsx index 801865491655f0c8b8c76fd18ef1c5742e27e896..10fef82ec0856eaf50649fc9059a675269bdefc1 100644 --- a/app/javascript/hooks/mutations/sessions/useCreateSession.jsx +++ b/app/javascript/hooks/mutations/sessions/useCreateSession.jsx @@ -49,6 +49,8 @@ export default function useCreateSession() { toast.error(t('toast.error.users.banned')); } else if (err.response.data.errors === 'UnverifiedUser') { navigate(`/verify?id=${err.response.data.data}`); + } else if (err.response.data.errors === 'PasswordNotSet') { + navigate(`/reset_password/${err.response.data.data}`); } else { toast.error(t('toast.error.session.invalid_credentials')); } diff --git a/app/javascript/hooks/mutations/users/useResetPwd.jsx b/app/javascript/hooks/mutations/users/useResetPwd.jsx index d2aae133492e49434afcc6198b7c7740393b2570..8ff67d4684492a148e7057e74ea4c5ce2ed59572 100644 --- a/app/javascript/hooks/mutations/users/useResetPwd.jsx +++ b/app/javascript/hooks/mutations/users/useResetPwd.jsx @@ -28,7 +28,7 @@ export default function useResetPwd() { (user) => axios.post('/reset_password/reset.json', { user }), { onSuccess: () => { - toast.success(t('toast.success.user.password_updated')); + toast.success(t('toast.success.user.password_changed')); navigate('/signin'); }, onError: () => { diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 7c61036e82baa83ae9f4c6756b6e9640b63270bc..e7f59cde50153a031ed84efb86fd5bb5447a27ab 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -25,7 +25,7 @@ RSpec.describe Api::V1::UsersController, type: :controller do before do ENV['SMTP_SERVER'] = 'test.com' - allow(controller).to receive(:external_authn_enabled?).and_return(false) + allow(controller).to receive(:external_auth?).and_return(false) request.headers['ACCEPT'] = 'application/json' end @@ -280,7 +280,7 @@ RSpec.describe Api::V1::UsersController, type: :controller do context 'External AuthN enabled' do before do - allow(controller).to receive(:external_authn_enabled?).and_return(true) + allow(controller).to receive(:external_auth?).and_return(true) end it 'returns :forbidden without creating the user account' do @@ -472,9 +472,9 @@ RSpec.describe Api::V1::UsersController, type: :controller do end context 'private methods' do - describe '#external_authn_enabled?' do + describe '#external_auth??' do before do - allow(controller).to receive(:external_authn_enabled?).and_call_original + allow(controller).to receive(:external_auth?).and_call_original end context 'OPENID_CONNECT_ISSUER is present?' do @@ -483,7 +483,7 @@ RSpec.describe Api::V1::UsersController, type: :controller do end it 'returns true' do - expect(controller).to be_external_authn_enabled + expect(controller).to be_external_auth end end @@ -493,7 +493,7 @@ RSpec.describe Api::V1::UsersController, type: :controller do end it 'returns false' do - expect(controller).not_to be_external_authn_enabled + expect(controller).not_to be_external_auth end end end