1package Dancer2::Plugin::Auth::Extensible::Provider::Unix; 2 3use Authen::Simple::PAM; 4use Unix::Passwd::File; 5use Moo; 6with "Dancer2::Plugin::Auth::Extensible::Role::Provider"; 7use namespace::clean; 8 9our $VERSION = '0.710'; 10 11=head1 NAME 12 13Dancer2::Plugin::Auth::Extensible::Unix - authenticate *nix system accounts 14 15=head1 DESCRIPTION 16 17An authentication provider for L<Dancer2::Plugin::Auth::Extensible> which 18authenticates Linux/Unix system accounts. 19 20Uses C<getpwnam> and C<getgrent> to read user and group details, 21and L<Authen::Simple::PAM> to perform authentication via PAM. 22 23Unix group membership is used as a reasonable facsimile for roles - this seems 24sensible. 25 26B<WARNING>: in order to use PAM authentication on most modern Linux/UNIX 27systems the application performing authentication must have read access 28to the C</etc/shadow> file. B<This is a security risk> since it can lead 29to accidental disclosure of sensitive data if you have any path traversal 30vulnerabilities, etc. We strongly recommend B<AGAINST> using this module 31and provide it purely as an example. Any use of it B<IS AT YOUR OWN RISK>. 32You have been warned. 33 34=head1 METHODS 35 36=head2 authenticate_user $username, $password 37 38=cut 39 40sub authenticate_user { 41 my ($class, $username, $password) = @_; 42 my $pam = Authen::Simple::PAM->new( service => 'login' ); 43 return $pam->authenticate($username, $password); 44} 45 46=head2 get_user_details $username 47 48Returns information from the C<passwd> file as a hash reference with the 49following keys: uid, gid, quota, comment, gecos, dir, shell, expire 50 51=cut 52 53sub get_user_details { 54 my ($class, $username) = @_; 55 56 my @result = getpwnam($username); 57 58 return unless @result; 59 60 return { 61 uid => $result[2], 62 gid => $result[3], 63 quota => $result[4], 64 comment => $result[5], 65 gecos => $result[6], 66 dir => $result[7], 67 shell => $result[8], 68 expire => $result[9], 69 }; 70} 71 72=head2 get_user_roles $username 73 74=cut 75 76sub get_user_roles { 77 my ($class, $username) = @_; 78 my %roles; 79 80 # we also need gid from user_details since username might not be listed 81 # in the group file as being in that group 82 return unless my $user_details = $class->get_user_details($username); 83 84 my @primary_group = getgrgid($user_details->{gid}) if $user_details->{gid}; 85 86 $roles{$primary_group[0]} = 1 if @primary_group; 87 88 while ( my ( $group_name, undef, undef, $members ) = getgrent() ) { 89 $roles{$group_name} = 1 if $members =~ m/\b$username\b/; 90 } 91 endgrent(); 92 93 return [keys %roles]; 94} 95 961; 97