Authentication through Apache

A good sources of what is not going well is the apache logs, see /var/log/httpd/error_log if you cannot acces to your share

https://code.google.com/p/mod-auth-external/

Modauthnzexternal and modauthexternal are flexible tools for building custom basic authentication systems for the Apache HTTP Daemon. “Basic Authentication” is a type of authentication built into the HTTP protocol, in which the browser automatically pops up a login box when the user requests a protected resource, and the login ids and passwords entered are checked by Apache. Modauth*external allows the password checking normally done inside Apache to be done by an separate external program running outside of Apache.

you must install some rpm from epel (already imported in nethforge)

yum install pwauth mod_authnz_external --enablerepo=epel

Use case only users authentication

you can create a virtual host for example in /etc/httpd/conf.d

AddExternalAuth pwauth /usr/bin/pwauth
SetExternalAuthMethod pwauth pipe

<Directory /path/2/the/web/app>
    AuthName 'plop'
    AuthBasicProvider external
    AuthType Basic
    AuthExternal pwauth
    order deny,allow
    deny from all
    allow from all # you can restrict to the local network
    Require user user1 user2 user3
    #Instead of above you can use the valid-user (all valid users) directive
    #Require valid-user
    Satisfy all
</Directory>

Use case authentication of groups and users

you can create a virtual host for example in /etc/httpd/conf.d

AddExternalAuth pwauth /usr/bin/pwauth
SetExternalAuthMethod pwauth pipe
AddExternalGroup unixgroup /usr/bin/unixgroup
SetExternalGroupMethod unixgroup environment

<Directory /path/2/the/web/app>
    AuthName 'plop'
    AuthBasicProvider external
    AuthType Basic
    AuthExternal pwauth
    GroupExternal unixgroup
    AuthzUserAuthoritative off
    order deny,allow
    deny from all
    allow from all # you can restrict to the local network
    Require user user1 user2 user3
    Require group group1 group2 group3
    Satisfy all
</Directory>

Code example of /etc/e-smith/templates/httpd/ibay-default/70UserMODDAV and /etc/e-smith/templates/httpd/ibay-default/35pwauth

allow users to write or read the webdav share (if enabled) or access to the webshare

  • /etc/e-smith/templates/httpd/ibay-default/35pwauth
{
use esmith::AccountsDB;

my $a = esmith::AccountsDB->open;
my $WebDav = $a->get_prop("$Name","HttpWebDav") || 'disabled';
my $UserAccess = $a->get_prop("$Name",'HttpUserAccess') || 'disabled';
if ($PasswordStatus eq 'UserGroup') {
    $OUT .= qq(
    #Set the path to pwauth/unixgroup for user/group authentication
    AddExternalAuth pwauth /usr/bin/pwauth
    SetExternalAuthMethod pwauth pipe
    AddExternalGroup unixgroup /usr/bin/unixgroup
    SetExternalGroupMethod unixgroup environment);
    }
}
  • /etc/e-smith/templates/httpd/ibay-default/70UserMODDAV
{
use esmith::AccountsDB;

my $a = esmith::AccountsDB->open_ro;

my @Writers = split (/[,]/, $AclWrite);
my @Readers = split (/[,]/, $AclRead);

#we retrieve the key name of user/group
my @users = map { $_->key } $a->users();
my @groups   = map { $_->key } $a->groups();

my @readuser   = 'admin';
my @readgroup  = ($GroupAccess eq 'r') ? $OwningGroup : '';
my @writeuser  = 'admin';
my @writegroup = ($GroupAccess eq 'rw') ? $OwningGroup : '';

#we separate user and group
foreach my $Reader  (@Readers) {
    push @readuser, $Reader if (grep /$Reader/,@users);
    push @readgroup, $Reader if (grep /$Reader/, @groups);
    }
foreach my $Writer  (@Writers) {
    push @writeuser, $Writer if (grep /$Writer/,@users);
    push @writegroup, $Writer if (grep /$Writer/, @groups);
    }

#we just want unique name, write access are also read access automatically
my %seen = ();
@readuser = sort (grep { ! $seen{ $_ }++ } (@readuser,@writeuser));
%seen = ();
@writeuser = sort (grep { ! $seen{ $_ }++ } (@writeuser));
%seen = ();
@readgroup = sort (grep { ! $seen{ $_ }++ } (@readgroup,@writegroup));
%seen = ();
@writegroup = sort (grep { ! $seen{ $_ }++ } (@writegroup));

#we delimit the allow permissions
my $webaccess;
if ($Access eq 'private') {
    $webaccess = join(" \\\n        ", split(' ', $PrivateAllow));
    }
else {
    $webaccess = 'all';
    }

#enable DAV if requested
my $DAVOn = ($WebDav eq 'enabled') ? 'DAV On':'';

if ($PasswordStatus eq 'UserGroup') {
    $OUT .= qq (
    $DAVOn
    AuthName $Name
    AuthBasicProvider external
    AuthType Basic
    AuthExternal pwauth
    GroupExternal unixgroup
    AuthzUserAuthoritative off
    # Read only access
    <Limit GET PROPFIND OPTIONS LOCK UNLOCK REPORT>
        order deny,allow
        deny from all
        allow from $webaccess
        Require user @readuser
        Require group @readgroup
    </Limit>
    # Write access
    <LimitExcept GET PROPFIND OPTIONS LOCK UNLOCK REPORT>
        order deny,allow
        deny from all
        allow from $webaccess
        Require user @writeuser
        Require group @writegroup
    </LimitExcept>);
    }
}

