Skip to content
Snippets Groups Projects
Commit 426716d1 authored by Yorick Peterse's avatar Yorick Peterse
Browse files

Merge branch 'security-pipeline-trigger-tokens-exposure-11-4' into 'security-11-4'

[11.4] Do not expose trigger token when user should not see it

See merge request gitlab/gitlabhq!2761

(cherry picked from commit bc660b08642de2a68e39a443566e7665f057a0a8)

1b81cbce Do not expose trigger token when user should not see it
parent c69471c7
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -99,7 +99,9 @@ module Projects
 
def define_triggers_variables
@triggers = @project.triggers
.present(current_user: current_user)
@trigger = ::Ci::Trigger.new
.present(current_user: current_user)
end
 
def define_badges_variables
Loading
Loading
Loading
Loading
@@ -66,12 +66,11 @@ class Projects::TriggersController < Projects::ApplicationController
end
 
def trigger
@trigger ||= project.triggers.find(params[:id]) || render_404
@trigger ||= project.triggers.find(params[:id])
.present(current_user: current_user)
end
 
def trigger_params
params.require(:trigger).permit(
:description
)
params.require(:trigger).permit(:description)
end
end
Loading
Loading
@@ -4,6 +4,7 @@ module Ci
class Trigger < ActiveRecord::Base
extend Gitlab::Ci::Model
include IgnorableColumn
include Presentable
 
ignore_column :deleted_at
 
Loading
Loading
@@ -29,7 +30,7 @@ module Ci
end
 
def short_token
token[0...4]
token[0...4] if token.present?
end
 
def legacy?
Loading
Loading
# frozen_string_literal: true
module Ci
class TriggerPresenter < Gitlab::View::Presenter::Delegated
presents :trigger
def has_token_exposed?
can?(current_user, :admin_trigger, trigger)
end
def token
if has_token_exposed?
trigger.token
else
trigger.short_token
end
end
end
end
%tr
%td
- if can?(current_user, :admin_trigger, trigger)
- if trigger.has_token_exposed?
%span= trigger.token
= clipboard_button(text: trigger.token, title: "Copy trigger token to clipboard")
- else
Loading
Loading
---
title: Expose CI/CD trigger token only to the trigger owner
merge_request:
author:
type: security
Loading
Loading
@@ -1161,8 +1161,11 @@ module API
end
 
class Trigger < Grape::Entity
include ::API::Helpers::Presentable
expose :id
expose :token, :description
expose :token
expose :description
expose :created_at, :updated_at, :last_used
expose :owner, using: Entities::UserBasic
end
Loading
Loading
# frozen_string_literal: true
module API
module Helpers
##
# This module makes it possible to use `app/presenters` with
# Grape Entities. It instantiates model presenter and passes
# options defined in the API endpoint to the presenter itself.
#
# present object, with: Entities::Something,
# current_user: current_user,
# another_option: 'my options'
#
# Example above will make `current_user` and `another_option`
# values available in the subclass of `Gitlab::View::Presenter`
# thorough a separate method in the presenter.
#
# The model class needs to have `::Presentable` module mixed in
# if you want to use `API::Helpers::Presentable`.
#
module Presentable
extend ActiveSupport::Concern
def initialize(object, options = {})
super(object.present(options), options)
end
end
end
end
Loading
Loading
@@ -51,7 +51,7 @@ module API
 
triggers = user_project.triggers.includes(:trigger_requests)
 
present paginate(triggers), with: Entities::Trigger
present paginate(triggers), with: Entities::Trigger, current_user: current_user
end
# rubocop: enable CodeReuse/ActiveRecord
 
Loading
Loading
@@ -68,7 +68,7 @@ module API
trigger = user_project.triggers.find(params.delete(:trigger_id))
break not_found!('Trigger') unless trigger
 
present trigger, with: Entities::Trigger
present trigger, with: Entities::Trigger, current_user: current_user
end
 
desc 'Create a trigger' do
Loading
Loading
@@ -85,7 +85,7 @@ module API
declared_params(include_missing: false).merge(owner: current_user))
 
if trigger.valid?
present trigger, with: Entities::Trigger
present trigger, with: Entities::Trigger, current_user: current_user
else
render_validation_error!(trigger)
end
Loading
Loading
@@ -106,7 +106,7 @@ module API
break not_found!('Trigger') unless trigger
 
if trigger.update(declared_params(include_missing: false))
present trigger, with: Entities::Trigger
present trigger, with: Entities::Trigger, current_user: current_user
else
render_validation_error!(trigger)
end
Loading
Loading
@@ -127,7 +127,7 @@ module API
 
if trigger.update(owner: current_user)
status :ok
present trigger, with: Entities::Trigger
present trigger, with: Entities::Trigger, current_user: current_user
else
render_validation_error!(trigger)
end
Loading
Loading
require 'spec_helper'
describe Ci::TriggerPresenter do
set(:user) { create(:user) }
set(:project) { create(:project) }
set(:trigger) do
create(:ci_trigger, token: '123456789abcd', project: project)
end
subject do
described_class.new(trigger, current_user: user)
end
before do
project.add_maintainer(user)
end
context 'when user is not a trigger owner' do
describe '#token' do
it 'exposes only short token' do
expect(subject.token).not_to eq trigger.token
expect(subject.token).to eq '1234'
end
end
describe '#has_token_exposed?' do
it 'does not have token exposed' do
expect(subject).not_to have_token_exposed
end
end
end
context 'when user is a trigger owner and builds admin' do
before do
trigger.update(owner: user)
end
describe '#token' do
it 'exposes full token' do
expect(subject.token).to eq trigger.token
end
end
describe '#has_token_exposed?' do
it 'has token exposed' do
expect(subject).to have_token_exposed
end
end
end
end
require 'spec_helper'
 
describe API::Triggers do
let(:user) { create(:user) }
let(:user2) { create(:user) }
set(:user) { create(:user) }
set(:user2) { create(:user) }
let!(:trigger_token) { 'secure_token' }
let!(:trigger_token_2) { 'secure_token_2' }
let!(:project) { create(:project, :repository, creator: user) }
Loading
Loading
@@ -132,14 +133,17 @@ describe API::Triggers do
end
 
describe 'GET /projects/:id/triggers' do
context 'authenticated user with valid permissions' do
it 'returns list of triggers' do
context 'authenticated user who can access triggers' do
it 'returns a list of triggers with tokens exposed correctly' do
get api("/projects/#{project.id}/triggers", user)
 
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to be_a(Array)
expect(json_response[0]).to have_key('token')
expect(json_response.size).to eq 2
expect(json_response.dig(0, 'token')).to eq trigger_token
expect(json_response.dig(1, 'token')).to eq trigger_token_2[0..3]
end
end
 
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment