Skip to content

Commit

Permalink
remove Knock auth
Browse files Browse the repository at this point in the history
  • Loading branch information
senid231 committed Nov 17, 2024
1 parent a5d5027 commit 5c63011
Show file tree
Hide file tree
Showing 74 changed files with 199 additions and 490 deletions.
1 change: 0 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ gem 'net-ldap', '~> 0.16.0'

# Seamless JWT authentication for Rails API
gem 'jwt'
gem 'knock', github: 'nsarno/knock'

# ActiveAdmin
gem 'activeadmin'
Expand Down
10 changes: 0 additions & 10 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,6 @@ GIT
jquery-ui-rails (7.0.0)
railties (>= 3.2.16)

GIT
remote: https://github.com/nsarno/knock.git
revision: 37e403a7c6d44f585b56a086245e41566a8d6fe1
specs:
knock (2.2.0)
bcrypt (~> 3.1)
jwt (~> 2.2.1)
rails (>= 5)

GIT
remote: https://github.com/senid231/excelinator.git
revision: 25afcc544a6f287a2ace9018adbe6fc96ea29cb2
Expand Down Expand Up @@ -900,7 +891,6 @@ DEPENDENCIES
jrpc!
jsonapi-resources (~> 0.9.12)
jwt
knock!
listen
matrix (~> 0.4.2)
mini_racer
Expand Down
34 changes: 22 additions & 12 deletions app/controllers/api/rest/admin/auth_controller.rb
Original file line number Diff line number Diff line change
@@ -1,40 +1,50 @@
# frozen_string_literal: true

class Api::Rest::Admin::AuthController < Knock::AuthTokenController
class Api::Rest::Admin::AuthController < ApplicationController
skip_before_action :verify_authenticity_token

include Memoizable
include WithPayloads

rescue_from Authentication::AdminAuth::AuthenticationError, with: :handle_authentication_error
rescue_from Authentication::AdminAuth::IpAddressNotAllowedError, with: :handle_ip_not_allowed

define_memoizable :debug_mode, apply: -> { System::ApiLogConfig.exists?(controller: self.class.name) }

before_action :authenticate

def create
render json: { jwt: @auth_token }, status: 201
end

def meta
nil
end

private

def entity_name
'AdminUser'
def authenticate
result = Authentication::AdminAuth.authenticate!(
auth_params[:username],
auth_params[:password],
remote_ip: request.remote_ip
)
@auth_token = result.token
end

def auth_params
params.require(:auth).permit :username, :password
params.require(:auth).permit(:username, :password)
end

def not_found
def handle_authentication_error
error = JSONAPI::Exceptions::AuthenticationFailed.new
render status: 401, json: { errors: error.errors.map(&:to_hash) }
end

def ip_not_allowed
def handle_ip_not_allowed
error = JSONAPI::Exceptions::AuthenticationFailed.new(
detail: 'Your IP address is not allowed.'
)
render status: 401, json: { errors: error.errors.map(&:to_hash) }
end

def authenticate
super

ip_not_allowed unless entity.ip_allowed?(request.remote_ip)
end
end
18 changes: 11 additions & 7 deletions app/controllers/concerns/admin_api_authorizable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ module AdminApiAuthorizable
extend ActiveSupport::Concern

included do
include Knock::Authenticable
undef :current_admin_user
rescue_from Authorization::AdminAuth::AuthorizationError, with: :handle_authorization_error

before_action :authenticate_admin_user!
before_action :authorize
attr_reader :current_admin_user
end

def context
Expand All @@ -27,9 +27,13 @@ def capture_user

private

def authenticate_admin_user!
if !authenticate_for(::AdminUser) || !current_admin_user.ip_allowed?(request.remote_ip)
unauthorized_entity('admin_user')
end
def authorize
auth_token = params[:token] || request.headers['Authorization']&.split&.last
result = Authorization::AdminAuth.authorize!(auth_token, remote_ip: request.remote_ip)
@current_admin_user = result.entity
end

def handle_authorization_error
head 401
end
end
56 changes: 56 additions & 0 deletions app/lib/authentication/admin_auth.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# frozen_string_literal: true

