Bug 1329487

Summary: non-admin user seeing 500 error when reviewing their host's PXE configs
Product: Red Hat Satellite Reporter: Neil Miao <nmiao>
Component: HostsAssignee: satellite6-bugs <satellite6-bugs>
Status: CLOSED CURRENTRELEASE QA Contact:
Severity: high Docs Contact:
Priority: high    
Version: 6.1.8CC: bbuckingham, tbrisker, vvasilev
Target Milestone: UnspecifiedKeywords: Triaged
Target Release: Unused   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2016-12-06 12:55:35 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:

Description Neil Miao 2016-04-22 05:28:35 UTC
Description of problem:

Info:
* non-admin users are granted all possible permissions to create and manage host and provisioning templates in their own organization and locations
* all provisioning templates are assigned to the users' locations and organization
* users can see view and edit the templates just fine in https://satellite/config_templates
* users are able to provision hosts

Problem:
After the hosts are built, non-admin users cannot view the host's PXE config.
A 500 error page (we are sorry, but something went wrong) appears when the users go to https://satellite/unattended/PXELinux?hostname=_provisioned_host_

2016-04-22 04:41:55 [I] Completed 500 Internal Server Error in 331ms
2016-04-22 04:41:55 [F]
ArgumentError (There was no default layout for UnattendedController in #<ActionView::PathSet:0x0000000f3d06f8 @paths=[/usr/share/foreman/app/views, /opt/rh/ruby193/root/usr/share/gems/gems/foreman_
bootdisk-4.0.2.14/app/views, /opt/rh/ruby193/root/usr/share/gems/gems/redhat_access-0.2.5/app/views, /opt/rh/ruby193/root/usr/share/gems/gems/katello-2.2.0.85/app/views, /opt/rh/ruby193/root/usr/sh
are/gems/gems/bastion-0.3.0.10/app/views, /opt/rh/ruby193/root/usr/share/gems/gems/foreman-tasks-0.6.15.7/app/views, /opt/rh/ruby193/root/usr/share/gems/gems/foreman_discovery-2.0.0.23/app/views, /
opt/rh/ruby193/root/usr/share/gems/gems/foreman_docker-1.2.0.24/app/views, /opt/rh/ruby193/root/usr/share/gems/gems/apipie-rails-0.2.5/app/views]>):
  app/controllers/application_controller.rb:303:in `generic_exception'
  lib/middleware/catch_json_parse_errors.rb:9:in `call'
  app/controllers/application_controller.rb:221:in `block (2 levels) in render_403'
  app/controllers/application_controller.rb:220:in `render_403'
  app/controllers/application_controller.rb:59:in `deny_access'
  app/controllers/application_controller.rb:51:in `authorize'
  app/controllers/unattended_controller.rb:20:in `block (2 levels) in <class:UnattendedController>'
  app/models/concerns/foreman/thread_session.rb:33:in `clear_thread'


However, the provisioning config is visible just fine
https://satellite/unattended/provision?hostname=_provisioned_host_


Version-Release number of selected component (if applicable):
foreman-1.7.2.55-1.el7sat.noarch

How reproducible:
always

Steps to Reproduce:
1. grant manager role to a user (a.k.a user1)
2. provision a RHEL7(a.k.a host1) as the user using templates: (kickstart default pxe and satellite kickstart default)
3. verify both templates are viewable and editable by user1
4. https://satellite/unattended/provision?hostname=host1 returns the rendered KS file

Actual results:
https://satellite/unattended/PXELinux?hostname=host1 returns a 500 error page
https://satellite/unattended/iPXE?hostname=host1 returns a 500 error page
https://satellite/unattended/finish?hostname=host1 returns a 500 error page
https://satellite/unattended/user_data?hostname=host1 returns a 500 error page

Expected results:
the above urls should returns the rendered files

