Skip to content

Commit

Permalink
add auth chain
Browse files Browse the repository at this point in the history
  • Loading branch information
JadeKharats authored and kickster97 committed Nov 27, 2024
1 parent 73da640 commit ca4e8ff
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 0 deletions.
62 changes: 62 additions & 0 deletions spec/auth_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
require "./spec_helper"

class MockAuthService < LavinMQ::AuthenticationService
property? should_succeed : Bool
property last_username : String?
property last_password : String?

def initialize(@should_succeed = false)
end

def authorize?(username : String, password : String)
@last_username = username
@last_password = password

if @should_succeed
"allow"
else
try_next(username, password)
end
end
end

describe LavinMQ::AuthenticationChain do
describe "#authorize?" do
it "returns nil when no services are configured" do
chain = LavinMQ::AuthenticationChain.new
chain.authorize?("user", "pass").should be_nil
end

it "tries services in order until success" do
# Arrange
chain = LavinMQ::AuthenticationChain.new
service1 = MockAuthService.new(should_succeed: false)
service2 = MockAuthService.new(should_succeed: true)
service3 = MockAuthService.new(should_succeed: true)

chain.add_service(service1)
chain.add_service(service2)
chain.add_service(service3)

# Act
user = chain.authorize?("test_user", "test_pass")

# Assert
user.should_not be_nil
service1.last_username.should eq("test_user")
service2.last_username.should eq("test_user")
service3.last_username.should be_nil # Ne devrait pas être appelé
end

it "returns nil if all services fail" do
chain = LavinMQ::AuthenticationChain.new
service1 = MockAuthService.new(should_succeed: false)
service2 = MockAuthService.new(should_succeed: false)

chain.add_service(service1)
chain.add_service(service2)

chain.authorize?("user", "pass").should be_nil
end
end
end
32 changes: 32 additions & 0 deletions src/lavinmq/auth/auth_chain.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
require "./services/auth_service"
require "./services/local_auth_service"
require "./services/http_service"

module LavinMQ
class AuthenticationChain
@first_service : AuthenticationService?

def initialize
@first_service = nil
end

def add_service(service : AuthenticationService)
if first = @first_service
current = first
while next_service = current.next_service
current = next_service
end
current.then(service)
else
@first_service = service
end
self
end

def authorize?(username : String, password : String)
if service = @first_service
service.authorize?(username, password)
end
end
end
end
18 changes: 18 additions & 0 deletions src/lavinmq/auth/services/auth_service.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module LavinMQ
abstract class AuthenticationService
property next_service : AuthenticationService?

abstract def authorize?(username : String, password : String)

def then(service : AuthenticationService) : AuthenticationService
@next_service = service
service
end

protected def try_next(username : String, password : String)
if next_service = @next_service
next_service.authorize?(username, password)
end
end
end
end
28 changes: 28 additions & 0 deletions src/lavinmq/auth/services/http_service.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require "http/client"
require "json"
require "./auth_service"

module LavinMQ
class HttpAuthService < AuthenticationService
def initialize(@method : String, @user_path : String, @whost_path : String, @resource_path : String, @topic_path : String)
end

def authorize?(username : String, password : String)

payload = {
"username" => username,
"password" => password
}.to_json

success = ::HTTP::Client.post(@user_path,
headers: ::HTTP::Headers{"Content-Type" => "application/json"},
body: payload).success?

if success
"allow"
else
try_next(username, password)
end
end
end
end
20 changes: 20 additions & 0 deletions src/lavinmq/auth/services/local_auth_service.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
require "./auth_service"

module LavinMQ
class LocalAuthService < AuthenticationService
def initialize(@users_store : UserStore)
end

def authorize?(username : String, password : String)
if user = @users_store[username]?
if user.password && user.password.not_nil!.verify(password)
"allow"
else
try_next(username, password)
end
else
try_next(username, password)
end
end
end
end
2 changes: 2 additions & 0 deletions src/lavinmq/server.cr
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ require "./exchange"
require "./amqp/queue"
require "./parameter"
require "./config"
require "./cache"
require "./auth/auth_chain"
require "./connection_info"
require "./proxy_protocol"
require "./client/client"
Expand Down

0 comments on commit ca4e8ff

Please sign in to comment.