Added a way to create the admin account linked to the PAM backend password authentication. ref #65

This commit is contained in:
emeric
2020-07-07 10:54:40 +02:00
parent 0623df3dae
commit 100d0f55a5
10 changed files with 160 additions and 31 deletions
+1
View File
@@ -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);
}
+1
View File
@@ -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);
+1
View File
@@ -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
+70 -15
View File
@@ -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>();
+4 -13
View File
@@ -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()
+42
View File
@@ -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;
}
}
+31
View File
@@ -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
View File
@@ -1,4 +1,3 @@
/*
* Copyright (C) 2019 Emeric Poupon
*