Skip to content

Fixes #39512 - Add audit logs for user login/logoff/failed attempts#11097

Open
sbernhard wants to merge 1 commit into
theforeman:developfrom
ATIX-AG:add_user_logging_info_for_audit
Open

Fixes #39512 - Add audit logs for user login/logoff/failed attempts#11097
sbernhard wants to merge 1 commit into
theforeman:developfrom
ATIX-AG:add_user_logging_info_for_audit

Conversation

@sbernhard

@sbernhard sbernhard commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Successful login:

2026-07-09T10:58:33 [I|app|ba31da65]   Parameters: {"login"=>{"login"=>"admin", "password"=>"[FILTERED]"}, "authenticity_token"=>"EkMyFekuoclH8TxT9dkqnqy3kNKAYuLFlknRwVjnvSRZQEJigWzJsOqn7f8zAu2yAUt7z2ZCY-76iF1G27UyOQ"}
2026-07-09T10:58:33 [I|app|ba31da65] User 'admin' logged in from '192.168.131.101'
2026-07-09T10:58:33 [I|aud|ba31da65] User (4) login event on authentication User 'admin' logged in

Logout:

2026-07-09T10:52:06 [I|app|7f288c89] Processing by UsersController#logout as HTML
2026-07-09T10:52:06 [I|app|7f288c89]   Parameters: {"authenticity_token"=>"0VKhYG4EQkGW2CXlqIg0nEzboJ4xgws2RuPTYCdFeHIJLiwkoeu2Vlp80n9nfGxngI1w--JfppBbdOWyxbkmZw"}
2026-07-09T10:52:06 [I|app|7f288c89] User 'admin' logged out
2026-07-09T10:52:06 [I|aud|7f288c89] User (4) logout event on authentication User 'admin' logged out

Failed login:

2026-07-09T10:57:44 [I|app|7c92de68]   Parameters: {"login"=>{"login"=>"asdfasdf", "password"=>"[FILTERED]"}, "authenticity_token"=>"U30R0dNgfIAc1IYKcdE-XdXHNfz6fvj_owN0-OgKDGCN_Ed4L2YvlMeZ6io4kGjJOGn65ixZN8SGb-x9_912Eg"}
2026-07-09T10:57:44 [I|app|7c92de68] invalid user
2026-07-09T10:57:44 [W|app|7c92de68] Failed login attempt from 192.168.131.101 with username 'asdfasdf'
2026-07-09T10:57:44 [I|aud|7c92de68] User (asdfasdf) failed_login event on authentication Failed login attempt for username 'asdfasdf'

In the UI, it looks like this:
image

@sbernhard
sbernhard force-pushed the add_user_logging_info_for_audit branch from 12c84aa to 720b56f Compare July 9, 2026 12:21
@sbernhard sbernhard changed the title Add audit logs for user login/logoff/failed logins Fixes #39512 - Add audit logs for user login/logoff/failed attempts Jul 9, 2026
Add manual audit events for user authentication activity, covering
successful login, logout, and failed login attempts.

Re-use the method to manually create a Audit event for the user
impersonate method which already created manually an Audit log.

Show failed login attempts for admins without limiting to location /
organization.

Co-authored-by: OpenAI Codex <codex@openai.com>
@sbernhard
sbernhard force-pushed the add_user_logging_info_for_audit branch from 720b56f to eec4b8e Compare July 9, 2026 13:50
@sbernhard
sbernhard marked this pull request as ready for review July 9, 2026 14:35
Comment on lines 148 to +149
log_bruteforce
log_authentication_event('failed_login', nil, "Blocked login attempt from #{request.remote_ip}")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to say that the ludit-Logging should be part of log_bruteforce(), assuming we want to audit any Brute-Force attempt. Downside: we cannot use log_authentication_event() in Foreman::Controller::BruteforceProtection.
Also it might not be tied to User's ID in other occurrences of log_bruteforce().

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

log_bruteforce is a method with a single line - which logs the login attempt. So, I dont see the requirement to move the log_authentication_event() to this method.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is to add the audit-log also into log_bruteforce(), so all invocations of that method also create an audit-log. For instance the log_bruteforce() method is also used here: https://github.com/ATIX-AG/foreman/blob/dc651706cd492de2ead0b1db57adf34f17419811/app/controllers/api/base_controller.rb#L203

@sbernhard sbernhard Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this would then log user access attempts to the API. actually, the current implementation of this PR is not about API.

Comment on lines +203 to +208
previous_user = User.current
User.current = nil
create!(audit_attributes)
ensure
User.current = previous_user
end

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got curious and now I know (finally) that this has no side-effects on other Threads, because User.current() is explicitly written to only modify Thread-variables 👍
https://github.com/ATIX-AG/foreman/blob/develop/app/models/concerns/foreman/thread_session.rb

@m-bucher m-bucher left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For what it's worth:

  • code looks good to me
  • tested on my forklift and works as expected

or(arel_table[:auditable_type].in(untaxable.map(&:to_s))).
or(arel_table.grouping(arel_taxed_only_by_organization)).
or(arel_table.grouping(arel_taxed_only_by_location))
statement = statement.or(arel_table.grouping(arel_global_failed_login)) if User.current.admin?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this is to deny a User that can read Audits but not the List of Users the ability to implicitly find out which User-Accounts exist/are disabled.
That is OK for me 😄

@sbernhard
sbernhard requested a review from stejskalleos July 27, 2026 18:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants