Bug #24547
openPuppet Configuration Error reports not delivered anymore when Role with hostgroup filtering exists
Description
I created a role with the following filter on the ressource "Host":
hostgroup_fullname = Linux/Desktop/Stationary/Ubuntu or hostgroup_fullname = Linux/Desktop/Mobile/Ubuntu
The role is assigned to a group, and the group owns all desktop machines.
After doing so, if an erroneous puppet report from a machine not in those hostgroups arrives (e.g. a "Server"), I see the following in production.log:
2018-08-06T18:02:41 cf3ff439 [app] [I] Started POST "/api/config_reports" for my_puppet_master_ip at 2018-08-06 18:02:41 +0200 2018-08-06T18:02:41 cf3ff439 [app] [I] Processing by Api::V2::ConfigReportsController#create as JSON 2018-08-06T18:02:41 cf3ff439 [app] [I] Parameters: {"config_report"=>"[FILTERED]", "apiv"=>"v2"} 2018-08-06T18:02:41 cf3ff439 [app] [I] Current user: foreman_api_admin (administrator) 2018-08-06T18:02:42 cf3ff439 [app] [I] Couldn't find Host::Managed with 'id'=176 [WHERE "hosts"."type" IN ('Host::Managed') AND ((("hostgroups"."title" = 'Linux/Desktop/Stationary/Ubuntu') OR ("hostgroups"."title" = 'Linux/Desktop/Mobile/Ubuntu')))] (ActiveRecord::RecordNotFound) 2018-08-06T18:02:42 cf3ff439 [app] [I] Rendering api/v2/errors/not_found.json.rabl within api/v2/layouts/error_layout 2018-08-06T18:02:42 cf3ff439 [app] [I] Rendered api/v2/errors/not_found.json.rabl within api/v2/layouts/error_layout (0.9ms) 2018-08-06T18:02:42 cf3ff439 [app] [I] Completed 404 Not Found in 266ms (Views: 2.1ms | ActiveRecord: 139.4ms)
No error report is sent.
Of course, the server with the erroneous report is owned by a different user group which does not have this role assigned.
Updated by Oliver Freyermuth over 5 years ago
Issue persists after upgrade to 1.18.0, with slightly changed log:
2018-08-06T20:59:41 [I|app|e37b8] Processing by Api::V2::ConfigReportsController#create as JSON 2018-08-06T20:59:41 [I|app|e37b8] Parameters: {"config_report"=>"[FILTERED]", "apiv"=>"v2"} 2018-08-06T20:59:41 [I|app|e37b8] Current user: foreman_api_admin (administrator) 2018-08-06T20:59:41 [I|app|e37b8] Scanning report with: Foreman::PuppetReportScanner 2018-08-06T20:59:42 [I|app|e37b8] Couldn't find Host::Managed with 'id'=177 [WHERE "hosts"."type" IN ('Host::Managed') AND ((("hostgroups"."title" = 'Linux/Desktop/Stationary/Ubuntu') OR ("hostgroups"."title" = 'Linux/Desktop/Mobile/Ubuntu')))] (ActiveRecord::RecordNotFound) 2018-08-06T20:59:42 [I|app|e37b8] Rendering api/v2/errors/not_found.json.rabl within api/v2/layouts/error_layout 2018-08-06T20:59:42 [I|app|e37b8] Rendered api/v2/errors/not_found.json.rabl within api/v2/layouts/error_layout (1.5ms) 2018-08-06T20:59:42 [I|app|e37b8] Completed 404 Not Found in 442ms (Views: 4.6ms | ActiveRecord: 234.7ms)
Updated by Oliver Freyermuth over 5 years ago
I've managed to pin it down using debug logs.
The following is needed for reproduction:
- A role with a filter on resource "Host", filtering by Hostgroup, e.g. `hostgroup_fullname = Linux/Desktop/Stationary/Ubuntu`.
In the following log snippet, that role has id 19.
- A usergroup with that role assigned, i.e. they can only "view_hosts" for that hostgroup.
- A user, let's call him/her "A", in that usergroup. In the following log snippet, that user has id "11".
- User "A" having set-up configuration error reports for "my hosts" or "all hosts".
- A second, completely different usergroup with user "B". That usergroup has id "3" in the following example log snippet, and contains users with ids 4 and 5.
- A host "C" owned by "B", and not in the hostgroup which is part of the filter above.
Then the following happens:
2018-08-06T21:35:41 [D|sql|7862b] Usergroup Load (0.8ms) SELECT "usergroups".* FROM "usergroups" WHERE "usergroups"."id" = $1 LIMIT $2 [["id", 3], ["LIMIT", 1]] 2018-08-06T21:35:41 [D|sql|7862b] Usergroup Load (0.8ms) SELECT "usergroups".* FROM "usergroups" INNER JOIN "usergroup_members" ON "usergroups"."id" = "usergroup_members"."member_id" WHERE "usergroup_members"."usergroup_id" = $1 AND "usergroup_members"."member_type" = $2 ORDER BY usergroups.name [["usergroup_id", 3], ["member_type", "Usergroup"]] 2018-08-06T21:35:41 [D|sql|7862b] User Load (0.9ms) SELECT "users".* FROM "users" INNER JOIN "usergroup_members" ON "users"."id" = "usergroup_members"."member_id" WHERE "usergroup_members"."usergroup_id" = $1 AND "usergroup_members"."member_type" = $2 ORDER BY firstname [["usergroup_id", 3], ["member_type", "User"]] 2018-08-06T21:35:41 [D|sql|7862b] MailNotification Load (0.9ms) SELECT "mail_notifications".* FROM "mail_notifications" WHERE "mail_notifications"."name" = $1 ORDER BY mail_notifications.name LIMIT $2 [["name", "config_error_state"], ["LIMIT", 1]] 2018-08-06T21:35:41 [D|sql|7862b] MailNotification Exists (1.2ms) SELECT 1 AS one FROM "mail_notifications" INNER JOIN "user_mail_notifications" ON "mail_notifications"."id" = "user_mail_notifications"."mail_notification_id" WHERE "user_mail_notifications"."user_id" = $1 AND "mail_notifications"."id" = $2 LIMIT $3 [["user_id", 5], ["id", 6], ["LIMIT", 1]] 2018-08-06T21:35:41 [D|sql|7862b] CACHE MailNotification Load (0.0ms) SELECT "mail_notifications".* FROM "mail_notifications" WHERE "mail_notifications"."name" = $1 ORDER BY mail_notifications.name LIMIT $2 [["name", "config_error_state"], ["LIMIT", 1]] 2018-08-06T21:35:41 [D|sql|7862b] MailNotification Exists (0.9ms) SELECT 1 AS one FROM "mail_notifications" INNER JOIN "user_mail_notifications" ON "mail_notifications"."id" = "user_mail_notifications"."mail_notification_id" WHERE "user_mail_notifications"."user_id" = $1 AND "mail_notifications"."id" = $2 LIMIT $3 [["user_id", 4], ["id", 6], ["LIMIT", 1]] 2018-08-06T21:35:41 [D|sql|7862b] SQL (1.0ms) SELECT "mail_notifications"."id" AS t0_r0, "mail_notifications"."name" AS t0_r1, "mail_notifications"."description" AS t0_r2, "mail_notifications"."mailer" AS t0_r3, "mail_notifications"."method" AS t0_r4, "mail_notifications"."subscriptable" AS t0_r5, "mail_notifications"."default_interval" AS t0_r6, "mail_notifications"."created_at" AS t0_r7, "mail_notifications"."updated_at" AS t0_r8, "mail_notifications"."subscription_type" AS t0_r9, "mail_notifications"."queryable" AS t0_r10, "mail_notifications"."type" AS t0_r11, "user_mail_notifications"."id" AS t1_r0, "user_mail_notifications"."user_id" AS t1_r1, "user_mail_notifications"."mail_notification_id" AS t1_r2, "user_mail_notifications"."last_sent" AS t1_r3, "user_mail_notifications"."interval" AS t1_r4, "user_mail_notifications"."created_at" AS t1_r5, "user_mail_notifications"."updated_at" AS t1_r6, "user_mail_notifications"."mail_query" AS t1_r7 FROM "mail_notifications" LEFT OUTER JOIN "user_mail_notifications" ON "user_mail_notifications"."mail_notification_id" = "mail_notifications"."id" WHERE "mail_notifications"."type" IN ('ConfigManagementError') AND "user_mail_notifications"."interval" = $1 ORDER BY mail_notifications.name [["interval", "Subscribe to all hosts"]] 2018-08-06T21:35:41 [D|sql|7862b] User Load (0.9ms) SELECT "users".* FROM "users" INNER JOIN "user_mail_notifications" ON "users"."id" = "user_mail_notifications"."user_id" WHERE "user_mail_notifications"."mail_notification_id" = $1 ORDER BY firstname [["mail_notification_id", 6]] 2018-08-06T21:35:41 [D|sql|7862b] Usergroup Load (1.1ms) SELECT "usergroups".* FROM "usergroups" INNER JOIN "cached_usergroup_members" ON "usergroups"."id" = "cached_usergroup_members"."usergroup_id" WHERE "cached_usergroup_members"."user_id" = $1 ORDER BY usergroups.name [["user_id", 11]] 2018-08-06T21:35:41 [D|per|7862b] checking permission view_hosts for class Host::Managed 2018-08-06T21:35:41 [D|sql|7862b] Filter Load (3.0ms) SELECT "filters".* FROM "filters" INNER JOIN "filterings" ON "filterings"."filter_id" = "filters"."id" INNER JOIN "permissions" ON "permissions"."id" = "filterings"."permission_id" INNER JOIN "roles" ON "filters"."role_id" = "roles"."id" INNER JOIN "cached_user_roles" ON "roles"."id" = "cached_user_roles"."role_id" WHERE "cached_user_roles"."user_id" = $1 AND (permissions.resource_type = 'Host') AND (permissions.name = 'view_hosts') [["user_id", 11]] 2018-08-06T21:35:41 [D|per|7862b] filter with role_id: 19 limited: true search: hostgroup_fullname = Linux/Desktop/Stationary/Ubuntu or hostgroup_fullname = Linux/Desktop/Mobile/Ubuntu taxonomy_search: 2018-08-06T21:35:41 [D|sql|7862b] SQL (2.4ms) SELECT "hosts"."id" AS t0_r0, "hosts"."name" AS t0_r1, "hosts"."last_compile" AS t0_r2, "hosts"."last_report" AS t0_r3, "hosts"."updated_at" AS t0_r4, "hosts"."created_at" AS t0_r5, "hosts"."root_pass" AS t0_r6, "hosts"."architecture_id" AS t0_r7, "hosts"."operatingsystem_id" AS t0_r8, "hosts"."environment_id" AS t0_r9, "hosts"."ptable_id" AS t0_r10, "hosts"."medium_id" AS t0_r11, "hosts"."build" AS t0_r12, "hosts"."comment" AS t0_r13, "hosts"."disk" AS t0_r14, "hosts"."installed_at" AS t0_r15, "hosts"."model_id" AS t0_r16, "hosts"."hostgroup_id" AS t0_r17, "hosts"."owner_id" AS t0_r18, "hosts"."owner_type" AS t0_r19, "hosts"."enabled" AS t0_r20, "hosts"."puppet_ca_proxy_id" AS t0_r21, "hosts"."managed" AS t0_r22, "hosts"."use_image" AS t0_r23, "hosts"."image_file" AS t0_r24, "hosts"."uuid" AS t0_r25, "hosts"."compute_resource_id" AS t0_r26, "hosts"."puppet_proxy_id" AS t0_r27, "hosts"."certname" AS t0_r28, "hosts"."image_id" AS t0_r29, "hosts"."organization_id" AS t0_r30, "hosts"."location_id" AS t0_r31, "hosts"."type" AS t0_r32, "hosts"."otp" AS t0_r33, "hosts"."realm_id" AS t0_r34, "hosts"."compute_profile_id" AS t0_r35, "hosts"."provision_method" AS t0_r36, "hosts"."grub_pass" AS t0_r37, "hosts"."global_status" AS t0_r38, "hosts"."lookup_value_matcher" AS t0_r39, "hosts"."pxe_loader" AS t0_r40, "hosts"."discovery_rule_id" AS t0_r41, "hostgroups"."id" AS t1_r0, "hostgroups"."name" AS t1_r1, "hostgroups"."created_at" AS t1_r2, "hostgroups"."updated_at" AS t1_r3, "hostgroups"."environment_id" AS t1_r4, "hostgroups"."operatingsystem_id" AS t1_r5, "hostgroups"."architecture_id" AS t1_r6, "hostgroups"."medium_id" AS t1_r7, "hostgroups"."ptable_id" AS t1_r8, "hostgroups"."root_pass" AS t1_r9, "hostgroups"."puppet_ca_proxy_id" AS t1_r10, "hostgroups"."use_image" AS t1_r11, "hostgroups"."image_file" AS t1_r12, "hostgroups"."ancestry" AS t1_r13, "hostgroups"."vm_defaults" AS t1_r14, "hostgroups"."subnet_id" AS t1_r15, "hostgroups"."domain_id" AS t1_r16, "hostgroups"."puppet_proxy_id" AS t1_r17, "hostgroups"."title" AS t1_r18, "hostgroups"."realm_id" AS t1_r19, "hostgroups"."compute_profile_id" AS t1_r20, "hostgroups"."grub_pass" AS t1_r21, "hostgroups"."lookup_value_matcher" AS t1_r22, "hostgroups"."subnet6_id" AS t1_r23, "hostgroups"."pxe_loader" AS t1_r24, "hostgroups"."description" AS t1_r25, "hostgroups"."compute_resource_id" AS t1_r26 FROM "hosts" LEFT OUTER JOIN "hostgroups" ON "hostgroups"."id" = "hosts"."hostgroup_id" WHERE "hosts"."type" IN ('Host::Managed') AND ((("hostgroups"."title" = 'Linux/Desktop/Stationary/Ubuntu') OR ("hostgroups"."title" = 'Linux/Desktop/Mobile/Ubuntu'))) AND "hosts"."id" = $1 LIMIT $2 [["id", 177], ["LIMIT", 1]] 2018-08-06T21:35:41 [I|app|7862b] Couldn't find Host::Managed with 'id'=177 [WHERE "hosts"."type" IN ('Host::Managed') AND ((("hostgroups"."title" = 'Linux/Desktop/Stationary/Ubuntu') OR ("hostgroups"."title" = 'Linux/Desktop/Mobile/Ubuntu')))] (ActiveRecord::RecordNotFound) 2018-08-06T21:35:41 [I|app|7862b] Rendering api/v2/errors/not_found.json.rabl within api/v2/layouts/error_layout 2018-08-06T21:35:41 [I|app|7862b] Rendered api/v2/errors/not_found.json.rabl within api/v2/layouts/error_layout (1.6ms)
I.e.: Some users not amongst the host owners are thrown into the "to be notified" list, and then the filtering rules for those users are applied, and we get "RecordNotFound".
Updated by Oliver Freyermuth over 5 years ago
I wondered why it fails both if the user "A" has set-up configuration error reports for "my hosts" or "all hosts".
Checking app/services/report_importer.rb and modifying "notify_on_report_error" to contain:
owners = host.owner.present? ? host.owner.recipients_for(:config_error_state) : [] users = ConfigManagementError.all_hosts.flat_map(&:users) logger.info "considering subscribers to be #{users.map(&:login).join(',')}"
The logger-info message outputs all users which either have subscribed to "all hosts", or subscribed to "my hosts".
Seems like there's a bug hidden somewhere, maybe it can be understood from the debug logs in the previous comment with more ruby knowledge.
Updated by Oliver Freyermuth over 5 years ago
So in total, I think there are at least two bugs in app/services/report_importer => notify_on_report_error.
1) The following code somehow collects both ALL users subscribed to "all hosts" and to "my hosts".
Since that is done independent of the host, that's wrong.
users = ConfigManagementError.all_hosts.flat_map(&:users)
2) The following code appears to fail if any of the users is not authorized (view_hosts), so finally, no user is notified.
users.select { |user| Host.authorized_as(user, :view_hosts).find(host.id).present? }
Updated by Oliver Freyermuth over 5 years ago
- Category set to Notifications
- Found in Releases 1.18.0 added
Updated by Tomer Brisker over 5 years ago
- Category changed from Notifications to Users, Roles and Permissions
- Target version set to 1.18.2
- Triaged changed from No to Yes
Updated by Tomer Brisker over 5 years ago
- Category changed from Users, Roles and Permissions to Notifications
Updated by Tomer Brisker over 5 years ago
- Category changed from Notifications to E-Mail
- Target version deleted (
1.18.2)
Updated by Oliver Freyermuth over 5 years ago
I see that the "targeted" version has been removed - and recently, 1.20 was released.
Is this bug still on somebody's radar?
Updated by Oliver Freyermuth over 5 years ago
- Found in Releases 1.18.1, 1.18.2, 1.18.3 added
Added additional, tested releases.
Seem all still broken :-(.
Updated by Marek Hulán over 5 years ago
I'm trying to think of why
users.select { |user| Host.authorized_as(user, :view_hosts).find(host.id).present? }
would fail if at least one user is not authorized. This should collect those users who are authrorized to view the given host. Could you try replacing with
users.select { |user| user.can?(:view_hosts, host) }
Another idea is, trying
users.select { |user| Host.authorized_as(user, :view_hosts, Host).find(host.id).present? }
since this resource uses STI.
Updated by Oliver Freyermuth over 5 years ago
I'm not the Ruby expert, but here's what I get.
I've modified the code as follows:
owners = host.owner.present? ? host.owner.recipients_for(:config_error_state) : [] logger.debug "found owners #{owners.map(&:login).join(',')}" users = ConfigManagementError.all_hosts.flat_map(&:users) logger.debug "found users_all #{users.map(&:login).join(',')}" #users.select { |user| Host.authorized_as(user, :view_hosts).find(host.id).present? } users.select { |user| user.can?(:view_hosts, host) } #users.select { |user| Host.authorized_as(user, :view_hosts, Host).find(host.id).present? } logger.debug "found users #{users.map(&:login).join(',')}"
i.e. we will always get extra debug output for "owners", "users_all" and the filtered users "found users").
For vanilla:
users.select { |user| Host.authorized_as(user, :view_hosts).find(host.id).present? }
I get:
2018-12-22T17:56:42 [D|app|42e64] found owners 2018-12-22T17:56:42 [D|sql|42e64] SQL (5.1ms) SELECT "mail_notifications"."id" AS t0_r0, "mail_notifications"."name" AS t0_r1, "mail_notifications"."description" AS t0_r2, "mail_notifications"."mailer" AS t0_r3, "mail_notifications"."method" AS t0_r4, "mail_notifications"."subscriptable" AS t0_r5, "mail_notifications"."default_interval" AS t0_r6, "mail_notifications"."created_at" AS t0_r7, "mail_notifications"."updated_at" AS t0_r8, "mail_notifications"."subscription_type" AS t0_r9, "mail_notifications"."queryable" AS t0_r10, "mail_notifications"."type" AS t0_r11, "user_mail_notifications"."id" AS t1_r0, "user_mail_notifications"."user_id" AS t1_r1, "user_mail_notifications"."mail_notification_id" AS t1_r2, "user_mail_notifications"."last_sent" AS t1_r3, "user_mail_notifications"."interval" AS t1_r4, "user_mail_notifications"."created_at" AS t1_r5, "user_mail_notifications"."updated_at" AS t1_r6, "user_mail_notifications"."mail_query" AS t1_r7 FROM "mail_notifications" LEFT OUTER JOIN "user_mail_notifications" ON "user_mail_notifications"."mail_notification_id" = "mail_notifications"."id" WHERE "mail_notifications"."type" IN ('ConfigManagementError') AND "user_mail_notifications"."interval" = $1 ORDER BY mail_notifications.name [["interval", "Subscribe to all hosts"]] 2018-12-22T17:56:42 [D|sql|42e64] User Load (1.1ms) SELECT "users".* FROM "users" INNER JOIN "user_mail_notifications" ON "users"."id" = "user_mail_notifications"."user_id" WHERE "user_mail_notifications"."mail_notification_id" = $1 ORDER BY firstname [["mail_notification_id", 6]] 2018-12-22T17:56:42 [D|app|42e64] found users_all admin1,admin2,testuser2 2018-12-22T17:56:42 [D|sql|42e64] Host::Managed Load (4.7ms) SELECT "hosts".* FROM "hosts" WHERE "hosts"."type" IN ('Host::Managed') AND "hosts"."id" = $1 LIMIT $2 [["id", 94], ["LIMIT", 1]] 2018-12-22T17:56:42 [D|sql|42e64] CACHE Host::Managed Load (0.1ms) SELECT "hosts".* FROM "hosts" WHERE "hosts"."type" IN ('Host::Managed') AND "hosts"."id" = $1 LIMIT $2 [["id", 94], ["LIMIT", 1]] 2018-12-22T17:56:42 [D|sql|42e64] CACHE Host::Managed Load (0.0ms) SELECT "hosts".* FROM "hosts" WHERE "hosts"."type" IN ('Host::Managed') AND "hosts"."id" = $1 LIMIT $2 [["id", 94], ["LIMIT", 1]] 2018-12-22T17:56:42 [D|sql|42e64] Usergroup Load (1.0ms) SELECT "usergroups".* FROM "usergroups" INNER JOIN "cached_usergroup_members" ON "usergroups"."id" = "cached_usergroup_members"."usergroup_id" WHERE "cached_usergroup_members"."user_id" = $1 ORDER BY usergroups.name [["user_id", 12]] 2018-12-22T17:56:42 [D|per|42e64] checking permission view_hosts for class Host::Managed 2018-12-22T17:56:42 [D|sql|42e64] Filter Load (8.2ms) SELECT "filters".* FROM "filters" INNER JOIN "filterings" ON "filterings"."filter_id" = "filters"."id" INNER JOIN "permissions" ON "permissions"."id" = "filterings"."permission_id" INNER JOIN "roles" ON "filters"."role_id" = "roles"."id" INNER JOIN "cached_user_roles" ON "roles"."id" = "cached_user_roles"."role_id" WHERE "cached_user_roles"."user_id" = $1 AND (permissions.resource_type = 'Host') AND (permissions.name = 'view_hosts') [["user_id", 12]] 2018-12-22T17:56:42 [D|per|42e64] filter with role_id: 19 limited: true search: hostgroup_fullname = Linux/Desktop/Stationary/Ubuntu or hostgroup_fullname = Linux/Desktop/Mobile/Ubuntu taxonomy_search: 2018-12-22T17:56:42 [D|sql|42e64] SQL (2.5ms) SELECT "hosts"."id" AS t0_r0, "hosts"."name" AS t0_r1, "hosts"."last_compile" AS t0_r2, "hosts"."last_report" AS t0_r3, "hosts"."updated_at" AS t0_r4, "hosts"."created_at" AS t0_r5, "hosts"."root_pass" AS t0_r6, "hosts"."architecture_id" AS t0_r7, "hosts"."operatingsystem_id" AS t0_r8, "hosts"."environment_id" AS t0_r9, "hosts"."ptable_id" AS t0_r10, "hosts"."medium_id" AS t0_r11, "hosts"."build" AS t0_r12, "hosts"."comment" AS t0_r13, "hosts"."disk" AS t0_r14, "hosts"."installed_at" AS t0_r15, "hosts"."model_id" AS t0_r16, "hosts"."hostgroup_id" AS t0_r17, "hosts"."owner_id" AS t0_r18, "hosts"."owner_type" AS t0_r19, "hosts"."enabled" AS t0_r20, "hosts"."puppet_ca_proxy_id" AS t0_r21, "hosts"."managed" AS t0_r22, "hosts"."use_image" AS t0_r23, "hosts"."image_file" AS t0_r24, "hosts"."uuid" AS t0_r25, "hosts"."compute_resource_id" AS t0_r26, "hosts"."puppet_proxy_id" AS t0_r27, "hosts"."certname" AS t0_r28, "hosts"."image_id" AS t0_r29, "hosts"."organization_id" AS t0_r30, "hosts"."location_id" AS t0_r31, "hosts"."type" AS t0_r32, "hosts"."otp" AS t0_r33, "hosts"."realm_id" AS t0_r34, "hosts"."compute_profile_id" AS t0_r35, "hosts"."provision_method" AS t0_r36, "hosts"."grub_pass" AS t0_r37, "hosts"."global_status" AS t0_r38, "hosts"."lookup_value_matcher" AS t0_r39, "hosts"."pxe_loader" AS t0_r40, "hosts"."discovery_rule_id" AS t0_r41, "hostgroups"."id" AS t1_r0, "hostgroups"."name" AS t1_r1, "hostgroups"."created_at" AS t1_r2, "hostgroups"."updated_at" AS t1_r3, "hostgroups"."environment_id" AS t1_r4, "hostgroups"."operatingsystem_id" AS t1_r5, "hostgroups"."architecture_id" AS t1_r6, "hostgroups"."medium_id" AS t1_r7, "hostgroups"."ptable_id" AS t1_r8, "hostgroups"."root_pass" AS t1_r9, "hostgroups"."puppet_ca_proxy_id" AS t1_r10, "hostgroups"."use_image" AS t1_r11, "hostgroups"."image_file" AS t1_r12, "hostgroups"."ancestry" AS t1_r13, "hostgroups"."vm_defaults" AS t1_r14, "hostgroups"."subnet_id" AS t1_r15, "hostgroups"."domain_id" AS t1_r16, "hostgroups"."puppet_proxy_id" AS t1_r17, "hostgroups"."title" AS t1_r18, "hostgroups"."realm_id" AS t1_r19, "hostgroups"."compute_profile_id" AS t1_r20, "hostgroups"."grub_pass" AS t1_r21, "hostgroups"."lookup_value_matcher" AS t1_r22, "hostgroups"."subnet6_id" AS t1_r23, "hostgroups"."pxe_loader" AS t1_r24, "hostgroups"."description" AS t1_r25, "hostgroups"."compute_resource_id" AS t1_r26 FROM "hosts" LEFT OUTER JOIN "hostgroups" ON "hostgroups"."id" = "hosts"."hostgroup_id" WHERE "hosts"."type" IN ('Host::Managed') AND ((("hostgroups"."title" = 'Linux/Desktop/Stationary/Ubuntu') OR ("hostgroups"."title" = 'Linux/Desktop/Mobile/Ubuntu'))) AND "hosts"."id" = $1 LIMIT $2 [["id", 94], ["LIMIT", 1]] 2018-12-22T17:56:42 [I|app|42e64] Couldn't find Host::Managed with 'id'=94 [WHERE "hosts"."type" IN ('Host::Managed') AND ((("hostgroups"."title" = 'Linux/Desktop/Stationary/Ubuntu') OR ("hostgroups"."title" = 'Linux/Desktop/Mobile/Ubuntu')))] (ActiveRecord::RecordNotFound) 2018-12-22T17:56:42 [I|app|42e64] Rendering api/v2/errors/not_found.json.rabl within api/v2/layouts/error_layout 2018-12-22T17:56:42 [I|app|42e64] Rendered api/v2/errors/not_found.json.rabl within api/v2/layouts/error_layout (1.2ms) 2018-12-22T17:56:42 [I|app|42e64] Completed 404 Not Found in 940ms (Views: 4.3ms | ActiveRecord: 484.2ms)
Note that testuser2 has no permission to view_hosts for the host. So he is found with the first query (since that person has subscribed to notifications for all hosts).
My understanding why:
users.select { |user| Host.authorized_as(user, :view_hosts).find(host.id).present? }
fails is that:
Host.authorized_as(user, :view_hosts)
yields no result when stumbling across the unauthorized user and subsequently "find(host.id)" fails since it is called upon an empty recordset, then the whole thing blows up and a 404 is shown. That appears to be what the debug information above suggests, and matches observation.
Trying out:
users.select { |user| user.can?(:view_hosts, host) }
yields the following:
2018-12-22T17:59:23 [D|app|67c6e] found owners 2018-12-22T17:59:23 [D|sql|67c6e] SQL (1.4ms) SELECT "mail_notifications"."id" AS t0_r0, "mail_notifications"."name" AS t0_r1, "mail_notifications"."description" AS t0_r2, "mail_notifications"."mailer" AS t0_r3, "mail_notifications"."method" AS t0_r4, "mail_notifications"."subscriptable" AS t0_r5, "mail_notifications"."default_interval" AS t0_r6, "mail_notifications"."created_at" AS t0_r7, "mail_notifications"."updated_at" AS t0_r8, "mail_notifications"."subscription_type" AS t0_r9, "mail_notifications"."queryable" AS t0_r10, "mail_notifications"."type" AS t0_r11, "user_mail_notifications"."id" AS t1_r0, "user_mail_notifications"."user_id" AS t1_r1, "user_mail_notifications"."mail_notification_id" AS t1_r2, "user_mail_notifications"."last_sent" AS t1_r3, "user_mail_notifications"."interval" AS t1_r4, "user_mail_notifications"."created_at" AS t1_r5, "user_mail_notifications"."updated_at" AS t1_r6, "user_mail_notifications"."mail_query" AS t1_r7 FROM "mail_notifications" LEFT OUTER JOIN "user_mail_notifications" ON "user_mail_notifications"."mail_notification_id" = "mail_notifications"."id" WHERE "mail_notifications"."type" IN ('ConfigManagementError') AND "user_mail_notifications"."interval" = $1 ORDER BY mail_notifications.name [["interval", "Subscribe to all hosts"]] 2018-12-22T17:59:23 [D|sql|67c6e] User Load (1.1ms) SELECT "users".* FROM "users" INNER JOIN "user_mail_notifications" ON "users"."id" = "user_mail_notifications"."user_id" WHERE "user_mail_notifications"."mail_notification_id" = $1 ORDER BY firstname [["mail_notification_id", 6]] 2018-12-22T17:59:23 [D|app|67c6e] found users_all admin1,admin2,testuser2 2018-12-22T17:59:23 [D|sql|67c6e] Usergroup Load (1.5ms) SELECT "usergroups".* FROM "usergroups" INNER JOIN "cached_usergroup_members" ON "usergroups"."id" = "cached_usergroup_members"."usergroup_id" WHERE "cached_usergroup_members"."user_id" = $1 ORDER BY usergroups.name [["user_id", 12]] 2018-12-22T17:59:23 [D|per|67c6e] checking permission view_hosts for class Host::Managed 2018-12-22T17:59:23 [D|sql|67c6e] Filter Load (3.4ms) SELECT "filters".* FROM "filters" INNER JOIN "filterings" ON "filterings"."filter_id" = "filters"."id" INNER JOIN "permissions" ON "permissions"."id" = "filterings"."permission_id" INNER JOIN "roles" ON "filters"."role_id" = "roles"."id" INNER JOIN "cached_user_roles" ON "roles"."id" = "cached_user_roles"."role_id" WHERE "cached_user_roles"."user_id" = $1 AND (permissions.resource_type = 'Host') AND (permissions.name = 'view_hosts') [["user_id", 12]] 2018-12-22T17:59:23 [D|per|67c6e] filter with role_id: 19 limited: true search: hostgroup_fullname = Linux/Desktop/Stationary/Ubuntu or hostgroup_fullname = Linux/Desktop/Mobile/Ubuntu taxonomy_search: 2018-12-22T17:59:23 [D|sql|67c6e] SQL (6.4ms) SELECT "hosts"."id" AS t0_r0, "hosts"."name" AS t0_r1, "hosts"."last_compile" AS t0_r2, "hosts"."last_report" AS t0_r3, "hosts"."updated_at" AS t0_r4, "hosts"."created_at" AS t0_r5, "hosts"."root_pass" AS t0_r6, "hosts"."architecture_id" AS t0_r7, "hosts"."operatingsystem_id" AS t0_r8, "hosts"."environment_id" AS t0_r9, "hosts"."ptable_id" AS t0_r10, "hosts"."medium_id" AS t0_r11, "hosts"."build" AS t0_r12, "hosts"."comment" AS t0_r13, "hosts"."disk" AS t0_r14, "hosts"."installed_at" AS t0_r15, "hosts"."model_id" AS t0_r16, "hosts"."hostgroup_id" AS t0_r17, "hosts"."owner_id" AS t0_r18, "hosts"."owner_type" AS t0_r19, "hosts"."enabled" AS t0_r20, "hosts"."puppet_ca_proxy_id" AS t0_r21, "hosts"."managed" AS t0_r22, "hosts"."use_image" AS t0_r23, "hosts"."image_file" AS t0_r24, "hosts"."uuid" AS t0_r25, "hosts"."compute_resource_id" AS t0_r26, "hosts"."puppet_proxy_id" AS t0_r27, "hosts"."certname" AS t0_r28, "hosts"."image_id" AS t0_r29, "hosts"."organization_id" AS t0_r30, "hosts"."location_id" AS t0_r31, "hosts"."type" AS t0_r32, "hosts"."otp" AS t0_r33, "hosts"."realm_id" AS t0_r34, "hosts"."compute_profile_id" AS t0_r35, "hosts"."provision_method" AS t0_r36, "hosts"."grub_pass" AS t0_r37, "hosts"."global_status" AS t0_r38, "hosts"."lookup_value_matcher" AS t0_r39, "hosts"."pxe_loader" AS t0_r40, "hosts"."discovery_rule_id" AS t0_r41, "hostgroups"."id" AS t1_r0, "hostgroups"."name" AS t1_r1, "hostgroups"."created_at" AS t1_r2, "hostgroups"."updated_at" AS t1_r3, "hostgroups"."environment_id" AS t1_r4, "hostgroups"."operatingsystem_id" AS t1_r5, "hostgroups"."architecture_id" AS t1_r6, "hostgroups"."medium_id" AS t1_r7, "hostgroups"."ptable_id" AS t1_r8, "hostgroups"."root_pass" AS t1_r9, "hostgroups"."puppet_ca_proxy_id" AS t1_r10, "hostgroups"."use_image" AS t1_r11, "hostgroups"."image_file" AS t1_r12, "hostgroups"."ancestry" AS t1_r13, "hostgroups"."vm_defaults" AS t1_r14, "hostgroups"."subnet_id" AS t1_r15, "hostgroups"."domain_id" AS t1_r16, "hostgroups"."puppet_proxy_id" AS t1_r17, "hostgroups"."title" AS t1_r18, "hostgroups"."realm_id" AS t1_r19, "hostgroups"."compute_profile_id" AS t1_r20, "hostgroups"."grub_pass" AS t1_r21, "hostgroups"."lookup_value_matcher" AS t1_r22, "hostgroups"."subnet6_id" AS t1_r23, "hostgroups"."pxe_loader" AS t1_r24, "hostgroups"."description" AS t1_r25, "hostgroups"."compute_resource_id" AS t1_r26 FROM "hosts" LEFT OUTER JOIN "hostgroups" ON "hostgroups"."id" = "hosts"."hostgroup_id" WHERE "hosts"."type" IN ('Host::Managed') AND ((("hostgroups"."title" = 'Linux/Desktop/Stationary/Ubuntu') OR ("hostgroups"."title" = 'Linux/Desktop/Mobile/Ubuntu'))) 2018-12-22T17:59:23 [D|app|67c6e] found users admin1,admin2,testuser2 2018-12-22T17:59:23 [D|app|67c6e] sending alert to admin1,admin2,testuser2
I don't understand why exactly, but now all users are getting the notification, also testuser2 who does not have view_hosts privilege for the host in question!
The host in question is not in the listed hostgroups.
Now finally, the third version:
users.select { |user| Host.authorized_as(user, :view_hosts, Host).find(host.id).present? }
yields:
2018-12-22T17:53:01 [D|app|b41f8] found owners 2018-12-22T17:53:01 [D|sql|b41f8] SQL (1.1ms) SELECT "mail_notifications"."id" AS t0_r0, "mail_notifications"."name" AS t0_r1, "mail_notifications"."description" AS t0_r2, "mail_notifications"."mailer" AS t0_r3, "mail_notifications"."method" AS t0_r4, "mail_notifications"."subscriptable" AS t0_r5, "mail_notifications"."default_interval" AS t0_r6, "mail_notifications"."created_at" AS t0_r7, "mail_notifications"."updated_at" AS t0_r8, "mail_notifications"."subscription_type" AS t0_r9, "mail_notifications"."queryable" AS t0_r10, "mail_notifications"."type" AS t0_r11, "user_mail_notifications"."id" AS t1_r0, "user_mail_notifications"."user_id" AS t1_r1, "user_mail_notifications"."mail_notification_id" AS t1_r2, "user_mail_notifications"."last_sent" AS t1_r3, "user_mail_notifications"."interval" AS t1_r4, "user_mail_notifications"."created_at" AS t1_r5, "user_mail_notifications"."updated_at" AS t1_r6, "user_mail_notifications"."mail_query" AS t1_r7 FROM "mail_notifications" LEFT OUTER JOIN "user_mail_notifications" ON "user_mail_notifications"."mail_notification_id" = "mail_notifications"."id" WHERE "mail_notifications"."type" IN ('ConfigManagementError') AND "user_mail_notifications"."interval" = $1 ORDER BY mail_notifications.name [["interval", "Subscribe to all hosts"]] 2018-12-22T17:53:01 [D|sql|b41f8] User Load (1.1ms) SELECT "users".* FROM "users" INNER JOIN "user_mail_notifications" ON "users"."id" = "user_mail_notifications"."user_id" WHERE "user_mail_notifications"."mail_notification_id" = $1 ORDER BY firstname [["mail_notification_id", 6]] 2018-12-22T17:53:01 [D|app|b41f8] found users_all admin1,admin2,testuser2 2018-12-22T17:53:01 [D|sql|b41f8] Host::Managed Load (0.9ms) SELECT "hosts".* FROM "hosts" WHERE "hosts"."type" IN ('Host::Managed') AND "hosts"."id" = $1 LIMIT $2 [["id", 94], ["LIMIT", 1]] 2018-12-22T17:53:01 [D|sql|b41f8] CACHE Host::Managed Load (0.1ms) SELECT "hosts".* FROM "hosts" WHERE "hosts"."type" IN ('Host::Managed') AND "hosts"."id" = $1 LIMIT $2 [["id", 94], ["LIMIT", 1]] 2018-12-22T17:53:01 [D|sql|b41f8] CACHE Host::Managed Load (0.0ms) SELECT "hosts".* FROM "hosts" WHERE "hosts"."type" IN ('Host::Managed') AND "hosts"."id" = $1 LIMIT $2 [["id", 94], ["LIMIT", 1]] 2018-12-22T17:53:01 [D|sql|b41f8] Usergroup Load (0.9ms) SELECT "usergroups".* FROM "usergroups" INNER JOIN "cached_usergroup_members" ON "usergroups"."id" = "cached_usergroup_members"."usergroup_id" WHERE "cached_usergroup_members"."user_id" = $1 ORDER BY usergroups.name [["user_id", 12]] 2018-12-22T17:53:01 [D|per|b41f8] checking permission view_hosts for class Host 2018-12-22T17:53:01 [D|sql|b41f8] Filter Load (3.6ms) SELECT "filters".* FROM "filters" INNER JOIN "filterings" ON "filterings"."filter_id" = "filters"."id" INNER JOIN "permissions" ON "permissions"."id" = "filterings"."permission_id" INNER JOIN "roles" ON "filters"."role_id" = "roles"."id" INNER JOIN "cached_user_roles" ON "roles"."id" = "cached_user_roles"."role_id" WHERE "cached_user_roles"."user_id" = $1 AND (permissions.resource_type = 'Host') AND (permissions.name = 'view_hosts') [["user_id", 12]] 2018-12-22T17:53:01 [D|per|b41f8] filter with role_id: 19 limited: true search: hostgroup_fullname = Linux/Desktop/Stationary/Ubuntu or hostgroup_fullname = Linux/Desktop/Mobile/Ubuntu taxonomy_search: 2018-12-22T17:53:01 [D|sql|b41f8] SQL (2.5ms) SELECT "hosts"."id" AS t0_r0, "hosts"."name" AS t0_r1, "hosts"."last_compile" AS t0_r2, "hosts"."last_report" AS t0_r3, "hosts"."updated_at" AS t0_r4, "hosts"."created_at" AS t0_r5, "hosts"."root_pass" AS t0_r6, "hosts"."architecture_id" AS t0_r7, "hosts"."operatingsystem_id" AS t0_r8, "hosts"."environment_id" AS t0_r9, "hosts"."ptable_id" AS t0_r10, "hosts"."medium_id" AS t0_r11, "hosts"."build" AS t0_r12, "hosts"."comment" AS t0_r13, "hosts"."disk" AS t0_r14, "hosts"."installed_at" AS t0_r15, "hosts"."model_id" AS t0_r16, "hosts"."hostgroup_id" AS t0_r17, "hosts"."owner_id" AS t0_r18, "hosts"."owner_type" AS t0_r19, "hosts"."enabled" AS t0_r20, "hosts"."puppet_ca_proxy_id" AS t0_r21, "hosts"."managed" AS t0_r22, "hosts"."use_image" AS t0_r23, "hosts"."image_file" AS t0_r24, "hosts"."uuid" AS t0_r25, "hosts"."compute_resource_id" AS t0_r26, "hosts"."puppet_proxy_id" AS t0_r27, "hosts"."certname" AS t0_r28, "hosts"."image_id" AS t0_r29, "hosts"."organization_id" AS t0_r30, "hosts"."location_id" AS t0_r31, "hosts"."type" AS t0_r32, "hosts"."otp" AS t0_r33, "hosts"."realm_id" AS t0_r34, "hosts"."compute_profile_id" AS t0_r35, "hosts"."provision_method" AS t0_r36, "hosts"."grub_pass" AS t0_r37, "hosts"."global_status" AS t0_r38, "hosts"."lookup_value_matcher" AS t0_r39, "hosts"."pxe_loader" AS t0_r40, "hosts"."discovery_rule_id" AS t0_r41, "hostgroups"."id" AS t1_r0, "hostgroups"."name" AS t1_r1, "hostgroups"."created_at" AS t1_r2, "hostgroups"."updated_at" AS t1_r3, "hostgroups"."environment_id" AS t1_r4, "hostgroups"."operatingsystem_id" AS t1_r5, "hostgroups"."architecture_id" AS t1_r6, "hostgroups"."medium_id" AS t1_r7, "hostgroups"."ptable_id" AS t1_r8, "hostgroups"."root_pass" AS t1_r9, "hostgroups"."puppet_ca_proxy_id" AS t1_r10, "hostgroups"."use_image" AS t1_r11, "hostgroups"."image_file" AS t1_r12, "hostgroups"."ancestry" AS t1_r13, "hostgroups"."vm_defaults" AS t1_r14, "hostgroups"."subnet_id" AS t1_r15, "hostgroups"."domain_id" AS t1_r16, "hostgroups"."puppet_proxy_id" AS t1_r17, "hostgroups"."title" AS t1_r18, "hostgroups"."realm_id" AS t1_r19, "hostgroups"."compute_profile_id" AS t1_r20, "hostgroups"."grub_pass" AS t1_r21, "hostgroups"."lookup_value_matcher" AS t1_r22, "hostgroups"."subnet6_id" AS t1_r23, "hostgroups"."pxe_loader" AS t1_r24, "hostgroups"."description" AS t1_r25, "hostgroups"."compute_resource_id" AS t1_r26 FROM "hosts" LEFT OUTER JOIN "hostgroups" ON "hostgroups"."id" = "hosts"."hostgroup_id" WHERE "hosts"."type" IN ('Host::Managed') AND ((("hostgroups"."title" = 'Linux/Desktop/Stationary/Ubuntu') OR ("hostgroups"."title" = 'Linux/Desktop/Mobile/Ubuntu'))) AND "hosts"."id" = $1 LIMIT $2 [["id", 94], ["LIMIT", 1]] 2018-12-22T17:53:01 [I|app|b41f8] Couldn't find Host::Managed with 'id'=94 [WHERE "hosts"."type" IN ('Host::Managed') AND ((("hostgroups"."title" = 'Linux/Desktop/Stationary/Ubuntu') OR ("hostgroups"."title" = 'Linux/Desktop/Mobile/Ubuntu')))] (ActiveRecord::RecordNotFound) 2018-12-22T17:53:01 [I|app|b41f8] Rendering api/v2/errors/not_found.json.rabl within api/v2/layouts/error_layout 2018-12-22T17:53:01 [I|app|b41f8] Rendered api/v2/errors/not_found.json.rabl within api/v2/layouts/error_layout (2.4ms) 2018-12-22T17:53:01 [I|app|b41f8] Completed 404 Not Found in 655ms (Views: 6.6ms | ActiveRecord: 271.0ms)
That looks very similar to the "vanilla" version.
Cheers and hope that helps,
Oliver
Updated by Oliver Freyermuth almost 5 years ago
- Found in Releases 1.21.2 added
Sorry to bump this, but since the new year has arrived...
Any update on this from someone more experienced in Ruby than I am?
I still see this in 1.21.2.