-
Notifications
You must be signed in to change notification settings - Fork 37
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
1 parent
73da640
commit ca4e8ff
Showing
6 changed files
with
162 additions
and
0 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
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 |
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,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 |
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,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 |
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,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 |
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,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 |
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