Commit 089ae288 authored by Robert Speicher's avatar Robert Speicher

Merge branch '804-jenkins-set-username-and-password-to-hook-url-if-provided' into 'master'

Add username and password to Jenkins hook url

Closes #804

See merge request !1035
parents f141afab f03449ab
...@@ -3,9 +3,10 @@ class JenkinsService < CiService ...@@ -3,9 +3,10 @@ class JenkinsService < CiService
prop_accessor :jenkins_url, :project_name, :username, :password prop_accessor :jenkins_url, :project_name, :username, :password
before_update :reset_password before_update :reset_password
validates :username,
presence: true, validates :jenkins_url, presence: true, url: true, if: :activated?
if: ->(service) { service.activated? && service.password_touched? } validates :project_name, presence: true, if: :activated?
validates :username, presence: true, if: ->(service) { service.activated? && service.password_touched? }
default_value_for :push_events, true default_value_for :push_events, true
default_value_for :merge_requests_events, false default_value_for :merge_requests_events, false
...@@ -43,13 +44,12 @@ class JenkinsService < CiService ...@@ -43,13 +44,12 @@ class JenkinsService < CiService
{ success: true, result: message } { success: true, result: message }
end end
def auth
require 'base64'
Base64.urlsafe_encode64("#{username}:#{password}")
end
def hook_url def hook_url
File.join(jenkins_url, "project/#{project_name}").to_s url = URI.parse(jenkins_url)
url.path = File.join(url.path || '/', "project/#{project_name}")
url.user = ERB::Util.url_encode(username) unless username.blank?
url.password = ERB::Util.url_encode(password) unless password.blank?
url.to_s
end end
def self.supported_events def self.supported_events
......
require 'spec_helper' require 'spec_helper'
describe JenkinsService do describe JenkinsService do
describe "Associations" do describe 'Associations' do
it { is_expected.to belong_to :project } it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook } it { is_expected.to have_one :service_hook }
end end
...@@ -13,6 +13,8 @@ describe JenkinsService do ...@@ -13,6 +13,8 @@ describe JenkinsService do
active: true, active: true,
project: project, project: project,
properties: { properties: {
password: 'pas$ word',
username: 'u$er name%2520',
jenkins_url: 'http://jenkins.example.com/', jenkins_url: 'http://jenkins.example.com/',
project_name: 'my_project' project_name: 'my_project'
} }
...@@ -62,26 +64,55 @@ describe JenkinsService do ...@@ -62,26 +64,55 @@ describe JenkinsService do
end end
describe '#hook_url' do describe '#hook_url' do
before do let(:username) { nil }
@jenkins_service = JenkinsService.create( let(:password) { nil }
let(:jenkins_service) do
JenkinsService.new(
project: project, project: project,
properties: { properties: {
jenkins_url: jenkins_url, jenkins_url: jenkins_url,
project_name: 'my_project' project_name: 'my_project',
username: username,
password: password,
} }
) )
end end
subject { @jenkins_service.hook_url }
subject { jenkins_service.hook_url }
context 'when the jenkins_url has no relative path' do context 'when the jenkins_url has no relative path' do
let(:jenkins_url) { 'http://jenkins.example.com/' } let(:jenkins_url) { 'http://jenkins.example.com/' }
it { is_expected.to eq('http://jenkins.example.com/project/my_project') } it { is_expected.to eq('http://jenkins.example.com/project/my_project') }
end end
context 'when the jenkins_url has relative path' do context 'when the jenkins_url has relative path' do
let(:jenkins_url) { 'http://organization.example.com/jenkins' } let(:jenkins_url) { 'http://organization.example.com/jenkins' }
it { is_expected.to eq('http://organization.example.com/jenkins/project/my_project') } it { is_expected.to eq('http://organization.example.com/jenkins/project/my_project') }
end end
context 'userinfo is missing and username and password are set' do
let(:jenkins_url) { 'http://organization.example.com/jenkins' }
let(:username) { 'u$ername' }
let(:password) { 'pas$ word' }
it { is_expected.to eq('http://u%24ername:pas%24%20word@organization.example.com/jenkins/project/my_project') }
end
context 'userinfo is provided and username and password are set' do
let(:jenkins_url) { 'http://u:p@organization.example.com/jenkins' }
let(:username) { 'username' }
let(:password) { 'password' }
it { is_expected.to eq('http://username:password@organization.example.com/jenkins/project/my_project') }
end
context 'userinfo is provided username and password are not set' do
let(:jenkins_url) { 'http://u:p@organization.example.com/jenkins' }
it { is_expected.to eq('http://u:p@organization.example.com/jenkins/project/my_project') }
end
end end
describe '#test' do describe '#test' do
...@@ -113,6 +144,20 @@ describe JenkinsService do ...@@ -113,6 +144,20 @@ describe JenkinsService do
.with(headers: { 'X-Gitlab-Event' => 'Push Hook' }) .with(headers: { 'X-Gitlab-Event' => 'Push Hook' })
).to have_been_made.once ).to have_been_made.once
end end
it 'request url contains properly serialized username and password' do
user = create(:user, username: 'username')
project = create(:project, name: 'project')
push_sample_data = Gitlab::DataBuilder::Push.build_sample(project, user)
jenkins_service = described_class.create(jenkins_params)
stub_request(:post, jenkins_service.hook_url)
jenkins_service.execute(push_sample_data)
expect(
a_request(:post, 'http://u%24er%20name%252520:pas%24%20word@jenkins.example.com/project/my_project')
).to have_been_made.once
end
end end
describe 'Stored password invalidation' do describe 'Stored password invalidation' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment