[Rt-commit] rt branch, 5.0/core-rt-authentoken, repushed
Craig Kaiser
craig at bestpractical.com
Fri May 8 10:22:21 EDT 2020
The branch 5.0/core-rt-authentoken was deleted and repushed:
was c41a3f2a7129e7e3eb2754587432bd27eb2f5cd3
now 3d6983609b6fb65e3b03a8d74aa36f2ea9cdb5f4
1: 85aad74ba5 ! 1: ba09539cdd Core RT::Authen::Token
@@ -104,18 +104,18 @@
+
+CREATE INDEX AuthTokensOwner ON AuthTokens (Owner);
-diff --git a/etc/upgrade/4.5.7/acl.Oracle b/etc/upgrade/4.5.7/acl.Oracle
-new file mode 100644
---- /dev/null
-+++ b/etc/upgrade/4.5.7/acl.Oracle
+diff --git a/etc/upgrade/4.5.5/acl.Oracle b/etc/upgrade/4.5.5/acl.Oracle
+new file mode 100644
+--- /dev/null
++++ b/etc/upgrade/4.5.5/acl.Oracle
@@
+sub acl { return () }
+1;
-diff --git a/etc/upgrade/4.5.7/acl.Pg b/etc/upgrade/4.5.7/acl.Pg
-new file mode 100644
---- /dev/null
-+++ b/etc/upgrade/4.5.7/acl.Pg
+diff --git a/etc/upgrade/4.5.5/acl.Pg b/etc/upgrade/4.5.5/acl.Pg
+new file mode 100644
+--- /dev/null
++++ b/etc/upgrade/4.5.5/acl.Pg
@@
+sub acl {
+ my $dbh = shift;
@@ -148,23 +148,18 @@
+1;
+
-diff --git a/etc/upgrade/4.5.7/acl.mysql b/etc/upgrade/4.5.7/acl.mysql
-new file mode 100644
---- /dev/null
-+++ b/etc/upgrade/4.5.7/acl.mysql
+diff --git a/etc/upgrade/4.5.5/acl.mysql b/etc/upgrade/4.5.5/acl.mysql
+new file mode 100644
+--- /dev/null
++++ b/etc/upgrade/4.5.5/acl.mysql
@@
+sub acl { return () }
+1;
-diff --git a/etc/upgrade/4.5.5/content b/etc/upgrade/4.5.7/content
-similarity index 100%
-rename from etc/upgrade/4.5.5/content
-rename to etc/upgrade/4.5.7/content
-
-diff --git a/etc/upgrade/4.5.7/schema.Oracle b/etc/upgrade/4.5.7/schema.Oracle
-new file mode 100644
---- /dev/null
-+++ b/etc/upgrade/4.5.7/schema.Oracle
+diff --git a/etc/upgrade/4.5.5/schema.Oracle b/etc/upgrade/4.5.5/schema.Oracle
+new file mode 100644
+--- /dev/null
++++ b/etc/upgrade/4.5.5/schema.Oracle
@@
+CREATE SEQUENCE AuthTokens_seq;
+CREATE TABLE AuthTokens (
@@ -182,10 +177,10 @@
+CREATE INDEX AuthTokensOwner ON AuthTokens (Owner);
+
-diff --git a/etc/upgrade/4.5.7/schema.Pg b/etc/upgrade/4.5.7/schema.Pg
-new file mode 100644
---- /dev/null
-+++ b/etc/upgrade/4.5.7/schema.Pg
+diff --git a/etc/upgrade/4.5.5/schema.Pg b/etc/upgrade/4.5.5/schema.Pg
+new file mode 100644
+--- /dev/null
++++ b/etc/upgrade/4.5.5/schema.Pg
@@
+CREATE SEQUENCE authtokens_id_seq;
+CREATE TABLE AuthTokens (
@@ -203,10 +198,10 @@
+
+CREATE INDEX AuthTokensOwner ON AuthTokens (Owner);
-diff --git a/etc/upgrade/4.5.7/schema.SQLite b/etc/upgrade/4.5.7/schema.SQLite
-new file mode 100644
---- /dev/null
-+++ b/etc/upgrade/4.5.7/schema.SQLite
+diff --git a/etc/upgrade/4.5.5/schema.SQLite b/etc/upgrade/4.5.5/schema.SQLite
+new file mode 100644
+--- /dev/null
++++ b/etc/upgrade/4.5.5/schema.SQLite
@@
+CREATE TABLE AuthTokens (
+ id INTEGER PRIMARY KEY,
@@ -223,10 +218,10 @@
+CREATE INDEX AuthTokensOwner on AuthTokens (Owner);
+
-diff --git a/etc/upgrade/4.5.7/schema.mysql b/etc/upgrade/4.5.7/schema.mysql
-new file mode 100644
---- /dev/null
-+++ b/etc/upgrade/4.5.7/schema.mysql
+diff --git a/etc/upgrade/4.5.5/schema.mysql b/etc/upgrade/4.5.5/schema.mysql
+new file mode 100644
+--- /dev/null
++++ b/etc/upgrade/4.5.5/schema.mysql
@@
+CREATE TABLE AuthTokens (
+ id int(11) NOT NULL AUTO_INCREMENT,
@@ -326,7 +321,7 @@
+ my $authstring = shift;
+ my $user = shift;
+
-+ my ($user_id, $cleartext_token) = RT::AuthToken->ParseAuthString($authstring);
++ my ($user_id, $cleartext_token) = RT::Authen::Token::AuthToken->ParseAuthString($authstring);
+ return unless $user_id;
+
+ my $user_obj = RT::CurrentUser->new;
@@ -339,7 +334,7 @@
+ return unless $check_user->Id && $user_obj->Id == $check_user->Id;
+ }
+
-+ my $tokens = RT::AuthTokens->new(RT->SystemUser);
++ my $tokens = RT::Authen::Token::AuthTokens->new(RT->SystemUser);
+ $tokens->LimitOwner(VALUE => $user_id);
+ while (my $token = $tokens->Next) {
+ if ($token->IsToken($cleartext_token)) {
@@ -357,13 +352,14 @@
+
+=head1 DESCRIPTION
+
-+Allow for users to generate and login with authentication tokens. Users
-+with the C<ManageAuthTokens> permission will see a new "Auth Tokens" menu
-+item under "Logged in as ____" -> Settings. On that page they will be able
-+to generate new tokens and modify or revoke existing tokens.
++This module adds the ability for users to generate and login with
++authentication tokens. Users with the C<ManageAuthTokens> permission
++will see a new "Auth Tokens" menu item under "Logged in as ____" ->
++Settings. On that page they will be able to generate new tokens and
++modify or revoke existing tokens.
+
+Once you have an authentication token, you may use it in place of a
-+password to log into RT. (Additionally, L<REST2> allows
++password to log into RT. (Additionally, L<RT::Extension::REST2> allows
+for using auth tokens with the C<Authorization: token> HTTP header.) One
+common use case is to use an authentication token as an
+application-specific password, so that you may revoke that application's
@@ -385,7 +381,6 @@
+Apache configuration to allow RT to access the Authorization header.
+
+ SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
-+
+=cut
+
+1;
@@ -442,7 +437,6 @@
+# those contributions and any derivatives thereof.
+#
+# END BPS TAGGED BLOCK }}}
-+
+use strict;
+use warnings;
+use 5.10.1;
@@ -820,7 +814,6 @@
+# those contributions and any derivatives thereof.
+#
+# END BPS TAGGED BLOCK }}}
-+
+use strict;
+use warnings;
+
@@ -888,63 +881,50 @@
# Authenticate if the user is trying to login via user/pass query args
my ($authed, $msg) = AttemptPasswordAuthentication($ARGS);
-+ AttemptTokenAuthentication($ARGS) unless $authed;
++ unless ($authed) {
++ my $get_env = sub {
++ my $key = shift;
++ if (RT::Interface::Web->can('RequestENV')) {
++ return RT::Interface::Web::RequestENV($key)
++ }
++ return $ENV{$key};
++ };
++
++ my ($pass, $user) = ('', '');
++ if (($get_env->('HTTP_AUTHORIZATION')||'') =~ /^token (.*)$/i) {
++ $pass ||= $1;
++ }
++ unless ( defined $pass ) {
++ my ($user_obj, $token) = RT::Authen::Token->UserForAuthString($pass, $user);
++ if ( $user_obj ) {
++ # log in
++ my $remote_addr = $get_env->('REMOTE_ADDR');
++ $RT::Logger->info("Successful login for @{[$user_obj->Name]} from $remote_addr using authentication token #@{[$token->Id]} (\"@{[$token->Description]}\")");
++
++ # It's important to nab the next page from the session before we blow
++ # the session away
++ my $next = RT::Interface::Web::RemoveNextPage($ARGS->{'next'});
++ $next = $next->{'url'} if ref $next;
++
++ RT::Interface::Web::InstantiateNewSession();
++ $HTML::Mason::Commands::session{'CurrentUser'} = $user_obj;
++
++ # Really the only time we don't want to redirect here is if we were
++ # passed user and pass as query params in the URL.
++ if ($next) {
++ RT::Interface::Web::Redirect($next);
++ }
++ elsif ($ARGS->{'next'}) {
++ # Invalid hash, but still wants to go somewhere, take them to /
++ RT::Interface::Web::Redirect(RT->Config->Get('WebURL'));
++ }
++ }
++ }
++ }
+
unless ($authed) {
my $m = $HTML::Mason::Commands::m;
-@@
- }
- }
-
-+sub AttemptTokenAuthentication {
-+ my $ARGS = shift;
-+ return if _UserLoggedIn();
-+
-+ my $get_env = sub {
-+ my $key = shift;
-+ if (RT::Interface::Web->can('RequestENV')) {
-+ return RT::Interface::Web::RequestENV($key)
-+ }
-+ return $ENV{$key};
-+ };
-+
-+ my ($pass, $user) = ('', '');
-+ if (($get_env->('HTTP_AUTHORIZATION')||'') =~ /^token (.*)$/i) {
-+ $pass ||= $1;
-+ }
-+ unless ( defined $pass ) {
-+ my ($user_obj, $token) = RT::Authen::Token->UserForAuthString($pass, $user);
-+ if ( $user_obj ) {
-+ # log in
-+ my $remote_addr = $get_env->('REMOTE_ADDR');
-+ $RT::Logger->info("Successful login for @{[$user_obj->Name]} from $remote_addr using authentication token #@{[$token->Id]} (\"@{[$token->Description]}\")");
-+
-+ # It's important to nab the next page from the session before we blow
-+ # the session away
-+ my $next = RT::Interface::Web::RemoveNextPage($ARGS->{'next'});
-+ $next = $next->{'url'} if ref $next;
-+
-+ RT::Interface::Web::InstantiateNewSession();
-+ $HTML::Mason::Commands::session{'CurrentUser'} = $user_obj;
-+
-+ # Really the only time we don't want to redirect here is if we were
-+ # passed user and pass as query params in the URL.
-+ if ($next) {
-+ RT::Interface::Web::Redirect($next);
-+ }
-+ elsif ($ARGS->{'next'}) {
-+ # Invalid hash, but still wants to go somewhere, take them to /
-+ RT::Interface::Web::Redirect(RT->Config->Get('WebURL'));
-+ }
-+ }
-+ }
-+}
-+
-+
- =head2 LoadSessionFromCookie
-
- Load or setup a session cookie for the current user.
diff --git a/lib/RT/Interface/Web/MenuBuilder.pm b/lib/RT/Interface/Web/MenuBuilder.pm
--- a/lib/RT/Interface/Web/MenuBuilder.pm
@@ -1034,7 +1014,6 @@
+%# those contributions and any derivatives thereof.
+%#
+%# END BPS TAGGED BLOCK }}}
-+
+<& /Admin/Elements/Header, Title => loc("[_1]'s authentication tokens",$UserObj->Name) &>
+<& /Elements/Tabs &>
+<& /Elements/ListActions, actions => \@results &>
@@ -1199,45 +1178,60 @@
+%# END BPS TAGGED BLOCK }}}
+<%ARGS>
+$Owner
-+$Error => ''
+$Description => ''
+</%ARGS>
+<%INIT>
+# Don't require password for systems with some form of federated auth
+my %res = $session{'CurrentUser'}->CurrentUserRequireToSetPassword();
+</%INIT>
-+<form class="authtoken-form" method="post" data-ajax-url="<% RT->Config->Get('WebPath') %>/Helpers/AuthToken/Create">
-+ <div class="form-row">
-+% if ($Error) {
-+ <div class="col-12">
-+ <p class="error"><% $Error %></p>
-+ </div>
++
++<div class="modal" id="create-auth-token">
++ <div class="modal-dialog modal-dialog-centered" role="document">
++ <div class="modal-content">
++ <div class="modal-header">
++ <h5 class="modal-title"><&|/l&>Create auth token</&></h5>
++ <a href="javascript:void(0)" class="close" data-dismiss="modal" aria-label="Close">
++ <span aria-hidden="true">×</span>
++ </a>
++ </div>
++ <div class="modal-body">
++ <form class="authtoken-form" method="post" data-ajax-url="<% RT->Config->Get('WebPath') %>/Helpers/AuthToken/Create">
++ <div class="form-row">
++ <input type="hidden" name="Owner" value="<% $Owner %>">
++% if ( $res{'CanSet'} ){
++ <div class="label col-3">
++ <&|/l, $session{'CurrentUser'}->Name()&>[_1]'s current password</&>:
++ </div>
++ <div class="value col-9">
++ <input class="form-control" type="password" name="Password" size="16" autocomplete="off" /></td>
++ </div>
+% }
-+ <input type="hidden" name="Owner" value="<% $Owner %>">
-+% if ( $res{'CanSet'} ){
-+ <div class="label col-3">
-+ <&|/l, $session{'CurrentUser'}->Name()&>[_1]'s current password</&>:
-+ </div>
-+ <div class="value col-8">
-+ <input class="form-control" type="password" name="Password" size="16" autocomplete="off" /></td>
-+ </div>
-+% }
-+ <div class="col-3 label">
-+ <&|/l&>Description</&>:<br><em><&|/l&>What's this token for?</&></em>
-+ </div>
-+ <div class="value col-9">
-+ <input class="form-control" type="text" name="Description" value="<% $Description %>" size="16" />
++ <div class="col-3 label">
++ <&|/l&>Description</&>:<br><em><&|/l&>What's this token for?</&></em>
++ </div>
++ <div class="value col-9">
++ <input class="form-control" type="text" name="Description" value="<% $Description %>" size="16" />
++ </div>
++ </div>
++
++ <div class="form-row">
++ <div class="col-12">
++ <& /Elements/Submit, Label => loc("Create"), Name => 'CreateToken' &>
++ </div>
++ </div>
++
++ <span class="loading"><img src="<%RT->Config->Get('WebPath')%>/static/images/loading.gif" alt="<%loc('Loading')%>" title="<%loc('Loading')%>" /></span>
++ </form>
++ </div>
+ </div>
+ </div>
-+
-+ <div class="form-row">
-+ <div class="col-12">
-+ <& /Elements/Submit, Label => loc("Create"), Name => 'CreateToken' &>
-+ </div>
++</div>
++
++<div class="form-row">
++ <div class="col-12">
++ <a class="button btn btn-primary" href="#create-auth-token" data-toggle="modal" rel="modal:open" name="create_auth_token"><&|/l&>Create Auth Token</&></a>
+ </div>
-+
-+ <span class="loading"><img src="<%RT->Config->Get('WebPath')%>/static/images/loading.gif" alt="<%loc('Loading')%>" title="<%loc('Loading')%>" /></span>
-+</form>
++</div>
diff --git a/share/html/Elements/AuthToken/CreateResults b/share/html/Elements/AuthToken/CreateResults
new file mode 100644
@@ -1297,7 +1291,7 @@
+$Description => ''
+</%ARGS>
+<%INIT>
-+my $token = RT::Authen::Token::AuthToken->new($session{CurrentUser});
++my $token = RT::AuthToken->new($session{CurrentUser});
+# Don't require password for systems with some form of federated auth
+my %res = $session{'CurrentUser'}->CurrentUserRequireToSetPassword();
+my ($error, $authstring);
@@ -1325,10 +1319,17 @@
+% if ($error) {
+ <& /Elements/AuthToken/CreateForm, Owner => $Owner, Error => $error, Description => $Description &>
+% } else {
-+ <div class="authtoken-success">
-+ <p><&|/l, $Description&>This is your new authentication token. Treat it carefully like a password. Please save it now because you cannot access it again.</&></p>
-+ <br>
-+ <span class="authstring"><% $authstring %></span>
++ <div class="authtoken-success">
++ <div class="col-12">
++ <p><&|/l, $Description&>This is your new authentication token. Treat
++ it carefully like a password. Please save it now because you cannot
++ access it again.
++ </&></p>
++ </div>
++ <div class="col-12 text-center">
++ <span class="authstring"><% $authstring %></span>
++ </div>
++ </div>
+ </div>
+</div>
+% }
@@ -1393,53 +1394,86 @@
+my $tokens = RT::Authen::Token::AuthTokens->new($session{CurrentUser});
+$tokens->LimitOwner(VALUE => $Owner);
+</%INIT>
-+<div class="form-row authtoken-list" data-owner="<% $Owner %>">
-+ <div class="col-6">
-+ <span class="loading"><img src="<%RT->Config->Get('WebPath')%>/static/images/loading.gif" alt="<%loc('Loading')%>" title="<%loc('Loading')%>" /></span>
-+
++<div class="authtoken-list" data-owner="<% $Owner %>">
++ <span class="loading"><img src="<%RT->Config->Get('WebPath')%>/static/images/loading.gif" alt="<%loc('Loading')%>" title="<%loc('Loading')%>" /></span>
+% if ($tokens->Count == 0) {
-+ <em><&|/l&>No authentication tokens.</&></em>
++ <em><&|/l&>No authentication tokens.</&></em>
+% } else {
-+ <ul class="list-group">
++ <ul class="list-group">
+% while (my $token = $tokens->Next) {
-+ <li class="list-group-item" id="token-<% $token->Id %>">
++ <div class="form-row">
++ <div class="col-6">
++ <li class="list-group" id="auth-token-<% $token->Id %>">
++
++% my $used = $token->LastUsedObj;
++% my $last_updated = '';
++% if ($used->IsSet) {
++% $last_updated = loc( $used->AgeAsString, "used [_1]" );
++% } else {
++% $last_updated = loc( "never used" );
++% }
++ <&| /Widgets/TitleBox,
++ title => $token->Description,
++ title_href => "#auth-token-".$token->Id,
++ titleright_raw => $last_updated,
++ rolledup => 0
++ &>
+% if ($ARGS{ShowModifyForm} && $ARGS{Token} == $token->Id) {
-+ <&| /Widgets/TitleBox, title => loc("Update Auth Token") &>
-+% if ($ARGS{Update} || $ARGS{Revoke}) {
-+ <& /Elements/AuthToken/ModifyResults, %ARGS, Token => $token->Id &>
++% if ($ARGS{Update} || $ARGS{Revoke}) {
++ <& /Elements/AuthToken/ModifyResults, %ARGS, Token => $token->Id, Owner => $Owner &>
++% }
++% }
++ <form class="authtoken-form" method="post" data-ajax-url="<% RT->Config->Get('WebPath') %>/Helpers/AuthToken/Modify" action="<% RT->Config->Get('WebPath') %><% $r->uri %>">
++ <div class="form-row">
++% if ($ARGS{id}) {
++ <input type="hidden" name="id" value="<% $ARGS{id} %>">
++% }
++ <input type="hidden" name="Token" value="<% $token->id %>">
++ <input type="hidden" name="Owner" value="<% $Owner %>">
++
++ <div class="col-4">
++ <label class="label"><&|/l&>Description</&>:
++ <span class="far fa-question-circle icon-helper" data-toggle="tooltip" data-placement="top" data-original-title="<&|/l&>What's this token for?</&>"></span>
++ </label>
++ </div>
++ <div class="col-8">
++ <span class="value"><input class="form-control" type="text" name="Description" value="<% $ARGS{Description} // $token->Description %>" size="16" /></span>
++ </div>
++
++ <div class="col-4">
++ <label class="label"><&|/l&>Last Used</&>:</label>
++ </div>
++ <div class="col-8">
++% my $used = $token->LastUsedObj;
++ <span class="value">
++% if ($used->IsSet) {
++ <% $used->AgeAsString %>
+% } else {
-+ <& /Elements/AuthToken/ModifyForm, %ARGS, TokenObj => $token &>
++ <&|/l&>never</&>
+% }
-+ </&>
-+% } else {
-+ <span class="description"><% $token->Description %></span>
-+ <span class="lastused">
-+% my $used = $token->LastUsedObj;
-+% if ($used->IsSet) {
-+ <&|/l, $used->AgeAsString &>used [_1]</&>
-+% } else {
-+ <&|/l&>never used</&>
-+% }
-+ </span>
++ </span>
++ </div>
++
++ <div class="col-4">
++ <label class="label"><&|/l&>Created</&>:</label>
++ </div>
++ <div class="col-8">
++ <span class="value"><% $token->CreatedObj->AgeAsString %></span>
++ </div>
++
++ <div class="col-6">
++ <input class="button btn btn-primary" type="submit" name="Update" value="<&|/l&>Save</&>"></input>
++ </div>
++ <div class="col-6">
++ <input class="button btn btn-primary" type="submit" name="Revoke" value="<&|/l&>Revoke</&>"></input>
++ </div>
++ <span class="loading"><img src="<%RT->Config->Get('WebPath')%>/static/images/loading.gif" alt="<%loc('Loading')%>" title="<%loc('Loading')%>" /></span>
++ </form>
++ </div>
++ </&>
++ </li>
+ </div>
-+
-+ <div class="col-6">
-+ <div class="authtoken-form-container">
-+ <& /Elements/AuthToken/ModifyForm, %ARGS, TokenObj => $token &>
-+ </div>
-+ <form method="GET" action="<%RT->Config->Get('WebPath')%><% $r->path_info %>#token-<% $token->Id %>">
-+ <input type="hidden" name="ShowModifyForm" value="1">
-+ <input type="hidden" name="id" value="<% $Owner %>">
-+ <input type="hidden" name="Token" value="<% $token->Id %>">
-+ <div class="form-row">
-+ <div class="col-auto">
-+ <& /Elements/Submit, Label => loc('Edit'), Name => 'EditAuthToken', id => 'EditAuthToken' &>
-+ </div>
-+ </div>
-+ </form>
-+ </div>
-+% }
-+ </li>
++ </div>
+% }
+ </ul>
+% }
@@ -1507,56 +1541,72 @@
+ $TokenObj = RT::Authen::Token::AuthToken->new($session{CurrentUser});
+ $TokenObj->Load($Token);
+}
-+
+Abort("Unable to load authentication token") if !$TokenObj->Id;
+Abort("Permission Denied") if !$TokenObj->CurrentUserCanSee;
+</%INIT>
-+<form class="authtoken-form" method="post" data-ajax-url="<% RT->Config->Get('WebPath') %>/Helpers/AuthToken/Modify" action="<% RT->Config->Get('WebPath') %><% $r->uri %>">
++
++<div class="modal" id="edit-auth-token">
++ <div class="modal-dialog modal-dialog-centered" role="document">
++ <div class="modal-content">
++ <div class="modal-header">
++ <h5 class="modal-title"><&|/l&>Edit auth token</&></h5>
++ <a href="javascript:void(0)" class="close" data-dismiss="modal" aria-label="Close">
++ <span aria-hidden="true">×</span>
++ </a>
++ </div>
++ <div class="modal-body">
++ <form class="authtoken-form" method="post" data-ajax-url="<% RT->Config->Get('WebPath') %>/Helpers/AuthToken/Modify" action="<% RT->Config->Get('WebPath') %><% $r->uri %>">
++ <div class="form-row">
+% if ($Error) {
-+<p class="error"><% $Error %></p>
++ <div class="col-12">
++ <p class="error"><% $Error %></p>
++ </div>
+% }
-+
+% if ($ARGS{id}) {
-+<input type="hidden" name="id" value="<% $ARGS{id} %>">
++ <input type="hidden" name="id" value="<% $ARGS{id} %>">
+% }
-+
-+<input type="hidden" name="ShowModifyForm" value="1">
-+<input type="hidden" name="Token" value="<% $TokenObj->id %>">
-+<div class="form-row">
-+ <div class="col-4 label">
-+ <&|/l&>Description</&>:<br><em><&|/l&>What's this token for?</&></em>
-+ </div>
-+ <div class="col-8 value">
-+ <input class="form-control" type="text" name="Description" value="<% $ARGS{Description} // $TokenObj->Description %>" size="16" />
-+ </div>
-+
-+ <div class="col-4 label">
-+ <&|/l&>Last Used</&>:
-+ </div>
-+ <div class="col-8 value">
++ <input type="hidden" name="Token" value="<% $TokenObj->id %>">
++
++ <div class="form-row">
++ <div class="col-4 label">
++ <&|/l&>Description</&>:<br><em><&|/l&>What's this token for?</&></em>
++ </div>
++ <div class="col-8 value">
++ <input class="form-control" type="text" name="Description" value="<% $ARGS{Description} // $TokenObj->Description %>" size="16" />
++ </div>
++
++ <div class="col-4 label">
++ <&|/l&>Last Used</&>:
++ </div>
++ <div class="col-8 value">
+% my $used = $TokenObj->LastUsedObj;
+% if ($used->IsSet) {
-+ <% $used->AgeAsString %>
++ <% $used->AgeAsString %>
+% } else {
-+ <&|/l&>never</&>
++ <&|/l&>never</&>
+% }
-+ </div>
-+
-+ <div class="col-4 label">
-+ <&|/l&>Created</&>:
-+ </div>
-+ <div class="col-8 value">
-+ <% $TokenObj->CreatedObj->AgeAsString %>
++ </div>
++
++ <div class="col-4 label">
++ <&|/l&>Created</&>:
++ </div>
++ <div class="col-8 value">
++ <% $TokenObj->CreatedObj->AgeAsString %>
++ </div>
++ </div>
++
++ <div class="buttons">
++ <input type="submit" name="Update" value="<&|/l&>Save</&>"></input>
++ <input type="submit" name="Revoke" value="<&|/l&>Revoke</&>"></input>
++ </div>
++
++ <span class="loading"><img src="<%RT->Config->Get('WebPath')%>/static/images/loading.gif" alt="<%loc('Loading')%>" title="<%loc('Loading')%>" /></span>
++ </div>
++ </form>
++ </div>
++ </div>
+ </div>
+</div>
-+
-+<div class="buttons">
-+ <input type="submit" name="Update" value="<&|/l&>Save</&>"></input>
-+ <input type="submit" name="Revoke" value="<&|/l&>Revoke</&>"></input>
-+</div>
-+
-+<span class="loading"><img src="<%RT->Config->Get('WebPath')%>/static/images/loading.gif" alt="<%loc('Loading')%>" title="<%loc('Loading')%>" /></span>
-+</form>
diff --git a/share/html/Elements/AuthToken/ModifyResults b/share/html/Elements/AuthToken/ModifyResults
new file mode 100644
@@ -1635,11 +1685,17 @@
+ ($ok, $msg) = $TokenObj->Delete;
+}
+</%INIT>
-+% if ($error || !$msg) {
-+<& /Elements/AuthToken/ModifyForm, TokenObj => $TokenObj, Error => $error, Description => $Description, id => $ARGS{id} &>
-+% } else {
-+<% $msg %>
++<div id="messages" class="auth-token-messages col-6">
++% if ( $error ) {
++ <div class="alert alert-danger" role="alert">
++ <% $error %>
++ </div>
++% } if ( $msg ) {
++ <div class="alert alert-success" role="alert">
++ <% $msg %>
++ </div>
+% }
++</div>
diff --git a/share/html/Helpers/AuthToken/Create b/share/html/Helpers/AuthToken/Create
new file mode 100644
@@ -1858,23 +1914,29 @@
+%# those contributions and any derivatives thereof.
+%#
+%# END BPS TAGGED BLOCK }}}
-+
+<& /Elements/Header, Title => loc('My authentication tokens') &>
+<& /Elements/Tabs &>
+<& /Elements/ListActions, actions => \@results &>
+
+<div class="form-row">
-+ <div class="auth-tokens col-12">
++ <div class="col-12">
+ <p><&|/l&>Authentication tokens allow other applications to use your user
+ account without having to share your password, while allowing you to
+ revoke access on an application-specific basis. Changing your password
+ <em>does not</em> invalidate your auth tokens; you must revoke them here.
+ </&></p>
+ </div>
-+</div>
-+
-+<& /Elements/AuthToken/CreateButton, %ARGS, Owner => $UserObj->Id &>
-+<& /Elements/AuthToken/List, %ARGS, Owner => $UserObj->Id &>
++
++ <div class="col-12">
++ <& /Elements/AuthToken/CreateForm, %ARGS, Owner => $UserObj->Id &>
++ </div>
++
++ <div id="auth-token-messages" class="auth-token-messages col-12">
++ </div>
++
++ <div class="col-12">
++ <& /Elements/AuthToken/List, %ARGS, Owner => $UserObj->Id &>
++ </div>
+</div>
+
+<%INIT>
@@ -1966,6 +2028,9 @@
+ float: left;
+}
+
++.auth-token-messages {
++ margin: 1rem 0rem 0rem 0px;
++}
diff --git a/share/static/images/loading.gif b/share/static/images/loading.gif
new file mode 100644
@@ -1977,24 +2042,6 @@
+++ b/share/static/js/rt-authen-token.js
@@
+jQuery(function() {
-+ var showModal = function(html) {
-+ jQuery("<div class='modal'></div>")
-+ .append(html).appendTo("body")
-+ .bind('modal:close', function(ev,modal) { modal.elm.remove(); })
-+ .modal();
-+ };
-+
-+ jQuery('.authtoken-create').click(function(e) {
-+ e.preventDefault();
-+ showModal(jQuery('.authtoken-form-container').html());
-+ });
-+
-+ jQuery('.auth-tokens').on('click', '.authtoken-modify', function(e) {
-+ e.preventDefault();
-+ var container = jQuery(e.currentTarget).closest('li');
-+ showModal(container.find('.authtoken-form-container').html());
-+ });
-+
+ var refreshTokenList = function () {
+ var list = jQuery('.authtoken-list');
+ jQuery.post(
@@ -2008,6 +2055,8 @@
+
+ var submitForm = function (form, extraParams) {
+ var payload = form.serializeArray();
++ var name = extraParams[0].name;
++
+ if (extraParams) {
+ Array.prototype.push.apply(payload, extraParams);
+ }
@@ -2015,13 +2064,18 @@
+ form.addClass('submitting');
+ form.find('input').attr('disabled', true);
+
-+ var renderResult = function(html) {
-+ var form = jQuery('.modal .authtoken-form');
-+ if (form.length) {
-+ form.replaceWith(html);
++ var renderResult = function(name, html) {
++ if ( name === 'CreateToken' ) {
++ var form = jQuery('.modal .authtoken-form');
++ if (form.length) {
++ form.replaceWith(html);
++ }
++ else {
++ jQuery('#body').append(html);
++ }
+ }
+ else {
-+ jQuery('#body').append(html);
++ jQuery('#auth-token-messages').replaceWith(html);
+ }
+ refreshTokenList();
+ };
@@ -2032,7 +2086,7 @@
+ data: payload,
+ timeout: 30000, /* 30 seconds */
+ success: function (data, status) {
-+ renderResult(data);
++ renderResult(name, data);
+ },
+ error: function (xhr, status, error) {
+ renderResult("<p>An error has occurred. Please refresh the page and try again.<p>");
2: a4767ecdf9 < -: ------- Make RT::Authen::Token behave like other parts of RT
-: ------- > 2: 34c4eb92e7 Migrate Authen-Token code to work like other RT pages
3: c41a3f2a71 ! 3: 3d6983609b Add documentation for using token auth
@@ -5,16 +5,6 @@
diff --git a/docs/authentication.pod b/docs/authentication.pod
--- a/docs/authentication.pod
+++ b/docs/authentication.pod
-@@
- provide new user creation as well as password setting and control of RT's
- privileged flag for existing users.
-
-+There is also built in token generation for users to authentificate with a
-+token, for more information on this see L<RT::Authen::Token>.
-+
- =head1 External Authentication
-
- There are two primary types of external authentication: in one you type your
@@
</Location>
@@ -55,7 +45,7 @@
+
=head1 DESCRIPTION
- Allow for users to generate and login with authentication tokens. Users
+ Allow for users to generate and login with authentication tokens.
@@
database just like passwords, and so cannot be recovered after they are
generated.
@@ -65,16 +55,3 @@
If you are running RT under Apache, add the following directive to your RT
Apache configuration to allow RT to access the Authorization header.
-
-diff --git a/lib/RT/Authen/Token/AuthTokens.pm b/lib/RT/Authen/Token/AuthTokens.pm
---- a/lib/RT/Authen/Token/AuthTokens.pm
-+++ b/lib/RT/Authen/Token/AuthTokens.pm
-@@
-
- RT::Authen::Token::AuthTokens - a collection of L<RT::Authen::Token::AuthToken> objects
-
-+=cut
-+
- =head2 LimitOwner
-
- Limit Owner
More information about the rt-commit
mailing list