-
Notifications
You must be signed in to change notification settings - Fork 20
Improve ebauth log parsing, and parse stepup-authentication logs also #558
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
phavekes
wants to merge
11
commits into
main
Choose a base branch
from
feature/improve_ebauth_parse_script
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
4b4db87
rsyslog: Only opdate the lastseen tabel for newer dates
phavekes 0cff50e
rsyslog: Also rotate and parse stepup-logs
phavekes c255aa4
rsyslog: Add ansible tasks for stepup log parsing
phavekes ff6862d
Fix name for parse_stepupauth template
phavekes 4089da9
Fix template name
phavekes 5e0ec79
Disable check for authentication_result
phavekes 5a7b328
Get data from the context object
phavekes adf12d2
Get data from the context object
phavekes a7aa40d
Log if data checks failed
phavekes 6669321
more robust parsing of data
phavekes 0107394
Add python3-dateutil to rsyslog role
phavekes File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| {{ rsyslog_dir }}/log_logins/{{ item.name }}/stepup-authentication.log | ||
| { | ||
| missingok | ||
| daily | ||
| rotate 180 | ||
| sharedscripts | ||
| dateext | ||
| dateyesterday | ||
| compress | ||
| delaycompress | ||
| create 0640 root {{ rsyslog_read_group }} | ||
| postrotate | ||
| /usr/local/sbin/parse_stepupauth_to_mysql_{{ item.name }}.py > /dev/null | ||
| systemctl kill -s HUP rsyslog.service | ||
| endscript | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
152 changes: 152 additions & 0 deletions
152
roles/rsyslog/templates/parse_stepupauth_to_mysql.py.j2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,152 @@ | ||
| #!/usr/bin/python3 | ||
| # This script parses rotated stepup-authentication.log files produced by engineblock. | ||
| # It filters for successful logins (authentication_result:OK) and inserts the data | ||
| # into the log_logins and last_login MySQL tables. | ||
| # This script is intended to be run separately during logrotate. | ||
|
|
||
| import os | ||
| import sys | ||
| import json | ||
| import MySQLdb | ||
| from dateutil.parser import parse | ||
|
|
||
| # Configuration variables (to be injected by Ansible/Jinja2) | ||
| mysql_host="{{ item.db_loglogins_host }}" | ||
| mysql_user="{{ item.db_loglogins_user }}" | ||
| mysql_password="{{ item.db_loglogins_password }}" | ||
| mysql_db="{{ item.db_loglogins_name }}" | ||
| workdir="{{ rsyslog_dir }}/log_logins/{{ item.name}}/" | ||
|
|
||
| # Establish database connection | ||
| try: | ||
| db = MySQLdb.connect(mysql_host,mysql_user,mysql_password,mysql_db ) | ||
| cursor = db.cursor() | ||
| except Exception as e: | ||
| print(f"Error connecting to MySQL: {e}") | ||
| sys.exit(1) | ||
|
|
||
| # --- Database Functions --- | ||
|
|
||
| def update_lastseen(user_id, date): | ||
| """ | ||
| Updates the last_login table. | ||
| Uses GREATEST() to ensure only newer dates overwrite the existing 'lastseen' value. | ||
| """ | ||
| query = """ | ||
| INSERT INTO last_login (userid, lastseen) | ||
| VALUES (%s, %s) | ||
| ON DUPLICATE KEY UPDATE | ||
| lastseen = GREATEST(lastseen, VALUES(lastseen)) | ||
| """ | ||
| try: | ||
| cursor.execute(query, (user_id, date)) | ||
| db.commit() | ||
| except Exception as e: | ||
| db.rollback() | ||
| print(f"Error updating last_login for user {user_id}: {e}") | ||
|
|
||
| def load_stepup_in_mysql(idp, sp, loginstamp, userid, requestid): | ||
| """ | ||
| Inserts Step-up login data into the log_logins table. | ||
| Fills keyid, sessionid, and trustedproxyentityid with NULL. | ||
| """ | ||
| # Columns in log_logins: idpentityid, spentityid, loginstamp, userid, keyid, sessionid, requestid, trustedproxyentityid | ||
|
|
||
| keyid = None | ||
| sessionid = None | ||
| trustedproxyentityid = None | ||
|
|
||
| sql = """ | ||
| INSERT INTO log_logins(idpentityid, spentityid, loginstamp, userid, keyid, sessionid, requestid, trustedproxyentityid) | ||
| VALUES(%s, %s, %s, %s, %s, %s, %s, %s) | ||
| """ | ||
| try: | ||
| cursor.execute(sql, (idp, sp, loginstamp, userid, keyid, sessionid, requestid, trustedproxyentityid)) | ||
| db.commit() | ||
| except Exception as e: | ||
| db.rollback() | ||
| print(f"Error inserting stepup data: {e}") | ||
| # Print the data that failed insertion | ||
| print((idp, sp, loginstamp, userid, keyid, sessionid, requestid, trustedproxyentityid)) | ||
|
|
||
| # --- Parsing Function --- | ||
|
|
||
| def parse_stepup_lines(a): | ||
| """ | ||
| Opens the stepup log file, parses each line, filters for successful logins, | ||
| and loads the data into MySQL. | ||
| """ | ||
| input_file = open((a), 'r') | ||
| for line in input_file: | ||
| try: | ||
| # Assumes JSON data starts after the first ']:' | ||
| jsonline = line.split(']:',2)[1] | ||
| data = json.loads(jsonline) | ||
| except: | ||
| continue | ||
|
|
||
| # 1. Filtering condition: Only parse logs having authentication_result:OK | ||
| # Only successful authentications are logged, so this check is not | ||
| # necessary. There is currently a bug in the Stepup-Gateway where | ||
| # FAILED is logged, even though the result is OK, making this check | ||
| # do the wrong thing now. | ||
| # | ||
| #if data.get("context").("authentication_result") != "OK": | ||
| # continue | ||
|
|
||
| # 2. Extract required fields | ||
phavekes marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| context = data.get("context") | ||
|
|
||
| if not isinstance(context, dict): | ||
| print("Skipping line: context is missing or invalid") | ||
| continue | ||
|
|
||
| user_id = context.get("identity_id") | ||
| timestamp = context.get("datetime") | ||
| request_id = context.get("request_id") | ||
| sp_entity_id = context.get("requesting_sp") | ||
| idp_entity_id = context.get("authenticating_idp") | ||
|
|
||
| # Basic data validation | ||
| if not user_id or not timestamp: | ||
phavekes marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| print( | ||
| "Skipping line: validation failed " | ||
| f"(user_id={user_id!r}, timestamp={timestamp!r}, request_id={request_id!r})" | ||
| ) | ||
| continue | ||
|
|
||
| try: | ||
| # 3. Format date and time for MySQL | ||
| loginstamp = parse(timestamp).strftime("%Y-%m-%d %H:%M:%S") | ||
| last_login_date = parse(timestamp).strftime("%Y-%m-%d") | ||
| except: | ||
| print( | ||
| "Skipping line: timestamp parsing failed " | ||
| f"(timestamp={timestamp!r}, user_id={user_id!r}, error={e})" | ||
| ) | ||
| continue | ||
phavekes marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| # 4. Insert into MySQL | ||
| load_stepup_in_mysql(idp_entity_id, sp_entity_id, loginstamp, user_id, request_id) | ||
|
|
||
| # 5. Update last login date | ||
| update_lastseen(user_id, last_login_date) | ||
|
|
||
|
|
||
| # --- Main Execution --- | ||
|
|
||
| ## Loop over the files and parse them one by one | ||
| for filename in os.listdir(workdir): | ||
| filetoparse=(os.path.join(workdir, filename)) | ||
|
|
||
| # Check for Stepup files, ignore compressed files | ||
| if os.path.isfile(filetoparse) and filename.startswith("stepup-authentication.log-") and not filename.endswith(".gz"): | ||
| print(f"Parsing stepup log file: {filename}") | ||
| parse_stepup_lines(filetoparse) | ||
| else: | ||
| continue | ||
|
|
||
| # Close database connection | ||
| cursor.close() | ||
| db.close() | ||
| print("Stepup log parsing complete.") | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.