[java-idp-log-analysis] 02/06: Initial comit of IdP audit log analysis tool - SC-30
Ian Young
ian at iay.org.uk
Mon Jan 23 11:33:02 EST 2017
This is an automated email from the git hooks/post-receive script.
iay pushed a commit to branch master
in repository java-idp-log-analysis.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-log-analysis.git;a=commit;h=12fba31a341629f8ed981f657fb554a2e6d74097
commit 12fba31a341629f8ed981f657fb554a2e6d74097
Author: Chad La Joie <clajoie at gmail.com>
AuthorDate: Tue Mar 16 06:29:06 2010 +0000
Initial comit of IdP audit log analysis tool - SC-30
---
.project | 11 ++++
README.txt | 29 +++++++++
loganalyais.py | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 225 insertions(+)
diff --git a/.project b/.project
new file mode 100644
index 0000000..c386349
--- /dev/null
+++ b/.project
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>java-idp-log-analysis</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ </buildSpec>
+ <natures>
+ </natures>
+</projectDescription>
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..a4f55b9
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,29 @@
+Shibboleth IdP 2 Audit Log Analysis Tool
+
+This analysis tool operates over one, or more, IdP audit log files and
+provides the follow statistics:
+ * Entity IDs of unique relying parties
+ * Number of unique relying parties
+ * Number of authentication events
+ * Number of unique authenticated principals
+ * Number of authentication events per relying party
+ * SAML profiles used per relying party
+
+ Requirements:
+ * Python
+ * Shibboleth 2 IdP Audit Log Files
+
+ Usage:
+ python loganalysis.py [options] <log_files>
+
+ Options:
+ -r, --relyingparties - list of unique relying parties, sorted by name
+ -c, --rpcount - number of unique relying parties
+ -u, --users - number of unique principals
+ -l, --logins - number of logins
+ -p, --rplogins - number of events per relying party, by name
+ -n, --rploginssort - number of events per relying party, sorted numerically
+ -m, --msgprofiles - usage of SAML message profiles per relying party
+ -q, --quiet - suppress all descriptive or decorative output
+
+ More than one option may be used at a time.
\ No newline at end of file
diff --git a/loganalyais.py b/loganalyais.py
new file mode 100644
index 0000000..d53e41f
--- /dev/null
+++ b/loganalyais.py
@@ -0,0 +1,185 @@
+#!/usr/bin/python
+"""Parse Shibboleth 2.1 Identity Provider audit logfile and generate simple stats.
+ Audit log file format: https://spaces.internet2.edu/display/SHIB2/IdPLogging"""
+
+import sys
+from optparse import OptionParser
+from operator import itemgetter
+
+def getLines(files):
+ """Return lines from file(s) or STDIN."""
+ lines = []
+ for file in files:
+ if file != "-":
+ try:
+ for line in open(file, "r"):
+ lines.append(line)
+ except IOError:
+ print "File '" + file + "' not found."
+ sys.exit(-1)
+ else:
+ for line in sys.stdin:
+ lines.append(line)
+ return lines
+
+def linesFromFiles(files):
+ """Return lists (events) of lists (data fields)."""
+ lines = getLines(files)
+ table = []
+ for line in lines:
+ table.append(line.rstrip().split("|"))
+ return table
+
+def parseFiles(files,options):
+ """Build datastructures from lines."""
+ lines = linesFromFiles(files)
+ db = {}
+ db['rp'], db['users'], db['msgprof'], db['logins'] = {},{},{},0
+
+ for event in lines:
+ datetime,reqBind,reqId,rp,msgProfile,idp,respBind,respId,user,authnMeth,relAttribs,nameId,assertIds,EOL = event
+ if msgProfile.lower().endswith(":sso"):
+ db['logins'] += 1
+
+ # we almost always need to cound rps:
+ if db['rp'].has_key(rp):
+ db['rp'][rp] += 1
+ else:
+ db['rp'][rp] = 1
+
+ # only count users if asked to
+ if options.uniqusers:
+ if db['users'].has_key(user):
+ db['users'][user] += 1
+ else:
+ db['users'][user] = 1
+
+ # only count message profiles and rps if asked to
+ if options.msgprofiles:
+ if db['msgprof'].has_key(msgProfile):
+ if db['msgprof'][msgProfile].has_key(rp):
+ db['msgprof'][msgProfile][rp] += 1
+ else:
+ db['msgprof'][msgProfile][rp] = 1
+ else:
+ db['msgprof'][msgProfile] = {}
+ db['msgprof'][msgProfile][rp] = 1
+ return db
+
+def uniqueRps(db):
+ """Output unique relying parties."""
+ for rp in sorted(db['rp'].keys()):
+ print rp
+
+def uniqueRpCount(db,options):
+ """Output number of unique relying parties."""
+ rps = len(db['rp'].keys())
+ if options.quiet:
+ print rps
+ else:
+ print "%d unique relying part%s" % (rps, ('y', 'ies')[rps!=1])
+
+def loginCount(db,options):
+ """Output total number of logins."""
+ logins = db['logins']
+ if not options.quiet:
+ print "%d login%s" % (logins, ('', 's')[logins!=1])
+ else:
+ print logins
+
+def uniqueUsers(db,options):
+ """Output number of unique userids."""
+ users = len(db['users'].keys())
+ if not options.quiet:
+ print "%d unique userid%s" % (users, ('', 's')[users!=1])
+ else:
+ print users
+
+def loginsPerRp(db,options):
+ """Output list of logins per relying party."""
+ for rp,i in db['rp'].items():
+ if options.quiet:
+ print "%d %s" % (i, rp)
+ else:
+ print "%d\t | %s" % (i, rp)
+
+def loginsPerRpSorted(db,options):
+ """Output sorted list of logins per relying party."""
+ for rp,i in sorted(db['rp'].iteritems(), key=itemgetter(1), reverse=True):
+ if options.quiet:
+ print "%d %s" % (i, rp)
+ else:
+ print "%d\t | %s" % (i, rp)
+
+def rpPerMessageProfile(db,options):
+ """Output usage of SAML message profiles per relying party."""
+ for mp,rps in db['msgprof'].items():
+ print mp
+ for rp,i in sorted(rps.iteritems(), key=itemgetter(1), reverse=True):
+ if options.quiet:
+ print "%d %s" % (i, rp)
+ else:
+ print "%d\t | %s" % (i, rp)
+ if not options.quiet:
+ print
+
+def main():
+ """Parse command line options and aguments and their contents."""
+ parser = OptionParser()
+ usage = "usage: %prog [options] [files ...]"
+ parser = OptionParser(usage)
+ parser.add_option("-r", "--relyingparties", help="list of unique relying parties, sorted by name",
+ action="store_true", dest="uniqrp")
+ parser.add_option("-c", "--rpcount", help="number of unique relying parties",
+ action="store_true")
+ parser.add_option("-u", "--users", help="number of unique userids",
+ action="store_true", dest="uniqusers")
+ parser.add_option("-l", "--logins", help="number of logins",
+ action="store_true")
+ parser.add_option("-p", "--rplogins", help="number of events per relying party, by name",
+ action="store_true")
+ parser.add_option("-n", "--rploginssort", help="number of events per relying party, sorted numerically",
+ action="store_true")
+ parser.add_option("-m", "--msgprofiles", help="usage of SAML message profiles per relying party ",
+ action="store_true")
+ parser.add_option("-q", "--quiet", help="suppress all descriptive or decorative output",
+ action="store_true" )
+
+ # Parse options and do basic sanity checking
+ (options, args) = parser.parse_args()
+ if len(args) == 0:
+ print "Missing filename(s). Specify '-' as filename to read from STDIN.\n"
+ parser.print_help()
+ sys.exit(-1)
+ if options.rplogins and options.rploginssort:
+ parser.error("Options -p and -n are mutually exclusive (just use one or the other).")
+
+ # Make sure that at least one option is set, otherwise don't bother parsing any logfiles
+ hasOpt = False
+ for value in options.__dict__.values():
+ if value:
+ hasOpt = True
+ break
+ if hasOpt:
+ db = parseFiles(args,options)
+ else:
+ print "Missing option: At least one option needs to be supplied.\n"
+ parser.print_help()
+ sys.exit(-1)
+
+ # map comman line options to procedures
+ if options.uniqrp: uniqueRps(db)
+ if options.rpcount: uniqueRpCount(db,options)
+ if options.uniqusers: uniqueUsers(db,options)
+ if options.logins: loginCount(db,options)
+ if options.rplogins or options.rploginssort:
+ if not options.quiet:
+ header = "logins\t | relyingPartyId"
+ print "\n" + header + "\n" + '-'*(len(header)+1)
+ if options.rplogins: loginsPerRp(db,options)
+ if options.rploginssort: loginsPerRpSorted(db,options)
+ if options.msgprofiles: rpPerMessageProfile(db,options)
+
+if __name__ == "__main__":
+ main()
+
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list