Project

General

Profile

« Previous | Next » 

Revision aaf30cda

Added by Eric Helms about 10 years ago

Fixes #4657: Removes Katello current user setting and moves consumer
authentication checking to the proxies controller.

Previously, the API controller was attempting to handle authentication for
standard users and consumers across all controllers. After moving all consumer
routes and functionality to the Candlepin proxies controller, client authentication
should be handled within the context of that controller and authentication/authorization
controller relegated to the underlying Foreman framework.

View differences:

app/controllers/katello/api/api_controller.rb
include ForemanTasks::Triggers
respond_to :json
before_filter :require_user
before_filter :verify_ldap
before_filter :add_candlepin_version_header
before_filter :turn_off_strong_params
# override warden current_user (returns nil because there is no user in that scope)
......
protected
def add_candlepin_version_header
response.headers["X-CANDLEPIN-VERSION"] = "katello/#{Katello.config.katello_version}"
# Override Foreman authorized method to call the Katello authorize check
def authorized
authorize_katello
end
def verify_ldap
......
end
end
def require_user
if authenticate && session[:user]
User.current = User.find(session[:user])
elsif (ssl_client_cert = client_cert_from_request).present?
consumer_cert = OpenSSL::X509::Certificate.new(ssl_client_cert)
uuid = uuid(consumer_cert)
User.current = CpConsumerUser.new(:uuid => uuid, :login => uuid, :remote_id => uuid)
elsif authenticate
User.current
else
deny_access
end
end
def request_from_katello_cli?
request.user_agent.to_s =~ /^katello-cli/
end
......
return send(method_name, options)
end
def client_cert_from_request
cert = request.env['SSL_CLIENT_CERT'] || request.env['HTTP_SSL_CLIENT_CERT'] ||
ENV['SSL_CLIENT_CERT'] || ENV['HTTP_SSL_CLIENT_CERT']
return nil if cert.blank? || cert == "(null)"
# apache does not preserve new lines in cert file - work-around:
if cert.include?("-----BEGIN CERTIFICATE----- ")
cert = cert.to_s.gsub("-----BEGIN CERTIFICATE----- ", "").gsub(" -----END CERTIFICATE-----", "")
cert.gsub!(" ", "\n")
cert = "-----BEGIN CERTIFICATE-----\n#{cert}-----END CERTIFICATE-----\n"
end
return cert
end
def uuid(cert)
drop_cn_prefix_from_subject(cert.subject.to_s)
end
def drop_cn_prefix_from_subject(subject_string)
subject_string.sub(/\/CN=/i, '')
end
end
end
app/controllers/katello/api/v1/candlepin_proxies_controller.rb
module Katello
class Api::V1::CandlepinProxiesController < Api::V1::ApiController
include Katello::Authentication::RhsmClientAuthentication
skip_before_filter :authorize
before_filter :authorize_client, :except => [:consumer_activate]
before_filter :add_candlepin_version_header
before_filter :proxy_request_path, :proxy_request_body
before_filter :find_organization, :only => [:rhsm_index]
before_filter :find_default_organization_and_or_environment, :only => [:consumer_create, :index, :consumer_activate]
......
before_filter :find_system, :only => [:consumer_show, :consumer_destroy, :consumer_checkin,
:upload_package_profile, :regenerate_identity_certificates, :facts]
before_filter :find_user_by_login, :only => [:list_owners]
before_filter :authorize, :except => [:consumer_activate, :upload_package_profile]
# TODO: break up method
# rubocop:disable MethodLength
app/controllers/katello/api/v2/systems_controller.rb
skip_before_filter :set_default_response_format, :only => :report
before_filter :find_default_organization_and_or_environment, :only => [:create, :index, :activate]
before_filter :find_optional_organization, :only => [:create, :hypervisors_update, :index, :activate, :report]
before_filter :find_only_environment, :only => [:create]
before_filter :find_environment, :only => [:index, :report]
before_filter :find_system_group, :only => [:index]
before_filter :find_environment_and_content_view, :only => [:create]
before_filter :find_hypervisor_environment_and_content_view, :only => [:hypervisors_update]
before_filter :find_system, :only => [:destroy, :show, :update, :regenerate_identity_certificates,
:upload_package_profile, :errata, :package_profile, :subscribe,
:unsubscribe, :subscriptions, :pools, :enabled_repos, :releases,
:available_system_groups, :add_system_groups, :remove_system_groups,
:refresh_subscriptions, :checkin,
:subscription_status, :tasks] # TODO: this should probably be :except
before_filter :find_content_view, :only => [:create, :update]
before_filter :find_environment, :only => [:index, :report]
before_filter :find_optional_organization, :only => [:create, :hypervisors_update, :index, :activate, :report]
before_filter :find_system_group, :only => [:index]
before_filter :find_default_organization_and_or_environment, :only => [:create, :index, :activate]
before_filter :find_only_environment, :only => [:create]
before_filter :authorize, :except => [:activate, :upload_package_profile]
before_filter :find_environment_and_content_view, :only => [:create]
before_filter :find_hypervisor_environment_and_content_view, :only => [:hypervisors_update]
before_filter :find_content_view, :only => [:create, :update]
before_filter :load_search_service, :only => [:index, :available_system_groups, :tasks]
def organization_id_keys
app/controllers/katello/application_controller.rb
include AuthorizationRules
include Menu
# Override Foreman authorized method to call the Katello authorize check
def authorized
authorize_katello
end
before_filter :verify_ldap
def section_id
app/lib/katello/authorization_rules.rb
before_filter :authorize
end
end
# authorize the user for the requested action
def authorize(ctrl = params[:controller], action = self.action_name)
def authorize_katello(ctrl = params[:controller], action = self.action_name)
user = current_user
fail StandardError, "Current user not set" unless user
logger.debug "Authorizing #{current_user.login} for #{ctrl}/#{action}"
app/services/katello/authentication/rhsm_client_authentication.rb
#
# Copyright 2013 Red Hat, Inc.
#
# This software is licensed to you under the GNU General Public
# License as published by the Free Software Foundation; either version
# 2 of the License (GPLv2) or (at your option) any later version.
# There is NO WARRANTY for this software, express or implied,
# including the implied warranties of MERCHANTABILITY,
# NON-INFRINGEMENT, or FITNESS FOR A PARTICULAR PURPOSE. You should
# have received a copy of GPLv2 along with this software; if not, see
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
require 'rhsm/cert'
module Katello
module Authentication
module RhsmClientAuthentication
extend ActiveSupport::Concern
included do
def authorize_client
ssl_client_cert = cert_from_request
if ssl_client_cert.present? && ssl_client_cert != "(null)"
rhsm_cert = Rhsm::Cert.new(cert_from_request)
uuid = rhsm_cert.uuid
User.current = CpConsumerUser.new(:uuid => uuid, :login => uuid, :remote_id => uuid)
elsif authenticate
User.current
else
deny_access
end
end
def cert_from_request
request.env['SSL_CLIENT_CERT'] ||
request.env['HTTP_SSL_CLIENT_CERT'] ||
ENV['SSL_CLIENT_CERT'] ||
ENV['HTTP_SSL_CLIENT_CERT']
end
def add_candlepin_version_header
response.headers["X-CANDLEPIN-VERSION"] = "katello/#{Katello.config.katello_version}"
end
end
end
end
end
app/services/rhsm/cert.rb
#
# Copyright 2014 Red Hat, Inc.
#
# This software is licensed to you under the GNU General Public
# License as published by the Free Software Foundation; either version
# 2 of the License (GPLv2) or (at your option) any later version.
# There is NO WARRANTY for this software, express or implied,
# including the implied warranties of MERCHANTABILITY,
# NON-INFRINGEMENT, or FITNESS FOR A PARTICULAR PURPOSE. You should
# have received a copy of GPLv2 along with this software; if not, see
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
require 'openssl'
require 'base64'
module Rhsm
class Cert
attr_accessor :cert
def initialize(cert)
self.cert = extract(cert)
end
def uuid
drop_cn_prefix_from_subject(@cert.subject.to_s)
end
private
def extract(cert)
if cert.empty?
fail('Invalid cert provided. Ensure that the provided cert is not empty.')
else
cert = strip_cert(cert)
cert = Base64.decode64(cert)
OpenSSL::X509::Certificate.new(cert)
end
end
def drop_cn_prefix_from_subject(subject_string)
subject_string.sub(/\/CN=/i, '')
end
def strip_cert(cert)
cert = cert.to_s.gsub("-----BEGIN CERTIFICATE-----", "").gsub("-----END CERTIFICATE-----", "")
cert.gsub!(' ', '')
cert.gsub!(/\n/, '')
cert
end
end
end
lib/katello/engine.rb
app.config.paths['db/migrate'] += Katello::Engine.paths['db/migrate'].existent
app.config.autoload_paths += Dir["#{config.root}/app/lib"]
app.config.autoload_paths += Dir["#{config.root}/app/services/katello"]
app.config.autoload_paths += Dir["#{config.root}/app/services/rhsm"]
app.config.autoload_paths += Dir["#{config.root}/app/views/foreman"]
end
lib/katello/tasks/test.rake
test_task = Rake::TestTask.new('katello_test_task') do |t|
t.libs << ["test", "#{Katello::Engine.root}/test"]
t.test_files = [
"#{Katello::Engine.root}/test/services/**/*_test.rb",
"#{Katello::Engine.root}/test/controllers/api/v1/*_test.rb",
"#{Katello::Engine.root}/test/controllers/api/v2/*_test.rb",
"#{Katello::Engine.root}/test/actions/**/*_test.rb",
test/services/rhsm/cert_test.rb
#
# Copyright 2014 Red Hat, Inc.
#
# This software is licensed to you under the GNU General Public
# License as published by the Free Software Foundation; either version
# 2 of the License (GPLv2) or (at your option) any later version.
# There is NO WARRANTY for this software, express or implied,
# including the implied warranties of MERCHANTABILITY,
# NON-INFRINGEMENT, or FITNESS FOR A PARTICULAR PURPOSE. You should
# have received a copy of GPLv2 along with this software; if not, see
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
require 'minitest/autorun'
require File.expand_path('../../../../app/services/rhsm/cert.rb', __FILE__)
module Rhsm
class CertTest < MiniTest::Unit::TestCase
CERT = '
-----BEGIN CERTIFICATE-----
MIIEaTCCA1GgAwIBAgIIMAikOB+/HpowDQYJKoZIhvcNAQEFBQAwezELMAkGA1UE
BhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRAwDgYDVQQHEwdSYWxlaWdo
MRAwDgYDVQQKEwdTb21lT3JnMRQwEgYDVQQLEwtTb21lT3JnVW5pdDEZMBcGA1UE
AxMQY2VudG9zLmluc3RhbGxlcjAeFw0xNDAzMTcxOTUwMjBaFw0zMDAzMTcxOTUw
MjBaMC8xLTArBgNVBAMTJDE0ZTk4MTU1LTczMWEtNGNhZS1iMTUxLTVjNTA0Y2Mz
MGUxYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKlWUgos9daHOxCg
rvRHzDBrScUVEYl+EzJADNiL0EXkKTzIlxxAU21QE0v0DyMjUGHZRQ6vwn+fX1rp
v1xLO7wH5G/+hQKLS4amSHF2EzOpuuOBE1bBLmuvg28PttLQb3OUCO1O87g+5cE/
EuX206zOcqs+9qcrOULrFyopaFpviA3F1C5R6AhNpOWerBvxtoLMfFFXL3MTj3d3
XzmTMycvxAjyBs3elSZgrf+b0lF/OIxL7xlgzW7IZGSl4e2Lx6dRgyUj+4dyx4X4
zkdhuj5Khnfvbut20BTyOVh/Y0uAAu4pm58B9PPIjxmkl03QPh0htMdtO/FRg3W8
9QgsYDcCAwEAAaOCATswggE3MBEGCWCGSAGG+EIBAQQEAwIFoDALBgNVHQ8EBAMC
BLAwga0GA1UdIwSBpTCBooAUkQeVYv8I+1JAExaABq5A/U3Fh7ahf6R9MHsxCzAJ
BgNVBAYTAlVTMRcwFQYDVQQIEw5Ob3J0aCBDYXJvbGluYTEQMA4GA1UEBxMHUmFs
ZWlnaDEQMA4GA1UEChMHU29tZU9yZzEUMBIGA1UECxMLU29tZU9yZ1VuaXQxGTAX
BgNVBAMTEGNlbnRvcy5pbnN0YWxsZXKCCQCqejy74F8t8TAdBgNVHQ4EFgQUK7io
wey/1DrRtCvzM/YgoyHbdQ0wEwYDVR0lBAwwCgYIKwYBBQUHAwIwMQYDVR0RBCow
KKQmMCQxIjAgBgNVBAMMGWRoY3AxMjktNzQucmR1LnJlZGhhdC5jb20wDQYJKoZI
hvcNAQEFBQADggEBAGYZWSCZsmpAJECW07q8FF8OgwLwQAqlPIO6wLtu9g5wL3c5
Aw3TDHoFcxMe7hADcUvi+n2SzupS94NqY4F3FOBH6IjFAeZZUpQXjy7nG6jN8Agx
n+iM9RXh+pmwxJtPWMq0gTbmBQvxcPxBHr6vFNKrXJm4WAKLihI4ErtgeKZMAFn7
/gkhjiyicxw+uxRHuNyMClM8Q5WVj4CpxrPHwZvN1OhM8D3VDnEaZj6J2k5g55Fl
3qQXsk8lPEJ2I5D00Up2cpDBy+CXj5zm/shmqEJlGOxILjpCzNhqER/YdBlGPP9b
okjCBjwYlp5cNyAJSQscLF7rj/iOJYhRdetWMZg=
-----END CERTIFICATE-----'
def test_uuid
rhsm_cert = Rhsm::Cert.new(CERT)
assert_equal rhsm_cert.uuid, '14e98155-731a-4cae-b151-5c504cc30e1a'
end
def test_empty_cert
assert_raises RuntimeError do
Rhsm::Cert.new('')
end
end
def test_bad_cert
assert_raises OpenSSL::X509::CertificateError do
Rhsm::Cert.new('This is not a real cert string.')
end
end
end
end

Also available in: Unified diff