module Authentication
class AdminAuth
EXPIRATION_INTERVAL = YetiConfig.api.token_lifetime.presence&.seconds&.freeze
AUDIENCE = 'admin'
AuthenticationError = Class.new(StandardError)
IpAddressNotAllowedError = Class.new(AuthenticationError)
Result = Data.define(:token)

class << self
# @param username [String]
# @param password [String]
# @param remote_ip [String]
# @return [Authentication::AdminAuth::Result] when success
# @raise [Authentication::AdminAuth::AuthenticationError] when failed caused by invalid username or password
# @raise [Authentication::AdminAuth::IpAddressNotAllowedError] when failed caused by IP address not allowed
def authenticate!(username, password, remote_ip:)
instance = new(username, password, remote_ip: remote_ip)
instance.authenticate!
end

# @param admin_user [AdminUser]
# @param expires_at [Time,nil] overrides default expiration
# @return [Authentication::CustomerV1Auth::Result]
def build_auth_data(admin_user, expires_at: nil)
expires_at ||= EXPIRATION_INTERVAL&.from_now
payload = { sub: admin_user.id, aud: AUDIENCE }
payload[:exp] = expires_at.to_i unless expires_at.nil?
token = JwtToken.encode(payload)
Result.new(token)
end
end

# @param username [String]
# @param password [String]
# @param remote_ip [String]
def initialize(username, password, remote_ip:)
@username = username
@password = password
@remote_ip = remote_ip
end

# @return [Authentication::AdminAuth::Result] when success
# @raise [Authentication::AdminAuth::AuthenticationError] when failed caused by invalid username or password
# @raise [Authentication::AdminAuth::IpAddressNotAllowedError] when failed caused by IP address not allowed
def authenticate!
admin_user = AdminUser.find_by(username: @username)
raise AuthenticationError if admin_user.nil?
raise AuthenticationError unless admin_user.authenticate(@password)
raise IpAddressNotAllowedError unless admin_user.ip_allowed?(@remote_ip)

self.class.build_auth_data(admin_user)
end
end
end
40 changes: 40 additions & 0 deletions app/lib/authorization/admin_auth.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# frozen_string_literal: true

module Authorization
class AdminAuth
Result = Struct.new(:entity)
AuthorizationError = Class.new(StandardError)

class << self
# @param token [String]
# @param remote_ip [String]
# @return [Authorization::AdminAuth::Result] when success
# @raise [Authorization::AdminAuth::AuthenticationError] when failed
def authorize!(token, remote_ip:)
new(token, remote_ip:).authorize!
end
end

# @param token [String]
# @param remote_ip [String]
def initialize(token, remote_ip:)
@token = token
@remote_ip = remote_ip
end

# @return [Authorization::AdminAuth::Result] when success
# @raise [Authorization::AdminAuth::AuthenticationError] when failed
def authorize!
verify_expiration = Authentication::AdminAuth::EXPIRATION_INTERVAL.present?
audience = Authentication::AdminAuth::AUDIENCE
payload = JwtToken.decode(@token, verify_expiration: verify_expiration, aud: audience)
raise AuthorizationError if payload.nil?

admin_user = AdminUser.find_by(id: payload[:sub])
raise AuthorizationError if admin_user.nil?
raise AuthorizationError unless admin_user.ip_allowed?(@remote_ip)

Result.new(admin_user)
end
end
end
59 changes: 0 additions & 59 deletions config/initializers/knock.rb

This file was deleted.

7 changes: 1 addition & 6 deletions spec/acceptance/rest/admin/api/accounting_profiles_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@
require 'rspec_api_documentation/dsl'

RSpec.resource 'Accounting profiles' do
header 'Accept', 'application/vnd.api+json'
header 'Content-Type', 'application/vnd.api+json'
header 'Authorization', :auth_token

let(:user) { create :admin_user }
let(:auth_token) { ::Knock::AuthToken.new(payload: { sub: user.id }).token }
include_context :acceptance_admin_user
let(:type) { 'accounting-profiles' }

required_params = %i[name server port secret timeout attempts]
Expand Down
7 changes: 1 addition & 6 deletions spec/acceptance/rest/admin/api/accounts_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@
require 'rspec_api_documentation/dsl'