Additional info:
ACL is the culprit, as always ...

  app/controllers/application_controller.rb:221:in `block (2 levels) in render_403'
  app/controllers/application_controller.rb:220:in `render_403'
  app/controllers/application_controller.rb:59:in `deny_access'
  app/controllers/application_controller.rb:51:in `authorize'
  app/controllers/unattended_controller.rb:20:in `block (2 levels) in <class:UnattendedController>'

-- snip --
  def authorize
    (render :json => { :error => "Authentication error" }, :status => :unauthorized and return) unless User.current.present?
    authorized ? true : deny_access
  end
-- snip --

For some reason 'authorized' returns false, which triggers the code to try render a 403 page within the unattended controller, which end up throwing 500 since unattended controller doesn't know how to render a 403 page. 

It took me a while to found the reason why authorized == false.

By adding additional logging in these places:

app/controllers/concerns/foreman/controller/authentication.rb
  def authorized
logger.debug(params.to_yaml)
    User.current.allowed_to?(params.slice(:controller, :action, :id))
  end

app/models/role.rb
  def allowed_to?(action)
logger.debug('XXX')
    if action.is_a? Hash
      action[:controller] = action[:controller][1..-1] if action[:controller].starts_with?('/')
logger.debug(allowed_actions.to_yaml)
logger.debug(action.to_yaml)
      allowed_actions.include? "#{action[:controller]}/#{action[:action]}"
    else
logger.debug(allowed_permissions.to_yaml)
logger.debug(action.to_yaml)
      allowed_permissions.include? action
    end
  end

I realized the manager role is blocked by ACL from reaching any actions other than 'provision' and 'template' in 'unattended' controller, even though all host/template permissions are already granted to role.

All allowed permissions debug log:
2016-04-22 03:29:47 [D]   Permission Load (1.9ms)  SELECT "permissions".* FROM "permissions" INNER JOIN "filterings" ON "permissions"."id" = "filterings"."permission_id" INNER JOIN "filters" ON "filterings"."filter_id" = "filters"."id" WHERE "filters"."role_id" = 21 ORDER BY role_id, filters.id
2016-04-22 03:29:47 [D] ---
- architectures/index
- architectures/show
- architectures/auto_complete_search
- api/v1/architectures/index
- api/v1/architectures/show
- api/v2/architectures/index
- api/v2/architectures/show
...
- unattended/template
- unattended/provision
...

2016-04-22 03:29:47 [D] --- !ruby/hash:ActionController::Parameters
controller: unattended
action: PXELinux

Apparently, the action is blocked since its not available in the allowed permissions list.

It seems the permissions for unattended controller is not configurable in GUI and no unattended related entry found in the db table 'permissions' as well. 

Turns out they are hard-coded in 'services/foreman/access_permissions.rb'

-- snip --
map.permission :view_hosts,    {:hosts => [:index, :show, :errors, :active, :out_of_sync, :disabled, :pending, :vm,
                                      :externalNodes, :pxe_config, :storeconfig_klasses, :auto_complete_search, :bmc,
                                      :runtime, :resources, :templates, :overview],
                                    :dashboard => [:OutOfSync, :errors, :active],
                                    :unattended => [:template, :provision],
                                     :"api/v1/hosts" => [:index, :show, :status],
                                     :"api/v2/hosts" => [:index, :show, :status],
                                     :"api/v2/interfaces" => [:index, :show],
                                     :locations =>  [:mismatches],
                                     :organizations =>  [:mismatches]
-- snip --
As soon as ':PXELinux' and the other template types are added into ':unattached', the issue is gone.

The fact that ':template' lists in there means at some point the unattended templates are all rendered via the unattended/template action, which will work just fine. But someone later change that behavior in the unattended_controller.rb, without changing the access_permissions.rb to match it...

Are we suppose to have some unit-test/functional-test to cover this sort of things??

Anyway, I was determined to get to the bottom of this POS and it does take me a few hours to track it down. (shows that I am not quite familiar with the foreman code base and the code is really not the easiest code in the world to follow)

Adding all those template types in access_permissions.rb stinks, hopefully someone finds a better way to fix it. 

Again, satellite 6 developers, PLEASE put in some effect to close the testing gap!!!
Bugs like these should never even reaches end users like me.

Comment 2 Tomer Brisker 2016-12-06 12:55:35 UTC
This seems to have been fixed in 6.2 as far as I can tell. 
Closing, feel free to reopen if issue still persists.