OAuth client authorization handling (Fixes #54)
Change-Id: I3dd3b995af5e53bc8347818727e9733859eb1af6
diff --git a/t/plugin/auth-oauth.t b/t/plugin/auth-oauth.t
index e8ac795..e12c394 100644
--- a/t/plugin/auth-oauth.t
+++ b/t/plugin/auth-oauth.t
@@ -752,6 +752,133 @@
->text_is('div.notify-error', 'invalid_request: http://localhost/FAIL is invalid.')
;
+# OAuth client authorization flow
+$t->get_ok(Mojo::URL->new('/settings/oauth/authorize'))
+ ->status_is(302)
+ ->header_is('location','/settings/oauth/authorize')
+ ;
+
+# Logout
+$t->get_ok('/x/expired-with-wrong-refresh');
+
+$t->get_ok('/user/logout')
+ ->status_is(302)
+ ->session_hasnt('/auth')
+ ->session_hasnt('/auth_r')
+ ->session_hasnt('/user')
+ ->header_is('Location' => '/');
+
+$csrf = $t->get_ok('/')
+ ->status_is(200)
+ ->element_exists_not('div.notify-error')
+ ->element_exists('div.notify-success')
+ ->text_is('div.notify-success', 'Logout successful')
+ ->element_exists("input[name=handle]")
+ ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
+ ;
+
+$fwd = $t->get_ok(Mojo::URL->new('/settings/oauth/authorize')->query({
+ client_id => 'xyz',
+ state => 'abcde',
+ scope => 'search match',
+ redirect_uri => 'http://test.com/',
+}))
+ ->status_is(200)
+ ->attr_is('input[name=client_id]','value','xyz')
+ ->attr_is('input[name=state]','value','abcde')
+ ->attr_is('input[name=name]','value','xyz')
+ ->attr_like('input[name=fwd]','value',qr!test\.com!)
+ ->text_is('span.client-name','xyz')
+ ->text_is('div.intro p:nth-child(2)', 'Please log in!')
+ ->tx->res->dom->at('input[name=fwd]')->attr('value')
+ ;
+
+$fwd = $t->post_ok(Mojo::URL->new('/user/login')->query({
+ csrf_token => $csrf,
+ client_id => 'xyz',
+ state => 'abcde',
+ scope => 'search match',
+ redirect_uri => 'http://test.com/',
+ handle => 'test',
+ pwd => 'pass',
+ fwd => $fwd
+}))
+ ->status_is(302)
+ ->header_like('location', qr!/settings/oauth/authorize!)
+ ->tx->res->headers->header('location')
+ ;
+
+$t->get_ok($fwd)
+ ->status_is(200)
+ ->attr_is('input[name=client_id]','value','xyz')
+ ->attr_is('input[name=state]','value','abcde')
+ ->attr_is('input[name=name]','value','xyz')
+ ->text_is('ul#scopes li:nth-child(1)','search')
+ ->text_is('ul#scopes li:nth-child(2)','match')
+ ->text_is('span.client-name','xyz')
+ ->attr_is('a.form-button','href','http://test.com/')
+ ->attr_is('a.embedded-link', 'href', '/doc/korap/kalamar')
+ ;
+
+$t->get_ok(Mojo::URL->new('/settings/oauth/authorize')->query({
+ client_id => 'xyz',
+ state => 'abcde',
+ scope => 'search match',
+ redirect_uri => 'http://test.com/'
+}))
+ ->status_is(200)
+ ->attr_is('input[name=client_id]','value','xyz')
+ ->attr_is('input[name=state]','value','abcde')
+ ->attr_is('input[name=name]','value','xyz')
+ ->text_is('ul#scopes li:nth-child(1)','search')
+ ->text_is('ul#scopes li:nth-child(2)','match')
+ ->text_is('span.client-name','xyz')
+ ->attr_is('a.form-button','href','http://test.com/')
+ ->attr_is('a.embedded-link', 'href', '/doc/korap/kalamar')
+ ;
+
+$t->post_ok(Mojo::URL->new('/settings/oauth/authorize')->query({
+ client_id => 'xyz',
+ state => 'abcde',
+ scope => 'search match',
+ redirect_uri => 'http://test.com/'
+}))
+ ->status_is(302)
+ ->header_is('location', '/?error_description=Bad+CSRF+token')
+ ;
+
+$fwd = $t->post_ok(Mojo::URL->new('/settings/oauth/authorize')->query({
+ client_id => 'xyz',
+ state => 'abcde',
+ scope => 'search match',
+ redirect_uri_server => 'http://example.com/',
+ redirect_uri => $fake_backend_app->url_for('return_uri')->to_abs,
+ csrf_token => $csrf,
+}))
+ ->status_is(302)
+ ->header_like('location', qr!/realapi/fakeclient/return!)
+ ->tx->res->headers->header('location')
+ ;
+
+$t->get_ok($fwd)
+ ->status_is(200)
+ ->content_like(qr'welcome back! \[(.+?)\]')
+ ;
+
+$t->post_ok(Mojo::URL->new('/settings/oauth/authorize')->query({
+ client_id => 'xyz',
+ state => 'fail',
+ scope => 'search match',
+ redirect_uri_server => 'http://example.com/',
+ redirect_uri => $fake_backend_app->url_for('return_uri')->to_abs,
+ csrf_token => $csrf,
+}))
+ ->status_is(302)
+ ->header_is('location', 'http://example.com/?error_description=FAIL')
+ ;
+
done_testing;
__END__
+
+
diff --git a/t/server/mock.pl b/t/server/mock.pl
index d7ec2ff..7deb12a 100644
--- a/t/server/mock.pl
+++ b/t/server/mock.pl
@@ -669,9 +669,31 @@
my $c = shift;
my $type = $c->param('response_type');
my $client_id = $c->param('client_id');
- my $redirect_uri = $c->param('redirect_uri');
+ my $scope = $c->param('scope');
+ my $state = $c->param('state');
+ my $redirect_uri = $c->param('redirect_uri') // 'NO';
- if ($type eq 'code') {
+ if ($type eq 'code' && $client_id eq 'xyz') {
+
+ if ($state eq 'fail') {
+ $c->res->headers->location(
+ Mojo::URL->new($redirect_uri)->query({
+ error_description => 'FAIL'
+ })
+ );
+ $c->res->code(400);
+ return $c->rendered;
+ };
+
+ return $c->redirect_to(
+ Mojo::URL->new($redirect_uri)->query({
+ code => $tokens{auth_token_1},
+ scope => $scope,
+ })
+ );
+ }
+
+ elsif ($type eq 'code') {
return $c->redirect_to(
Mojo::URL->new($redirect_uri)->query({
@@ -812,6 +834,13 @@
return $c->render(text => 'SUCCESS');
};
+get '/fakeclient/return' => sub {
+ my $c = shift;
+ $c->render(
+ text => 'welcome back! [' . $c->param('code') . ']'
+ );
+} => 'return_uri';
+
app->start;