Commit f1a74a65 authored by Grzegorz Bizon's avatar Grzegorz Bizon

Encrypt new instance runners registration tokens

parent 9a830f1e
......@@ -7,7 +7,7 @@ class ApplicationSetting < ActiveRecord::Base
include IgnorableColumn
include ChronicDurationAttribute
add_authentication_token_field :runners_registration_token
add_authentication_token_field :runners_registration_token, encrypted: true, fallback: true
add_authentication_token_field :health_check_access_token
DOMAIN_LIST_SEPARATOR = %r{\s*[,;]\s* # comma or semicolon, optionally surrounded by whitespace
......
......@@ -9,7 +9,7 @@ module TokenAuthenticatable
private # rubocop:disable Lint/UselessAccessModifier
def add_authentication_token_field(token_field, options = {})
@token_fields = [] unless @token_fields
@token_fields ||= []
unique = options.fetch(:unique, true)
if @token_fields.include?(token_field)
......@@ -22,6 +22,8 @@ module TokenAuthenticatable
strategy = if options[:digest]
TokenAuthenticatableStrategies::Digest.new(self, token_field, options)
elsif options[:encrypted]
TokenAuthenticatableStrategies::Encrypted.new(self, token_field, options)
else
TokenAuthenticatableStrategies::Insecure.new(self, token_field, options)
end
......
......@@ -24,6 +24,7 @@ module TokenAuthenticatableStrategies
def ensure_token(instance)
write_new_token(instance) unless token_set?(instance)
get_token(instance)
end
# Returns a token, but only saves when the database is in read & write mode
......
......@@ -28,6 +28,7 @@ module TokenAuthenticatableStrategies
raise ArgumentError unless token.present?
instance[encrypted_field] = Gitlab::CryptoHelper.aes256_gcm_encrypt(token)
token
end
protected
......
# frozen_string_literal: true
class AddEncryptedRunnersTokenToSettings < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :application_settings, :runners_registration_token_encrypted, :string
end
end
......@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20181107054254) do
ActiveRecord::Schema.define(version: 20181115140140) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......@@ -167,6 +167,7 @@ ActiveRecord::Schema.define(version: 20181107054254) do
t.integer "diff_max_patch_bytes", default: 102400, null: false
t.integer "archive_builds_in_seconds"
t.string "commit_email_hostname"
t.string "runners_registration_token_encrypted"
end
create_table "audit_events", force: :cascade do |t|
......
......@@ -21,44 +21,59 @@ end
describe ApplicationSetting, 'TokenAuthenticatable' do
let(:token_field) { :runners_registration_token }
let(:settings) { described_class.new }
it_behaves_like 'TokenAuthenticatable'
describe 'generating new token' do
context 'token is not generated yet' do
describe 'token field accessor' do
subject { described_class.new.send(token_field) }
subject { settings.send(token_field) }
it { is_expected.not_to be_blank }
end
describe 'ensured token' do
subject { described_class.new.send("ensure_#{token_field}") }
describe "ensure_runners_registration_token" do
subject { settings.send("ensure_#{token_field}") }
it { is_expected.to be_a String }
it { is_expected.not_to be_blank }
it 'does not persist token' do
expect(settings).not_to be_persisted
end
end
describe 'ensured! token' do
subject { described_class.new.send("ensure_#{token_field}!") }
describe 'ensure_runners_registration_token!' do
subject { settings.send("ensure_#{token_field}!") }
it 'persists new token as an encrypted string' do
expect(subject).to eq settings.reload.runners_registration_token
expect(settings.read_attribute('runners_registration_token_encrypted'))
.to eq Gitlab::CryptoHelper.aes256_gcm_encrypt(subject)
expect(settings).to be_persisted
end
it 'persists new token' do
expect(subject).to eq described_class.current[token_field]
it 'does not persist token in a clear text' do
expect(subject).not_to eq settings.reload
.read_attribute('runners_registration_token_encrypted')
end
end
end
context 'token is generated' do
before do
subject.send("reset_#{token_field}!")
settings.send("reset_#{token_field}!")
end
it 'persists a new token' do
expect(subject.send(:read_attribute, token_field)).to be_a String
expect(settings.runners_registration_token).to be_a String
end
end
end
describe 'setting new token' do
subject { described_class.new.send("set_#{token_field}", '0123456789') }
subject { settings.send("set_#{token_field}", '0123456789') }
it { is_expected.to eq '0123456789' }
end
......
......@@ -60,11 +60,11 @@ describe TokenAuthenticatableStrategies::Encrypted do
end
describe '#set_token' do
it 'writes encrypted token to a model instance' do
it 'writes encrypted token to a model instance and returns it' do
expect(instance).to receive(:[]=)
.with('some_field_encrypted', encrypted)
subject.set_token(instance, 'my-value')
expect(subject.set_token(instance, 'my-value')).to eq 'my-value'
end
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