-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsrpchecker.pm
153 lines (143 loc) · 5.56 KB
/
srpchecker.pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package SRP::Command::check;
use Mojo::Base 'Mojolicious::Command';
use Mojo::mysql;
use Net::LDAP qw(LDAP_SUCCESS LDAP_INSUFFICIENT_ACCESS);
use Net::LDAP::Util qw(canonical_dn);
has description => 'Check and clean security groups';
has usage => "Usage: APPLICATION check\n";
sub run {
my $self = shift;
my $app = $self->app;
$app->log->info('Check started '.localtime());
# ldap operations
my $ldap = Net::LDAP->new($app->config('ldapservers'), port => 389, timeout => 10);
unless ($ldap) {
$app->log->fatal("Ldap connection error. Create object failed. $@");
exit 1;
}
my $mesg = $ldap->bind($app->config('ldapuser'), password => $app->config('ldappass'), version => 3);
if ($mesg->code) {
$app->log->fatal('Ldap bind error: '.$mesg->error);
exit 1;
}
# group config
my @sec_groups = map { { %$_ } } @{$app->config('sec_groups')}; # copy structure
# load all group members into hash
foreach my $sg (@sec_groups) {
#say "Group: ".$sg->{dn};
# search ldap for group members
my $res = $ldap->search(base => $sg->{dn}, filter => '(objectClass=group)', scope => 'base', attrs => ['member']);
if ($res->code) {
$app->log->fatal('Ldap group search error: '.$res->error);
$ldap->unbind;
exit 1;
}
if ($res->count > 0) {
my @member_list;
# resolve dn-s to logins
foreach my $m ($res->entry(0)->get_value('member')) {
utf8::decode($m);
my $res1 = $ldap->search(base => $m, filter => '(|(objectClass=person)(objectClass=group))', scope => 'base', attrs => ['sAMAccountName']);
if ($res1->code) {
$app->log->fatal('Ldap search error: '.$res1->error);
$ldap->unbind;
exit 1;
}
if ($res1->count > 0) {
my $user_login = $res1->entry(0)->get_value('sAMAccountName');
utf8::decode($user_login);
#say "Member: ".canonical_dn($m).", Login: ".lc($user_login);
push @member_list, { dn => canonical_dn($m), login => lc($user_login) }
} else {
$app->log->warning("User or group $m can not be found in active directory");
}
}# resolve members dn-s
$sg->{members} = \@member_list;
} else {
$app->log->fatal("Ldap group $sg->{dn} is not found in active directory");
$ldap->unbind;
exit 1;
}
} #foreach my $sg
# cleaning ---
my $db_sec = $app->mysql_secraise->db;
my $db_otrs = $app->mysql_tickets->db;
my $rec = $db_sec->query("SELECT id, login, tn, priv_code FROM secraise");
while (my $next = $rec->hash) {
#say $app->dumper($next);
my $delete_flag = 0;
my $ttitle = 'н/д';
if ($next->{tn}) {
# lookup for ticket
my $ticket_rec = $db_otrs->query("SELECT t.title, ts.type_id AS tstate_id \
FROM ticket t \
INNER JOIN ticket_state ts ON t.ticket_state_id = ts.id \
WHERE t.tn = ?", $next->{tn}
);
if (my $v = $ticket_rec->array) {
# ticket closed?
if ($app->is_ticket_closed($v->[1])) {
$ttitle = $v->[0] || 'н/д';
$delete_flag = 1;
}
} else { # ticket not found
$app->log->error("Ticket number $next->{tn} is not found for request id: ".$next->{id});
$delete_flag = 1;
}
$ticket_rec->finish;
} else { # empty ticket number
$app->log->error('Empty ticket number for request id: '.$next->{id});
$delete_flag = 1;
}
# delete request from table
my $user_login = $next->{login};
if ($delete_flag) {
$app->log->info("Releasing request $next->{id} for user: $user_login, ticket: $next->{tn}, privilege: $next->{priv_code}.");
my $r = $db_sec->query("DELETE FROM secraise WHERE id = ?", $next->{id});
if ($r->affected_rows != 1) {
$app->log->error("Secraise record hasn't been deleted.");
}
# add to secraise_log
$app->dblog(login => $user_login, tn => $next->{tn}, title => $ttitle,
priv_code => $next->{priv_code}, state_code => 2, reason => 'Закрытие заявки');
} else {
# (consistency) check corresponding membership in ldap group
my $user_found_in_group;
MEMBERLOOP1:
foreach (@{$sec_groups[$next->{priv_code}]->{members}}) {
if ($_->{login} eq $user_login) { $user_found_in_group = 1; last MEMBERLOOP1; }
}
unless ($user_found_in_group) {
$app->log->error("Consistency check failure. User $user_login is not found in group $sec_groups[$next->{priv_code}]->{dn} as he should be.");
}
}
} # loop all requests
$rec->finish;
# now the final check
my $cur_priv = 0;
foreach my $sg (@sec_groups) { #say "Group: ".$sg->{dn};
foreach my $m (@{$sg->{members}}) { #say "Login: $m->{login}";
# looking for at least one request exist
$rec = $db_sec->query("SELECT COUNT(*) FROM secraise WHERE login = ? AND priv_code = ?", $m->{login}, $cur_priv);
if (my $v = $rec->array) { #say $v->[0];
# delete members having no requests
if ($v->[0] == 0) {
$app->log->info("Removing user $m->{login} from group $sg->{dn}");
my $mesg = $ldap->modify($sg->{dn}, delete => { member => [$m->{dn}] });
if ($mesg->code) {
$app->log->error("Error removing user $m->{dn} from group $sg->{dn}, code: ".$mesg->code.', error: '.$mesg->error);
}
}
} else {
$app->log->fatal("A kind of database error occurs during final check $m->{login}, privilege $cur_priv.");
}
$rec->finish;
}
$cur_priv++;
} #foreach my $sg
$ldap->unbind;
$ldap = undef;
$app->log->debug('Check finished '.localtime());
exit 0;
}
1;