Refactor ID card sign-in

- Extract to Devise custom strategy
- Use `SSL_CLIENT_S_DN_CN` env variable instead of `SSL_CLIENT_S_DN` to
get ID card data
- Remove `database_authenticatable` strategy from `RegistrantUser`

Closes #1047
This commit is contained in:
Artur Beljajev 2019-01-30 19:08:29 +02:00
parent 27976c3fbd
commit a08f063640
20 changed files with 266 additions and 89 deletions

View file

@ -1,26 +1,6 @@
class Registrant::SessionsController < Devise::SessionsController
layout 'registrant/application'
def new; end
def id
client_certificate_subject = request.env['SSL_CLIENT_S_DN']
client_certificate_issuer = request.env['SSL_CLIENT_I_DN_O']
if Rails.env.development?
client_certificate_subject = 'test'
client_certificate_issuer = RegistrantUser::ACCEPTED_ISSUER
end
@user = RegistrantUser.find_or_create_by_idc_data(client_certificate_subject, client_certificate_issuer)
if @user
sign_in_and_redirect(:registrant_user, @user, event: :authentication)
else
flash[:alert] = t('login_failed_check_id_card')
redirect_to new_registrant_user_session_url
end
end
def login_mid
@user = User.new
end

View file

@ -48,15 +48,22 @@ class Registrar
end
end
def id
@user = ApiUser.find_by_idc_data_and_allowed(request.env['SSL_CLIENT_S_DN'], request.ip)
def id_card
self.resource = warden.authenticate!(auth_options)
if @user
sign_in_and_redirect(:registrar_user, @user, event: :authentication)
else
flash[:alert] = t('no_such_user')
redirect_to new_registrar_user_session_url
restricted_ip = Authorization::RestrictedIP.new(request.ip)
ip_allowed = restricted_ip.can_access_registrar_area?(resource.registrar)
unless ip_allowed
render text: t('registrar.authorization.ip_not_allowed', ip: request.ip)
warden.logout(:registrar_user)
return
end
set_flash_message!(:notice, :signed_in)
sign_in(resource_name, resource)
yield resource if block_given?
respond_with resource, location: after_sign_in_path_for(resource)
end
def login_mid

View file

@ -2,7 +2,8 @@ require 'open3'
class ApiUser < User
include EppErrors
devise :database_authenticatable, :trackable, :timeoutable, authentication_keys: [:username]
devise :database_authenticatable, :trackable, :timeoutable, :id_card_authenticatable,
authentication_keys: [:username]
def epp_code_map
{
@ -47,19 +48,9 @@ class ApiUser < User
end
class << self
def find_by_idc_data_and_allowed(idc_data, ip)
return false if idc_data.blank?
identity_code = idc_data.scan(/serialNumber=(\d+)/).flatten.first
return false if ip.blank?
possible_users = where(identity_code: identity_code)
possible_users.each do |selected_user|
if selected_user.registrar.white_ips.registrar_area.include_ip?(ip)
return selected_user
end
end
def find_by_id_card(id_card)
find_by(identity_code: id_card.personal_code)
end
end
def registrar_typeahead

6
app/models/id_card.rb Normal file
View file

@ -0,0 +1,6 @@
class IdCard
attr_accessor :first_name
attr_accessor :last_name
attr_accessor :personal_code
attr_accessor :country_code
end

View file

@ -1,8 +1,7 @@
class RegistrantUser < User
ACCEPTED_ISSUER = 'AS Sertifitseerimiskeskus'.freeze
attr_accessor :idc_data
devise :database_authenticatable, :trackable, :timeoutable
devise :trackable, :timeoutable, :id_card_authenticatable
def ability
@ability ||= Ability.new(self)
@ -56,30 +55,6 @@ class RegistrantUser < User
end
class << self
def find_or_create_by_idc_data(idc_data, issuer_organization)
return false if idc_data.blank?
return false if issuer_organization != ACCEPTED_ISSUER
idc_data.force_encoding('UTF-8')
user_data = {}
# handling here new and old mode
if idc_data.starts_with?('/')
user_data[:ident] = idc_data.scan(/serialNumber=(\d+)/).flatten.first
user_data[:country_code] = idc_data.scan(/^\/C=(.{2})/).flatten.first
user_data[:first_name] = idc_data.scan(%r{/GN=(.+)/serialNumber}).flatten.first
user_data[:last_name] = idc_data.scan(%r{/SN=(.+)/GN}).flatten.first
else
parse_str = ',' + idc_data
user_data[:ident] = parse_str.scan(/,serialNumber=(\d+)/).flatten.first
user_data[:country_code] = parse_str.scan(/,C=(.{2})/).flatten.first
user_data[:first_name] = parse_str.scan(/,GN=([^,]+)/).flatten.first
user_data[:last_name] = parse_str.scan(/,SN=([^,]+)/).flatten.first
end
find_or_create_by_user_data(user_data)
end
def find_or_create_by_api_data(user_data = {})
return false unless user_data[:ident]
return false unless user_data[:first_name]
@ -98,6 +73,16 @@ class RegistrantUser < User
find_or_create_by_user_data(user_data)
end
def find_by_id_card(id_card)
registrant_ident = "#{id_card.country_code}-#{id_card.personal_code}"
username = [id_card.first_name, id_card.last_name].join("\s")
user = find_or_initialize_by(registrant_ident: registrant_ident)
user.username = username
user.save!
user
end
private
def find_or_create_by_user_data(user_data = {})

View file

@ -11,7 +11,7 @@
<%= link_to '/registrant/login/mid' do %>
<%= image_tag 'mid.gif' %>
<% end %>
<%= link_to '/registrant/id', method: :post do %>
<%= link_to registrant_id_card_sign_in_path, method: :post do %>
<%= image_tag 'id_card.gif' %>
<% end %>
</div>

View file

@ -23,7 +23,7 @@
<%= image_tag 'mid.gif' %>
<% end %>
<%= link_to '/registrar/id', method: :post do %>
<%= link_to registrar_id_card_sign_in_path, method: :post do %>
<%= image_tag 'id_card.gif' %>
<% end %>
</div>