mirror of
https://github.com/internetee/registry.git
synced 2025-05-31 09:53:56 +02:00
Merge pull request #2105 from internetee/implement-api-endpoint-for-login-info
added api endpoint for registrar login
This commit is contained in:
commit
c5719a35f1
21 changed files with 511 additions and 7 deletions
|
@ -0,0 +1,67 @@
|
|||
require 'serializers/repp/domain'
|
||||
|
||||
module Api
|
||||
module V1
|
||||
module AccreditationCenter
|
||||
class AuthController < ::Api::V1::AccreditationCenter::BaseController
|
||||
before_action :authenticate_user
|
||||
|
||||
def index
|
||||
login = @current_user
|
||||
registrar = @current_user.registrar
|
||||
|
||||
# rubocop:disable Style/AndOr
|
||||
render_success(data: nil) and return unless login
|
||||
# rubocop:enable Style/AndOr
|
||||
|
||||
data = set_values_to_data(login: login, registrar: registrar)
|
||||
|
||||
render_success(data: data)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def authenticate_user
|
||||
username, password = Base64.urlsafe_decode64(basic_token).split(':')
|
||||
@current_user ||= ApiUser.find_by(username: username, plain_text_password: password)
|
||||
|
||||
return if @current_user
|
||||
|
||||
raise(ArgumentError)
|
||||
rescue NoMethodError, ArgumentError
|
||||
@response = { code: 2202, message: 'Invalid authorization information' }
|
||||
render(json: @response, status: :unauthorized)
|
||||
end
|
||||
|
||||
def basic_token
|
||||
pattern = /^Basic /
|
||||
header = request.headers['Authorization']
|
||||
header = header.gsub(pattern, '') if header&.match(pattern)
|
||||
header.strip
|
||||
end
|
||||
|
||||
def set_values_to_data(login:, registrar:)
|
||||
data = login.as_json(only: %i[id
|
||||
username
|
||||
name
|
||||
uuid
|
||||
roles
|
||||
accreditation_date
|
||||
accreditation_expire_date])
|
||||
data[:registrar_name] = registrar.name
|
||||
data[:registrar_reg_no] = registrar.reg_no
|
||||
data[:registrar_email] = registrar.email
|
||||
data[:code] = registrar.code
|
||||
data
|
||||
end
|
||||
|
||||
def render_success(code: nil, message: nil, data: nil)
|
||||
@response = { code: code || 1000, message: message || 'Command completed successfully',
|
||||
data: data || {} }
|
||||
|
||||
render(json: @response, status: :ok)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,28 @@
|
|||
require 'auth_token/auth_token_decryptor'
|
||||
|
||||
module Api
|
||||
module V1
|
||||
module AccreditationCenter
|
||||
class BaseController < ActionController::API
|
||||
rescue_from ActiveRecord::RecordNotFound, with: :show_not_found_error
|
||||
rescue_from ActiveRecord::RecordInvalid, with: :show_invalid_record_error
|
||||
rescue_from(ActionController::ParameterMissing) do |parameter_missing_exception|
|
||||
error = {}
|
||||
error[parameter_missing_exception.param] = ['parameter is required']
|
||||
response = { errors: [error] }
|
||||
render json: response, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def show_not_found_error
|
||||
render json: { errors: [{ base: ['Not found'] }] }, status: :not_found
|
||||
end
|
||||
|
||||
def show_invalid_record_error(exception)
|
||||
render json: { errors: exception.record.errors }, status: :bad_request
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,21 @@
|
|||
require 'serializers/repp/contact'
|
||||
|
||||
module Api
|
||||
module V1
|
||||
module AccreditationCenter
|
||||
class ContactsController < ::Api::V1::AccreditationCenter::BaseController
|
||||
def show
|
||||
@contact = Contact.find_by(code: params[:id])
|
||||
|
||||
if @contact
|
||||
render json: { code: 1000, contact: Serializers::Repp::Contact.new(@contact,
|
||||
show_address: false).to_json },
|
||||
status: :found
|
||||
else
|
||||
render json: { errors: 'Contact not found' }, status: :not_found
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,21 @@
|
|||
require 'serializers/repp/domain'
|
||||
|
||||
module Api
|
||||
module V1
|
||||
module AccreditationCenter
|
||||
class DomainsController < ::Api::V1::AccreditationCenter::BaseController
|
||||
def show
|
||||
@domain = Domain.find_by(name: params[:name])
|
||||
|
||||
if @domain
|
||||
render json: { code: 1000, domain: Serializers::Repp::Domain.new(@domain,
|
||||
sponsored: true).to_json },
|
||||
status: :found
|
||||
else
|
||||
render json: { errors: 'Domain not found' }, status: :not_found
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,32 @@
|
|||
module Api
|
||||
module V1
|
||||
module AccreditationCenter
|
||||
class InvoiceStatusController < ::Api::V1::AccreditationCenter::BaseController
|
||||
def index
|
||||
username, password = Base64.urlsafe_decode64(basic_token).split(':')
|
||||
@current_user ||= ApiUser.find_by(username: username, plain_text_password: password)
|
||||
|
||||
return render json: { errors: 'No user found' }, status: :not_found if @current_user.nil?
|
||||
|
||||
@invoices = @current_user.registrar.invoices.select { |i| i.cancelled_at != nil }
|
||||
|
||||
if @invoices
|
||||
render json: { code: 1000, invoices: @invoices },
|
||||
status: :found
|
||||
else
|
||||
render json: { errors: 'No invoices' }, status: :not_found
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def basic_token
|
||||
pattern = /^Basic /
|
||||
header = request.headers['Authorization']
|
||||
header = header.gsub(pattern, '') if header&.match(pattern)
|
||||
header.strip
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -116,6 +116,9 @@ module Repp
|
|||
def webclient_request?
|
||||
return if Rails.env.test?
|
||||
|
||||
header = request.headers['AccreditationToken']
|
||||
return if header == ENV['accreditation_secret']
|
||||
|
||||
ENV['webclient_ips'].split(',').map(&:strip).include?(request.ip)
|
||||
end
|
||||
|
||||
|
@ -131,6 +134,10 @@ module Repp
|
|||
|
||||
render(json: @response, status: :unauthorized)
|
||||
end
|
||||
|
||||
def logger
|
||||
Rails.logger
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -33,7 +33,7 @@ module Repp
|
|||
param :registrant, String, required: true, desc: 'Registrant contact code'
|
||||
param :reserved_pw, String, required: false, desc: 'Reserved password for domain'
|
||||
param :transfer_code, String, required: false, desc: 'Desired transfer code for domain'
|
||||
param :period, Integer, required: true, desc: 'Registration period in months or years'
|
||||
# param :period, String, required: true, desc: 'Registration period in months or years'
|
||||
param :period_unit, String, required: true, desc: 'Period type (month m) or (year y)'
|
||||
param :nameservers_attributes, Array, required: false, desc: 'Domain nameservers' do
|
||||
param :hostname, String, required: true, desc: 'Nameserver hostname'
|
||||
|
@ -64,7 +64,7 @@ module Repp
|
|||
handle_errors(@domain) and return unless action.call
|
||||
# rubocop:enable Style/AndOr
|
||||
|
||||
render_success(data: { domain: { name: @domain.name } })
|
||||
render_success(data: { domain: { name: @domain.name, transfer_code: @domain.transfer_code } })
|
||||
end
|
||||
|
||||
api :PUT, '/repp/v1/domains/:domain_name'
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
module Repp
|
||||
module V1
|
||||
module Registrar
|
||||
class AccreditationInfoController < BaseController
|
||||
api :GET, 'repp/v1/registrar/accreditation/get_info'
|
||||
desc 'check login user and return data'
|
||||
|
||||
def index
|
||||
login = current_user
|
||||
registrar = current_user.registrar
|
||||
|
||||
# rubocop:disable Style/AndOr
|
||||
render_success(data: nil) and return unless login
|
||||
# rubocop:enable Style/AndOr
|
||||
|
||||
data = set_values_to_data(login: login, registrar: registrar)
|
||||
|
||||
render_success(data: data)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_values_to_data(login:, registrar:)
|
||||
data = login.as_json(only: %i[id
|
||||
username
|
||||
name
|
||||
uuid
|
||||
roles
|
||||
accreditation_date
|
||||
accreditation_expire_date])
|
||||
data[:registrar_name] = registrar.name
|
||||
data[:registrar_reg_no] = registrar.reg_no
|
||||
data
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,61 @@
|
|||
module Repp
|
||||
module V1
|
||||
module Registrar
|
||||
class AccreditationResultsController < ActionController::API
|
||||
before_action :authenticate_shared_key
|
||||
|
||||
TEMPORARY_SECRET_KEY = ENV['accreditation_secret'].freeze
|
||||
|
||||
api :POST, 'repp/v1/registrar/accreditation/push_results'
|
||||
desc 'added datetime results'
|
||||
|
||||
def create
|
||||
username = params[:accreditation_result][:username]
|
||||
result = params[:accreditation_result][:result]
|
||||
|
||||
record_accreditation_result(username, result) if result
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
record_not_found(username)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def record_accreditation_result(username, result)
|
||||
user = ApiUser.find_by(username: username)
|
||||
|
||||
raise ActiveRecord::RecordNotFound if user.nil?
|
||||
|
||||
user.accreditation_date = DateTime.current
|
||||
|
||||
return unless user.save
|
||||
|
||||
render_success(data: { user: user,
|
||||
result: result,
|
||||
message: 'Accreditation info successfully added' })
|
||||
end
|
||||
|
||||
def authenticate_shared_key
|
||||
api_key = "Basic #{TEMPORARY_SECRET_KEY}"
|
||||
render_failed unless api_key == request.authorization
|
||||
end
|
||||
|
||||
def record_not_found(username)
|
||||
@response = { code: 2303, message: "Object '#{username}' does not exist" }
|
||||
render(json: @response)
|
||||
end
|
||||
|
||||
def render_failed
|
||||
@response = { code: 2202, message: 'Invalid authorization information' }
|
||||
render(json: @response, status: :unauthorized)
|
||||
end
|
||||
|
||||
def render_success(code: nil, message: nil, data: nil)
|
||||
@response = { code: code || 1000, message: message || 'Command completed successfully',
|
||||
data: data || {} }
|
||||
|
||||
render(json: @response, status: :ok)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -106,7 +106,7 @@ module Actions
|
|||
end
|
||||
|
||||
def assign_domain_period
|
||||
domain.period = params[:period]
|
||||
domain.period = params[:period].to_i
|
||||
domain.period_unit = params[:period_unit]
|
||||
end
|
||||
|
||||
|
|
|
@ -90,6 +90,9 @@ sk_digi_doc_service_name: 'Testimine'
|
|||
registrant_api_base_url:
|
||||
registrant_api_auth_allowed_ips: '127.0.0.1, 0.0.0.0' #ips, separated with commas
|
||||
|
||||
# Accreditation Center API
|
||||
accr_center_api_auth_allowed_ips: '127.0.0.1, 0.0.0.0' #ips, separated with commas
|
||||
|
||||
# Shared key for REST-WHOIS Bounces API incl. CERT
|
||||
rwhois_bounces_api_shared_key: testkey
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@ require_dependency 'epp_constraint'
|
|||
require 'sidekiq/web'
|
||||
|
||||
Rails.application.routes.draw do
|
||||
get 'practice/index'
|
||||
get 'practice/contact'
|
||||
# https://github.com/internetee/epp_proxy#translation-of-epp-calls
|
||||
namespace :epp do
|
||||
constraints(EppConstraint.new(:session)) do
|
||||
|
@ -72,6 +74,12 @@ Rails.application.routes.draw do
|
|||
get '/all_notifications', to: 'notifications#all_notifications'
|
||||
end
|
||||
end
|
||||
resource :accreditation, only: [:index] do
|
||||
collection do
|
||||
get '/get_info', to: 'accreditation_info#index'
|
||||
post '/push_results', to: 'accreditation_results#create'
|
||||
end
|
||||
end
|
||||
resources :nameservers do
|
||||
collection do
|
||||
put '/', to: 'nameservers#update'
|
||||
|
@ -118,6 +126,16 @@ Rails.application.routes.draw do
|
|||
resources :companies, only: %i[index]
|
||||
end
|
||||
|
||||
namespace :accreditation_center do
|
||||
# At the moment invoice_status endpoint returns only cancelled invoices. But in future logic of this enpoint can change.
|
||||
# And it will need to return invoices of different statuses. I decided to leave the name of the endpoint "invoice_status"
|
||||
resources :invoice_status, only: [ :index ]
|
||||
resource :domains, only: [ :show ], param: :name
|
||||
resource :contacts, only: [ :show ], param: :id
|
||||
# resource :auth, only: [ :index ]
|
||||
get 'auth', to: 'auth#index'
|
||||
end
|
||||
|
||||
resources :auctions, only: %i[index show update], param: :uuid
|
||||
resources :contact_requests, only: %i[create update], param: :id
|
||||
resources :bounces, only: %i[create]
|
||||
|
|
6
db/migrate/20210729131100_add_field_to_user.rb
Normal file
6
db/migrate/20210729131100_add_field_to_user.rb
Normal file
|
@ -0,0 +1,6 @@
|
|||
class AddFieldToUser < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
add_column :users, :accreditation_date, :datetime
|
||||
add_column :users, :accreditation_expire_date, :datetime
|
||||
end
|
||||
end
|
5
db/migrate/20210729134625_add_column_to_user.rb
Normal file
5
db/migrate/20210729134625_add_column_to_user.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class AddColumnToUser < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
add_column :users, :uuid, :uuid, default: 'gen_random_uuid()'
|
||||
end
|
||||
end
|
|
@ -2582,7 +2582,10 @@ 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,
|
||||
accreditation_date timestamp without time zone,
|
||||
accreditation_expire_date timestamp without time zone,
|
||||
uuid uuid DEFAULT public.gen_random_uuid()
|
||||
);
|
||||
|
||||
|
||||
|
@ -5230,6 +5233,6 @@ INSERT INTO "schema_migrations" (version) VALUES
|
|||
('20210616112332'),
|
||||
('20210629074044'),
|
||||
('20210628090353'),
|
||||
('20210708131814');
|
||||
|
||||
|
||||
('20210708131814'),
|
||||
('20210729131100'),
|
||||
('20210729134625');
|
||||
|
|
33
test/integration/api/accreditation_center/auth_test.rb
Normal file
33
test/integration/api/accreditation_center/auth_test.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
require 'test_helper'
|
||||
|
||||
class AuthTest < ApplicationIntegrationTest
|
||||
def setup
|
||||
super
|
||||
|
||||
@user = users(:api_bestnames)
|
||||
@header = { 'Authorization' => "Basic #{generate_base64}" }
|
||||
end
|
||||
|
||||
def test_should_return_successful
|
||||
get 'https://registry.test/api/v1/accreditation_center/auth', headers: @header
|
||||
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
assert_equal json[:code], 1000
|
||||
assert_equal json[:message], 'Command completed successfully'
|
||||
end
|
||||
|
||||
def test_should_return_failed
|
||||
get 'https://registry.test/api/v1/accreditation_center/auth', headers: { 'Authorization' => "Basic LAHSDHDSAFSF#@" }
|
||||
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_equal json[:code], 2202
|
||||
assert_equal json[:message], 'Invalid authorization information'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generate_base64
|
||||
Base64.encode64("#{@user.username}:#{@user.plain_text_password}")
|
||||
end
|
||||
end
|
23
test/integration/api/accreditation_center/contacts_test.rb
Normal file
23
test/integration/api/accreditation_center/contacts_test.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
require 'test_helper'
|
||||
|
||||
class ContactsTest < ApplicationIntegrationTest
|
||||
def setup
|
||||
super
|
||||
|
||||
@contact = contacts(:john)
|
||||
end
|
||||
|
||||
def test_return_code_error_if_valid_domain_name
|
||||
get '/api/v1/accreditation_center/contacts/?id=Alyosha'
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_equal json[:errors], 'Contact not found'
|
||||
end
|
||||
|
||||
def test_return_code_error_if_sdfsdf
|
||||
get "/api/v1/accreditation_center/contacts/?id=#{@contact.code}"
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_equal json[:contact][:name], 'John'
|
||||
end
|
||||
end
|
21
test/integration/api/accreditation_center/domains_test.rb
Normal file
21
test/integration/api/accreditation_center/domains_test.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
require 'test_helper'
|
||||
|
||||
class DomainsTest < ApplicationIntegrationTest
|
||||
def setup
|
||||
@domain = domains(:shop)
|
||||
end
|
||||
|
||||
def test_get_domain_info
|
||||
get "/api/v1/accreditation_center/domains/?name=shop.test"
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_equal json[:domain][:name], "shop.test"
|
||||
end
|
||||
|
||||
def test_return_code_error_if_valid_domain_name
|
||||
get "/api/v1/accreditation_center/domains/?name=some.ee"
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_equal json[:errors], "Domain not found"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,33 @@
|
|||
require 'test_helper'
|
||||
|
||||
class DomainsTest < ApplicationIntegrationTest
|
||||
def setup
|
||||
super
|
||||
|
||||
@user = users(:api_bestnames)
|
||||
@header = { 'Authorization' => "Basic #{generate_base64}" }
|
||||
end
|
||||
|
||||
def test_should_return_cancelled_invoices
|
||||
date_now = Time.now
|
||||
|
||||
get "/api/v1/accreditation_center/invoice_status", headers: @header
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_equal json[:invoices].count, 0
|
||||
|
||||
invoice = @user.registrar.invoices.last
|
||||
invoice.update(cancelled_at: date_now)
|
||||
|
||||
get "/api/v1/accreditation_center/invoice_status", headers: @header
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_equal json[:invoices].count, 1
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generate_base64
|
||||
Base64.encode64("#{@user.username}:#{@user.plain_text_password}")
|
||||
end
|
||||
end
|
35
test/integration/repp/v1/registrar/accreditaion_info_test.rb
Normal file
35
test/integration/repp/v1/registrar/accreditaion_info_test.rb
Normal file
|
@ -0,0 +1,35 @@
|
|||
require 'test_helper'
|
||||
|
||||
class ReppV1AccreditationInfoTest < ActionDispatch::IntegrationTest
|
||||
def setup
|
||||
@user = users(:api_bestnames)
|
||||
token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}")
|
||||
token = "Basic #{token}"
|
||||
|
||||
@auth_headers = { 'Authorization' => token }
|
||||
end
|
||||
|
||||
def test_valid_login
|
||||
get '/repp/v1/registrar/accreditation/get_info', headers: @auth_headers
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :ok
|
||||
assert_equal json[:data][:username], @user.username
|
||||
assert json[:data][:roles].include? 'super'
|
||||
assert_equal json[:data][:registrar_name], 'Best Names'
|
||||
assert_equal json[:data][:registrar_reg_no], '1234'
|
||||
end
|
||||
|
||||
def test_invalid_login
|
||||
token = Base64.encode64("#{@user.username}:0066600")
|
||||
token = "Basic #{token}"
|
||||
|
||||
auth_headers = { 'Authorization' => token }
|
||||
|
||||
get '/repp/v1/registrar/accreditation/get_info', headers: auth_headers
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :unauthorized
|
||||
assert_equal json[:message], 'Invalid authorization information'
|
||||
end
|
||||
end
|
|
@ -0,0 +1,49 @@
|
|||
require 'test_helper'
|
||||
|
||||
class ReppV1AccreditationResultsTest < ActionDispatch::IntegrationTest
|
||||
TEMPORARY_SECRET_KEY = ENV['accreditation_secret'].freeze
|
||||
|
||||
def setup
|
||||
@user = users(:api_bestnames)
|
||||
|
||||
token = "Basic #{TEMPORARY_SECRET_KEY}"
|
||||
|
||||
@auth_headers = { 'Authorization' => token }
|
||||
end
|
||||
|
||||
def test_should_return_valid_response
|
||||
post '/repp/v1/registrar/accreditation/push_results',
|
||||
headers: @auth_headers,
|
||||
params: {accreditation_result: {username: @user.username, result: true} }
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :ok
|
||||
assert_equal json[:data][:user][:username], @user.username
|
||||
assert_equal json[:data][:result], "true"
|
||||
assert_equal json[:data][:message], "Accreditation info successfully added"
|
||||
end
|
||||
|
||||
def test_should_return_valid_response_invalid_authorization
|
||||
post '/repp/v1/registrar/accreditation/push_results',
|
||||
headers: { 'Authorization' => 'Basic temporary-secret-ke'},
|
||||
params: {accreditation_result: {username: @user.username, result: true} }
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :unauthorized
|
||||
|
||||
assert_equal json[:code], 2202
|
||||
assert_equal json[:message], 'Invalid authorization information'
|
||||
end
|
||||
|
||||
def test_should_return_valid_response_record_exception
|
||||
post '/repp/v1/registrar/accreditation/push_results',
|
||||
headers: @auth_headers,
|
||||
params: {accreditation_result: { username: "chungachanga", result: true} }
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :ok
|
||||
|
||||
assert_equal json[:code], 2303
|
||||
assert_equal json[:message], "Object 'chungachanga' does not exist"
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue