-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
74 changed files
with
199 additions
and
490 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.