From e81b1cb52e386f03b4a2912fbffb88bac8e428d0 Mon Sep 17 00:00:00 2001 From: dakkar Date: Sat, 16 Dec 2017 18:36:46 +0000 Subject: authentication middleware --- lib/Ultramarine/Middleware/Authentication.pm6 | 30 +++++++++++++ t/tests/middleware/authentication.t | 65 +++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 lib/Ultramarine/Middleware/Authentication.pm6 create mode 100644 t/tests/middleware/authentication.t diff --git a/lib/Ultramarine/Middleware/Authentication.pm6 b/lib/Ultramarine/Middleware/Authentication.pm6 new file mode 100644 index 0000000..d71f75c --- /dev/null +++ b/lib/Ultramarine/Middleware/Authentication.pm6 @@ -0,0 +1,30 @@ +use v6.d.PREVIEW; +use Cro::HTTP::Middleware; + +# mixin for requests, carrying authentication info +role Ultramarine::Request::Authed { + has Str $.user; +} + +class Ultramarine::Middleware::Authentication + does Cro::HTTP::Middleware::Request { + has $.users; + method process(Supply:D $request-stream) { + supply whenever $request-stream -> $request { + # here we would have some proper authentication logic + my $user = $request.query-value('u')[0]; + my $valid; + if (my $password = $request.query-value('p')[0]) { + $valid = $.users.authenticate(:$user,:$password); + } + elsif (my $token = $request.query-value('t')[0] + and my $salt = $request.query-value('s')[0]) { + $valid = $.users.authenticate(:$user,:$token,:$salt); + } + $request does Ultramarine::Request::Authed(:user($user)) + if $valid; + + emit $request; + } + } +} diff --git a/t/tests/middleware/authentication.t b/t/tests/middleware/authentication.t new file mode 100644 index 0000000..b696aaa --- /dev/null +++ b/t/tests/middleware/authentication.t @@ -0,0 +1,65 @@ +use v6.d.PREVIEW; +use Test; +use Ultramarine::Middleware::Authentication; + +class TestUsers { + has @.responses; + has @!calls; + + method authenticate(|c) { + @!calls.push(c); + return @.responses.shift; + } + + method calls() { return @!calls } +} + +class TestRequest { + has %!query; + submethod BUILD(:%!query) {} + method query-value($key) { + return [ %!query{$key} ]; + } +} + +my $users = TestUsers.new(responses=>[0,1,0,1]); + +my $auth = Ultramarine::Middleware::Authentication.new(:$users); + +sub test_auth(%query,$expected,$message?) { + my $req = TestRequest.new(:%query); + my $supply = supply { emit $req }; + react { + whenever $auth.process($supply) -> $maybe-authed { + my $is-authed = $maybe-authed ~~ Ultramarine::Request::Authed; + if ($expected) { + subtest { + ok($is-authed,'should be authed'); + is($maybe-authed.user,%query,'with the correct user'); + }, $message; + } + else { + nok($is-authed,$message); + } + done; + }; + }; +} + +my %user-password = ( :u,:p ); +my %user-token = ( :u,:t,:s ); + +# the fail-pass-fail-pass comes from $users.responses +test_auth(%user-password,0,'auth fail should pass through'); +test_auth(%user-password,1,'auth pass should apply trait'); +test_auth(%user-token,0,'auth fail should pass through'); +test_auth(%user-token,1,'auth pass should apply trait'); + +is-deeply( + $users.calls, + [ |(\(:user,:password) xx 2), + |(\(:user,:token,:salt) xx 2) ], + 'the model should have been called with the correct parameters' +); + +done-testing; -- cgit v1.2.3