RSpec.resource 'Accounts' do
header 'Accept', 'application/vnd.api+json'
header 'Content-Type', 'application/vnd.api+json'
header 'Authorization', :auth_token

let(:user) { create :admin_user }
let(:auth_token) { ::Knock::AuthToken.new(payload: { sub: user.id }).token }
include_context :acceptance_admin_user
let(:type) { 'accounts' }

required_params = %i[name min-balance max-balance]
Expand Down
7 changes: 1 addition & 6 deletions spec/acceptance/rest/admin/api/active_calls_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@
require 'rspec_api_documentation/dsl'

RSpec.resource 'ActiveCalls' do
header 'Accept', 'application/vnd.api+json'
header 'Content-Type', 'application/vnd.api+json'
header 'Authorization', :auth_token

let(:user) { create :admin_user }
let(:auth_token) { ::Knock::AuthToken.new(payload: { sub: user.id }).token }
include_context :acceptance_admin_user
let(:type) { 'active-calls' }

include_context :active_calls_stub_helpers do
Expand Down
7 changes: 1 addition & 6 deletions spec/acceptance/rest/admin/api/api_accesses_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@
require 'rspec_api_documentation/dsl'

RSpec.resource 'ApiAccesses' do
header 'Accept', 'application/vnd.api+json'
header 'Content-Type', 'application/vnd.api+json'
header 'Authorization', :auth_token

let(:user) { create :admin_user }
let(:auth_token) { ::Knock::AuthToken.new(payload: { sub: user.id }).token }
include_context :acceptance_admin_user
let(:type) { 'api-accesses' }

required_params = %i[customer-id login password]
Expand Down
7 changes: 1 addition & 6 deletions spec/acceptance/rest/admin/api/auth_profiles_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@
require 'rspec_api_documentation/dsl'

RSpec.resource 'Auth profiles' do
header 'Accept', 'application/vnd.api+json'
header 'Content-Type', 'application/vnd.api+json'
header 'Authorization', :auth_token

let(:user) { create :admin_user }
let(:auth_token) { ::Knock::AuthToken.new(payload: { sub: user.id }).token }
include_context :acceptance_admin_user
let(:type) { 'auth-profiles' }

required_params = %i[name server port secret timeout attempts]
Expand Down
7 changes: 1 addition & 6 deletions spec/acceptance/rest/admin/api/cdr_exports_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@
require 'rspec_api_documentation/dsl'

RSpec.resource 'Cdr Exports' do
header 'Accept', 'application/vnd.api+json'
header 'Content-Type', 'application/vnd.api+json'
header 'Authorization', :auth_token

let(:user) { create :admin_user }
let(:auth_token) { ::Knock::AuthToken.new(payload: { sub: user.id }).token }
include_context :acceptance_admin_user
let(:type) { 'cdr-exports' }
let(:country) { System::Country.take! }

Expand Down
7 changes: 1 addition & 6 deletions spec/acceptance/rest/admin/api/cdrs_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@
require 'rspec_api_documentation/dsl'

RSpec.resource 'Cdrs' do
header 'Accept', 'application/vnd.api+json'
header 'Content-Type', 'application/vnd.api+json'
header 'Authorization', :auth_token

let(:user) { create :admin_user }
let(:auth_token) { ::Knock::AuthToken.new(payload: { sub: user.id }).token }
include_context :acceptance_admin_user
let(:type) { 'cdrs' }

get '/api/rest/admin/cdrs' do
Expand Down
7 changes: 1 addition & 6 deletions spec/acceptance/rest/admin/api/codec_groups_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@
require 'rspec_api_documentation/dsl'

RSpec.resource 'Codec groups' do
header 'Accept', 'application/vnd.api+json'
header 'Content-Type', 'application/vnd.api+json'
header 'Authorization', :auth_token

let(:user) { create :admin_user }
let(:auth_token) { ::Knock::AuthToken.new(payload: { sub: user.id }).token }
include_context :acceptance_admin_user
let(:type) { 'codec-groups' }

get '/api/rest/admin/codec-groups' do
Expand Down
Loading

0 comments on commit 5c63011

Please sign in to comment.