Api Token: store token in an encrypted form

This commit is contained in:
simon lehericey 2018-08-24 16:45:43 +02:00
parent 1997f45d7e
commit 8c4f8347ca
7 changed files with 34 additions and 13 deletions

View file

@ -61,6 +61,7 @@ gem 'fog-openstack'
gem 'pg' gem 'pg'
gem 'rbnacl-libsodium' gem 'rbnacl-libsodium'
gem 'bcrypt'
gem 'rgeo-geojson' gem 'rgeo-geojson'
gem 'leaflet-rails' gem 'leaflet-rails'

View file

@ -812,6 +812,7 @@ DEPENDENCIES
after_party after_party
apipie-rails apipie-rails
axlsx (~> 3.0.0.pre) axlsx (~> 3.0.0.pre)
bcrypt
bootstrap-sass (~> 3.3.5) bootstrap-sass (~> 3.3.5)
bootstrap-wysihtml5-rails (~> 0.3.3.8) bootstrap-wysihtml5-rails (~> 0.3.3.8)
brakeman brakeman

View file

@ -4,8 +4,7 @@ module NewAdministrateur
end end
def renew_api_token def renew_api_token
current_administrateur.renew_api_token @token = current_administrateur.renew_api_token
@token = current_administrateur.api_token
flash.now.notice = 'Votre jeton a été regénéré.' flash.now.notice = 'Votre jeton a été regénéré.'
render :show render :show
end end

View file

@ -1,6 +1,7 @@
class Administrateur < ApplicationRecord class Administrateur < ApplicationRecord
include CredentialsSyncableConcern include CredentialsSyncableConcern
include EmailSanitizableConcern include EmailSanitizableConcern
include ActiveRecord::SecureToken
devise :database_authenticatable, :registerable, :async, devise :database_authenticatable, :registerable, :async,
:recoverable, :rememberable, :trackable, :validatable :recoverable, :rememberable, :trackable, :validatable
@ -36,7 +37,10 @@ class Administrateur < ApplicationRecord
end end
def renew_api_token def renew_api_token
update(api_token: generate_api_token) api_token = Administrateur.generate_unique_secure_token
encrypted_token = BCrypt::Password.create(api_token)
update(api_token: api_token, encrypted_token: encrypted_token)
api_token
end end
def registration_state def registration_state
@ -109,13 +113,4 @@ class Administrateur < ApplicationRecord
def owns?(procedure) def owns?(procedure)
id == procedure.administrateur_id id == procedure.administrateur_id
end end
private
def generate_api_token
loop do
token = SecureRandom.hex(20)
break token if !Administrateur.find_by(api_token: token)
end
end
end end

View file

@ -0,0 +1,5 @@
class AddEncryptedTokenColumnToAdministrateur < ActiveRecord::Migration[5.2]
def change
add_column :administrateurs, :encrypted_token, :string
end
end

View file

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2018_09_24_074121) do ActiveRecord::Schema.define(version: 2018_09_25_084403) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -53,6 +53,7 @@ ActiveRecord::Schema.define(version: 2018_09_24_074121) do
t.string "api_token" t.string "api_token"
t.boolean "active", default: false t.boolean "active", default: false
t.jsonb "features", default: {}, null: false t.jsonb "features", default: {}, null: false
t.string "encrypted_token"
t.index ["email"], name: "index_administrateurs_on_email", unique: true t.index ["email"], name: "index_administrateurs_on_email", unique: true
t.index ["reset_password_token"], name: "index_administrateurs_on_reset_password_token", unique: true t.index ["reset_password_token"], name: "index_administrateurs_on_reset_password_token", unique: true
end end

View file

@ -32,6 +32,25 @@ describe Administrateur, type: :model do
end end
end end
describe "#renew_api_token" do
let(:administrateur) { create(:administrateur) }
before do
administrateur.renew_api_token
administrateur.reload
end
it { expect(administrateur.api_token).to be_present }
it { expect(administrateur.api_token).not_to eq(administrateur.encrypted_token) }
it { expect(BCrypt::Password.new(administrateur.encrypted_token)).to eq(administrateur.api_token) }
context 'when it s called twice' do
let!(:previous_token) { administrateur.api_token }
it { expect(previous_token).not_to eq(administrateur.renew_api_token) }
end
end
describe '#find_inactive_by_token' do describe '#find_inactive_by_token' do
let(:administrateur) { create(:administration).invite_admin('paul@tps.fr') } let(:administrateur) { create(:administration).invite_admin('paul@tps.fr') }
let(:reset_password_token) { administrateur.invite!(administration.id) } let(:reset_password_token) { administrateur.invite!(administration.id) }