[users] Move the configuration of password checks to Config
- the Widget (Page) does not need to know the password checks, that's business logic that belongs to Config.
This commit is contained in:
parent
7b87242107
commit
900deb5dc8
@ -26,6 +26,7 @@
|
|||||||
#include "utils/String.h"
|
#include "utils/String.h"
|
||||||
#include "utils/Variant.h"
|
#include "utils/Variant.h"
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QRegExp>
|
#include <QRegExp>
|
||||||
|
|
||||||
@ -379,6 +380,27 @@ Config::setRequireStrongPasswords( bool strong )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Config::isPasswordAcceptable(const QString& password, QString& message)
|
||||||
|
{
|
||||||
|
bool failureIsFatal = requireStrongPasswords();
|
||||||
|
|
||||||
|
for ( auto pc : m_passwordChecks )
|
||||||
|
{
|
||||||
|
QString s = pc.filter( password );
|
||||||
|
|
||||||
|
if ( !s.isEmpty() )
|
||||||
|
{
|
||||||
|
message = s;
|
||||||
|
return !failureIsFatal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
STATICTEST void
|
STATICTEST void
|
||||||
setConfigurationDefaultGroups( const QVariantMap& map, QStringList& defaultGroups )
|
setConfigurationDefaultGroups( const QVariantMap& map, QStringList& defaultGroups )
|
||||||
@ -409,10 +431,59 @@ getHostNameActions( const QVariantMap& configurationMap )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HostNameAction writeHosts = CalamaresUtils::getBool( configurationMap, "writeHostsFile", true ) ? HostNameAction::WriteEtcHosts : HostNameAction::None;
|
HostNameAction writeHosts = CalamaresUtils::getBool( configurationMap, "writeHostsFile", true )
|
||||||
|
? HostNameAction::WriteEtcHosts
|
||||||
|
: HostNameAction::None;
|
||||||
return setHostName | writeHosts;
|
return setHostName | writeHosts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Process entries in the passwordRequirements config entry
|
||||||
|
*
|
||||||
|
* Called once for each item in the config entry, which should
|
||||||
|
* be a key-value pair. What makes sense as a value depends on
|
||||||
|
* the key. Supported keys are documented in users.conf.
|
||||||
|
*
|
||||||
|
* @return if the check was added, returns @c true
|
||||||
|
*/
|
||||||
|
STATICTEST bool
|
||||||
|
addPasswordCheck( const QString& key, const QVariant& value, PasswordCheckList& passwordChecks )
|
||||||
|
{
|
||||||
|
if ( key == "minLength" )
|
||||||
|
{
|
||||||
|
add_check_minLength( passwordChecks, value );
|
||||||
|
}
|
||||||
|
else if ( key == "maxLength" )
|
||||||
|
{
|
||||||
|
add_check_maxLength( passwordChecks, value );
|
||||||
|
}
|
||||||
|
else if ( key == "nonempty" )
|
||||||
|
{
|
||||||
|
if ( value.toBool() )
|
||||||
|
{
|
||||||
|
passwordChecks.push_back(
|
||||||
|
PasswordCheck( []() { return QCoreApplication::translate( "PWQ", "Password is empty" ); },
|
||||||
|
[]( const QString& s ) { return !s.isEmpty(); },
|
||||||
|
PasswordCheck::Weight( 1 ) ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cDebug() << "nonempty check is mentioned but set to false";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef CHECK_PWQUALITY
|
||||||
|
else if ( key == "libpwquality" )
|
||||||
|
{
|
||||||
|
add_check_libpwquality( passwordChecks, value );
|
||||||
|
}
|
||||||
|
#endif // CHECK_PWQUALITY
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cWarning() << "Unknown password-check key" << key;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Config::setConfigurationMap( const QVariantMap& configurationMap )
|
Config::setConfigurationMap( const QVariantMap& configurationMap )
|
||||||
@ -441,4 +512,12 @@ Config::setConfigurationMap( const QVariantMap& configurationMap )
|
|||||||
m_permitWeakPasswords = CalamaresUtils::getBool( configurationMap, "allowWeakPasswords", false );
|
m_permitWeakPasswords = CalamaresUtils::getBool( configurationMap, "allowWeakPasswords", false );
|
||||||
m_requireStrongPasswords
|
m_requireStrongPasswords
|
||||||
= !m_permitWeakPasswords || !CalamaresUtils::getBool( configurationMap, "allowWeakPasswordsDefault", false );
|
= !m_permitWeakPasswords || !CalamaresUtils::getBool( configurationMap, "allowWeakPasswordsDefault", false );
|
||||||
|
|
||||||
|
// If the value doesn't exist, or isn't a map, this gives an empty map -- no problem
|
||||||
|
auto pr_checks( configurationMap.value( "passwordRequirements" ).toMap() );
|
||||||
|
for ( decltype( pr_checks )::const_iterator i = pr_checks.constBegin(); i != pr_checks.constEnd(); ++i )
|
||||||
|
{
|
||||||
|
addPasswordCheck( i.key(), i.value(), m_passwordChecks );
|
||||||
|
}
|
||||||
|
std::sort( m_passwordChecks.begin(), m_passwordChecks.end() );
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
#ifndef USERS_CONFIG_H
|
#ifndef USERS_CONFIG_H
|
||||||
#define USERS_CONFIG_H
|
#define USERS_CONFIG_H
|
||||||
|
|
||||||
|
#include "CheckPWQuality.h"
|
||||||
|
|
||||||
#include "utils/NamedEnum.h"
|
#include "utils/NamedEnum.h"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
@ -110,6 +112,17 @@ public:
|
|||||||
|
|
||||||
const QStringList& defaultGroups() const { return m_defaultGroups; }
|
const QStringList& defaultGroups() const { return m_defaultGroups; }
|
||||||
|
|
||||||
|
/** @brief Checks if the password is acceptable.
|
||||||
|
*
|
||||||
|
* If all is well, sets @p message to empty and returns @c true.
|
||||||
|
* If there are warnings, but acceptable, sets @p message to something
|
||||||
|
* non-empty and returns @c true. This happens if requireStrongPasswords
|
||||||
|
* is turned off (by config or user).
|
||||||
|
* If the password is not acceptable, sets @p message to something
|
||||||
|
* non-empty and returns @c false.
|
||||||
|
*/
|
||||||
|
bool isPasswordAcceptable( const QString& password, QString& message );
|
||||||
|
|
||||||
static const QStringList& forbiddenLoginNames();
|
static const QStringList& forbiddenLoginNames();
|
||||||
static const QStringList& forbiddenHostNames();
|
static const QStringList& forbiddenHostNames();
|
||||||
|
|
||||||
@ -178,6 +191,7 @@ private:
|
|||||||
bool m_customHostName = false;
|
bool m_customHostName = false;
|
||||||
|
|
||||||
HostNameActions m_hostNameActions;
|
HostNameActions m_hostNameActions;
|
||||||
|
PasswordCheckList m_passwordChecks;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -283,38 +283,21 @@ UsersPage::checkPasswordAcceptance( const QString& pw1, const QString& pw2, QLab
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool failureIsFatal = ui->checkBoxValidatePassword->isChecked();
|
QString s;
|
||||||
bool failureFound = false;
|
bool ok = m_config->isPasswordAcceptable( pw1, s );
|
||||||
|
if ( !ok )
|
||||||
if ( m_passwordChecksChanged )
|
|
||||||
{
|
{
|
||||||
std::sort( m_passwordChecks.begin(), m_passwordChecks.end() );
|
labelError( badge, message, s, Badness::Fatal );
|
||||||
m_passwordChecksChanged = false;
|
|
||||||
}
|
}
|
||||||
|
else if ( !s.isEmpty() )
|
||||||
for ( auto pc : m_passwordChecks )
|
|
||||||
{
|
{
|
||||||
QString s = pc.filter( pw1 );
|
labelError( badge, message, s, Badness::Warning );
|
||||||
|
|
||||||
if ( !s.isEmpty() )
|
|
||||||
{
|
|
||||||
labelError( badge, message, s, failureIsFatal ? Badness::Fatal : Badness::Warning );
|
|
||||||
failureFound = true;
|
|
||||||
if ( failureIsFatal )
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
}
|
|
||||||
|
|
||||||
if ( !failureFound )
|
|
||||||
{
|
{
|
||||||
labelOk( badge, message );
|
labelOk( badge, message );
|
||||||
}
|
}
|
||||||
|
return ok;
|
||||||
// Here, if failureFound is true then we've found **warnings**,
|
|
||||||
// which is ok to continue but the user should know.
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,38 +343,3 @@ UsersPage::onReuseUserPasswordChanged( const int checked )
|
|||||||
ui->textBoxVerifiedRootPassword->setVisible( visible );
|
ui->textBoxVerifiedRootPassword->setVisible( visible );
|
||||||
checkReady( isReady() );
|
checkReady( isReady() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
UsersPage::addPasswordCheck( const QString& key, const QVariant& value )
|
|
||||||
{
|
|
||||||
m_passwordChecksChanged = true;
|
|
||||||
|
|
||||||
if ( key == "minLength" )
|
|
||||||
{
|
|
||||||
add_check_minLength( m_passwordChecks, value );
|
|
||||||
}
|
|
||||||
else if ( key == "maxLength" )
|
|
||||||
{
|
|
||||||
add_check_maxLength( m_passwordChecks, value );
|
|
||||||
}
|
|
||||||
else if ( key == "nonempty" )
|
|
||||||
{
|
|
||||||
if ( value.toBool() )
|
|
||||||
{
|
|
||||||
m_passwordChecks.push_back(
|
|
||||||
PasswordCheck( []() { return QCoreApplication::translate( "PWQ", "Password is empty" ); },
|
|
||||||
[]( const QString& s ) { return !s.isEmpty(); },
|
|
||||||
PasswordCheck::Weight( 1 ) ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef CHECK_PWQUALITY
|
|
||||||
else if ( key == "libpwquality" )
|
|
||||||
{
|
|
||||||
add_check_libpwquality( m_passwordChecks, value );
|
|
||||||
}
|
|
||||||
#endif // CHECK_PWQUALITY
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cWarning() << "Unknown password-check key" << key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -24,8 +24,6 @@
|
|||||||
#ifndef USERSPAGE_H
|
#ifndef USERSPAGE_H
|
||||||
#define USERSPAGE_H
|
#define USERSPAGE_H
|
||||||
|
|
||||||
#include "CheckPWQuality.h"
|
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
class Config;
|
class Config;
|
||||||
@ -50,14 +48,6 @@ public:
|
|||||||
|
|
||||||
void onActivate();
|
void onActivate();
|
||||||
|
|
||||||
/** @brief Process entries in the passwordRequirements config entry
|
|
||||||
*
|
|
||||||
* Called once for each item in the config entry, which should
|
|
||||||
* be a key-value pair. What makes sense as a value depends on
|
|
||||||
* the key. Supported keys are documented in users.conf.
|
|
||||||
*/
|
|
||||||
void addPasswordCheck( const QString& key, const QVariant& value );
|
|
||||||
|
|
||||||
///@brief Root password, depends on settings, may be empty
|
///@brief Root password, depends on settings, may be empty
|
||||||
QString getRootPassword() const;
|
QString getRootPassword() const;
|
||||||
///@brief User name and password
|
///@brief User name and password
|
||||||
@ -88,9 +78,6 @@ private:
|
|||||||
Ui::Page_UserSetup* ui;
|
Ui::Page_UserSetup* ui;
|
||||||
Config* m_config;
|
Config* m_config;
|
||||||
|
|
||||||
PasswordCheckList m_passwordChecks;
|
|
||||||
bool m_passwordChecksChanged = false;
|
|
||||||
|
|
||||||
bool m_readyFullName;
|
bool m_readyFullName;
|
||||||
bool m_readyUsername;
|
bool m_readyUsername;
|
||||||
bool m_readyHostname;
|
bool m_readyHostname;
|
||||||
|
@ -151,19 +151,4 @@ void
|
|||||||
UsersViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
UsersViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
||||||
{
|
{
|
||||||
m_config->setConfigurationMap( configurationMap );
|
m_config->setConfigurationMap( configurationMap );
|
||||||
|
|
||||||
// Create the widget, after all .. as long as writing configuration to the UI is needed
|
|
||||||
(void)this->widget();
|
|
||||||
using CalamaresUtils::getBool;
|
|
||||||
|
|
||||||
if ( configurationMap.contains( "passwordRequirements" )
|
|
||||||
&& configurationMap.value( "passwordRequirements" ).type() == QVariant::Map )
|
|
||||||
{
|
|
||||||
auto pr_checks( configurationMap.value( "passwordRequirements" ).toMap() );
|
|
||||||
|
|
||||||
for ( decltype( pr_checks )::const_iterator i = pr_checks.constBegin(); i != pr_checks.constEnd(); ++i )
|
|
||||||
{
|
|
||||||
m_widget->addPasswordCheck( i.key(), i.value() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user