[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