Here we don't need to install some apache module, they are already loaded in apache, I'm talking about

LoadModule ldap_module /path/to/mod_ldap.so
LoadModule authnz_ldap_module /path/to/mod_authnz_ldap.so

You have an excellent howTo on ldap authentication → http://archive09.linux.com/feature/120050

Use case user authentication

you can create a virtual host for example in /etc/httpd/conf.d

    Alias /cygwin /usr/share/BackupPC/cygwin

    <Directory /usr/share/BackupPC/cygwin>
        Options -Indexes
        AllowOverride None
        Order Deny,Allow
        Deny from All
        allow from all
        AuthName "cygwin-rsyncd setup"
        AuthType Basic
        AuthBasicProvider ldap
        AuthLDAPBindDN cn=libuser,dc=directory,dc=nh
        AuthLDAPBindPassword **PASSWORDVALUE**   # see 'cat /var/lib/nethserver/secrets/libuser' to retrieve the password
        AuthLDAPURL "ldap://localhost/ou=People,dc=directory,dc=nh?uid?sub?(objectClass=posixAccount)"
        require user admin user1 user2 
        #Instead of above you can use the valid-user (all valid users) directive
        #Require valid-user
        Satisfy all
    </Directory>

Use case Group and user authentications

you can create a virtual host for example in /etc/httpd/conf.d

    Alias /cygwin /usr/share/BackupPC/cygwin

    <Directory /usr/share/BackupPC/cygwin>
        Options -Indexes
        AllowOverride None
        Order Deny,Allow
        Deny from All
        allow from all
        AuthName "cygwin-rsyncd setup"
        AuthType Basic
        AuthzLDAPAuthoritative on          #Could be omitted since the default setting is "on," but is left here for clarity.
        AuthLDAPGroupAttribute memberUid   #indicates which attribute in the LDAP group record to match with the Uid

        AuthLDAPGroupAttributeIsDN off     #tells Apache to use the distinguished name of the client. Otherwise, the username will be used.

        AuthBasicProvider ldap
        AuthLDAPBindDN cn=libuser,dc=directory,dc=nh
        
        AuthLDAPBindPassword **PASSWORDVALUE**   # see 'cat /var/lib/nethserver/secrets/libuser' to retrieve the password
        
        AuthLDAPURL "ldap://localhost/ou=People,dc=directory,dc=nh?uid?sub?(objectClass=posixAccount)"
        Require ldap-user user1 user2 user3 user4
        Require ldap-group cn=group1,ou=Groups,dc=directory,dc=nh   #grants access to members of the group. For multiple groups, add an additional directive for each.
        Require ldap-attribute gidNumber=420                        #handles the primary users of gid 420, For multiple groups, add an additional directive for each.
        Satisfy all
    </Directory>

Code example of /etc/e-smith/templates/httpd/ibay-default/70UserMODDAV

allow users to write or read the webdav share (if enabled) or access to the webshare

{
use esmith::AccountsDB;
use NethServer::Password;

return '' unless ($PasswordStatus eq 'UserGroup');

my $a = esmith::AccountsDB->open_ro;
my $HttpPass = NethServer::Password::store('libuser');

#admin RW permissions, we retrieve permissions of the owning group
my @readuser   = 'admin';
my @readgroup  = ($GroupAccess eq 'r') ? $OwningGroup : '';
my @writeuser  = 'admin';
my @writegroup = ($GroupAccess eq 'rw') ? $OwningGroup : '';

#we separate user and group
my @users = map { $_->key } $a->users();
my @groups   = map { $_->key } $a->groups();

foreach my $Reader  (split (/[,]/, $AclRead)) {
    push @readuser, $Reader if (grep /$Reader/,@users);
    push @readgroup, $Reader if (grep /$Reader/, @groups);
    }
foreach my $Writer  (split (/[,]/, $AclWrite)) {
    push @writeuser, $Writer if (grep /$Writer/,@users);
    push @writegroup, $Writer if (grep /$Writer/, @groups);
    }

#we just want unique name, write access are also read access automatically
my %seen = ();
@readuser = sort (grep { ! $seen{ $_ }++ } (@readuser,@writeuser));
%seen = ();
@writeuser = sort (grep { ! $seen{ $_ }++ } (@writeuser));
%seen = ();
@readgroup = sort (grep { ! $seen{ $_ }++ } (@readgroup,@writegroup));
%seen = ();
@writegroup = sort (grep { ! $seen{ $_ }++ } (@writegroup));

#we delimit the allow permissions
my $webaccess;
if ($Access eq 'private') {
    $webaccess = join(" \\\n        ", split(' ', $PrivateAllow));
    }
else {
    $webaccess = 'all';
    }

#enable DAV if requested
my $DAVOn = ($WebDav eq 'enabled') ? 'DAV On':'';

    $OUT .= qq (
#
## User and group authentification
#
    $DAVOn
    AuthName $Name
    AuthType Basic
    AuthBasicProvider ldap
    AuthzLDAPAuthoritative on
    AuthLDAPGroupAttribute memberUid
    AuthLDAPGroupAttributeIsDN off
    AuthLDAPBindDN cn=libuser,dc=directory,dc=nh
    AuthLDAPBindPassword $HttpPass
    AuthLDAPURL "ldap://localhost/ou=People,dc=directory,dc=nh?uid?sub?(objectClass=posixAccount)"

    # Read only access
    <Limit GET PROPFIND OPTIONS LOCK UNLOCK REPORT>
        order deny,allow
        deny from all
        allow from $webaccess
        Require ldap-user @readuser
);

    foreach my $rgroup (@readgroup) {
    $OUT .= "        Require ldap-group cn=$rgroup,ou=Groups,dc=directory,dc=nh\n" if ($rgroup);
    }

    $OUT .= qq (        Satisfy all
    </Limit>
    # Write access
    <LimitExcept GET PROPFIND OPTIONS LOCK UNLOCK REPORT>
        order deny,allow
        deny from all
        allow from $webaccess
        Require ldap-user @writeuser
);

    foreach my $wgroup (@writegroup) {
    $OUT .= "        Require ldap-group cn=$wgroup,ou=Groups,dc=directory,dc=nh\n" if ($wgroup);
    }

    $OUT .= qq (        Satisfy all
    </LimitExcept>);
}

Debug and deploy

Testing LDAP authentication from a Web browser can be frustrating, because the only thing you know is whether access was granted or not. You don't get any kind of feedback on why something did not work. For verbose information on each step in the process, set the LogLevel debug option in Apache. With debugging active, Apache will record the connection status to the LDAP server, what attributes and values were requested, what was returned, and why conditions were met or not met. This information can be invaluable in fine-tuning LDAP access controls.

Here we will use the pam authentication needed specially for NS7 since we can have two LDAP (openldap or SAMBA4)

First you need to install modauthnzpam

yum install mod_authnz_pam
  • then you must uncomment the apache module
vim /etc/httpd/conf.modules.d/55-authnz_pam.conf
#LoadModule authnz_pam_module modules/mod_authnz_pam.so

to

LoadModule authnz_pam_module modules/mod_authnz_pam.so
  • or add after the 'Alias'
  <IfModule !authnz_pam_module>
  LoadModule authnz_pam_module modules/mod_authnz_pam.so
  </IfModule>

For example this is the apache configuration I made to authenticate a user in ttrss

cat /etc/httpd/conf.d/tt-rss.conf
Alias /tt-rss /usr/share/tt-rss
    <IfModule !authnz_pam_module>
    LoadModule authnz_pam_module modules/mod_authnz_pam.so
    </IfModule>
    
    <Location /tt-rss>
    AuthName "Tiny Tiny RSS"
    AuthType Basic
    AuthBasicProvider PAM
    AuthPAMService ttrss
    Require valid-user
    </Location>


<Directory /usr/share/tt-rss>
    AddType application/x-httpd-php .php
    php_admin_value open_basedir /usr/share/tt-rss:/var/lock/tt-rss:/var/cache/tt-rss:/tmp
    php_admin_value memory_limit 256M
    php_admin_flag allow_url_fopen on
    SSLRequireSSL on
    Require ip 127.0.0.1 192.168.12.0/255.255.255.0
</Directory>

<Directory /usr/share/tt-rss/schema>
    Require all denied
</Directory>

<Directory /usr/share/tt-rss/install>
    Require all denied
</Directory>

Then you must set pam to use the service ttrss you created

vim /etc/pam.d/ttrss
auth    required   pam_sss.so
account required   pam_sss.so

Restart apache

systemctl restart httpd