Allow remote users to change password

v7

(Dan) #1

Building on the discussion in this thread

Most of my users are remote. They don’t have VPN access to my network, and I don’t particularly want to give it to them. I also don’t want to make the server manager available to the entire Internet. Fortunately, on that thread, @dnutan pointed out Self-Service Password (SSP), a web app designed to do this very thing. So here are some notes on setting it up on Nethserver 7.6.

NOTE: At present, these instructions (and templates) work only with local OpenLDAP authentication–not with Active Directory, and not with remote OpenLDAP servers.

Install Self-Service Password

You’ll first need to add the LDAP Tool Box repository. To do that, using your favorite editor, create /etc/yum.repos.d/ltb-project.repo with the following contents:

[ltb-project-noarch]
name=LTB project packages (noarch)
baseurl=https://ltb-project.org/rpm/$releasever/noarch
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-LTB-project

Then run the following commands:

rpm --import https://ltb-project.org/wiki/lib/RPM-GPG-KEY-LTB-project
yum update
yum install nethserver-rh-php71-php-fpm self-service-password

Create Templates

You’ll need to create three template fragments. For the first, do

nano /etc/e-smith/templates/etc/httpd/conf.d/default-virtualhost.inc/50selfservicepassword

…with the following contents:

{
my $path = $ssp{DefaultPath} || '/ssp';
my $status = $ssp{UseDefaultHost} || 'enabled';

$OUT .= <<EOF;

#
# 50selfservicepassword
#

EOF

if ( $status eq 'enabled' ) {
$OUT .= <<EOF
Alias $path /usr/share/self-service-password

<Directory /usr/share/self-service-password>
	<FilesMatch \\.php\$>
    	SetHandler "proxy:fcgi://127.0.0.1:9001"
	</FilesMatch>
	AllowOverride None
	Require all granted
	DirectoryIndex index.php
	AddDefaultCharset UTF-8
</Directory>

<Directory /usr/share/self-service-password/scripts>
	AllowOverride None
	Require all denied
</Directory>

EOF
}

}

For the second template, run

mkdir -p /etc/e-smith/templates/etc/httpd/conf.d/self-service-password.conf
nano /etc/e-smith/templates/etc/httpd/conf.d/self-service-password.conf/10main

…with the following contents:

{
my $status = $ssp{UseVhost} || 'disabled';
my $vhost = $ssp{VHostName} || 'ssp.'.$DomainName;
$OUT .= "\n";

if ( $status eq 'enabled' ) {
$OUT .= <<EOF
<VirtualHost *:80>
	DocumentRoot "/usr/share/self-service-password"
	ServerName $vhost
	RewriteEngine on
	RewriteRule ^/\\.well-known/ - [L]
	RewriteRule (.*) https://$vhost\$1 [R,L]
	Alias "/.well-known/acme-challenge/" "/var/www/html/.well-known/acme-challenge/"
	<Directory "/var/www/html/.well-known/acme-challenge/">
		Require all granted
		Options -Indexes -FollowSymLinks
		AllowOverride None
	</Directory>
</VirtualHost>

<VirtualHost *:443>
	ServerName $vhost
	DocumentRoot /usr/share/self-service-password
	DirectoryIndex index.php
	AddDefaultCharset UTF-8
	SSLEngine on

	<FilesMatch \\.php\$>
    	SetHandler "proxy:fcgi://127.0.0.1:9001"
	</FilesMatch>
	
	<Directory /usr/share/self-service-password>
    	AllowOverride None
        Require all granted
    </Directory>

    <Directory /usr/share/self-service-password/scripts>
    	AllowOverride None
                Require all denied
    </Directory>

    LogLevel warn
    ErrorLog /var/log/httpd/ssp_error_log
    CustomLog /var/log/httpd/ssp_access_log combined
</VirtualHost>
EOF
}

}

Finally, the third template. Run

mkdir -p /etc/e-smith/templates/usr/share/self-service-password/conf/config.inc.local.php
touch /etc/e-smith/templates/usr/share/self-service-password/conf/config.inc.local.php/template-begin
nano /etc/e-smith/templates/usr/share/self-service-password/conf/config.inc.local.php/10main

…with the following contents:

