Markus
Markus

Reputation: 5807

nginx group http auth

coming from apache2 the only feature i cannot archive: have users in a password-database (htpasswd) and allow the access to different files/folders/virtual servers.

Basic http auth I enabled works:

location ~ ^/a/ {
    # should allow access for user1, user2
    auth_basic            "Restricted";
    auth_basic_user_file  /etc/nginx/auth/file_a;
}
location ~ ^/b/ {
    # should allow access for user2, user3
    auth_basic            "Restricted";
    auth_basic_user_file  /etc/nginx/auth/file_b;
}

If I have user1, user2 in file_a and user2, user3 in file_b, this works but I have to update both files when I change the password for user2 (password should be the same for all locations). Since I will have >15 different locations with different access rights and >10 users, this is not really easy to handle. (I love fine grained access rights!)

With Apache I defined different groups for each location and required the right group. Changing access was as easy as adding/removing users to groups.

Is there something like that or how can this scenario be handled easily with nginx?

Upvotes: 7

Views: 6924

Answers (3)

Guido Flohr
Guido Flohr

Reputation: 2340

I am using a script nginx-groups.pl that parses apache style password and groups files and generates individual password files for each group. So it essentially does the same thing as the Ruby script in Markus' answer but it uses only one single file for all groups and the group file is in the same format as for apache.

The current version of the script is:

#! /usr/bin/env perl

use strict;

die "Usage: $0 USERSFILE GROUPSFILE\n" unless @ARGV == 2;
my ($users_file, $groups_file) = @ARGV;

my %users;
open my $fh, "<$users_file" or die "cannot open '$users_file': $!\n";
while (my $line = <$fh>) {
    chomp $line;
    my ($name, $password) = split /:/, $line, 2;
    next if !defined $password;
    $users{$name} = $line;
}

open my $fh, "<$groups_file" or die "cannot open '$groups_file': $!\n";
while (my $line = <$fh>) {
    my ($name, $members) = split /:/, $line, 2 or next;
    next if !defined $members;
    $name =~ s/[ \t]//g;
    next if $name eq '';
    my @members = grep { length $_ && exists $users{$_} } 
                  split /[ \t\r\n]+/, $members;

    my $groups_users_file = $name . '.users';

    print "Writing users file '$groups_users_file'.\n";

    open my $wh, ">$groups_users_file" 
        or die "Cannot open '$groups_users_file' for writing: $!\n";

    foreach my $user (@members) {
        print $wh "$users{$user}\n"
            or die "Cannot write to '$groups_users_file': $!\n";
    }

    close $wh or die "Cannot close '$groups_users_file': $!\n";
}

Save it under whatever name you like and make it executable. Invoking it without arguments will print a short usage info.

See http://www.guido-flohr.net/group-authentication-for-nginx/ for details!

Upvotes: 1

Markus
Markus

Reputation: 5807

I finally manage it like this with basic http auth:

  • For each group I have a seperate password file, eg group_a.auth, group_b.auth, ...
  • In addition, I have a file where each user and password is written, eg passwords.txt
  • passwords.txt has the same format like auth files, so something like user1:password_hash
  • I have a ruby script update.rb to sync user's passwords from password.txt to all .auth files (well more a wrapper to sed):

Ruby script update.rb:

#!/usr/bin/env ruby

passwords = File.new("./passwords.txt","r")

while pwline = passwords.gets
    pwline.strip!
    next if pwline.empty?

    user, _ = pwline.split(':')
    %x(sed -i 's/#{user}:.*/#{pwline.gsub('/','\/')}/g' *.auth)
end
  • To update a user's password: update password in passwords.txt and execute update.rb
  • To add a user to a group (eg new_user to group_a): open group_a.auth and add the line new_user:. Then add new_user:password_hash to passwords.txt if the user is not already present and finally run update.rb

Upvotes: 2

c2h5oh
c2h5oh

Reputation: 4560

You can get this working using AuthDigest module and realms as groups - you'll have multiple entries for one user, but you can have them line after line in a single file. Not perfect, but better than the nightmare you have now.

Small change in configuration (see auth_digest and user_file for 2nd location):

location ~ ^/a/ {
    # should allow access for user1, user2
    auth_digest            "Restricted";
    auth_digest_user_file  /etc/nginx/auth/file_a;
}
location ~ ^/b/ {
    # should allow access for user2, user3
    auth_digest            "Restricted2";
    auth_digest_user_file  /etc/nginx/auth/file_a;
}

and file_a:

user1:Restricted1:password_hash
user2:Restricted1:password_hash
user2:Restricted2:password_hash
user3:Restricted2:password_hash

Upvotes: 16

Related Questions