diff --git a/.gitignore b/.gitignore index b14ef0756..3d0bb1b25 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ config/initializers/token.rb config/initializers/super_admin.rb doc/*.svg config/france_connect.yml +config/github_secrets.yml config/initializers/mailjet.rb config/fog_credentials.yml uploads/* diff --git a/Gemfile b/Gemfile index fec62ee7f..00e2af737 100644 --- a/Gemfile +++ b/Gemfile @@ -44,6 +44,7 @@ gem 'unicode_utils' # Gestion des comptes utilisateurs gem 'devise' gem 'openid_connect' +gem 'omniauth-github' gem 'rest-client' diff --git a/Gemfile.lock b/Gemfile.lock index 994f844f5..4e7551cd9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -357,6 +357,7 @@ GEM url_safe_base64 jsonapi (0.1.1.beta2) json (~> 1.8) + jwt (1.5.6) kaminari (0.17.0) actionpack (>= 3.0.0) activesupport (>= 3.0.0) @@ -396,6 +397,7 @@ GEM mini_portile2 (2.3.0) minitest (5.10.3) multi_json (1.12.1) + multi_xml (0.6.0) multipart-post (2.0.0) mustermann (1.0.1) nenv (0.3.0) @@ -406,6 +408,21 @@ GEM notiffany (0.1.1) nenv (~> 0.1) shellany (~> 0.0) + oauth2 (1.4.0) + faraday (>= 0.8, < 0.13) + jwt (~> 1.0) + multi_json (~> 1.3) + multi_xml (~> 0.5) + rack (>= 1.2, < 3) + omniauth (1.7.1) + hashie (>= 3.4.6, < 3.6.0) + rack (>= 1.6.2, < 3) + omniauth-github (1.3.0) + omniauth (~> 1.5) + omniauth-oauth2 (>= 1.4.0, < 2.0) + omniauth-oauth2 (1.5.0) + oauth2 (~> 1.1) + omniauth (~> 1.2) open4 (1.3.4) openid_connect (0.12.0) activemodel @@ -720,6 +737,7 @@ DEPENDENCIES mailjet maruku mina! + omniauth-github openid_connect openstack pg diff --git a/app/assets/stylesheets/new_design/flex.scss b/app/assets/stylesheets/new_design/flex.scss index 43416c333..0689c004c 100644 --- a/app/assets/stylesheets/new_design/flex.scss +++ b/app/assets/stylesheets/new_design/flex.scss @@ -16,4 +16,8 @@ &.justify-between { justify-content: space-between; } + + &.justify-center { + justify-content: center; + } } diff --git a/app/assets/stylesheets/new_design/super_admin.scss b/app/assets/stylesheets/new_design/super_admin.scss new file mode 100644 index 000000000..949f1aa4d --- /dev/null +++ b/app/assets/stylesheets/new_design/super_admin.scss @@ -0,0 +1,11 @@ +@import "constants"; + +.super-admin { + margin-top: 40px; + text-align: center; + + h2 { + font-size: 24px; + margin-bottom: 4 * $default-spacer; + } +} diff --git a/app/controllers/administrations/omniauth_callbacks_controller.rb b/app/controllers/administrations/omniauth_callbacks_controller.rb new file mode 100644 index 000000000..71910756f --- /dev/null +++ b/app/controllers/administrations/omniauth_callbacks_controller.rb @@ -0,0 +1,16 @@ +class Administrations::OmniauthCallbacksController < Devise::OmniauthCallbacksController + def github + administration = Administration.from_omniauth(request.env["omniauth.auth"]) + if administration.present? + sign_in administration + redirect_to administrations_path + else + flash[:alert] = "Compte GitHub non autorisé" + redirect_to root_path + end + end + + def failure + redirect_to root_path + end +end diff --git a/app/controllers/administrations/sessions_controller.rb b/app/controllers/administrations/sessions_controller.rb new file mode 100644 index 000000000..5c1c66000 --- /dev/null +++ b/app/controllers/administrations/sessions_controller.rb @@ -0,0 +1,11 @@ +class Administrations::SessionsController < ApplicationController + layout "new_application" + + def new + end + + def destroy + sign_out :administration if administration_signed_in? + redirect_to root_path + end +end diff --git a/app/controllers/administrations_controller.rb b/app/controllers/administrations_controller.rb index 2a8e22c16..c907a3b7a 100644 --- a/app/controllers/administrations_controller.rb +++ b/app/controllers/administrations_controller.rb @@ -18,7 +18,7 @@ class AdministrationsController < ApplicationController if admin.save flash.notice = "Administrateur créé" - NewAdminMailer.new_admin_email(admin).deliver_now! + NewAdminMailer.new_admin_email(admin, current_administration).deliver_now! else flash.alert = admin.errors.full_messages end diff --git a/app/mailers/new_admin_mailer.rb b/app/mailers/new_admin_mailer.rb index 71ea69b4f..96d0e76d4 100644 --- a/app/mailers/new_admin_mailer.rb +++ b/app/mailers/new_admin_mailer.rb @@ -1,6 +1,7 @@ class NewAdminMailer < ApplicationMailer - def new_admin_email admin + def new_admin_email admin, administration @admin = admin + @administration = administration mail(to: 'tech@tps.apientreprise.fr', subject: "Création d'un compte Admin TPS") diff --git a/app/models/administration.rb b/app/models/administration.rb index bab810519..f19ea8226 100644 --- a/app/models/administration.rb +++ b/app/models/administration.rb @@ -1,5 +1,9 @@ class Administration < ActiveRecord::Base # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable - devise :database_authenticatable, :rememberable, :trackable, :validatable + devise :database_authenticatable, :rememberable, :trackable, :validatable, :omniauthable, omniauth_providers: [:github] + + def self.from_omniauth(params) + find_by(email: params["info"]["email"]) + end end diff --git a/app/views/administrations/index.html.haml b/app/views/administrations/index.html.haml index c4e7eefc5..869242426 100644 --- a/app/views/administrations/index.html.haml +++ b/app/views/administrations/index.html.haml @@ -13,4 +13,4 @@ %br .text-center - = link_to 'Deconnexion', '/administrations/sign_out', method: :delete + = link_to 'Deconnexion', administrations_sign_out_path, method: :delete diff --git a/app/views/administrations/sessions/new.html.haml b/app/views/administrations/sessions/new.html.haml new file mode 100644 index 000000000..8ed5fb4d9 --- /dev/null +++ b/app/views/administrations/sessions/new.html.haml @@ -0,0 +1,6 @@ +.super-admin.flex.justify-center + %div + %h2 Espace Admin + = link_to administration_github_omniauth_authorize_path, class: "button large" do + %span.icon.lock + Connexion avec GitHub diff --git a/app/views/new_admin_mailer/new_admin_email.text.erb b/app/views/new_admin_mailer/new_admin_email.text.erb index e0946ef9a..17e1d99c5 100644 --- a/app/views/new_admin_mailer/new_admin_email.text.erb +++ b/app/views/new_admin_mailer/new_admin_email.text.erb @@ -4,6 +4,8 @@ Plateforme : <%= TPS::Application::URL %> Login : <%= @admin.email %> +Créateur : <%= @administration.email %> + Bonne journée, L'équipe Téléprocédures Simplifiées diff --git a/config/deploy.rb b/config/deploy.rb index 843687779..5e6b92153 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -65,6 +65,7 @@ set :shared_paths, [ "config/unicorn.rb", "config/initializers/raven.rb", 'config/france_connect.yml', + 'config/github_secrets.yml', 'config/initializers/mailjet.rb', 'config/initializers/storage_url.rb' ] diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 60f55f640..a12c61265 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -232,7 +232,10 @@ Devise.setup do |config| # ==> OmniAuth # Add a new OmniAuth provider. Check the wiki for more information on setting # up on your models and hooks. - # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo' + if !Rails.env.test? + github_secrets = YAML::load_file(File.join(__dir__, '../github_secrets.yml')) + config.omniauth :github, github_secrets['client_id'], github_secrets['client_secret'], scope: 'user:email' + end # ==> Warden configuration # If you want to use other strategies, that are not supported by Devise, or diff --git a/config/routes.rb b/config/routes.rb index cfbd00c09..275c8431c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,7 +1,11 @@ Rails.application.routes.draw do get "/ping" => "ping#index", :constraints => {:ip => /127.0.0.1/} - devise_for :administrations, skip: [:password, :registrations] + devise_for :administrations, + skip: [:password, :registrations, :sessions], + controllers: { + omniauth_callbacks: 'administrations/omniauth_callbacks' + } devise_for :administrateurs, controllers: { sessions: 'administrateurs/sessions' @@ -42,6 +46,8 @@ Rails.application.routes.draw do get 'admin' => 'admin#index' get 'backoffice' => 'backoffice#index' + get 'administrations/sign_in' => 'administrations/sessions#new' + delete 'administrations/sign_out' => 'administrations/sessions#destroy' authenticate :administration do resources :administrations, only: [:index, :create] namespace :administrations do diff --git a/lib/tasks/2017_12_20_delete_old_administration.rake b/lib/tasks/2017_12_20_delete_old_administration.rake new file mode 100644 index 000000000..2f72d4165 --- /dev/null +++ b/lib/tasks/2017_12_20_delete_old_administration.rake @@ -0,0 +1,8 @@ +namespace :'2017_12_20_delete_old_administration' do + task set: :environment do + Administration.all.each do |a| + puts "Deleting #{a.email}" + a.destroy + end + end +end diff --git a/lib/tasks/admin.rake b/lib/tasks/admin.rake new file mode 100644 index 000000000..93c89183e --- /dev/null +++ b/lib/tasks/admin.rake @@ -0,0 +1,12 @@ +namespace :admin do + task :create_admin, [:email] => :environment do |t, args| + email = args[:email] + puts "Creating Administration for #{email}" + a = Administration.new(email: email, password: Devise.friendly_token[0,20]) + if a.save + puts "#{a.email} created" + else + puts "An error occured : #{a.errors.full_messages}" + end + end +end diff --git a/spec/controllers/administrations/omniauth_callbacks_controller_spec.rb b/spec/controllers/administrations/omniauth_callbacks_controller_spec.rb new file mode 100644 index 000000000..b037cb6d3 --- /dev/null +++ b/spec/controllers/administrations/omniauth_callbacks_controller_spec.rb @@ -0,0 +1,38 @@ +require 'spec_helper' + +describe Administrations::OmniauthCallbacksController, type: :controller do + before(:each) do + @request.env["devise.mapping"] = Devise.mappings[:administration] + end + + describe 'POST #github' do + let(:params) { { "info" => { "email" => email } } } + before do + controller.stub(:sign_in).and_return true + @request.env["omniauth.auth"] = params + end + subject { post :github } + + context 'with an authorized email' do + let(:email) { "ivan@tps.fr" } + let(:administration) { create(:administration, email: email) } + before { administration } + + it { is_expected.to redirect_to(administrations_path) } + it do + expect(controller).to receive(:sign_in).with(administration) + subject + end + end + + context 'with an unauthorized email' do + let(:email) { "michel@tps.fr" } + + it { is_expected.to redirect_to(root_path) } + it do + expect(controller).to_not receive(:sign_in) + subject + end + end + end +end