From e93daa21d573558b48631eec832bf340e4f87b02 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Tue, 15 Sep 2020 13:02:05 +0500 Subject: [PATCH] Add Tara field to users, add routes & controller --- app/controllers/registrar/tara_controller.rb | 64 +++++++++++++++++++ app/errors/tampering_detected.rb | 3 + app/models/user.rb | 33 ++++++++++ config/locales/en.yml | 2 + config/locales/tara.en.yml | 14 ++++ config/locales/tara.et.yml | 14 ++++ config/routes.rb | 5 ++ ...00915073245_add_omniauth_fields_to_user.rb | 10 +++ db/structure.sql | 13 +++- 9 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 app/controllers/registrar/tara_controller.rb create mode 100644 app/errors/tampering_detected.rb create mode 100644 config/locales/tara.en.yml create mode 100644 config/locales/tara.et.yml create mode 100644 db/migrate/20200915073245_add_omniauth_fields_to_user.rb diff --git a/app/controllers/registrar/tara_controller.rb b/app/controllers/registrar/tara_controller.rb new file mode 100644 index 000000000..ce986c798 --- /dev/null +++ b/app/controllers/registrar/tara_controller.rb @@ -0,0 +1,64 @@ +require 'tampering_detected' + +class TaraController < ApplicationController + rescue_from Errors::TamperingDetected do + redirect_to root_url, alert: t('auth.tara.tampering') + end + + def callback + session[:omniauth_hash] = user_hash + + @user = User.from_omniauth(user_hash) + + return unless @user.persisted? + + sign_in(User, @user) + redirect_to user_path(@user.uuid), notice: t('devise.sessions.signed_in') + end + + # rubocop:disable Metrics/MethodLength + def create + @user = User.new(create_params) + check_for_tampering + create_password + + respond_to do |format| + if @user.save + format.html do + sign_in(User, @user) + redirect_to user_path(@user.uuid), notice: t(:created) + end + else + format.html { render :callback } + end + end + end + # rubocop:enable Metrics/MethodLength + + def cancel + redirect_to root_path, notice: t(:sign_in_cancelled) + end + + private + + def create_params + params.require(:user) + .permit(:email, :identity_code, :country_code, :given_names, :surname, + :accepts_terms_and_conditions, :locale, :uid, :provider) + end + + def check_for_tampering + return unless @user.tampered_with?(session[:omniauth_hash]) + + session.delete(:omniauth_hash) + raise Errors::TamperingDetected + end + + def create_password + @user.password = Devise.friendly_token[0..20] + end + + def user_hash + request.env['omniauth.auth'] + end +end diff --git a/app/errors/tampering_detected.rb b/app/errors/tampering_detected.rb new file mode 100644 index 000000000..1cf72ba58 --- /dev/null +++ b/app/errors/tampering_detected.rb @@ -0,0 +1,3 @@ +module Errors + class TamperingDetected < ActionController::BadRequest; end +end diff --git a/app/models/user.rb b/app/models/user.rb index 6b16bd508..2234a3154 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,6 +1,9 @@ class User < ApplicationRecord include Versions # version/user_version.rb + ESTONIAN_COUNTRY_CODE = 'EE'.freeze + TARA_PROVIDER = 'tara'.freeze + has_many :actions, dependent: :restrict_with_exception attr_accessor :phone @@ -11,4 +14,34 @@ class User < ApplicationRecord "#{self.id}-#{self.class}: #{self.username}" end + # rubocop:disable Metrics/AbcSize + def tampered_with?(omniauth_hash) + uid_from_hash = omniauth_hash['uid'] + provider_from_hash = omniauth_hash['provider'] + + begin + uid != uid_from_hash || + provider != provider_from_hash || + country_code != uid_from_hash.slice(0..1) || + identity_code != uid_from_hash.slice(2..-1) || + given_names != omniauth_hash.dig('info', 'first_name') || + surname != omniauth_hash.dig('info', 'last_name') + end + end + # rubocop:enable Metrics/AbcSize + + def self.from_omniauth(omniauth_hash) + uid = omniauth_hash['uid'] + provider = omniauth_hash['provider'] + + User.find_or_initialize_by(provider: provider, uid: uid) do |user| + user.given_names = omniauth_hash.dig('info', 'first_name') + user.surname = omniauth_hash.dig('info', 'last_name') + if provider == TARA_PROVIDER + user.country_code = uid.slice(0..1) + user.identity_code = uid.slice(2..-1) + end + end + end + end diff --git a/config/locales/en.yml b/config/locales/en.yml index 9c5b98a1b..398a423f0 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -295,6 +295,8 @@ en: authentication_error: 'Authentication error' + sign_in_cancelled: "Sign in cancelled" + transfer_requested: 'Transfer requested.' message_was_not_found: 'Message was not found' only_one_parameter_allowed: 'Only one parameter allowed: %{param_1} or %{param_2}' diff --git a/config/locales/tara.en.yml b/config/locales/tara.en.yml new file mode 100644 index 000000000..ff37e8ff7 --- /dev/null +++ b/config/locales/tara.en.yml @@ -0,0 +1,14 @@ +en: + auth: + tara: + tampering: "Tampering detected. Sign in cancelled." + + callback: + title: "Create a user" + errors: "prohibited this user from being saved" + + form: + contact_data: "Contact Data" + data_from_identity_document: "Data from identity document" + new_password: "New password" + sign_up: "Sign up" diff --git a/config/locales/tara.et.yml b/config/locales/tara.et.yml new file mode 100644 index 000000000..a4ccaf6dd --- /dev/null +++ b/config/locales/tara.et.yml @@ -0,0 +1,14 @@ +et: + auth: + tara: + tampering: "Avastatud urkimine. Sisselogimine tühistatud." + + callback: + title: "Loo kasutaja" + errors: "seda kasutajat ei saa salvestada" + + form: + contact_data: "Kontaktandmed" + data_from_identity_document: "Andmed elektroonselt isikutunnistuselt" + new_password: "Uus salasõna" + sign_up: "Registreeru" diff --git a/config/routes.rb b/config/routes.rb index 223cf3171..73d482cf0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -85,6 +85,11 @@ Rails.application.routes.draw do post 'id' => 'sessions#id_card', as: :id_card_sign_in post 'mid' => 'sessions#mid' + + match '/tara/callback', via: %i[get post], to: 'tara#callback', as: :tara_callback + match '/tara/cancel', via: %i[get post delete], to: 'tara#cancel', + as: :tara_cancel + match '/tara/create', via: [:post], to: 'tara#create', as: :tara_create end resources :invoices, except: %i[new create edit update destroy] do diff --git a/db/migrate/20200915073245_add_omniauth_fields_to_user.rb b/db/migrate/20200915073245_add_omniauth_fields_to_user.rb new file mode 100644 index 000000000..8826559e3 --- /dev/null +++ b/db/migrate/20200915073245_add_omniauth_fields_to_user.rb @@ -0,0 +1,10 @@ +class AddOmniauthFieldsToUser < ActiveRecord::Migration[6.0] + disable_ddl_transaction! + + def change + add_column :users, :provider, :string + add_column :users, :uid, :string + add_index :users, [:provider, :uid], algorithm: :concurrently, + unique: true + end +end diff --git a/db/structure.sql b/db/structure.sql index 6a30fbc84..e4e9b8c2f 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -2437,7 +2437,9 @@ CREATE TABLE public.users ( remember_created_at timestamp without time zone, failed_attempts integer DEFAULT 0 NOT NULL, locked_at timestamp without time zone, - legacy_id integer + legacy_id integer, + provider character varying, + uid character varying ); @@ -4190,6 +4192,12 @@ CREATE UNIQUE INDEX index_settings_on_thing_type_and_thing_id_and_var ON public. CREATE INDEX index_users_on_identity_code ON public.users USING btree (identity_code); +-- +-- Name: index_users_on_provider_and_uid; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE UNIQUE INDEX index_users_on_provider_and_uid ON public.users USING btree (provider, uid); + -- -- Name: index_users_on_registrar_id; Type: INDEX; Schema: public; Owner: -; Tablespace: @@ -4906,5 +4914,6 @@ INSERT INTO "schema_migrations" (version) VALUES ('20200902131603'), ('20200908131554'), ('20200910085157'), -('20200910102028'); +('20200910102028'), +('20200915073245');