{
my @chars = ("A".."Z", "a".."z", "0".."9");
my $secret;
$secret .= $chars[rand @chars] for 1..12;

my $lang = ($ssp{lang} || 'en');
my $email = ($ssp{'UseEmail'} || 'false');

$OUT .= <<EOF;
<?php

/*
 /usr/share/self-service-password/conf/config.inc.local.php
*/

\$lang = "$lang";
\$show_menu = true;
\$use_questions = false;
\$use_sms = false;
\$pwd_show_policy = "always";
\$pwd_show_policy_pos = "above";
\$keyphrase = "$secret";
\$use_tokens = $email;

EOF

if ( $email eq 'true') {
	$OUT .= <<EOF;
	\$mail_address_use_ldap = true;
	\$mail_attribute = "mail";
	\$crypt_tokens = true;
	\$token_lifetime = "900";
	\$mail_sendmailpath = '/usr/sbin/sendmail';
	\$mail_protocol = 'sendmail';
	\$mail_smtp_debug = 0;
	\$mail_debug_format = 'html';
	\$mail_contenttype = 'text/plain';
	\$mail_wordwrap = 0;
	\$mail_charset = 'utf-8';
	\$mail_priority = 3;
	\$mail_newline = PHP_EOL;
	\$notify_on_change = true;
EOF
}

if ($passwordstrength{Users} eq 'none') {
	$OUT .= <<EOF;
	\$pwd_min_length = 7;
EOF
}
elsif ($passwordstrength{Users} eq 'strong') {
	$OUT .= <<EOF;
	\$pwd_min_length = 7;
	\$pwd_min_lower = 1;
	\$pwd_min_upper = 1;
	\$pwd_min_digit = 1;
	\$pwd_min_special = 1;
	\$pwd_complexity = 4;
	\$use_pwnedpasswords = true;
EOF
}

if ($sssd{Provider} eq 'ldap') {
	$OUT .= <<EOF;
	\$ldap_binddn = "";
	\$ldap_bindpw = "";
	\$ldap_base = "dc=directory,dc=nh";
	\$ldap_filter = "(&(objectClass=person)(uid={login})(!(uid=admin)))";
	\$who_change_password = "user";
EOF
}
elsif ($sssd{Provider} eq 'ad') {
	$OUT .= <<EOF;
	\$ad_mode = true;
	\$ldap_starttls = false;
	\$ldap_url = "$sssd{LdapURI}";
	\$ldap_binddn = "$sssd{BindDN}";
	\$ldap_bindpw = "$sssd{BindPassword}";
	\$ldap_base = "dc=ad,dc=domain,dc=local";
	\$ldap_login_attribute = "sAMAccountName";
	\$ldap_fullname_attribute = "cn";
	\$ldap_filter = "(&(objectClass=user)(sAMAccountName={login})(!(userAccountControl:1.2.840.113556.1.4.803:=2)))";
	\$who_change_password = "manager";
EOF
}

}

Configure (if desired)

These templates will let you configure SSP to be accessible at a path under your main domain (e.g., www.yourdomain.com/ssp), a separate virtual host (e.g., ssp.yourdomain.com), or both. By default, SSP will be accessible at the path of /ssp under your default virtual host, but will not be available on its own virtual host. To change either of these, first run config set ssp configuration. Then:

  • To change the name of the path (for example, to make SSP available on www.yourdomain.com/password), run config setprop ssp DefaultPath /password.
  • To make SSP unavailable on the default virtual host, run config setprop ssp UseDefaultHost disabled.
  • To enable a separate virtual host for SSP, run config setprop ssp UseVhost enabled. By default, it will be available at ssp.yourdomain.com
  • To change the virtual host name, run config setprop ssp VHostName password.yourdomain.com (to set it to password.yourdomain.com).

NOTE: The SSP virtual host requires SSL, and there is no configuration option to remove that requirement. This means that whatever hostname you choose for that virtual host will need to appear on your certificate.

Also, there’s an option for SSP to use email. This will send users email notifications when their passwords are changed. The hope is for this to also allow users to reset their passwords using email tokens, but that isn’t currently implemented. To enable this, run config setprop ssp UseEmail true.

Expand the templates

expand-template /etc/httpd/conf.d/default-virtualhost.inc
expand-template /etc/httpd/conf.d/self-service-password.conf
expand-template /usr/share/self-service-password/conf/config.inc.local.php
systemctl reload httpd

Change a password!

Browse to the appropriate URL, and you’ll see this page:


