refactor(api): create api_token with validity and network filtering
This commit is contained in:
parent
943368c68f
commit
852eedbc50
3 changed files with 184 additions and 9 deletions
|
@ -3,11 +3,11 @@ class APITokensController < ApplicationController
|
|||
before_action :set_api_token, only: [:destroy]
|
||||
|
||||
def nom
|
||||
@name = params[:name]
|
||||
@name = name
|
||||
end
|
||||
|
||||
def autorisations
|
||||
@name = params[:name]
|
||||
@name = name
|
||||
@libelle_id_procedures = current_administrateur
|
||||
.procedures
|
||||
.order(:libelle)
|
||||
|
@ -21,7 +21,8 @@ class APITokensController < ApplicationController
|
|||
def create
|
||||
@api_token, @packed_token = APIToken.generate(current_administrateur)
|
||||
|
||||
render :index
|
||||
@api_token.update!(name:, write_access:,
|
||||
allowed_procedure_ids:, authorized_networks:, expires_at:)
|
||||
end
|
||||
|
||||
def destroy
|
||||
|
@ -32,19 +33,56 @@ class APITokensController < ApplicationController
|
|||
|
||||
private
|
||||
|
||||
def authorized_networks
|
||||
if params[:networkFiltering] == "customNetworks"
|
||||
networks
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def networks
|
||||
params[:networks]
|
||||
.split
|
||||
.map { begin IPAddr.new(_1) rescue nil end }
|
||||
.compact
|
||||
end
|
||||
|
||||
def set_api_token
|
||||
@api_token = current_administrateur.api_tokens.find(params[:id])
|
||||
end
|
||||
|
||||
def become_full_access?
|
||||
api_token_params[:become_full_access].present?
|
||||
def name
|
||||
params[:name]
|
||||
end
|
||||
|
||||
def disallow_procedure_id
|
||||
api_token_params[:disallow_procedure_id]
|
||||
def write_access
|
||||
params[:access] == "read_write"
|
||||
end
|
||||
|
||||
def api_token_params
|
||||
params.require(:api_token).permit(:name, :write_access, :become_full_access, :disallow_procedure_id, allowed_procedure_ids: [])
|
||||
def allowed_procedure_ids
|
||||
if params[:target] == "custom"
|
||||
current_administrateur
|
||||
.procedure_ids
|
||||
.intersection(params[:targets].map(&:to_i))
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def expires_at
|
||||
case params[:lifetime]
|
||||
in 'oneWeek'
|
||||
1.week.from_now.to_date
|
||||
in 'custom'
|
||||
[
|
||||
Date.parse(params[:customLifetime]),
|
||||
1.year.from_now
|
||||
].min
|
||||
in 'infinite' if authorized_networks.present?
|
||||
nil
|
||||
else
|
||||
1.week.from_now.to_date
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
40
app/views/api_tokens/create.html.haml
Normal file
40
app/views/api_tokens/create.html.haml
Normal file
|
@ -0,0 +1,40 @@
|
|||
- content_for :title, "jeton « #{@name} » créé"
|
||||
|
||||
= render partial: 'administrateurs/breadcrumbs',
|
||||
locals: { steps: [['Tableau de bord', tableau_de_bord_helper_path],
|
||||
[t('users.profil.show.profile'), profil_path],
|
||||
[t('api_tokens.nom.new_token')]] }
|
||||
|
||||
.fr-container.fr-mt-2w
|
||||
%h1 Votre jeton est prêt
|
||||
|
||||
%p
|
||||
Vous pouvez maintenant utiliser votre jeton pour accéder à vos données.<br />
|
||||
%b Attention, vous ne pourrez plus le consulter après avoir quitté cette page.
|
||||
|
||||
%p{ data: { controller: 'clipboard', clipboard_text_value: @packed_token } }
|
||||
%code= @packed_token
|
||||
%button.fr-btn.fr-btn-primary.fr-btn-small.fr-ml-2w{ data: { action: 'clipboard#copy' }, title: 'Copier dans le presse-papier' } Copier
|
||||
|
||||
%p.fr-mt-4w Résumé des informations du jeton :
|
||||
%ul
|
||||
%li
|
||||
%strong Nom du jeton :
|
||||
#{@api_token.name}
|
||||
%li
|
||||
%strong Accès :
|
||||
#{@api_token.write_access? ? 'lecture et écriture' : 'lecture'}
|
||||
%li
|
||||
%strong Démarches :
|
||||
= @api_token.full_access? ? 'toutes' : @api_token.procedures.map(&:libelle).join(', ')
|
||||
%li
|
||||
%strong Réseaux autorisés :
|
||||
= @api_token.authorized_networks.empty? ? 'tout internet' : @api_token.authorized_networks_for_ui
|
||||
%li
|
||||
%strong Date de fin de validité :
|
||||
- if @api_token.expires_at.present?
|
||||
%span= l(@api_token.expires_at, format: :long)
|
||||
- else
|
||||
%span aucune
|
||||
|
||||
= link_to 'Retour au profil', profil_path, class: 'fr-btn fr-btn--secondary fr-mt-2w'
|
97
spec/controllers/api_tokens_controller_spec.rb
Normal file
97
spec/controllers/api_tokens_controller_spec.rb
Normal file
|
@ -0,0 +1,97 @@
|
|||
describe APITokensController, type: :controller do
|
||||
let(:admin) { create(:administrateur) }
|
||||
let(:procedure) { create(:procedure, administrateur: admin) }
|
||||
|
||||
before { sign_in(admin.user) }
|
||||
|
||||
before { Timecop.freeze(Time.zone.local(2020, 1, 1, 12, 0, 0)) }
|
||||
after { Timecop.return }
|
||||
|
||||
describe 'create' do
|
||||
let(:default_params) do
|
||||
{
|
||||
name: 'Test',
|
||||
access: 'read_write',
|
||||
target: 'all',
|
||||
lifetime: 'oneWeek'
|
||||
}
|
||||
end
|
||||
let(:token) { APIToken.last }
|
||||
|
||||
subject { post :create, params: }
|
||||
|
||||
before { subject }
|
||||
|
||||
context 'with write access, no filtering, one week' do
|
||||
let(:params) { default_params }
|
||||
|
||||
it 'creates a token' do
|
||||
expect(token.name).to eq('Test')
|
||||
expect(token.write_access?).to be true
|
||||
expect(token.full_access?).to be true
|
||||
expect(token.authorized_networks).to be_blank
|
||||
expect(token.expires_at).to eq(1.week.from_now.to_date)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with read access' do
|
||||
let(:params) { default_params.merge(access: 'read') }
|
||||
|
||||
it { expect(token.write_access?).to be false }
|
||||
end
|
||||
|
||||
context 'without network filtering but requiring infinite lifetime' do
|
||||
let(:params) { default_params.merge(lifetime: 'infinite') }
|
||||
|
||||
it { expect(token.expires_at).to eq(1.week.from_now.to_date) }
|
||||
end
|
||||
|
||||
context 'with bad network and infinite lifetime' do
|
||||
let(:networks) { 'bad' }
|
||||
let(:params) { default_params.merge(networkFiltering: 'customNetworks', networks:) }
|
||||
|
||||
it do
|
||||
expect(token.authorized_networks).to be_blank
|
||||
expect(token.expires_at).to eq(1.week.from_now.to_date)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with network filtering' do
|
||||
let(:networks) { '192.168.1.23/32 2001:41d0:304:400::52f/128 bad' }
|
||||
let(:params) { default_params.merge(restriction: 'customNetworks', networks: ) }
|
||||
|
||||
it {
|
||||
expect(token.authorized_networks).to eq([
|
||||
IPAddr.new('192.168.1.23/32'),
|
||||
IPAddr.new('2001:41d0:304:400::52f/128')
|
||||
])
|
||||
}
|
||||
end
|
||||
|
||||
context 'with network filtering and infinite lifetime' do
|
||||
let(:networks) { '192.168.1.23/32 2001:41d0:304:400::52f/128' }
|
||||
let(:params) { default_params.merge(networkFiltering: 'customNetworks', networks:, lifetime: 'infinite') }
|
||||
|
||||
it { expect(token.expires_at).to eq(nil) }
|
||||
end
|
||||
|
||||
context 'with procedure filtering' do
|
||||
let(:params) { default_params.merge(target: 'custom', targets: [procedure.id]) }
|
||||
|
||||
it do
|
||||
expect(token.allowed_procedure_ids).to eq([procedure.id])
|
||||
expect(token.full_access?).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'with procedure filtering on a procedure not owned by the admin' do
|
||||
let(:another_procedure) { create(:procedure) }
|
||||
let(:params) { default_params.merge(target: 'custom', targets: [another_procedure.id]) }
|
||||
|
||||
it do
|
||||
expect(token.allowed_procedure_ids).to eq([])
|
||||
expect(token.full_access?).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue