source: LATMOS-Accounts/lib/LATMOS/Accounts/Acls.pm @ 315

Last change on this file since 315 was 315, checked in by nanardon, 15 years ago
  • add script to test acls and eventually dump it
File size: 5.3 KB
Line 
1package LATMOS::Accounts::Acls;
2
3use strict;
4use warnings;
5use LATMOS::Accounts::Log;
6
7our $VERSION = (q$Rev: 330 $ =~ /^Rev: (\d+) /)[0];
8
9sub new {
10    my ($class, $file) = @_;
11    my $acls = bless(
12        {
13            _acls => []
14        }, $class
15    );
16    if ($file) {
17        $acls->read_acl_file($file) or return;
18    }
19    $acls
20}
21
22=head1 ACL FILE FORMAT
23
24    OBJ_TYPE.ATTRIBUTE
25        USER:  read,write
26        USER2: read
27
28=over 4
29
30=item OBJ_TYPE is the type the object, '*' match all
31
32=item ATTRIBUTE is either an attribute, either an comma separate attribute
33enclose into bracket, either a '*' to match any attribute
34
35=item USER can be
36
37=over 4
38
39=item a username
40
41=item group, prefixed by a '%'
42
43=item an attribute of the accessed object which should contains the username,
44prefixed by '$'
45
46=back
47
48=item Permission are read and or write, or deny.
49
50=back
51
52ACL are applied in the order they appear in the file.
53
54=cut
55
56sub read_acl_file {
57    my ($self, $file) = @_;
58
59    my $acl;
60    my $line_nb = 0;
61    my $prevline = "";
62    if (open(my $handle, '<', $file)) {
63        while(my $realline = <$handle>) {
64            $line_nb++;
65            chomp($realline);
66            if ($realline =~ /\\$/) {
67                # continuation line
68                $prevline .= $realline;
69                $prevline =~ s/\s*\\$//;
70                next;
71            }
72            my $line = $prevline . $realline; # keep track to report malformed file
73            $prevline = "";
74            $line =~ s/\s*#.*//;
75            if ($line =~ /^(\S.*)/) {
76                if ($acl) {
77                    push(@{$self->{_acls}}, $acl);
78                }
79                $acl = LATMOS::Accounts::Acls::acl->new($1) or do {
80                    la_log(LA_ERR, "Error in %s at line %d", $file,
81                        $line_nb);
82                    return;
83                };
84            } elsif ($line =~ /^\s+(\S.*)/) {
85                if ($acl) {
86                    $acl->add_perm($line) or do {
87                        la_log(LA_ERR, "Error in %s at line %d", $file,
88                            $line_nb);
89                        return;
90                    };
91                } else {
92                    # err no acl
93                    return;
94                }
95            } elsif ($line =~ /^\s*$/) {
96                # just empty line
97            } else {
98            }
99        }
100        if ($acl) {
101            push(@{$self->{_acls}}, $acl);
102        }
103    } else {
104        la_log(LA_ERR, "Cannot open acl file %s", $file);
105    }
106    1;
107}
108
109sub add {
110    my ($self, $obj, $list) = @_;
111    my $acl = LATMOS::Accounts::Acls::acl->new(
112        $obj, $list) or return;
113    push(@{$self->{_acls}}, $acl);
114    return 1;
115}
116
117sub check {
118    my ($self, $obj, $attr, $perm, $who, $groups) = @_;
119    foreach my $acl (@{$self->{_acls}}) {
120        my $res = $acl->match($obj, $attr, $perm, $who, $groups);
121        defined($res) and return $res;
122    }
123    return 0;
124}
125
126sub dump {
127    my ($self) = @_;
128    foreach my $acl (@{$self->{_acls}}) {
129        print $acl->dump, "\n";
130    }
131}
132
133package LATMOS::Accounts::Acls::acl;
134use strict;
135use warnings;
136
137sub new {
138    my ($class, $objdotatt, $list) = @_;
139    my ($obj, $attr) = $objdotatt =~ /^([^.]+)\.(.*)/ or return;
140    my @attrs = ($attr =~ /^\{(.*)\}$/)
141        ? (split(/\s*,\s*/, $1))
142        : ($attr);
143    @attrs or return;
144    my $acl = {
145        obj => lc($obj),
146        attr => [ map { lc } @attrs ],
147        users => [], # user->{r} = 1
148    };
149    bless($acl, $class);
150    foreach my $k (@{ $list || [] }) {
151        $acl->add_perm($k) or return;
152    }
153    $acl
154}
155
156sub add_perm {
157    my ($self, $perm) = @_;
158    my ($username, $perms) = $perm =~ /^\s*(\S*):\s*(.*)$/;
159    $username && $perms or return;
160    my $user = { user => $username };
161    foreach (split(/\s*,\s*/, $perms)) {
162        /^read$/i  and do { $user->{r} = 1; next; };
163        /^write$/i and do { $user->{w} = 1; next; };
164        /^deny$/i and do {
165            # reseting...
166            $user->{r} = 0;
167            $user->{w} = 0;
168            last; # we end here, life is hard
169        };
170        return;
171    }
172    push(@{$self->{users}}, $user);
173    1
174}
175
176sub match {
177    my ($self, $obj, $attr, $perm, $who, $groups) = @_;
178    my $objtype = lc($obj->type); $attr = lc($attr);
179    if (!($self->{obj} eq '*' || $self->{obj} eq $objtype)) {
180        return
181    }
182    grep { $_ eq '*' || $_ eq $attr } @{$self->{attr}} or return;
183
184    foreach my $u (@{ $self->{users} }) {
185        if (substr($u->{user}, 0, 1) eq '$') { # check attr content
186            my $attribute = substr($u->{user}, 1);
187            my $val = $obj->get_c_field($attribute);
188            my @vals = ref $val ? (@{ $val }) : ($val);
189            return ($u->{$perm} || 0) if (grep { $_ eq $who } @vals);
190        } elsif (substr($u->{user}, 0, 1) eq '%') { # group
191            my $group = substr($u->{user}, 1);
192            return ($u->{$perm} || 0) if (grep { $group eq $_ } @{$groups ||[]});
193        } elsif ($u->{user} eq '*' || $u->{user} eq $who) {
194            return $u->{$perm} || 0;
195        } else {
196            return
197        }
198    }
199}
200
201sub dump {
202    my ($self) = @_;
203    my $dump = sprintf("%s.{%s}\n", $self->{obj}, join(', ', @{$self->{attr}}));
204    foreach my $u (@{ $self->{users} }) {
205        $dump .= sprintf("\t%s: %s\n",
206            $u->{user},
207            join(', ', ($u->{r} ? 'read' : ()), ($u->{w} ? 'write' : ())) ||
208            'deny');
209    }
210    $dump
211}
212
2131;
214
215__END__
Note: See TracBrowser for help on using the repository browser.