Added support for OAuth2 client listing

Change-Id: Ie6766c79f33a2403aa116cc6e5f02316401d43be
diff --git a/Changes b/Changes
index 7267d4d..8539b59 100755
--- a/Changes
+++ b/Changes
@@ -1,8 +1,9 @@
-0.38 2020-02-05
+0.38 2020-03-17
         - Support X-Forwarded-Host name for proxy.
         - Document API URI.
         - Improve redirect handling in proxy.
         - Added support for OAuth2 client registration.
+        - Added support for OAuth2 client listing.
 
 0.37 2020-01-16
         - Removed deprecated 'kalamar_test_port' helper.
diff --git a/Gruntfile.js b/Gruntfile.js
index f06f558..3b31663 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -150,7 +150,7 @@
 		            'dev/scss/header/{header,hint,menu,searchbar,vc,statistics,datepicker}.scss',
 		            'dev/scss/main/{alertify,intro,koralquery,highlight,kwic,logos,tagger,' +
 		            'main,matchinfo,panel,tree,pagination,query,'+
-		            'resultinfo,sidebar,tutorial,plugin,buttongroup,introjs-ids,introjs}.scss'
+		            'resultinfo,sidebar,tutorial,plugin,buttongroup,introjs-ids,introjs,oauth}.scss'
 	             ],
 	      tasks: ['sass'],
 	      options: {
diff --git a/dev/scss/main/main.scss b/dev/scss/main/main.scss
index c97973b..f1d0048 100644
--- a/dev/scss/main/main.scss
+++ b/dev/scss/main/main.scss
@@ -16,6 +16,9 @@
 @import "plugin";      // Plugin mechanism
 @import "introjs";     // Guided Tour
 @import "introjs-ids"; // Guided Tour: IDS specific 
+@import "oauth";       // OAuth Management styles
+
+
 main {
   margin: {
     left: $standard-margin; 
diff --git a/dev/scss/main/oauth.scss b/dev/scss/main/oauth.scss
new file mode 100644
index 0000000..fc41fcb
--- /dev/null
+++ b/dev/scss/main/oauth.scss
@@ -0,0 +1,23 @@
+ul.client-list {
+  padding-left: 1.5em;
+  li {
+    list-style-type: none;
+    span.client-name {
+      &::before {
+        display: inline-block;
+        width: 1.5em;
+        margin-left: -1.5em;
+        content: $fa-plugin;
+        font-family: 'FontAwesome';
+        color: $ids-blue-1;
+        font-size: 100%;
+      }
+      font-weight: bold;
+      display: block;
+    }
+    span.client-desc {
+      font-size: 70%;
+      display: block;
+    }
+  }
+}
\ No newline at end of file
diff --git a/lib/Kalamar/Plugin/Auth.pm b/lib/Kalamar/Plugin/Auth.pm
index 184a028..f038638 100644
--- a/lib/Kalamar/Plugin/Auth.pm
+++ b/lib/Kalamar/Plugin/Auth.pm
@@ -283,6 +283,37 @@
       }
     );
 
+    # Get a list of registered clients
+    $app->helper(
+      'auth.client_list_p' => sub {
+        my $c = shift;
+
+        # Get list of registered clients
+        state $r_url = Mojo::URL->new($c->korap->api)->path('oauth2/client/list');
+
+        return $c->korap_request(post => $r_url, {} => form => {
+          client_id => $client_id,
+          client_secret => $client_secret,
+          authorized_only => 'no'
+        })->then(
+          sub {
+            my $tx = shift;
+            my $json = $tx->result->json;
+
+            # Response is fine
+            if ($tx->res->is_success) {
+              return Mojo::Promise->resolve($json);
+            };
+
+            $c->log->error($c->dumper($tx->res->to_string));
+
+            # Failure
+            $c->notify(error => $c->loc('Auth_responseError'));
+            return Mojo::Promise->reject($json // 'No response');
+          }
+        );
+      }
+    );
 
     # Issue a korap request with "oauth"orization
     # This will override the core request helper
@@ -621,7 +652,31 @@
       # Route to oauth settings
       $r->get('/settings/oauth')->to(
         cb => sub {
-          return shift->render(template => 'auth/tokens')
+          my $c = shift;
+
+          unless ($c->auth->token) {
+            return $c->render(
+              content => 'Unauthorized',
+              status => 401
+            );
+          };
+
+          # Wait for async result
+          $c->render_later;
+
+          $c->auth->client_list_p->then(
+            sub {
+              $c->stash('client_list' => shift);
+            }
+          )->catch(
+            sub {
+              return;
+            }
+          )->finally(
+            sub {
+              return $c->render(template => 'auth/tokens')
+            }
+          );
         }
       );
 
@@ -632,9 +687,10 @@
           my $v = $c->validation;
 
           unless ($c->auth->token) {
-
-            # TODO: not allowed
-            return $c->reply->not_found;
+            return $c->render(
+              content => 'Unauthorized',
+              status => 401
+            );
           };
 
           $v->csrf_protect;
diff --git a/lib/Kalamar/Plugin/Auth/templates/auth/tokens.html.ep b/lib/Kalamar/Plugin/Auth/templates/auth/tokens.html.ep
index d5fe095..74f59ef 100644
--- a/lib/Kalamar/Plugin/Auth/templates/auth/tokens.html.ep
+++ b/lib/Kalamar/Plugin/Auth/templates/auth/tokens.html.ep
@@ -2,6 +2,19 @@
 
 %= page_title
 
+% my $list = stash('client_list');
+% if ($list) {
+<ul class="client-list">
+%   foreach (@$list) {
+  <li>
+    <span class="client-name"><%= $_->{clientName} %></span>
+    <span class="client-desc"><%= $_->{description} %></span>
+  </li>
+%   };
+</ul>
+% };
+
+
 %= form_for 'oauth-register', class => 'form-table oauth-register', begin
   <fieldset>
     %= csrf_field
diff --git a/t/plugin/auth-oauth.t b/t/plugin/auth-oauth.t
index c9c4207..93cd3ca 100644
--- a/t/plugin/auth-oauth.t
+++ b/t/plugin/auth-oauth.t
@@ -407,6 +407,8 @@
 $t->get_ok('/settings/oauth')
   ->text_is('form.form-table legend', 'Register new client application')
   ->attr_is('form.oauth-register','action', '/settings/oauth/register')
+  ->text_is('ul.client-list > li > span.client-name', 'R statistical computing tool')
+  ->text_is('ul.client-list > li > span.client-desc', 'R is a free software environment for statistical computing and graphics.')
   ;
 
 $csrf = $t->post_ok('/settings/oauth/register' => form => {
diff --git a/t/server/mock.pl b/t/server/mock.pl
index 21192f0..4073d8d 100644
--- a/t/server/mock.pl
+++ b/t/server/mock.pl
@@ -515,6 +515,32 @@
 };
 
 
+# Register a client
+post '/v1.0/oauth2/client/list' => sub {
+  my $c = shift;
+
+  # $c->param('client_secret');
+  return $c->render(
+    json => [
+      {
+        "clientId" => "9aHsGW6QflV13ixNpez",
+        "clientName" => "R statistical computing tool",
+        "description" => "R is a free software environment for statistical computing and graphics.",
+        "url" => "https://www.r-project.org/"
+      },
+      {
+        "clientId" => "8bIDtZnH6NvRkW2Fq",
+        "clientName" => "EasyPDF Exporter",
+        "description" => "EasyPDF is a tool for exporting data to PDF.",
+        "url" => "https://www.easypdf.org/"
+      }
+    ],
+    status => 200
+  );
+};
+
+
+
 app->start;