2019-08-22 06:57:44 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2017-06-02 12:28:54 -04:00
|
|
|
require 'spec_helper'
|
|
|
|
|
2020-06-24 14:09:03 -04:00
|
|
|
RSpec.describe Gitlab::OtpKeyRotator do
|
2017-06-02 12:28:54 -04:00
|
|
|
let(:file) { Tempfile.new("otp-key-rotator-test") }
|
|
|
|
let(:filename) { file.path }
|
|
|
|
let(:old_key) { Gitlab::Application.secrets.otp_key_base }
|
|
|
|
let(:new_key) { "00" * 32 }
|
|
|
|
let!(:users) { create_list(:user, 5, :two_factor) }
|
|
|
|
|
|
|
|
after do
|
|
|
|
file.close
|
|
|
|
file.unlink
|
|
|
|
end
|
|
|
|
|
|
|
|
def data
|
|
|
|
CSV.read(filename)
|
|
|
|
end
|
|
|
|
|
|
|
|
def build_row(user, applied = false)
|
|
|
|
[user.id.to_s, encrypt_otp(user, old_key), encrypt_otp(user, new_key)]
|
|
|
|
end
|
|
|
|
|
|
|
|
def encrypt_otp(user, key)
|
|
|
|
opts = {
|
|
|
|
value: user.otp_secret,
|
|
|
|
iv: user.encrypted_otp_secret_iv.unpack("m").join,
|
|
|
|
salt: user.encrypted_otp_secret_salt.unpack("m").join,
|
|
|
|
algorithm: 'aes-256-cbc',
|
|
|
|
insecure_mode: true,
|
|
|
|
key: key
|
|
|
|
}
|
|
|
|
[Encryptor.encrypt(opts)].pack("m")
|
|
|
|
end
|
|
|
|
|
|
|
|
subject(:rotator) { described_class.new(filename) }
|
|
|
|
|
|
|
|
describe '#rotate!' do
|
|
|
|
subject(:rotation) { rotator.rotate!(old_key: old_key, new_key: new_key) }
|
|
|
|
|
|
|
|
it 'stores the calculated values in a spreadsheet' do
|
|
|
|
rotation
|
|
|
|
|
2022-08-01 23:09:33 -04:00
|
|
|
expect(data).to match_array(users.map { |u| build_row(u) })
|
2017-06-02 12:28:54 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
context 'new key is too short' do
|
|
|
|
let(:new_key) { "00" * 31 }
|
|
|
|
|
|
|
|
it { expect { rotation }.to raise_error(ArgumentError) }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'new key is the same as the old key' do
|
|
|
|
let(:new_key) { old_key }
|
|
|
|
|
|
|
|
it { expect { rotation }.to raise_error(ArgumentError) }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#rollback!' do
|
|
|
|
it 'updates rows to the old value' do
|
|
|
|
file.puts("#{users[0].id},old,new")
|
|
|
|
file.close
|
|
|
|
|
|
|
|
rotator.rollback!
|
|
|
|
|
|
|
|
expect(users[0].reload.encrypted_otp_secret).to eq('old')
|
|
|
|
expect(users[1].reload.encrypted_otp_secret).not_to eq('old')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|