refactor(api): create api_token with validity and network filtering

This commit is contained in:
simon lehericey 2024-01-17 11:11:38 +01:00
parent 943368c68f
commit 852eedbc50
3 changed files with 184 additions and 9 deletions

View file

@ -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

View 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'

View 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