Allow apache access per user/group with Mod DAV

Actually the http access to an Ibay can be restricted by a password that you must share between each users. With few users that can be done, but in a company it is not conceivable :slight_smile:

I have done some coding on that purpose for allowing groups, users to apache shares and activating mod DAV (file transfer by apache.). From my side it is workable except if I load a new require (after the official require IBAYNAME) it is evident that the former password protection of the Ibay will not work and my user/group require will be used. I do believe that few people is using this type of authentication, but for question of compatibility I would keep in work this older option.

So I have some questions to the @giacomo, @davidep, @filippo_carletti, @alep, @stephdl, @Stll0, @alefattorini

  • Do I code to modify an official rpm
  • Do I code for a module and for those who will install it, the former authentication by a unique password won’t work anymore.

some examples of what I’m modifying :

[root@nethserver-dev4 ~]# cat  /etc/e-smith/templates/httpd/ibay-default/35pwauth 
{
use esmith::AccountsDB;
use esmith::DB;

my $a = esmith::AccountsDB->open;
my $WebDav = $a->get_prop("$Name","HttpWebDav") || 'disabled';
my $UserAccess = $a->get_prop("$Name",'HttpUserAccess') || 'disabled';
if (($WebDav eq 'enabled') || ($UserAccess eq 'enabled')) {
    $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);
    }
}

[root@nethserver-dev4 ~]# cat  /etc/e-smith/templates/httpd/ibay-default/70UserModDav 
{
use esmith::AccountsDB;

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

#we retrieve the the values of properties
my @Writers = split (/[,]/, ($a->get_prop("$Name","AclWrite") || ''));
my @Readers = split (/[,]/, ($a->get_prop("$Name","AclRead") || ''));
my $UserAccess = $a->get_prop("$Name",'HttpUserAccess') || 'disabled';
my $WebDav  = $a->get_prop("$Name","HttpWebDav") || 'disabled';
my $DavAllow = $a->get_prop("$Name","HttpWebDavAllow") || '';

#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  = '';
my @writeuser  = 'admin';
my @writegroup = '';

#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';
    }

#we can set a different allow for external access
my $davallow = $webaccess if ($DavAllow eq '');
#enable DAV if requested
my $DAVOn = ($WebDav eq 'enabled') ? 'DAV On':'';

if (($WebDav eq 'enabled') || ($UserAccess eq 'enabled')) {
    $OUT .= qq (
    # Enable DAV access
    $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 $davallow
        Require user @writeuser
        Require group @writegroup
    </LimitExcept>);
    }
}

[root@nethserver-dev4 ~]# cat /etc/e-smith/events/actions/nethserver-full-apache-write
#!/usr/bin/perl
use esmith::ConfigDB;
use strict;

eval { require esmith::AccountsDB };
if($@) {
    exit(0); # AccountsDB is not available, exit
}

use esmith::AccountsDB;
my $db = esmith::ConfigDB->open_ro();
my $adb  = esmith::AccountsDB->open_ro();


my $event = shift || die("Missing event argument");
my $ibay = shift || die("Missing ibay argument");
my $ibaydir = '/var/lib/nethserver/ibay/' . $ibay;

my $httpdststatus = $adb->get_prop($ibay, 'HttpStatus') || 'disabled';
print $httpdststatus;
exit 0 if ($httpdststatus eq 'disabled');

my $httpwrite = $adb->get_prop($ibay,'HttpWritable') || 'disabled';

if ($httpwrite eq 'enabled') {
system ('/usr/bin/setfacl','-P','-R','-m','u:apache:rwX,d:u:apache:rwX', "$ibaydir") == '0' 
|| die "Failed to set apache acl on the ibay $ibay\n";
}

I’d say “code for official”, show a pull request and we will be able to evaluate it better.

1 Like

PR waiting your reviews and comments

2 Likes

Well done @stephdl, your PR looks complex but complete!

I believe we should Require SSL encrypted connection to protect user passwords when DAV is enabled. Anyway this could be coded later.

1 Like

Almost of time I code alone, so if the code could be written shorter or better, please do it, I will learn something :wink:

The ‘complexity’ comes from the way on how the acl are stored (user and group mixed).[quote=“davidep, post:4, topic:2529”]
I believe we should Require SSL encrypted connection to protect user passwords when DAV is enabled.
[/quote]

Yes…and ask for a redirection if the communication is started on the port 80[quote=“davidep, post:4, topic:2529”]
Anyway this could be coded later.
[/quote]

At the hotel for two days…it will be delayed…except if someone shoots first

Yeah, of course you’re not responsible for the ACLs implementation complexity. If someone should be beaten, here I am :smile:

Executing setfacl recursively two times, the first in nethserver-ibays-set-permissions and the second in nethserver-httpd-ModDav-permissions is not optimal. It could be enhanced by moving nethserver-httpd-ModDav-permissions logic into /etc/e-smith/templates/ibays/system-acls/10httpd template. However, doing it in this way requires also the modification of nethserver-httpd-sethtwritable action because it must be aware of the write permissions due to WebDAV.

An alternative to the setfacl approach is discussed on the other thread:

Both ways have their limitations, however I see ACLs are becoming a complex beast and I’m becoming a KISS fan, too :blush:

Before going further I’d like to listen to other opinions from @dev_team (@giacomo, @davidep, @filippo_carletti, @alep, @stephdl, @Stll0, @alefattorini) and others…

In the meantime I opened an issue here: http://dev.nethserver.org/issues/3336


I want also to report here, as written by @stephdl, that the PR could be splitted into two parts:

  • LDAP based authentication
  • WebDAV protocol support

I don’t see any problem for the LDAP based authentication. Only we should discuss if it is worth implementing it on NS6, or wait and see how it goes with Samba 4.

I’m completely lost. :open_mouth:
Just give me at least a week to dig into this stuff :smiley:

1 Like

Done and incorporated in the PR

same, Done and incorporated in the PR

2 Likes

yeah, this is why i’m a bit upset :slight_smile:

Man, you have to call @davidep insistently :slight_smile:

I admit I left this proposal aside, waiting to see how the things proceed on ns7 before introducing any change on ns6. I’m sorry for disappointing you!

2 Likes

Just for my curiosity, it is possible to authentify in apache via samba4 ?

IIRC @Stll0 succeeded on configuring Apache 2.4 + PAM authentication (mod_authnz_pam?), no matter what the auth provider is.

1 Like

I got it also, a new step forward

2 Likes
<?php if (isset($_POST['username']) && isset($_POST['password'])) { $ldaphost = "mydomain.com"; $ldapport = 389; $ds = ldap_connect($ldaphost, $ldapport) or die("Could not connect to $ldaphost"); if ($ds) { $username = $_POST['username']; $password = $_POST['password']; $binddn = "uid=" . $username . ",ou=People,dc=directory,dc=nh"; //cn=admin or whatever you use to login by phpldapadmin $ldapbind = ldap_bind($ds,$binddn, $password); //check if ldap was sucessfull if ($ldapbind) { $loggedin = "LDAP bind successful..."; } else { $loggedin = "LDAP bind failed..."; } } } else { echo "You Must Enter a Username and Password"; } // uid=username,ou=people,dc=directory,dc=nh ?> <?php echo $loggedin; ?>