Pick a user and go. For security reasons, you can’t reset the admin user’s password using this system.


So, what are you working on? 17 Jan 2019
(Alessio Fattorini) #2

Well, good job! Thanks for sharing :smiley:


(HF) #3

Thanks Dan!

Works exactly as it says on the tin.


(HF) #4

@danb35, following your procedure above, config show ssp does not show me anything. If no options are available by default and have to be set, then ‘setprop’ should be ‘set’ right?


(Dan) #5

…as noted here:


(HF) #6

Yep, I need to learn to read carefully…


(Dan) #7

The concern I have is that, from what @mrmarkuz says on the other thread, AD won’t work with the user credentials, and it also won’t work using the bind user (ldapservice) and password–it needs admin credentials. In addition to the security concerns I raised there, I think that also (effectively) makes it impossible to create a template for the config file that will work with AD. I mean, I guess you could config setprop ssp AdminUser blah AdminPassword blahblahblah (with the actual system administrator credentials), but that really doesn’t sound like a good idea at all.


(Markus Neuberger) #8

Active Directory password changing works with ldapservice, I didn’t understand the documentation.

With user domain\ldapservice and $who_change_password = "user" Users can change their passwords in AD.

I am going to test SSL auth…


(Dan) #9

Ah, much better news. And that user (and password) are already in the config database, so should be template-able.


(Markus Neuberger) #10

And STARTTLS and LDAPS are working too, even with self-signed certificate so no need for low security in the container smb.conf.


(HF) #11

I would be willing to put the how-to on the wiki, BUT if someone is considering creating a module, I’ll hold off for now.


(Dan) #12

I have no problem with putting it in the wiki myself, but I’d like (1) to get the templates working with AD, and (2) to have some further confirmation that it works for other folks too, before putting it there.

As to making a module, it should be straightforward enough, except that you’d still need to manually add the LTB repo–they don’t have an RPM for the repo itself, and I don’t think it’d really be appropriate for us to push one. So those installation instructions would look like “create this repo file, add the GPG key, then yum install --enablerepo=whatever nethserver-self-service-password, then config set ssp configuration (plus whatever other properties are called for), then signal-event nethserver-self-service-password-update.” Not too bad, and a definite improvement over what’s above, but not quite ideal.


(Dan) #13

Outstanding. How do the settings need to look to make that work?


(Markus Neuberger) #14

It works like expected on LDAP side. :sunglasses:
For AD I needed to add some lines to /etc/e-smith/templates/usr/share/self-service-password/conf/config.inc.local.php/10main.
We need the baseDN for AD. I only changed who_change_password from manager to user and added the baseDN.

