Added a way to create the admin account linked to the PAM backend password authentication. ref #65
This commit is contained in:
@@ -81,6 +81,7 @@ checkUserPassword(Database::Session& session, const std::string& loginName, cons
|
||||
{
|
||||
case Database::User::AuthMode::Internal:
|
||||
{
|
||||
LMS_LOG(AUTH, DEBUG) << "Checking internal password for user '" << loginName << "'";
|
||||
const Wt::Auth::BCryptHashFunction hashFunc {6}; // TODO parametrize this
|
||||
return hashFunc.verify(password, passwordHash.salt, passwordHash.hash);
|
||||
}
|
||||
|
||||
@@ -164,6 +164,7 @@ checkUserPassword(const std::string& loginName, const std::string& password)
|
||||
{
|
||||
try
|
||||
{
|
||||
LMS_LOG(AUTH, DEBUG) << "Checking PAM password for user '" << loginName << "'";
|
||||
PAMContext pamContext {loginName};
|
||||
|
||||
pamContext.authenticate(password);
|
||||
|
||||
@@ -14,6 +14,7 @@ add_executable(lms
|
||||
ui/admin/InitWizardView.cpp
|
||||
ui/admin/UserView.cpp
|
||||
ui/admin/UsersView.cpp
|
||||
ui/common/AuthModeModel.cpp
|
||||
ui/common/Validators.cpp
|
||||
ui/explore/ArtistListHelpers.cpp
|
||||
ui/explore/ArtistView.cpp
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "InitWizardView.hpp"
|
||||
|
||||
#include <Wt/WComboBox.h>
|
||||
#include <Wt/WFormModel.h>
|
||||
#include <Wt/WLineEdit.h>
|
||||
#include <Wt/WPushButton.h>
|
||||
@@ -29,6 +30,7 @@
|
||||
#include "utils/Service.hpp"
|
||||
|
||||
#include "common/Validators.hpp"
|
||||
#include "common/AuthModeModel.hpp"
|
||||
#include "LmsApplication.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
@@ -41,18 +43,23 @@ class InitWizardModel : public Wt::WFormModel
|
||||
static const Field AdminLoginField;
|
||||
static const Field PasswordField;
|
||||
static const Field PasswordConfirmField;
|
||||
static inline const Field AuthModeField{"auth-mode"};
|
||||
|
||||
InitWizardModel() : Wt::WFormModel()
|
||||
{
|
||||
addField(AdminLoginField);
|
||||
addField(AuthModeField);
|
||||
addField(PasswordField);
|
||||
addField(PasswordConfirmField);
|
||||
|
||||
setValidator(AuthModeField, createMandatoryValidator());
|
||||
setValidator(AdminLoginField, createNameValidator());
|
||||
setValidator(PasswordField, createMandatoryValidator());
|
||||
setValidator(PasswordConfirmField, createMandatoryValidator());
|
||||
}
|
||||
|
||||
std::shared_ptr<AuthModeModel> getAuthModeModel() const { return _authModeModel; }
|
||||
|
||||
void saveData()
|
||||
{
|
||||
const Database::User::PasswordHash passwordHash {ServiceProvider<::Auth::IPasswordService>::get()->hashPassword(valueText(PasswordField).toUTF8())};
|
||||
@@ -64,10 +71,54 @@ class InitWizardModel : public Wt::WFormModel
|
||||
if (!Database::User::getAll(LmsApp->getDbSession()).empty())
|
||||
throw LmsException("Admin user already created");
|
||||
|
||||
auto authModeRow {_authModeModel->getRowFromString(valueText(AuthModeField))};
|
||||
if (!authModeRow)
|
||||
throw LmsException {"Bad authentication mode"};
|
||||
|
||||
const Database::User::AuthMode authMode {_authModeModel->getValue(*authModeRow)};
|
||||
|
||||
Database::User::pointer user {Database::User::create(LmsApp->getDbSession(), valueText(AdminLoginField).toUTF8())};
|
||||
user.modify()->setType(Database::User::Type::ADMIN);
|
||||
user.modify()->setAuthMode(Database::User::AuthMode::Internal);
|
||||
user.modify()->setPasswordHash(passwordHash);
|
||||
user.modify()->setAuthMode(authMode);
|
||||
if (authMode == Database::User::AuthMode::Internal)
|
||||
user.modify()->setPasswordHash(passwordHash);
|
||||
}
|
||||
|
||||
void validatePassword(Wt::WString& error) const
|
||||
{
|
||||
auto authModeRow {_authModeModel->getRowFromString(valueText(AuthModeField))};
|
||||
if (!authModeRow)
|
||||
throw LmsException {"Bad authentication mode"};
|
||||
|
||||
const Database::User::AuthMode authMode {_authModeModel->getValue(*authModeRow)};
|
||||
if (authMode != Database::User::AuthMode::Internal)
|
||||
return;
|
||||
|
||||
if (!valueText(PasswordField).empty())
|
||||
{
|
||||
// Evaluate the strength of the password
|
||||
if (!ServiceProvider<::Auth::IPasswordService>::get()->evaluatePasswordStrength(valueText(AdminLoginField).toUTF8(), valueText(PasswordField).toUTF8()))
|
||||
error = Wt::WString::tr("Lms.password-too-weak");
|
||||
}
|
||||
else
|
||||
error = Wt::WString::tr("Lms.password-must-not-be-empty");
|
||||
}
|
||||
|
||||
void validatePasswordConfirm(Wt::WString& error) const
|
||||
{
|
||||
auto authModeRow {_authModeModel->getRowFromString(valueText(AuthModeField))};
|
||||
if (!authModeRow)
|
||||
throw LmsException {"Bad authentication mode"};
|
||||
|
||||
const Database::User::AuthMode authMode {_authModeModel->getValue(*authModeRow)};
|
||||
if (authMode != Database::User::AuthMode::Internal)
|
||||
return;
|
||||
|
||||
if (validation(PasswordField).state() == Wt::ValidationState::Valid)
|
||||
{
|
||||
if (valueText(PasswordField) != valueText(PasswordConfirmField))
|
||||
error = Wt::WString::tr("Lms.passwords-dont-match");
|
||||
}
|
||||
}
|
||||
|
||||
bool validateField(Field field)
|
||||
@@ -76,22 +127,11 @@ class InitWizardModel : public Wt::WFormModel
|
||||
|
||||
if (field == PasswordField)
|
||||
{
|
||||
if (!valueText(PasswordField).empty())
|
||||
{
|
||||
// Evaluate the strength of the password
|
||||
if (!ServiceProvider<::Auth::IPasswordService>::get()->evaluatePasswordStrength(valueText(AdminLoginField).toUTF8(), valueText(PasswordField).toUTF8()))
|
||||
error = Wt::WString::tr("Lms.password-too-weak");
|
||||
}
|
||||
else
|
||||
return Wt::WFormModel::validateField(field);
|
||||
validatePassword(error);
|
||||
}
|
||||
else if (field == PasswordConfirmField)
|
||||
{
|
||||
if (validation(PasswordField).state() == Wt::ValidationState::Valid)
|
||||
{
|
||||
if (valueText(PasswordField) != valueText(PasswordConfirmField))
|
||||
error = Wt::WString::tr("Lms.passwords-dont-match");
|
||||
}
|
||||
validatePasswordConfirm(error);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -103,6 +143,7 @@ class InitWizardModel : public Wt::WFormModel
|
||||
return (validation(field).state() == Wt::ValidationState::Valid);
|
||||
}
|
||||
|
||||
std::shared_ptr<AuthModeModel> _authModeModel {createAuthModeModel()};
|
||||
};
|
||||
|
||||
const Wt::WFormModel::Field InitWizardModel::AdminLoginField = "admin-login";
|
||||
@@ -121,6 +162,20 @@ InitWizardView::InitWizardView()
|
||||
setFormWidget(InitWizardModel::AdminLoginField, std::move(adminLogin));
|
||||
}
|
||||
|
||||
// Auth mode
|
||||
auto authMode = std::make_unique<Wt::WComboBox>();
|
||||
authMode->setModel(model->getAuthModeModel());
|
||||
authMode->activated().connect([=](int row)
|
||||
{
|
||||
const Database::User::AuthMode authMode {model->getAuthModeModel()->getValue(row)};
|
||||
|
||||
model->setReadOnly(InitWizardModel::PasswordField, authMode != Database::User::AuthMode::Internal);
|
||||
model->setReadOnly(InitWizardModel::PasswordConfirmField, authMode != Database::User::AuthMode::Internal);
|
||||
updateModel(model.get());
|
||||
updateView(model.get());
|
||||
});
|
||||
setFormWidget(InitWizardModel::AuthModeField, std::move(authMode));
|
||||
|
||||
// Password
|
||||
{
|
||||
auto passwordEdit = std::make_unique<Wt::WLineEdit>();
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "utils/Service.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
#include "common/AuthModeModel.hpp"
|
||||
#include "common/Validators.hpp"
|
||||
#include "common/ValueStringModel.hpp"
|
||||
#include "LmsApplication.hpp"
|
||||
@@ -58,8 +59,6 @@ class UserModel : public Wt::WFormModel
|
||||
UserModel(std::optional<Database::IdType> userId)
|
||||
: _userId {userId}
|
||||
{
|
||||
initializeModels();
|
||||
|
||||
if (!_userId)
|
||||
{
|
||||
addField(LoginField);
|
||||
@@ -70,6 +69,8 @@ class UserModel : public Wt::WFormModel
|
||||
addField(PasswordField);
|
||||
addField(DemoField);
|
||||
|
||||
setValidator(AuthModeField, createMandatoryValidator());
|
||||
|
||||
loadData();
|
||||
}
|
||||
|
||||
@@ -234,18 +235,8 @@ class UserModel : public Wt::WFormModel
|
||||
return false;
|
||||
}
|
||||
|
||||
void initializeModels()
|
||||
{
|
||||
_authModeModel = std::make_shared<AuthModeModel>();
|
||||
|
||||
if (ServiceProvider<::Auth::IPasswordService>::get()->isAuthModeSupported(User::AuthMode::Internal))
|
||||
_authModeModel->add(Wt::WString::tr("Lms.Admin.User.auth-mode.internal"), User::AuthMode::Internal);
|
||||
if (ServiceProvider<::Auth::IPasswordService>::get()->isAuthModeSupported(User::AuthMode::PAM))
|
||||
_authModeModel->add(Wt::WString::tr("Lms.Admin.User.auth-mode.pam"), User::AuthMode::PAM);
|
||||
}
|
||||
|
||||
std::optional<Database::IdType> _userId;
|
||||
std::shared_ptr<AuthModeModel> _authModeModel;
|
||||
std::shared_ptr<AuthModeModel> _authModeModel {createAuthModeModel()};
|
||||
};
|
||||
|
||||
UserView::UserView()
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "AuthModeModel.hpp"
|
||||
|
||||
#include "auth/IPasswordService.hpp"
|
||||
#include "utils/Service.hpp"
|
||||
|
||||
namespace UserInterface
|
||||
{
|
||||
|
||||
std::unique_ptr<AuthModeModel>
|
||||
createAuthModeModel()
|
||||
{
|
||||
auto model {std::make_unique<AuthModeModel>()};
|
||||
|
||||
if (ServiceProvider<::Auth::IPasswordService>::get()->isAuthModeSupported(Database::User::AuthMode::Internal))
|
||||
model->add(Wt::WString::tr("Lms.Admin.User.auth-mode.internal"), Database::User::AuthMode::Internal);
|
||||
if (ServiceProvider<::Auth::IPasswordService>::get()->isAuthModeSupported(Database::User::AuthMode::PAM))
|
||||
model->add(Wt::WString::tr("Lms.Admin.User.auth-mode.pam"), Database::User::AuthMode::PAM);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "database/User.hpp"
|
||||
#include "common/ValueStringModel.hpp"
|
||||
|
||||
namespace UserInterface
|
||||
{
|
||||
using AuthModeModel = ValueStringModel<Database::User::AuthMode>;
|
||||
|
||||
std::unique_ptr<AuthModeModel> createAuthModeModel();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Emeric Poupon
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user