use
POSIX
qw(setuid setgid)
;
our
$VERSION
=
'1.4.1'
;
our
$status
= {};
our
$activity
= [];
our
$start
=
int
(
time
/ 60 );
our
$page_title
=
'Lemonldap::NG statistics'
;
sub
portalTab {
return
{
-5
=>
'PORTAL_IMG_NOK'
,
-4
=>
'PORTAL_IMG_OK'
,
-3
=>
'PORTAL_INFO'
,
-2
=>
'PORTAL_REDIRECT'
,
-1
=>
'PORTAL_DONE'
,
0
=>
'PORTAL_OK'
,
1
=>
'PORTAL_SESSIONEXPIRED'
,
2
=>
'PORTAL_FORMEMPTY'
,
3
=>
'PORTAL_WRONGMANAGERACCOUNT'
,
4
=>
'PORTAL_USERNOTFOUND'
,
5
=>
'PORTAL_BADCREDENTIALS'
,
6
=>
'PORTAL_LDAPCONNECTFAILED'
,
7
=>
'PORTAL_LDAPERROR'
,
8
=>
'PORTAL_APACHESESSIONERROR'
,
9
=>
'PORTAL_FIRSTACCESS'
,
10
=>
'PORTAL_BADCERTIFICATE'
,
21
=>
'PORTAL_PP_ACCOUNT_LOCKED'
,
22
=>
'PORTAL_PP_PASSWORD_EXPIRED'
,
23
=>
'PORTAL_CERTIFICATEREQUIRED'
,
24
=>
'PORTAL_ERROR'
,
25
=>
'PORTAL_PP_CHANGE_AFTER_RESET'
,
26
=>
'PORTAL_PP_PASSWORD_MOD_NOT_ALLOWED'
,
27
=>
'PORTAL_PP_MUST_SUPPLY_OLD_PASSWORD'
,
28
=>
'PORTAL_PP_INSUFFICIENT_PASSWORD_QUALITY'
,
29
=>
'PORTAL_PP_PASSWORD_TOO_SHORT'
,
30
=>
'PORTAL_PP_PASSWORD_TOO_YOUNG'
,
31
=>
'PORTAL_PP_PASSWORD_IN_HISTORY'
,
32
=>
'PORTAL_PP_GRACE'
,
33
=>
'PORTAL_PP_EXP_WARNING'
,
34
=>
'PORTAL_PASSWORD_MISMATCH'
,
35
=>
'PORTAL_PASSWORD_OK'
,
36
=>
'PORTAL_NOTIFICATION'
,
37
=>
'PORTAL_BADURL'
,
38
=>
'PORTAL_NOSCHEME'
,
39
=>
'PORTAL_BADOLDPASSWORD'
,
40
=>
'PORTAL_MALFORMEDUSER'
,
41
=>
'PORTAL_SESSIONNOTGRANTED'
,
42
=>
'PORTAL_CONFIRM'
,
43
=>
'PORTAL_MAILFORMEMPTY'
,
44
=>
'PORTAL_BADMAILTOKEN'
,
45
=>
'PORTAL_MAILERROR'
,
46
=>
'PORTAL_MAILOK'
,
47
=>
'PORTAL_LOGOUT_OK'
,
48
=>
'PORTAL_SAML_ERROR'
,
49
=>
'PORTAL_SAML_LOAD_SERVICE_ERROR'
,
50
=>
'PORTAL_SAML_LOAD_IDP_ERROR'
,
51
=>
'PORTAL_SAML_SSO_ERROR'
,
52
=>
'PORTAL_SAML_UNKNOWN_ENTITY'
,
53
=>
'PORTAL_SAML_DESTINATION_ERROR'
,
54
=>
'PORTAL_SAML_CONDITIONS_ERROR'
,
55
=>
'PORTAL_SAML_IDPSSOINITIATED_NOTALLOWED'
,
56
=>
'PORTAL_SAML_SLO_ERROR'
,
57
=>
'PORTAL_SAML_SIGNATURE_ERROR'
,
58
=>
'PORTAL_SAML_ART_ERROR'
,
59
=>
'PORTAL_SAML_SESSION_ERROR'
,
60
=>
'PORTAL_SAML_LOAD_SP_ERROR'
,
61
=>
'PORTAL_SAML_ATTR_ERROR'
,
62
=>
'PORTAL_OPENID_EMPTY'
,
63
=>
'PORTAL_OPENID_BADID'
,
64
=>
'PORTAL_MISSINGREQATTR'
,
65
=>
'PORTAL_BADPARTNER'
,
66
=>
'PORTAL_MAILCONFIRMATION_ALREADY_SENT'
,
67
=>
'PORTAL_PASSWORDFORMEMPTY'
,
68
=>
'PORTAL_CAS_SERVICE_NOT_ALLOWED'
,
69
=>
'PORTAL_MAILFIRSTACCESS'
,
70
=>
'PORTAL_MAILNOTFOUND'
,
71
=>
'PORTAL_PASSWORDFIRSTACCESS'
,
72
=>
'PORTAL_MAILCONFIRMOK'
,
73
=>
'PORTAL_RADIUSCONNECTFAILED'
,
74
=>
'PORTAL_MUST_SUPPLY_OLD_PASSWORD'
,
75
=>
'PORTAL_FORBIDDENIP'
,
76
=>
'PORTAL_CAPTCHAERROR'
,
77
=>
'PORTAL_CAPTCHAEMPTY'
,
78
=>
'PORTAL_REGISTERFIRSTACCESS'
,
79
=>
'PORTAL_REGISTERFORMEMPTY'
,
80
=>
'PORTAL_REGISTERALREADYEXISTS'
,
};
}
eval
{
setgid( (
getgrnam
(
$ENV
{APACHE_RUN_GROUP} ) )[2] );
setuid( (
getpwnam
(
$ENV
{APACHE_RUN_USER} ) )[2] );
};
sub
run {
my
(
$localStorage
,
$localStorageOptions
) = (
shift
,
shift
);
my
$refLocalStorage
;
eval
"use $localStorage; \$refLocalStorage = new $localStorage(\$localStorageOptions);"
;
die
($@)
if
($@);
$| = 1;
my
(
$lastMn
,
$mn
,
$count
);
while
(<STDIN>) {
$mn
=
int
(
time
/ 60 ) -
$start
+ 1;
if
(
$mn
>
$lastMn
) {
for
(
my
$i
= 0 ;
$i
<
$mn
-
$lastMn
;
$i
++ ) {
unshift
@$activity
, {};
delete
$activity
->[ MN_COUNT + 1 ];
}
}
$lastMn
=
$mn
;
if
(
/^(\S+)\s+=>\s+(\S+)\s+(OK|REJECT|REDIRECT|LOGOUT|UNPROTECT|\-?\d+)$/
)
{
my
(
$user
,
$uri
,
$code
) = ( $1, $2, $3 );
$code
= portalTab->{
$code
} ||
$code
if
(
$code
=~ /^\-?\d+$/ );
$status
->{user}->{
$user
}->{
$code
}++;
$uri
=~ s/^(.*?)\?.*$/$1/;
$status
->{uri}->{
$uri
}->{
$code
}++;
$count
->{uri}->{
$uri
}++;
my
(
$vhost
) = (
$uri
=~ /^([^\/]+)/ );
$status
->{vhost}->{
$vhost
}->{
$code
}++;
$count
->{vhost}->{
$vhost
}++;
$activity
->[0]->{
$code
}++;
}
elsif
(/^STATUS(?:\s+(\S+))?$/) {
my
$tmp
= $1;
my
$args
= {};
%$args
=
split
( /[=&]/,
$tmp
)
if
(
$tmp
);
&head
;
my
(
$c
,
$m
,
$u
);
while
(
my
(
$user
,
$v
) =
each
( %{
$status
->{user} } ) ) {
$u
++
unless
(
$user
=~ /^\d+\.\d+\.\d+\.\d+$/ );
foreach
(
keys
%$v
) {
$c
->{
$_
} +=
$v
->{
$_
};
}
}
for
(
my
$i
= 1 ;
$i
<
@$activity
;
$i
++ ) {
$m
->{
$_
} +=
$activity
->[
$i
]->{
$_
}
foreach
(
keys
%{
$activity
->[
$i
] } );
}
foreach
(
keys
%$m
) {
$m
->{
$_
} =
sprintf
(
"%.2f"
,
$m
->{
$_
} / MN_COUNT );
$m
->{
$_
} =
int
(
$m
->{
$_
} )
if
(
$m
->{
$_
} > 99 );
}
if
(
$args
->{
'dump'
} ) {
print
"<div id=\"dump\"><pre>\n"
;
print
Dumper(
$status
,
$activity
,
$count
);
print
"</pre></div>\n"
;
&end
;
}
else
{
print
"<h2>Total</h2>\n<div id=\"total\"><pre>\n"
;
print
sprintf
(
"%-30s : \%6d (%.02f / mn)\n"
,
$_
,
$c
->{
$_
},
$c
->{
$_
} /
$mn
)
foreach
(
sort
keys
%$c
);
print
"\n</pre></div>\n"
;
print
"<h2>Average for last "
. MN_COUNT
.
" minutes</h2>\n<div id=\"average\"><pre>\n"
;
print
sprintf
(
"%-30s : %6s / mn\n"
,
$_
,
$m
->{
$_
} )
foreach
(
sort
keys
%$m
);
print
"\n</pre></div>\n"
;
print
"<div id=\"users\"><p>\nTotal users : $u\n</p></div>\n"
;
print
"<div id=\"up\"><p>\nServer up for : "
.
&timeUp
(
$mn
)
.
"\n</p></div>\n"
;
if
(
$args
->{top} ) {
print
"<hr/>\n"
;
$args
->{categories} ||=
'REJECT,PORTAL_FIRSTACCESS,LOGOUT,OK'
;
print
"<h2>Virtual Host activity</h2>\n<div id=\"vhost\"><pre>\n"
;
foreach
(
sort
{
$count
->{vhost}->{
$b
} <=>
$count
->{vhost}->{
$a
} }
keys
%{
$count
->{vhost} }
)
{
print
sprintf
(
"%-40s : %6d\n"
,
$_
,
$count
->{vhost}->{
$_
} );
}
print
"\n</pre></div>\n"
;
print
"<h2>Top used URI</h2>\n<div id=\"uri\"><pre>\n"
;
my
$i
= 0;
foreach
(
sort
{
$count
->{uri}->{
$b
} <=>
$count
->{uri}->{
$a
} }
keys
%{
$count
->{uri} }
)
{
last
if
(
$i
==
$args
->{top} );
last
unless
(
$count
->{uri}->{
$_
} );
$i
++;
print
sprintf
(
"%-80s : %6d\n"
,
$_
,
$count
->{uri}->{
$_
} );
}
print
"\n</pre></div>\n"
;
print
"<table class=\"topByCat\"><tr><th style=\"width:20%\">Code</th><th>Top</th></tr>\n"
;
foreach
my
$cat
(
split
/,/,
$args
->{categories} ) {
print
"<tr><td>$cat</td><td nowrap>\n<div id=\"$cat\">\n"
;
topByCat(
$cat
,
$args
->{top} );
print
"</div>\n</td></tr>"
;
}
print
"</table>\n"
;
}
&end
;
}
}
}
}
sub
timeUp {
my
$d
=
shift
;
my
$mn
=
$d
% 60;
$d
= (
$d
-
$mn
) / 60;
my
$h
=
$d
% 24;
$d
= (
$d
-
$h
) / 24;
return
"${d}d ${h}h ${mn}mn"
;
}
sub
topByCat {
my
(
$cat
,
$max
) =
splice
@_
;
my
$i
= 0;
print
"<pre>\n"
;
foreach
(
sort
{
$status
->{uri}->{
$b
}->{
$cat
} <=>
$status
->{uri}->{
$a
}->{
$cat
} }
keys
%{
$status
->{uri} }
)
{
last
if
(
$i
==
$max
);
last
unless
(
$status
->{uri}->{
$_
}->{
$cat
} );
$i
++;
print
sprintf
(
"%-80s : %6d\n"
,
$_
,
$status
->{uri}->{
$_
}->{
$cat
} );
}
print
"</pre>\n"
;
}
sub
head {
print
<<"EOF";
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<head>
<title>$page_title</title>
<style type="text/css">
<!--
body{
background: #000;
color:#fff;
padding:10px 50px;
font-family:sans-serif;
}
h1 {
margin:5px 20px;
}
h2 {
margin:30px 0 0 0;
padding:0 10px;
border-left:20px solid orange;
line-height:20px;
}
hr {
height:1px;
background-color:orange;
margin:10px 0;
border:0;
}
a {
color:orange;
text-decoration:none;
font-weight:bold;
}
#footer {
text-align:center;
}
#footer a {
margin-left:10px;
padding:5px;
border-bottom:1px solid #fff;
}
#footer a:hover {
border-color:orange;
}
table.topByCat {
table-layout:fixed;
border-collapse:collapse;
border:1px solid #fff;
width:100%;
}
table.topByCat td, table.topByCat th {
padding:5px;
border:1px solid #fff;
}
table.topByCat th {
color:orange;
text-align:center;
}
-->
</style>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<table>
<tr>
<td style="width:30px;height:30px;background:orange;"> </td>
<td> </td>
<td rowspan=2><h1>$page_title</h1></td>
</tr>
</tr>
<td> </td>
<td style="width:30px;height:30px;background:orange;"> </td>
</tr>
</table>
EOF
}
sub
end {
print
<<"EOF";
<hr/>
<div id="footer">
<script type="text/javascript" language="Javascript">
//<!--
var a = document.location.href;
a=a.replace(/\\?.*\$/,'');
document.write('<a href="'+a+'">Standard view</a>');
document.write('<a href="'+a+'?top=10&categories=REJECT,PORTAL_FIRSTACCESS,LOGOUT,OK">Top 10</a>');
document.write('<a href="'+a+'?dump=1">Raw results</a>');
//-->
</script>
</div>
</body>
</html>
END
EOF
}
1;