diff --git a/api/user.go b/api/user.go
index 204b5e34b..5a08b307a 100644
--- a/api/user.go
+++ b/api/user.go
@@ -63,6 +63,7 @@ type UserAPI struct {
PasswordStrength int
UserChangeNotifier *UserChangeNotifier
Registration bool
+ LocalAuthEnabled bool
}
// GetUsers returns all the users
@@ -396,6 +397,11 @@ func (a *UserAPI) DeleteUserByID(ctx *gin.Context) {
// schema:
// $ref: "#/definitions/Error"
func (a *UserAPI) ChangePassword(ctx *gin.Context) {
+ if !a.LocalAuthEnabled {
+ ctx.AbortWithError(403, errors.New("local authentication is disabled"))
+ return
+ }
+
pw := model.UserExternalPass{}
if err := ctx.Bind(&pw); err == nil {
if err := password.ValidateNewPassword(pw.Pass); err != nil {
diff --git a/api/user_test.go b/api/user_test.go
index 583bb64e7..139527ff2 100644
--- a/api/user_test.go
+++ b/api/user_test.go
@@ -49,7 +49,7 @@ func (s *UserSuite) BeforeTest(suiteName, testName string) {
s.notifiedAdd = true
return nil
})
- s.a = &UserAPI{DB: s.db, UserChangeNotifier: s.notifier}
+ s.a = &UserAPI{DB: s.db, UserChangeNotifier: s.notifier, LocalAuthEnabled: true}
}
func (s *UserSuite) AfterTest(suiteName, testName string) {
@@ -493,6 +493,25 @@ func (s *UserSuite) Test_UpdatePassword_EmptyPassword() {
assert.True(s.T(), password.ComparePassword(user.Pass, []byte("old")))
}
+func (s *UserSuite) Test_UpdatePassword_LocalAuthDisabled_Expect403() {
+ pw, err := password.CreatePassword("old", 5)
+ require.NoError(s.T(), err)
+ s.db.CreateUser(&model.User{ID: 1, Name: "jmattheis", Pass: pw})
+ s.a.LocalAuthEnabled = false
+
+ test.WithUser(s.ctx, 1)
+ s.ctx.Request = httptest.NewRequest("POST", "/user/current/password", strings.NewReader(`{"pass": "new"}`))
+ s.ctx.Request.Header.Set("Content-Type", "application/json")
+
+ s.a.ChangePassword(s.ctx)
+
+ assert.Equal(s.T(), 403, s.recorder.Code)
+ user, err := s.db.GetUserByID(1)
+ assert.NoError(s.T(), err)
+ assert.NotNil(s.T(), user)
+ assert.True(s.T(), password.ComparePassword(user.Pass, []byte("old")))
+}
+
func (s *UserSuite) Test_UpdatePassword_TooLongPassword_Expect400() {
pw, err := password.CreatePassword("old", 5)
require.NoError(s.T(), err)
diff --git a/router/router.go b/router/router.go
index 74e770d3b..9e7a39eeb 100644
--- a/router/router.go
+++ b/router/router.go
@@ -104,7 +104,7 @@ func Create(db *database.GormDatabase, vInfo *model.VersionInfo, conf *config.Co
}
sessionHandler := api.SessionAPI{DB: db, NotifyDeleted: streamHandler.NotifyDeletedClient, SecureCookie: conf.Server.SecureCookie, LocalAuthEnabled: conf.LocalAuthEnabled}
userChangeNotifier := new(api.UserChangeNotifier)
- userHandler := api.UserAPI{DB: db, PasswordStrength: conf.PassStrength, UserChangeNotifier: userChangeNotifier, Registration: conf.Registration}
+ userHandler := api.UserAPI{DB: db, PasswordStrength: conf.PassStrength, UserChangeNotifier: userChangeNotifier, Registration: conf.Registration, LocalAuthEnabled: conf.LocalAuthEnabled}
pluginManager, err := plugin.NewManager(db, conf.PluginsDir, g.Group("/plugin/:id/custom/"), streamHandler)
if err != nil {
diff --git a/ui/src/common/SettingsDialog.tsx b/ui/src/common/SettingsDialog.tsx
deleted file mode 100644
index 04125739e..000000000
--- a/ui/src/common/SettingsDialog.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-import React, {useState} from 'react';
-import Button from '@mui/material/Button';
-import Dialog from '@mui/material/Dialog';
-import DialogActions from '@mui/material/DialogActions';
-import DialogContent from '@mui/material/DialogContent';
-import DialogTitle from '@mui/material/DialogTitle';
-import TextField from '@mui/material/TextField';
-import Tooltip from '@mui/material/Tooltip';
-import {observer} from 'mobx-react-lite';
-import {useStores} from '../stores';
-import ElevationForm from './ElevationForm';
-
-interface IProps {
- fClose: VoidFunction;
-}
-
-const SettingsDialog = observer(({fClose}: IProps) => {
- const [pass, setPass] = useState('');
- const {currentUser, elevateStore} = useStores();
-
- const handleClose = () => {
- elevateStore.cleanupOidcElevate();
- fClose();
- };
-
- const submitAndClose = () => {
- currentUser.changePassword(pass);
- fClose();
- };
-
- return (
-
- );
-});
-
-export default SettingsDialog;
diff --git a/ui/src/layout/Header.tsx b/ui/src/layout/Header.tsx
index 4ffc38a02..992ef7904 100644
--- a/ui/src/layout/Header.tsx
+++ b/ui/src/layout/Header.tsx
@@ -78,7 +78,6 @@ interface IProps {
version: string;
themeMode: ThemeKey;
toggleTheme: VoidFunction;
- showSettings: VoidFunction;
logout: VoidFunction;
style: CSSProperties;
setNavOpen: (open: boolean) => void;
@@ -93,7 +92,6 @@ const Header = ({
logout,
style,
setNavOpen,
- showSettings,
themeMode,
}: IProps) => {
const {classes} = useStyles();
@@ -124,13 +122,7 @@ const Header = ({
{loggedIn && (
-