/etc/e-smith/templates/usr/share/self-service-password/conf/config.inc.local.php/10main
{
use NethServer::SSSD;

my $sssd = new NethServer::SSSD();
my $baseDN = $sssd->baseDN();
my $bindDN = $sssd->bindDN();
    $bindDN =~ s/\\/\\\\/g;
    my $userDN = $sssd->userDN();
    my $groupDN = $sssd->groupDN();
    my $bindPassword = $sssd->bindPassword();
    my $host = $sssd->host();
my $ldapURI = $sssd->ldapURI();

my @chars = ("A".."Z", "a".."z", "0".."9");
my $secret;
$secret .= $chars[rand @chars] for 1..12;

my $lang = ($ssp{lang} || 'en');
my $email = ($ssp{'UseEmail'} || 'false');

$OUT .= <<EOF;
<?php

/*
 /usr/share/self-service-password/conf/config.inc.local.php
*/

\$lang = "$lang";
\$show_menu = true;
\$use_questions = false;
\$use_sms = false;
\$pwd_show_policy = "always";
\$pwd_show_policy_pos = "above";
\$keyphrase = "$secret";
\$use_tokens = $email;

EOF

if ( $email eq 'true') {
        $OUT .= <<EOF;
        \$mail_address_use_ldap = true;
        \$crypt_tokens = true;
        \$token_lifetime = "900";
        \$mail_sendmailpath = '/usr/sbin/sendmail';
        \$mail_protocol = 'sendmail';
        \$mail_smtp_debug = 0;
        \$mail_debug_format = 'html';
        \$mail_contenttype = 'text/plain';
        \$mail_wordwrap = 0;
        \$mail_charset = 'utf-8';
        \$mail_priority = 3;
        \$mail_newline = PHP_EOL;
        \$notify_on_change = true;
EOF
}

if ($passwordstrength{Users} eq 'none') {
        $OUT .= <<EOF;
        \$pwd_min_length = 7;
EOF
}
elsif ($passwordstrength{Users} eq 'strong') {
        $OUT .= <<EOF;
        \$pwd_min_length = 7;
        \$pwd_min_lower = 1;
        \$pwd_min_upper = 1;
        \$pwd_min_digit = 1;
        \$pwd_min_special = 1;
        \$pwd_complexity = 4;
        \$use_pwnedpasswords = true;
EOF
}

if ($sssd{Provider} eq 'ldap') {
        my $libuserpass = `cat /var/lib/nethserver/secrets/libuser | tr -d '\n'`;
        $OUT .= <<EOF;
        // \$ldap_url = "ldaps://localhost";
        // \$ldap_starttls = true;
        \$ldap_binddn = "cn=libuser,dc=directory,dc=nh";
        \$ldap_bindpw = "$libuserpass";
        \$ldap_base = "dc=directory,dc=nh";
        \$ldap_filter = "(&(objectClass=person)(uid={login})(!(uid=admin)))";
        \$who_change_password = "user";
        \$mail_attribute = "mail";
EOF
}
elsif ($sssd{Provider} eq 'ad') {
        my $ssppass = `cat /var/lib/nethserver/secrets/ssp | tr -d '\n'`;
        $OUT .= <<EOF;
        \$ad_mode = true;
        \$ldap_starttls = false;
        \$ldap_url = "$ldapURI";
        \$ldap_binddn = "ssp\@$sssd{Realm}";
        \$ldap_bindpw = "$ssppass";
        // \$ldap_binddn = "$sssd{BindDN}";
        // \$ldap_bindpw = "$sssd{BindPassword}";
        \$ldap_base = "$baseDN";
        \$ldap_login_attribute = "sAMAccountName";
        \$ldap_fullname_attribute = "cn";
        \$ldap_filter = "(&(objectClass=user)(sAMAccountName={login})(!(userAccountControl:1.2.840.113556.1.4.803:=2)))";
        \$who_change_password = "user";
        \$mail_attribute = "userPrincipalName";
EOF
}

}

(Dan) #15

Are these lines:

actually necessary? Or can we just do:

\$ldap_base = "$sssd{BaseDN}";

?

In any event, it’s looking very promising. I think I’m still going to need to clean up the email stuff (as I don’t think we’re going to be able to make email tokens work, but sending an email confirmation would still be a nice option), but looks like it’s getting close to something suitable for general release.


(Markus Neuberger) #16

The lines are necessary.

$sssd{something} only grabs the database (config show sssd).

See perldoc NethServer::SSSD and for example the sogo.conf

Fully agree.


(Markus Neuberger) #17

And it works, LDAP with libuser and AD with a special user who only is allowed to change passwords (described here, search for rights to change password of users) but is no admin.

How to set the permission with Windows ADUC (The only way I found, samba-tool seems to not support it):

I changed the config template in a previous post to reflect the changes.

Additionaly I created a user ssp and created a file /var/lib/nethserver/secrets/ssp with the password of the ssp user. It would also be possible to give the “change password permission” to ldapservice so we don’t need an additional user.

If we want the token to work we need special users (libuser/ssp).

If we could manage to set the password changing permission in AD on command line somehow, we could write a random password to the file or use ldapservice and automate the whole process.

At least we won’t be able to do that with remote AD.


(Dan) #18

OK, first draft of a module is up on my repo. To install, add the LTB repo and import the key as above, then yum --enablerepo=danb35 install nethserver-self-service-password. Other configuration options are noted above; if you change any of them, do signal-event nethserver-self-service-password-update afterward.

This has had very minimal testing. It installs and works to change a user’s password on a local LDAP system. I’ve included @mrmarkuz’ configuration changes, but haven’t worked with AD at all, so can’t vouch for anything on that. I certainly wouldn’t expect changing passwords using email tokens to work in AD, as nothing in this RPM makes the user role changes noted above.

Github repo is here:


(HF) #19

Thanks @danb35, works as advertised!


(Dan) #20

On the wiki, but not yet linked into the user guides index:
https://wiki.nethserver.org/doku.php?id=userguide:self-service-password