Commit 04094afc authored by Oswaldo Ferreira's avatar Oswaldo Ferreira

Allow only requests from DVCS connector for Github-like endpoints

parent 0b5f80b4
...@@ -52,8 +52,8 @@ module API ...@@ -52,8 +52,8 @@ module API
# Although the following endpoints are kept behind V3 namespace, they're not # Although the following endpoints are kept behind V3 namespace, they're not
# deprecated neither should be removed when V3 get removed. # deprecated neither should be removed when V3 get removed.
# They're needed as a layer to integrate with Jira development panel. # They're needed as a layer to integrate with Jira Development Panel.
mount ::API::V3::GithubRepos mount ::API::V3::Github
end end
before { header['X-Frame-Options'] = 'SAMEORIGIN' } before { header['X-Frame-Options'] = 'SAMEORIGIN' }
......
...@@ -1090,73 +1090,5 @@ module API ...@@ -1090,73 +1090,5 @@ module API
expose :failing_on_hosts expose :failing_on_hosts
expose :total_failures expose :total_failures
end end
module Github
class Namespace < Grape::Entity
expose :path, as: :login
end
class Repository < Grape::Entity
expose :id
expose :namespace, as: :owner, using: Namespace
expose :name
end
class BranchCommit < Grape::Entity
expose :id, as: :sha
expose :type do |model|
'commit'
end
end
class RepoCommit < Grape::Entity
expose :id, as: :sha
expose :author do |commit|
{
login: commit.author&.username,
email: commit.author_email
}
end
expose :committer do |commit|
{
login: commit.author&.username,
email: commit.committer_email
}
end
expose :commit do |commit|
# TODO: export to entity
{
author: {
name: commit.author_name,
email: commit.author_email,
date: commit.authored_date.iso8601,
type: 'User'
},
committer: {
name: commit.committer_name,
email: commit.committer_email,
date: commit.committed_date.iso8601,
type: 'User'
},
message: commit.safe_message
}
end
expose :parents do |commit|
# TODO: export to entity
commit.parent_ids.map { |id| { sha: id } }
end
expose :files do |commit|
[]
end
end
class Branch < Grape::Entity
expose :name
expose :commit, using: BranchCommit do |repo_branch, options|
options[:project].repository.commit(repo_branch.dereferenced_target)
end
end
end
end end
end end
# Simplified version of Github API entities.
# It's mainly used to mimic Github API and integrate with Jira Development Panel.
#
module API
module Github
module Entities
class Namespace < Grape::Entity
expose :path, as: :login
end
class Repository < Grape::Entity
expose :id
expose :namespace, as: :owner, using: Namespace
expose :name
end
class BranchCommit < Grape::Entity
expose :id, as: :sha
expose :type do |model|
'commit'
end
end
class RepoCommit < Grape::Entity
expose :id, as: :sha
expose :author do |commit|
{
login: commit.author&.username,
email: commit.author_email
}
end
expose :committer do |commit|
{
login: commit.author&.username,
email: commit.committer_email
}
end
expose :commit do |commit|
# TODO: export to entity
{
author: {
name: commit.author_name,
email: commit.author_email,
date: commit.authored_date.iso8601,
type: 'User'
},
committer: {
name: commit.committer_name,
email: commit.committer_email,
date: commit.committed_date.iso8601,
type: 'User'
},
message: commit.safe_message
}
end
expose :parents do |commit|
# TODO: export to entity
commit.parent_ids.map { |id| { sha: id } }
end
expose :files do |commit|
[]
end
end
class Branch < Grape::Entity
expose :name
expose :commit, using: BranchCommit do |repo_branch, options|
options[:project].repository.commit(repo_branch.dereferenced_target)
end
end
end
end
end
module API module API
module V3 module V3
class GithubRepos < Grape::API class Github < Grape::API
before { authenticate! } before do
authenticate!
authorize_jira_user_agent!(request)
end
helpers do helpers do
params :project_full_path do params :project_full_path do
...@@ -9,6 +12,10 @@ module API ...@@ -9,6 +12,10 @@ module API
requires :project, type: String requires :project, type: String
end end
def authorize_jira_user_agent!(request)
not_found! unless Gitlab::Jira::Middleware.jira_dvcs_connector?(request.env)
end
def find_project_with_access(full_path) def find_project_with_access(full_path)
project = find_project!(full_path) project = find_project!(full_path)
not_found! unless project.feature_available?(:jira_dev_panel_integration) not_found! unless project.feature_available?(:jira_dev_panel_integration)
...@@ -32,7 +39,7 @@ module API ...@@ -32,7 +39,7 @@ module API
get ':namespace/repos' do get ':namespace/repos' do
projects = current_user.authorized_projects.select { |project| project.feature_available?(:jira_dev_panel_integration) } projects = current_user.authorized_projects.select { |project| project.feature_available?(:jira_dev_panel_integration) }
projects = ::Kaminari.paginate_array(projects) projects = ::Kaminari.paginate_array(projects)
present paginate(projects), with: ::API::Entities::Github::Repository present paginate(projects), with: ::API::Github::Entities::Repository
end end
end end
...@@ -51,9 +58,7 @@ module API ...@@ -51,9 +58,7 @@ module API
branches = ::Kaminari.paginate_array(user_project.repository.branches.sort_by(&:name)) branches = ::Kaminari.paginate_array(user_project.repository.branches.sort_by(&:name))
present paginate(branches), present paginate(branches), with: ::API::Github::Entities::Branch, project: user_project
with: ::API::Entities::Github::Branch,
project: user_project
end end
params do params do
...@@ -68,7 +73,7 @@ module API ...@@ -68,7 +73,7 @@ module API
not_found! 'Commit' unless commit not_found! 'Commit' unless commit
present commit, with: ::API::Entities::Github::RepoCommit present commit, with: ::API::Github::Entities::RepoCommit
end end
end end
end end
......
module Gitlab module Gitlab
module Jira module Jira
class Middleware class Middleware
def self.jira_dvcs_connector?(env)
env['HTTP_USER_AGENT']&.start_with?('JIRA DVCS Connector')
end
def initialize(app) def initialize(app)
@app = app @app = app
end end
def call(env) def call(env)
env['HTTP_AUTHORIZATION'].sub!('token', 'Bearer') if jira_dvcs_connector?(env) env['HTTP_AUTHORIZATION'].sub!('token', 'Bearer') if self.class.jira_dvcs_connector?(env)
@app.call(env) @app.call(env)
end end
private
def jira_dvcs_connector?(env)
/JIRA DVCS Connector/.match(env['HTTP_USER_AGENT'])
end
end end
end end
end end
...@@ -3,15 +3,24 @@ require 'spec_helper' ...@@ -3,15 +3,24 @@ require 'spec_helper'
describe Gitlab::Jira::Middleware do describe Gitlab::Jira::Middleware do
let(:app) { double(:app) } let(:app) { double(:app) }
let(:middleware) { described_class.new(app) } let(:middleware) { described_class.new(app) }
let(:jira_user_agent) { 'JIRA DVCS Connector Vertigo/5.0.0-D20170810T012915' }
describe '.jira_dvcs_connector?' do
it 'returns true when DVCS connector' do
expect(described_class.jira_dvcs_connector?('HTTP_USER_AGENT' => jira_user_agent)).to eq(true)
end
it 'returns false when not DVCS connector' do
expect(described_class.jira_dvcs_connector?('HTTP_USER_AGENT' => 'pokemon')).to eq(false)
end
end
describe '#call' do describe '#call' do
it 'adjusts HTTP_AUTHORIZATION env when request from JIRA DVCS user agent' do it 'adjusts HTTP_AUTHORIZATION env when request from JIRA DVCS user agent' do
user_agent = 'JIRA DVCS Connector Vertigo/5.0.0-D20170810T012915' expect(app).to receive(:call).with('HTTP_USER_AGENT' => jira_user_agent,
expect(app).to receive(:call).with('HTTP_USER_AGENT' => user_agent,
'HTTP_AUTHORIZATION' => 'Bearer hash-123') 'HTTP_AUTHORIZATION' => 'Bearer hash-123')
middleware.call('HTTP_USER_AGENT' => user_agent, 'HTTP_AUTHORIZATION' => 'token hash-123') middleware.call('HTTP_USER_AGENT' => jira_user_agent, 'HTTP_AUTHORIZATION' => 'token hash-123')
end end
it 'does not change HTTP_AUTHORIZATION env when request is not from JIRA DVCS user agent' do it 'does not change HTTP_AUTHORIZATION env when request is not from JIRA DVCS user agent' do
......
require 'spec_helper' require 'spec_helper'
describe API::V3::GithubRepos do describe API::V3::Github do
let(:user) { create(:user) } let(:user) { create(:user) }
let!(:project) { create(:project, :repository, creator: user) } let!(:project) { create(:project, :repository, creator: user) }
before do before do
allow(Gitlab::Jira::Middleware).to receive(:jira_dvcs_connector?) { true }
project.add_master(user) project.add_master(user)
end end
......
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