merge with an existing account by using the password
This commit is contained in:
parent
218e4633a9
commit
19f81b594b
8 changed files with 153 additions and 14 deletions
|
@ -85,6 +85,10 @@ class ApplicationController < ActionController::Base
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def ajax_redirect(path)
|
||||||
|
"window.location.href='#{path}'"
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def feature_enabled?(feature_name)
|
def feature_enabled?(feature_name)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
class FranceConnect::ParticulierController < ApplicationController
|
class FranceConnect::ParticulierController < ApplicationController
|
||||||
before_action :redirect_to_login_if_fc_aborted, only: [:callback]
|
before_action :redirect_to_login_if_fc_aborted, only: [:callback]
|
||||||
before_action :securely_retrieve_fci, only: [:merge]
|
before_action :securely_retrieve_fci, only: [:merge, :merge_with_existing_account]
|
||||||
|
|
||||||
def login
|
def login
|
||||||
if FranceConnectService.enabled?
|
if FranceConnectService.enabled?
|
||||||
|
@ -41,6 +41,28 @@ class FranceConnect::ParticulierController < ApplicationController
|
||||||
def merge
|
def merge
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def merge_with_existing_account
|
||||||
|
user = User.find_by(email: sanitized_email_params)
|
||||||
|
|
||||||
|
if user.valid_for_authentication? { user.valid_password?(password_params) }
|
||||||
|
if !user.can_france_connect?
|
||||||
|
flash.alert = "#{user.email} ne peut utiliser FranceConnect"
|
||||||
|
|
||||||
|
render js: ajax_redirect(root_path)
|
||||||
|
else
|
||||||
|
@fci.update(user: user)
|
||||||
|
@fci.delete_merge_token!
|
||||||
|
|
||||||
|
flash.notice = "Les comptes FranceConnect et #{APPLICATION_NAME} sont à présent fusionnés"
|
||||||
|
connect_france_connect_particulier(user)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
flash.alert = 'Mauvais mot de passe'
|
||||||
|
|
||||||
|
render js: helpers.render_flash
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def securely_retrieve_fci
|
def securely_retrieve_fci
|
||||||
|
@ -49,7 +71,10 @@ class FranceConnect::ParticulierController < ApplicationController
|
||||||
if @fci.nil? || !@fci.valid_for_merge?
|
if @fci.nil? || !@fci.valid_for_merge?
|
||||||
flash.alert = 'Votre compte FranceConnect a expiré, veuillez recommencer.'
|
flash.alert = 'Votre compte FranceConnect a expiré, veuillez recommencer.'
|
||||||
|
|
||||||
redirect_to root_path
|
respond_to do |format|
|
||||||
|
format.html { redirect_to root_path }
|
||||||
|
format.js { render js: ajax_redirect(root_path) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -68,7 +93,12 @@ class FranceConnect::ParticulierController < ApplicationController
|
||||||
|
|
||||||
user.update_attribute('loged_in_with_france_connect', User.loged_in_with_france_connects.fetch(:particulier))
|
user.update_attribute('loged_in_with_france_connect', User.loged_in_with_france_connects.fetch(:particulier))
|
||||||
|
|
||||||
redirect_to stored_location_for(current_user) || root_path(current_user)
|
redirection_location = stored_location_for(current_user) || root_path(current_user)
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.html { redirect_to redirection_location }
|
||||||
|
format.js { render js: ajax_redirect(root_path) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def redirect_france_connect_error_connection
|
def redirect_france_connect_error_connection
|
||||||
|
@ -79,4 +109,12 @@ class FranceConnect::ParticulierController < ApplicationController
|
||||||
def merge_token_params
|
def merge_token_params
|
||||||
params[:merge_token]
|
params[:merge_token]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def password_params
|
||||||
|
params[:password]
|
||||||
|
end
|
||||||
|
|
||||||
|
def sanitized_email_params
|
||||||
|
params[:email]&.gsub(/[[:space:]]/, ' ')&.strip&.downcase
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
5
app/javascript/new_design/fc-fusion.js
Normal file
5
app/javascript/new_design/fc-fusion.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { show, hide } from '@utils';
|
||||||
|
|
||||||
|
export function showFusion() {
|
||||||
|
show(document.querySelector('.fusion'));
|
||||||
|
}
|
|
@ -41,6 +41,9 @@ import {
|
||||||
acceptEmailSuggestion,
|
acceptEmailSuggestion,
|
||||||
discardEmailSuggestionBox
|
discardEmailSuggestionBox
|
||||||
} from '../new_design/user-sign_up';
|
} from '../new_design/user-sign_up';
|
||||||
|
import {
|
||||||
|
showFusion
|
||||||
|
} from '../new_design/fc-fusion';
|
||||||
|
|
||||||
// This is the global application namespace where we expose helpers used from rails views
|
// This is the global application namespace where we expose helpers used from rails views
|
||||||
const DS = {
|
const DS = {
|
||||||
|
@ -49,6 +52,7 @@ const DS = {
|
||||||
showMotivation,
|
showMotivation,
|
||||||
motivationCancel,
|
motivationCancel,
|
||||||
showImportJustificatif,
|
showImportJustificatif,
|
||||||
|
showFusion,
|
||||||
replaceSemicolonByComma,
|
replaceSemicolonByComma,
|
||||||
acceptEmailSuggestion,
|
acceptEmailSuggestion,
|
||||||
discardEmailSuggestionBox
|
discardEmailSuggestionBox
|
||||||
|
|
|
@ -52,4 +52,8 @@ class FranceConnectInformation < ApplicationRecord
|
||||||
def valid_for_merge?
|
def valid_for_merge?
|
||||||
(MERGE_VALIDITY.ago < merge_token_created_at) && user_id.nil?
|
(MERGE_VALIDITY.ago < merge_token_created_at) && user_id.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def delete_merge_token!
|
||||||
|
update(merge_token: nil, merge_token_created_at: nil)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,3 +10,24 @@
|
||||||
Votre compte FranceConnect utilise <b class='bold'>#{@fci.email_france_connect}</b> comme email de contact.
|
Votre compte FranceConnect utilise <b class='bold'>#{@fci.email_france_connect}</b> comme email de contact.
|
||||||
%br
|
%br
|
||||||
Or il existe un compte sur #{APPLICATION_NAME} avec cet email.
|
Or il existe un compte sur #{APPLICATION_NAME} avec cet email.
|
||||||
|
|
||||||
|
.form.mt-2
|
||||||
|
%label Ce compte #{@fci.email_france_connect} vous appartient-il ?
|
||||||
|
%fieldset.radios
|
||||||
|
%label{ onclick: "DS.showFusion(event);" }
|
||||||
|
= radio_button_tag :value, true, false, autocomplete: "off"
|
||||||
|
Oui
|
||||||
|
|
||||||
|
%label
|
||||||
|
= radio_button_tag :value, false, false, autocomplete: "off"
|
||||||
|
Non
|
||||||
|
|
||||||
|
.fusion.hidden
|
||||||
|
%p Pour les fusionner, entrez votre mot de passe
|
||||||
|
|
||||||
|
= form_tag france_connect_particulier_merge_with_existing_account_path, remote: true, class: 'mt-2 form' do
|
||||||
|
= hidden_field_tag :merge_token, @fci.merge_token
|
||||||
|
= hidden_field_tag :email, @fci.email_france_connect
|
||||||
|
= label_tag :password, 'Mot de passe (8 caractères minimum)'
|
||||||
|
= password_field_tag :password, nil, autocomplete: 'current-password'
|
||||||
|
= submit_tag 'Fusionner les comptes', class: 'button primary'
|
||||||
|
|
|
@ -125,6 +125,7 @@ Rails.application.routes.draw do
|
||||||
get 'particulier' => 'particulier#login'
|
get 'particulier' => 'particulier#login'
|
||||||
get 'particulier/callback' => 'particulier#callback'
|
get 'particulier/callback' => 'particulier#callback'
|
||||||
get 'particulier/merge/:merge_token' => 'particulier#merge', as: :particulier_merge
|
get 'particulier/merge/:merge_token' => 'particulier#merge', as: :particulier_merge
|
||||||
|
post 'particulier/merge_with_existing_account' => 'particulier#merge_with_existing_account'
|
||||||
end
|
end
|
||||||
|
|
||||||
namespace :champs do
|
namespace :champs do
|
||||||
|
|
|
@ -136,16 +136,7 @@ describe FranceConnect::ParticulierController, type: :controller do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#merge' do
|
RSpec.shared_examples "a method that needs a valid merge token" do
|
||||||
let(:fci) { FranceConnectInformation.create!(user_info) }
|
|
||||||
let(:merge_token) { fci.create_merge_token! }
|
|
||||||
|
|
||||||
subject { get :merge, params: { merge_token: merge_token } }
|
|
||||||
|
|
||||||
context 'when the merge token is valid' do
|
|
||||||
it { expect(subject).to have_http_status(:ok) }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the merge token is invalid' do
|
context 'when the merge token is invalid' do
|
||||||
before do
|
before do
|
||||||
merge_token
|
merge_token
|
||||||
|
@ -153,10 +144,29 @@ describe FranceConnect::ParticulierController, type: :controller do
|
||||||
end
|
end
|
||||||
|
|
||||||
it do
|
it do
|
||||||
expect(subject).to redirect_to root_path
|
if format == :js
|
||||||
|
subject
|
||||||
|
expect(response.body).to eq("window.location.href='/'")
|
||||||
|
else
|
||||||
|
expect(subject).to redirect_to root_path
|
||||||
|
end
|
||||||
expect(flash.alert).to eq('Votre compte FranceConnect a expiré, veuillez recommencer.')
|
expect(flash.alert).to eq('Votre compte FranceConnect a expiré, veuillez recommencer.')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#merge' do
|
||||||
|
let(:fci) { FranceConnectInformation.create!(user_info) }
|
||||||
|
let(:merge_token) { fci.create_merge_token! }
|
||||||
|
let(:format) { :html }
|
||||||
|
|
||||||
|
subject { get :merge, params: { merge_token: merge_token } }
|
||||||
|
|
||||||
|
context 'when the merge token is valid' do
|
||||||
|
it { expect(subject).to have_http_status(:ok) }
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like "a method that needs a valid merge token"
|
||||||
|
|
||||||
context 'when the merge token does not exist' do
|
context 'when the merge token does not exist' do
|
||||||
let(:merge_token) { 'i do not exist' }
|
let(:merge_token) { 'i do not exist' }
|
||||||
|
@ -167,4 +177,56 @@ describe FranceConnect::ParticulierController, type: :controller do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#merge_with_existing_account' do
|
||||||
|
let(:fci) { FranceConnectInformation.create!(user_info) }
|
||||||
|
let(:merge_token) { fci.create_merge_token! }
|
||||||
|
let(:email) { 'EXISTING_account@a.com ' }
|
||||||
|
let(:password) { 'my-s3cure-p4ssword' }
|
||||||
|
let(:format) { :js }
|
||||||
|
|
||||||
|
subject { post :merge_with_existing_account, params: { merge_token: merge_token, email: email, password: password }, format: format }
|
||||||
|
|
||||||
|
it_behaves_like "a method that needs a valid merge token"
|
||||||
|
|
||||||
|
context 'when the credentials are ok' do
|
||||||
|
let!(:user) { create(:user, email: email, password: password) }
|
||||||
|
|
||||||
|
it 'merges the account, signs in, and delete the merge token' do
|
||||||
|
subject
|
||||||
|
fci.reload
|
||||||
|
|
||||||
|
expect(fci.user).to eq(user)
|
||||||
|
expect(fci.merge_token).to be_nil
|
||||||
|
expect(controller.current_user).to eq(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'but the targeted user is an instructeur' do
|
||||||
|
let!(:user) { create(:instructeur, email: email, password: password).user }
|
||||||
|
|
||||||
|
it 'redirects to the root page' do
|
||||||
|
subject
|
||||||
|
fci.reload
|
||||||
|
|
||||||
|
expect(fci.user).to be_nil
|
||||||
|
expect(fci.merge_token).not_to be_nil
|
||||||
|
expect(controller.current_user).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the credentials are not ok' do
|
||||||
|
let!(:user) { create(:user, email: email, password: 'another password #$21$%%') }
|
||||||
|
|
||||||
|
it 'increases the failed attempts counter' do
|
||||||
|
subject
|
||||||
|
fci.reload
|
||||||
|
|
||||||
|
expect(fci.user).to be_nil
|
||||||
|
expect(fci.merge_token).not_to be_nil
|
||||||
|
expect(controller.current_user).to be_nil
|
||||||
|
expect(user.reload.failed_attempts).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue