Skip to content

Commit

Permalink
WIP initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
vpereira authored and Dany Marcoux committed Apr 26, 2021
1 parent ac53b78 commit d7534d1
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 1 deletion.
49 changes: 48 additions & 1 deletion src/api/app/controllers/trigger_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ class TriggerController < ApplicationController
validate_action release: { method: :post, response: :status }
validate_action runservice: { method: :post, response: :status }

before_action :validate_token, :set_package, :set_user, only: [:create]

before_action :disallow_project_param, only: [:release]

before_action :extract_auth_from_request, :validate_auth_token, :require_valid_token
before_action :extract_auth_from_request, :validate_auth_token, :require_valid_token, except: [:create]
#
# Authentication happens with tokens, so no login is required
#
Expand Down Expand Up @@ -55,6 +57,18 @@ def runservice
@pkg.sources_changed
end

def create
if !@user.is_active? || !@user.can_modify?(@package)
render_error message: 'Token not found or not valid.', status: 404
return
end

Backend::Api::Sources::Package.trigger_services(@package.project.name, @package.name, @user.login)
render_ok
end



private

def prepare_path_for_runservice
Expand Down Expand Up @@ -103,4 +117,37 @@ def require_valid_token
@pkg = Package.get_by_project_and_name(params[:project].to_s, params[:package].to_s, opts)
end
end


def set_package
@package = @token.package || Package.get_by_project_and_name(params[:project], params[:package], use_source: true)
end

def validate_token
@token = Token::Service.find_by(id: params[:id])
return if @token && @token.valid_signature?(signature, request.body.read)

render_error message: 'Token not found or not valid.', status: 403
false
end

def set_user
@user = @token.user
end

# To trigger the webhook, the sender needs to
# generate a signature with a secret token.
# The signature needs to be generated over the
# payload of the HTTP request and stored
# in a HTTP header.
# GitHub: HTTP_X_HUB_SIGNATURE
# https://developer.github.com/webhooks/securing/
# Pagure: HTTP_X-Pagure-Signature-256
# https://docs.pagure.org/pagure/usage/using_webhooks.html
# Custom signature: HTTP_X_OBS_SIGNATURE
def signature
request.env['HTTP_X_OBS_SIGNATURE'] ||
request.env['HTTP_X_HUB_SIGNATURE'] ||
request.env['HTTP_X-Pagure-Signature-256']
end
end
93 changes: 93 additions & 0 deletions src/api/spec/controllers/trigger_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,97 @@

it { expect(response).to have_http_status(:success) }
end

describe '#create' do
let(:user) { create(:confirmed_user, :with_home, login: 'tom') }
let(:service_token) { create(:service_token, user: user) }
let(:body) { { hello: :world }.to_json }
let(:project) { user.home_project }
let(:package) { create(:package_with_service, name: 'apache2', project: project) }
let(:signature) { 'sha1=' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), service_token.string, body) }

shared_examples 'it verifies the signature' do
before do
request.headers[signature_header_name] = signature
end

context 'when signature is valid' do
let(:path) { "#{CONFIG['source_url']}/source/#{project.name}/#{package.name}?cmd=runservice&user=#{user.login}" }

before do
stub_request(:get, path).and_return(body: 'does not matter')
post :create, body: body, params: { id: service_token.id, project: project.name, package: package.name, format: :xml }
end

it { expect(response).to have_http_status(:success) }
end

context 'when token is invalid' do
it 'renders an error with an invalid signature' do
request.headers[signature_header_name] = 'sha1=invalid'
post :create, body: body, params: { id: service_token.id, project: project.name, package: package.name, format: :xml }
expect(response).to be_forbidden
end

it 'renders an error with an invalid token' do
invalid_token_id = 42
post :create, body: body, params: { id: invalid_token_id, project: project.name, package: package.name, format: :xml }
expect(response).to be_forbidden
end
end

context 'when user has no permissions' do
let(:project_without_permissions) { create(:project, name: 'Apache') }
let(:package_without_permissions) { create(:package_with_service, name: 'apache2', project: project_without_permissions) }
let(:inactive_user) { create(:user) }
let(:invalid_service_token) { create(:service_token, user: inactive_user) }

it 'renders an error for missing package permissions' do
params = { id: service_token.id, project: project_without_permissions.name, package: package_without_permissions.name, format: :xml }
post :create, body: body, params: params
expect(response).to be_not_found
end

it 'renders an error for an inactive user' do
signature = 'sha1=' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), invalid_service_token.string, body)
request.headers[signature_header_name] = signature
params = { id: invalid_service_token.id, project: project.name, package: package.name, format: :xml }
post :create, body: body, params: params
expect(response).to be_not_found
end
end

context 'when entity does not exist' do
it 'renders an error for package' do
params = { id: service_token.id, project: project.name, package: 'does-not-exist', format: :xml }
post :create, body: body, params: params
expect(response).to be_not_found
end

it 'renders an error for project' do
params = { id: service_token.id, project: 'does-not-exist', package: package.name, format: :xml }
post :create, body: body, params: params
expect(response).to be_not_found
end
end
end

context 'with HTTP_X_OBS_SIGNATURE http header' do
let(:signature_header_name) { 'HTTP_X_OBS_SIGNATURE' }

it_behaves_like 'it verifies the signature'
end

context 'with HTTP_X_HUB_SIGNATURE http header' do
let(:signature_header_name) { 'HTTP_X_HUB_SIGNATURE' }

it_behaves_like 'it verifies the signature'
end

context 'with HTTP_X-Pagure-Signature-256 http header' do
let(:signature_header_name) { 'HTTP_X-Pagure-Signature-256' }

it_behaves_like 'it verifies the signature'
end
end
end

0 comments on commit d7534d1

Please sign in to comment.