[Rt-commit] rt branch, 5.0/core-rt-authentoken, repushed
Craig Kaiser
craig at bestpractical.com
Thu May 7 18:02:07 EDT 2020
The branch 5.0/core-rt-authentoken was deleted and repushed:
was 0f005b83ff49104b8de55503ba8061e5f39765e8
now c41a3f2a7129e7e3eb2754587432bd27eb2f5cd3
1: 549b57065e ! 1: 85aad74ba5 Core RT::Authen::Token
@@ -9,8 +9,8 @@
ObjectCustomRoles
configurations_id_seq
Configurations
-+ rtxauthtokens_id_seq
-+ RTxAuthTokens
++ authtokens_id_seq
++ AuthTokens
);
my $db_user = RT->Config->Get('DatabaseUser');
@@ -23,9 +23,9 @@
CREATE INDEX Configurations1 ON Configurations (LOWER(Name), Disabled);
CREATE INDEX Configurations2 ON Configurations (Disabled);
+
-+CREATE SEQUENCE RTxAuthTokens_seq;
-+CREATE TABLE RTxAuthTokens (
-+ id NUMBER(11,0) CONSTRAINT RTxAuthTokens_key PRIMARY KEY,
++CREATE SEQUENCE AuthTokens_seq;
++CREATE TABLE AuthTokens (
++ id NUMBER(11,0) CONSTRAINT AuthTokens_key PRIMARY KEY,
+ Owner NUMBER(11,0) DEFAULT 0 NOT NULL,
+ Token VARCHAR2(256),
+ Description varchar2(255) DEFAULT '',
@@ -36,7 +36,7 @@
+ LastUpdated DATE
+);
+
-+CREATE INDEX RTxAuthTokensOwner ON RTxAuthTokens (Owner);
++CREATE INDEX AuthTokensOwner ON AuthTokens (Owner);
diff --git a/etc/schema.Pg b/etc/schema.Pg
--- a/etc/schema.Pg
@@ -45,9 +45,9 @@
CREATE INDEX Configurations1 ON Configurations (LOWER(Name), Disabled);
CREATE INDEX Configurations2 ON Configurations (Disabled);
-+CREATE SEQUENCE rtxauthtokens_id_seq;
-+CREATE TABLE RTxAuthTokens (
-+ id integer DEFAULT nextval('rtxauthtokens_id_seq'),
++CREATE SEQUENCE authtokens_id_seq;
++CREATE TABLE AuthTokens (
++ id integer DEFAULT nextval('authtokens_id_seq'),
+ Owner integer NOT NULL DEFAULT 0,
+ Token varchar(256) NULL,
+ Description varchar(255) NOT NULL DEFAULT '',
@@ -59,7 +59,7 @@
+ PRIMARY KEY (id)
+);
+
-+CREATE INDEX RTxAuthTokensOwner ON RTxAuthTokens (Owner);
++CREATE INDEX AuthTokensOwner ON AuthTokens (Owner);
diff --git a/etc/schema.SQLite b/etc/schema.SQLite
--- a/etc/schema.SQLite
@@ -68,7 +68,7 @@
CREATE INDEX Configurations1 ON Configurations (Name, Disabled);
CREATE INDEX Configurations2 ON Configurations (Disabled);
-+CREATE TABLE RTxAuthTokens (
++CREATE TABLE AuthTokens (
+ id INTEGER PRIMARY KEY,
+ Owner int(11) NOT NULL DEFAULT 0,
+ Token varchar(256) collate NOCASE NULL ,
@@ -80,7 +80,7 @@
+ LastUpdated timestamp DEFAULT NULL
+);
+
-+CREATE INDEX RTxAuthTokensOwner on RTxAuthTokens (Owner);
++CREATE INDEX AuthTokensOwner on AuthTokens (Owner);
diff --git a/etc/schema.mysql b/etc/schema.mysql
--- a/etc/schema.mysql
@@ -89,7 +89,7 @@
CREATE INDEX Configurations1 ON Configurations (Name, Disabled);
CREATE INDEX Configurations2 ON Configurations (Disabled);
-+CREATE TABLE RTxAuthTokens (
++CREATE TABLE AuthTokens (
+ id int(11) NOT NULL AUTO_INCREMENT,
+ Owner int(11) NOT NULL DEFAULT 0,
+ Token varchar(256) NULL,
@@ -102,28 +102,28 @@
+ PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
-+CREATE INDEX RTxAuthTokensOwner ON RTxAuthTokens (Owner);
-
-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
++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
@@
+sub acl { return () }
+1;
-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
+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
@@
+sub acl {
+ my $dbh = shift;
+
+ my @acls;
+ my @tables = qw (
-+ rtxauthtokens_id_seq
-+ RTxAuthTokens
++ authtokens_id_seq
++ AuthTokens
+ );
+
+ my $db_user = RT->Config->Get('DatabaseUser');
@@ -148,22 +148,27 @@
+1;
+
-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
+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
@@
+sub acl { return () }
+1;
-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 RTxAuthTokens_seq;
-+CREATE TABLE RTxAuthTokens (
-+ id NUMBER(11,0) CONSTRAINT RTxAuthTokens_key PRIMARY KEY,
+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
+@@
++CREATE SEQUENCE AuthTokens_seq;
++CREATE TABLE AuthTokens (
++ id NUMBER(11,0) CONSTRAINT AuthTokens_key PRIMARY KEY,
+ Owner NUMBER(11,0) DEFAULT 0 NOT NULL,
+ Token VARCHAR2(256),
+ Description varchar2(255) DEFAULT '',
@@ -174,17 +179,17 @@
+ LastUpdated DATE
+);
+
-+CREATE INDEX RTxAuthTokensOwner ON RTxAuthTokens (Owner);
-+
-
-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 rtxauthtokens_id_seq;
-+CREATE TABLE RTxAuthTokens (
-+ id integer DEFAULT nextval('rtxauthtokens_id_seq'),
++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
+@@
++CREATE SEQUENCE authtokens_id_seq;
++CREATE TABLE AuthTokens (
++ id integer DEFAULT nextval('authtokens_id_seq'),
+ Owner integer NOT NULL DEFAULT 0,
+ Token varchar(256) NULL,
+ Description varchar(255) NOT NULL DEFAULT '',
@@ -196,14 +201,14 @@
+ PRIMARY KEY (id)
+);
+
-+CREATE INDEX RTxAuthTokensOwner ON RTxAuthTokens (Owner);
-
-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 RTxAuthTokens (
++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
+@@
++CREATE TABLE AuthTokens (
+ id INTEGER PRIMARY KEY,
+ Owner int(11) NOT NULL DEFAULT 0,
+ Token varchar(256) collate NOCASE NULL ,
@@ -215,15 +220,15 @@
+ LastUpdated timestamp DEFAULT NULL
+);
+
-+CREATE INDEX RTxAuthTokensOwner on RTxAuthTokens (Owner);
-+
-
-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 RTxAuthTokens (
++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
+@@
++CREATE TABLE AuthTokens (
+ id int(11) NOT NULL AUTO_INCREMENT,
+ Owner int(11) NOT NULL DEFAULT 0,
+ Token varchar(256) NULL,
@@ -236,7 +241,7 @@
+ PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
-+CREATE INDEX RTxAuthTokensOwner ON RTxAuthTokens (Owner);
++CREATE INDEX AuthTokensOwner ON AuthTokens (Owner);
+
diff --git a/lib/RT.pm b/lib/RT.pm
@@ -352,14 +357,13 @@
+
+=head1 DESCRIPTION
+
-+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.
++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.
+
+Once you have an authentication token, you may use it in place of a
-+password to log into RT. (Additionally, L<RT::Extension::REST2> allows
++password to log into RT. (Additionally, L<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
@@ -381,6 +385,7 @@
+Apache configuration to allow RT to access the Authorization header.
+
+ SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
++
+=cut
+
+1;
@@ -390,11 +395,59 @@
--- /dev/null
+++ b/lib/RT/Authen/Token/AuthToken.pm
@@
++# BEGIN BPS TAGGED BLOCK {{{
++#
++# COPYRIGHT:
++#
++# This software is Copyright (c) 1996-2019 Best Practical Solutions, LLC
++# <sales at bestpractical.com>
++#
++# (Except where explicitly superseded by other copyright notices)
++#
++#
++# LICENSE:
++#
++# This work is made available to you under the terms of Version 2 of
++# the GNU General Public License. A copy of that license should have
++# been provided with this software, but in any event can be snarfed
++# from www.gnu.org.
++#
++# This work is distributed in the hope that it will be useful, but
++# WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++# General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++# 02110-1301 or visit their web page on the internet at
++# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
++#
++#
++# CONTRIBUTION SUBMISSION POLICY:
++#
++# (The following paragraph is not intended to limit the rights granted
++# to you to modify and distribute this software under the terms of
++# the GNU General Public License and is only of importance to you if
++# you choose to contribute your changes and enhancements to the
++# community by submitting them to Best Practical Solutions, LLC.)
++#
++# By intentionally submitting any modifications, corrections or
++# derivatives to this work, or any other work intended for use with
++# Request Tracker, to Best Practical Solutions, LLC, you confirm that
++# you are the copyright holder for those contributions and you grant
++# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
++# royalty-free, perpetual, license to use, copy, create derivative
++# works based on those contributions, and sublicense and distribute
++# those contributions and any derivatives thereof.
++#
++# END BPS TAGGED BLOCK }}}
++
+use strict;
+use warnings;
+use 5.10.1;
+
-+package RT::AuthToken;
++package RT::Authen::Token::AuthToken;
+use base 'RT::Record';
+
+require RT::User;
@@ -403,7 +456,7 @@
+
+=head1 NAME
+
-+RT::AuthToken - Represents an authentication token for a user
++RT::Authen::Token::AuthToken - Represents an authentication token for a user
+
+=cut
+
@@ -616,7 +669,7 @@
+=head1 PRIVATE METHODS
+
+Documented for internal use only, do not call these from outside
-+RT::AuthToken itself.
++RT::Authen::Token::AuthToken itself.
+
+=head2 _Set
+
@@ -697,7 +750,7 @@
+ return $self->_CryptToken_bcrypt(@_);
+}
+
-+sub Table { "RTxAuthTokens" }
++sub Table { "AuthTokens" }
+
+sub _CoreAccessible {
+ {
@@ -720,15 +773,63 @@
--- /dev/null
+++ b/lib/RT/Authen/Token/AuthTokens.pm
@@
++# BEGIN BPS TAGGED BLOCK {{{
++#
++# COPYRIGHT:
++#
++# This software is Copyright (c) 1996-2019 Best Practical Solutions, LLC
++# <sales at bestpractical.com>
++#
++# (Except where explicitly superseded by other copyright notices)
++#
++#
++# LICENSE:
++#
++# This work is made available to you under the terms of Version 2 of
++# the GNU General Public License. A copy of that license should have
++# been provided with this software, but in any event can be snarfed
++# from www.gnu.org.
++#
++# This work is distributed in the hope that it will be useful, but
++# WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++# General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++# 02110-1301 or visit their web page on the internet at
++# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
++#
++#
++# CONTRIBUTION SUBMISSION POLICY:
++#
++# (The following paragraph is not intended to limit the rights granted
++# to you to modify and distribute this software under the terms of
++# the GNU General Public License and is only of importance to you if
++# you choose to contribute your changes and enhancements to the
++# community by submitting them to Best Practical Solutions, LLC.)
++#
++# By intentionally submitting any modifications, corrections or
++# derivatives to this work, or any other work intended for use with
++# Request Tracker, to Best Practical Solutions, LLC, you confirm that
++# you are the copyright holder for those contributions and you grant
++# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
++# royalty-free, perpetual, license to use, copy, create derivative
++# works based on those contributions, and sublicense and distribute
++# those contributions and any derivatives thereof.
++#
++# END BPS TAGGED BLOCK }}}
++
+use strict;
+use warnings;
+
-+package RT::AuthTokens;
++package RT::Authen::Token::AuthTokens;
+use base 'RT::SearchBuilder';
+
+=head1 NAME
+
-+RT::AuthTokens - a collection of L<RT::AuthToken> objects
++RT::Authen::Token::AuthTokens - a collection of L<RT::Authen::Token::AuthToken> objects
+
+=cut
+
@@ -751,7 +852,7 @@
+
+sub NewItem {
+ my $self = shift;
-+ return RT::AuthToken->new( $self->CurrentUser );
++ return RT::Authen::Token::AuthToken->new( $self->CurrentUser );
+}
+
+=head2 _Init
@@ -767,7 +868,7 @@
+ return $self->SUPER::_Init( @_ );
+}
+
-+sub Table { "RTxAuthTokens" }
++sub Table { "AuthTokens" }
+
+1;
+
@@ -787,50 +888,63 @@
# Authenticate if the user is trying to login via user/pass query args
my ($authed, $msg) = AttemptPasswordAuthentication($ARGS);
-+ 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'));
-+ }
-+ }
-+ }
-+ }
++ AttemptTokenAuthentication($ARGS) unless $authed;
+
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
@@ -873,6 +987,54 @@
--- /dev/null
+++ b/share/html/Admin/Users/AuthTokens.html
@@
++%# BEGIN BPS TAGGED BLOCK {{{
++%#
++%# COPYRIGHT:
++%#
++%# This software is Copyright (c) 1996-2019 Best Practical Solutions, LLC
++%# <sales at bestpractical.com>
++%#
++%# (Except where explicitly superseded by other copyright notices)
++%#
++%#
++%# LICENSE:
++%#
++%# This work is made available to you under the terms of Version 2 of
++%# the GNU General Public License. A copy of that license should have
++%# been provided with this software, but in any event can be snarfed
++%# from www.gnu.org.
++%#
++%# This work is distributed in the hope that it will be useful, but
++%# WITHOUT ANY WARRANTY; without even the implied warranty of
++%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++%# General Public License for more details.
++%#
++%# You should have received a copy of the GNU General Public License
++%# along with this program; if not, write to the Free Software
++%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++%# 02110-1301 or visit their web page on the internet at
++%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
++%#
++%#
++%# CONTRIBUTION SUBMISSION POLICY:
++%#
++%# (The following paragraph is not intended to limit the rights granted
++%# to you to modify and distribute this software under the terms of
++%# the GNU General Public License and is only of importance to you if
++%# you choose to contribute your changes and enhancements to the
++%# community by submitting them to Best Practical Solutions, LLC.)
++%#
++%# By intentionally submitting any modifications, corrections or
++%# derivatives to this work, or any other work intended for use with
++%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
++%# you are the copyright holder for those contributions and you grant
++%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
++%# royalty-free, perpetual, license to use, copy, create derivative
++%# works based on those contributions, and sublicense and distribute
++%# 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 &>
@@ -910,6 +1072,53 @@
--- /dev/null
+++ b/share/html/Elements/AuthToken/CreateButton
@@
++%# BEGIN BPS TAGGED BLOCK {{{
++%#
++%# COPYRIGHT:
++%#
++%# This software is Copyright (c) 1996-2019 Best Practical Solutions, LLC
++%# <sales at bestpractical.com>
++%#
++%# (Except where explicitly superseded by other copyright notices)
++%#
++%#
++%# LICENSE:
++%#
++%# This work is made available to you under the terms of Version 2 of
++%# the GNU General Public License. A copy of that license should have
++%# been provided with this software, but in any event can be snarfed
++%# from www.gnu.org.
++%#
++%# This work is distributed in the hope that it will be useful, but
++%# WITHOUT ANY WARRANTY; without even the implied warranty of
++%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++%# General Public License for more details.
++%#
++%# You should have received a copy of the GNU General Public License
++%# along with this program; if not, write to the Free Software
++%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++%# 02110-1301 or visit their web page on the internet at
++%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
++%#
++%#
++%# CONTRIBUTION SUBMISSION POLICY:
++%#
++%# (The following paragraph is not intended to limit the rights granted
++%# to you to modify and distribute this software under the terms of
++%# the GNU General Public License and is only of importance to you if
++%# you choose to contribute your changes and enhancements to the
++%# community by submitting them to Best Practical Solutions, LLC.)
++%#
++%# By intentionally submitting any modifications, corrections or
++%# derivatives to this work, or any other work intended for use with
++%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
++%# you are the copyright holder for those contributions and you grant
++%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
++%# royalty-free, perpetual, license to use, copy, create derivative
++%# works based on those contributions, and sublicense and distribute
++%# those contributions and any derivatives thereof.
++%#
++%# END BPS TAGGED BLOCK }}}
+<%ARGS>
+$Owner
+$ShowCreateForm => 0
@@ -941,6 +1150,53 @@
--- /dev/null
+++ b/share/html/Elements/AuthToken/CreateForm
@@
++%# BEGIN BPS TAGGED BLOCK {{{
++%#
++%# COPYRIGHT:
++%#
++%# This software is Copyright (c) 1996-2019 Best Practical Solutions, LLC
++%# <sales at bestpractical.com>
++%#
++%# (Except where explicitly superseded by other copyright notices)
++%#
++%#
++%# LICENSE:
++%#
++%# This work is made available to you under the terms of Version 2 of
++%# the GNU General Public License. A copy of that license should have
++%# been provided with this software, but in any event can be snarfed
++%# from www.gnu.org.
++%#
++%# This work is distributed in the hope that it will be useful, but
++%# WITHOUT ANY WARRANTY; without even the implied warranty of
++%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++%# General Public License for more details.
++%#
++%# You should have received a copy of the GNU General Public License
++%# along with this program; if not, write to the Free Software
++%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++%# 02110-1301 or visit their web page on the internet at
++%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
++%#
++%#
++%# CONTRIBUTION SUBMISSION POLICY:
++%#
++%# (The following paragraph is not intended to limit the rights granted
++%# to you to modify and distribute this software under the terms of
++%# the GNU General Public License and is only of importance to you if
++%# you choose to contribute your changes and enhancements to the
++%# community by submitting them to Best Practical Solutions, LLC.)
++%#
++%# By intentionally submitting any modifications, corrections or
++%# derivatives to this work, or any other work intended for use with
++%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
++%# you are the copyright holder for those contributions and you grant
++%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
++%# royalty-free, perpetual, license to use, copy, create derivative
++%# works based on those contributions, and sublicense and distribute
++%# those contributions and any derivatives thereof.
++%#
++%# END BPS TAGGED BLOCK }}}
+<%ARGS>
+$Owner
+$Error => ''
@@ -988,13 +1244,60 @@
--- /dev/null
+++ b/share/html/Elements/AuthToken/CreateResults
@@
++%# BEGIN BPS TAGGED BLOCK {{{
++%#
++%# COPYRIGHT:
++%#
++%# This software is Copyright (c) 1996-2019 Best Practical Solutions, LLC
++%# <sales at bestpractical.com>
++%#
++%# (Except where explicitly superseded by other copyright notices)
++%#
++%#
++%# LICENSE:
++%#
++%# This work is made available to you under the terms of Version 2 of
++%# the GNU General Public License. A copy of that license should have
++%# been provided with this software, but in any event can be snarfed
++%# from www.gnu.org.
++%#
++%# This work is distributed in the hope that it will be useful, but
++%# WITHOUT ANY WARRANTY; without even the implied warranty of
++%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++%# General Public License for more details.
++%#
++%# You should have received a copy of the GNU General Public License
++%# along with this program; if not, write to the Free Software
++%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++%# 02110-1301 or visit their web page on the internet at
++%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
++%#
++%#
++%# CONTRIBUTION SUBMISSION POLICY:
++%#
++%# (The following paragraph is not intended to limit the rights granted
++%# to you to modify and distribute this software under the terms of
++%# the GNU General Public License and is only of importance to you if
++%# you choose to contribute your changes and enhancements to the
++%# community by submitting them to Best Practical Solutions, LLC.)
++%#
++%# By intentionally submitting any modifications, corrections or
++%# derivatives to this work, or any other work intended for use with
++%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
++%# you are the copyright holder for those contributions and you grant
++%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
++%# royalty-free, perpetual, license to use, copy, create derivative
++%# works based on those contributions, and sublicense and distribute
++%# those contributions and any derivatives thereof.
++%#
++%# END BPS TAGGED BLOCK }}}
+<%ARGS>
+$Owner => undef
+$Password => ''
+$Description => ''
+</%ARGS>
+<%INIT>
-+my $token = RT::AuthToken->new($session{CurrentUser});
++my $token = RT::Authen::Token::AuthToken->new($session{CurrentUser});
+# Don't require password for systems with some form of federated auth
+my %res = $session{'CurrentUser'}->CurrentUserRequireToSetPassword();
+my ($error, $authstring);
@@ -1036,11 +1339,58 @@
--- /dev/null
+++ b/share/html/Elements/AuthToken/List
@@
++%# BEGIN BPS TAGGED BLOCK {{{
++%#
++%# COPYRIGHT:
++%#
++%# This software is Copyright (c) 1996-2019 Best Practical Solutions, LLC
++%# <sales at bestpractical.com>
++%#
++%# (Except where explicitly superseded by other copyright notices)
++%#
++%#
++%# LICENSE:
++%#
++%# This work is made available to you under the terms of Version 2 of
++%# the GNU General Public License. A copy of that license should have
++%# been provided with this software, but in any event can be snarfed
++%# from www.gnu.org.
++%#
++%# This work is distributed in the hope that it will be useful, but
++%# WITHOUT ANY WARRANTY; without even the implied warranty of
++%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++%# General Public License for more details.
++%#
++%# You should have received a copy of the GNU General Public License
++%# along with this program; if not, write to the Free Software
++%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++%# 02110-1301 or visit their web page on the internet at
++%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
++%#
++%#
++%# CONTRIBUTION SUBMISSION POLICY:
++%#
++%# (The following paragraph is not intended to limit the rights granted
++%# to you to modify and distribute this software under the terms of
++%# the GNU General Public License and is only of importance to you if
++%# you choose to contribute your changes and enhancements to the
++%# community by submitting them to Best Practical Solutions, LLC.)
++%#
++%# By intentionally submitting any modifications, corrections or
++%# derivatives to this work, or any other work intended for use with
++%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
++%# you are the copyright holder for those contributions and you grant
++%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
++%# royalty-free, perpetual, license to use, copy, create derivative
++%# works based on those contributions, and sublicense and distribute
++%# those contributions and any derivatives thereof.
++%#
++%# END BPS TAGGED BLOCK }}}
+<%ARGS>
+$Owner
+</%ARGS>
+<%INIT>
-+my $tokens = RT::AuthTokens->new($session{CurrentUser});
++my $tokens = RT::Authen::Token::AuthTokens->new($session{CurrentUser});
+$tokens->LimitOwner(VALUE => $Owner);
+</%INIT>
+<div class="form-row authtoken-list" data-owner="<% $Owner %>">
@@ -1100,6 +1450,53 @@
--- /dev/null
+++ b/share/html/Elements/AuthToken/ModifyForm
@@
++%# BEGIN BPS TAGGED BLOCK {{{
++%#
++%# COPYRIGHT:
++%#
++%# This software is Copyright (c) 1996-2019 Best Practical Solutions, LLC
++%# <sales at bestpractical.com>
++%#
++%# (Except where explicitly superseded by other copyright notices)
++%#
++%#
++%# LICENSE:
++%#
++%# This work is made available to you under the terms of Version 2 of
++%# the GNU General Public License. A copy of that license should have
++%# been provided with this software, but in any event can be snarfed
++%# from www.gnu.org.
++%#
++%# This work is distributed in the hope that it will be useful, but
++%# WITHOUT ANY WARRANTY; without even the implied warranty of
++%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++%# General Public License for more details.
++%#
++%# You should have received a copy of the GNU General Public License
++%# along with this program; if not, write to the Free Software
++%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++%# 02110-1301 or visit their web page on the internet at
++%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
++%#
++%#
++%# CONTRIBUTION SUBMISSION POLICY:
++%#
++%# (The following paragraph is not intended to limit the rights granted
++%# to you to modify and distribute this software under the terms of
++%# the GNU General Public License and is only of importance to you if
++%# you choose to contribute your changes and enhancements to the
++%# community by submitting them to Best Practical Solutions, LLC.)
++%#
++%# By intentionally submitting any modifications, corrections or
++%# derivatives to this work, or any other work intended for use with
++%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
++%# you are the copyright holder for those contributions and you grant
++%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
++%# royalty-free, perpetual, license to use, copy, create derivative
++%# works based on those contributions, and sublicense and distribute
++%# those contributions and any derivatives thereof.
++%#
++%# END BPS TAGGED BLOCK }}}
+<%ARGS>
+$Token => undef
+$TokenObj => undef
@@ -1107,7 +1504,7 @@
+</%ARGS>
+<%INIT>
+if (!$TokenObj) {
-+ $TokenObj = RT::AuthToken->new($session{CurrentUser});
++ $TokenObj = RT::Authen::Token::AuthToken->new($session{CurrentUser});
+ $TokenObj->Load($Token);
+}
+
@@ -1166,6 +1563,53 @@
--- /dev/null
+++ b/share/html/Elements/AuthToken/ModifyResults
@@
++%# BEGIN BPS TAGGED BLOCK {{{
++%#
++%# COPYRIGHT:
++%#
++%# This software is Copyright (c) 1996-2019 Best Practical Solutions, LLC
++%# <sales at bestpractical.com>
++%#
++%# (Except where explicitly superseded by other copyright notices)
++%#
++%#
++%# LICENSE:
++%#
++%# This work is made available to you under the terms of Version 2 of
++%# the GNU General Public License. A copy of that license should have
++%# been provided with this software, but in any event can be snarfed
++%# from www.gnu.org.
++%#
++%# This work is distributed in the hope that it will be useful, but
++%# WITHOUT ANY WARRANTY; without even the implied warranty of
++%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++%# General Public License for more details.
++%#
++%# You should have received a copy of the GNU General Public License
++%# along with this program; if not, write to the Free Software
++%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++%# 02110-1301 or visit their web page on the internet at
++%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
++%#
++%#
++%# CONTRIBUTION SUBMISSION POLICY:
++%#
++%# (The following paragraph is not intended to limit the rights granted
++%# to you to modify and distribute this software under the terms of
++%# the GNU General Public License and is only of importance to you if
++%# you choose to contribute your changes and enhancements to the
++%# community by submitting them to Best Practical Solutions, LLC.)
++%#
++%# By intentionally submitting any modifications, corrections or
++%# derivatives to this work, or any other work intended for use with
++%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
++%# you are the copyright holder for those contributions and you grant
++%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
++%# royalty-free, perpetual, license to use, copy, create derivative
++%# works based on those contributions, and sublicense and distribute
++%# those contributions and any derivatives thereof.
++%#
++%# END BPS TAGGED BLOCK }}}
+<%ARGS>
+$Token
+$Description => ''
@@ -1173,7 +1617,7 @@
+$Revoke => 0
+</%ARGS>
+<%INIT>
-+my $TokenObj = RT::AuthToken->new($session{CurrentUser});
++my $TokenObj = RT::Authen::Token::AuthToken->new($session{CurrentUser});
+$TokenObj->Load($Token);
+my ($error, $ok, $msg);
+
@@ -1202,6 +1646,53 @@
--- /dev/null
+++ b/share/html/Helpers/AuthToken/Create
@@
++%# BEGIN BPS TAGGED BLOCK {{{
++%#
++%# COPYRIGHT:
++%#
++%# This software is Copyright (c) 1996-2019 Best Practical Solutions, LLC
++%# <sales at bestpractical.com>
++%#
++%# (Except where explicitly superseded by other copyright notices)
++%#
++%#
++%# LICENSE:
++%#
++%# This work is made available to you under the terms of Version 2 of
++%# the GNU General Public License. A copy of that license should have
++%# been provided with this software, but in any event can be snarfed
++%# from www.gnu.org.
++%#
++%# This work is distributed in the hope that it will be useful, but
++%# WITHOUT ANY WARRANTY; without even the implied warranty of
++%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++%# General Public License for more details.
++%#
++%# You should have received a copy of the GNU General Public License
++%# along with this program; if not, write to the Free Software
++%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++%# 02110-1301 or visit their web page on the internet at
++%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
++%#
++%#
++%# CONTRIBUTION SUBMISSION POLICY:
++%#
++%# (The following paragraph is not intended to limit the rights granted
++%# to you to modify and distribute this software under the terms of
++%# the GNU General Public License and is only of importance to you if
++%# you choose to contribute your changes and enhancements to the
++%# community by submitting them to Best Practical Solutions, LLC.)
++%#
++%# By intentionally submitting any modifications, corrections or
++%# derivatives to this work, or any other work intended for use with
++%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
++%# you are the copyright holder for those contributions and you grant
++%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
++%# royalty-free, perpetual, license to use, copy, create derivative
++%# works based on those contributions, and sublicense and distribute
++%# those contributions and any derivatives thereof.
++%#
++%# END BPS TAGGED BLOCK }}}
+<& /Elements/AuthToken/CreateResults, %ARGS &>
+% $m->abort;
@@ -1210,6 +1701,53 @@
--- /dev/null
+++ b/share/html/Helpers/AuthToken/List
@@
++%# BEGIN BPS TAGGED BLOCK {{{
++%#
++%# COPYRIGHT:
++%#
++%# This software is Copyright (c) 1996-2019 Best Practical Solutions, LLC
++%# <sales at bestpractical.com>
++%#
++%# (Except where explicitly superseded by other copyright notices)
++%#
++%#
++%# LICENSE:
++%#
++%# This work is made available to you under the terms of Version 2 of
++%# the GNU General Public License. A copy of that license should have
++%# been provided with this software, but in any event can be snarfed
++%# from www.gnu.org.
++%#
++%# This work is distributed in the hope that it will be useful, but
++%# WITHOUT ANY WARRANTY; without even the implied warranty of
++%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++%# General Public License for more details.
++%#
++%# You should have received a copy of the GNU General Public License
++%# along with this program; if not, write to the Free Software
++%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++%# 02110-1301 or visit their web page on the internet at
++%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
++%#
++%#
++%# CONTRIBUTION SUBMISSION POLICY:
++%#
++%# (The following paragraph is not intended to limit the rights granted
++%# to you to modify and distribute this software under the terms of
++%# the GNU General Public License and is only of importance to you if
++%# you choose to contribute your changes and enhancements to the
++%# community by submitting them to Best Practical Solutions, LLC.)
++%#
++%# By intentionally submitting any modifications, corrections or
++%# derivatives to this work, or any other work intended for use with
++%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
++%# you are the copyright holder for those contributions and you grant
++%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
++%# royalty-free, perpetual, license to use, copy, create derivative
++%# works based on those contributions, and sublicense and distribute
++%# those contributions and any derivatives thereof.
++%#
++%# END BPS TAGGED BLOCK }}}
+<& /Elements/AuthToken/List, Owner => $ARGS{owner} &>
+% $m->abort;
@@ -1218,6 +1756,53 @@
--- /dev/null
+++ b/share/html/Helpers/AuthToken/Modify
@@
++%# BEGIN BPS TAGGED BLOCK {{{
++%#
++%# COPYRIGHT:
++%#
++%# This software is Copyright (c) 1996-2019 Best Practical Solutions, LLC
++%# <sales at bestpractical.com>
++%#
++%# (Except where explicitly superseded by other copyright notices)
++%#
++%#
++%# LICENSE:
++%#
++%# This work is made available to you under the terms of Version 2 of
++%# the GNU General Public License. A copy of that license should have
++%# been provided with this software, but in any event can be snarfed
++%# from www.gnu.org.
++%#
++%# This work is distributed in the hope that it will be useful, but
++%# WITHOUT ANY WARRANTY; without even the implied warranty of
++%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++%# General Public License for more details.
++%#
++%# You should have received a copy of the GNU General Public License
++%# along with this program; if not, write to the Free Software
++%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++%# 02110-1301 or visit their web page on the internet at
++%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
++%#
++%#
++%# CONTRIBUTION SUBMISSION POLICY:
++%#
++%# (The following paragraph is not intended to limit the rights granted
++%# to you to modify and distribute this software under the terms of
++%# the GNU General Public License and is only of importance to you if
++%# you choose to contribute your changes and enhancements to the
++%# community by submitting them to Best Practical Solutions, LLC.)
++%#
++%# By intentionally submitting any modifications, corrections or
++%# derivatives to this work, or any other work intended for use with
++%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
++%# you are the copyright holder for those contributions and you grant
++%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
++%# royalty-free, perpetual, license to use, copy, create derivative
++%# works based on those contributions, and sublicense and distribute
++%# those contributions and any derivatives thereof.
++%#
++%# END BPS TAGGED BLOCK }}}
+<& /Elements/AuthToken/ModifyResults, %ARGS &>
+% $m->abort;
@@ -1226,6 +1811,54 @@
--- /dev/null
+++ b/share/html/Prefs/AuthTokens.html
@@
++%# BEGIN BPS TAGGED BLOCK {{{
++%#
++%# COPYRIGHT:
++%#
++%# This software is Copyright (c) 1996-2019 Best Practical Solutions, LLC
++%# <sales at bestpractical.com>
++%#
++%# (Except where explicitly superseded by other copyright notices)
++%#
++%#
++%# LICENSE:
++%#
++%# This work is made available to you under the terms of Version 2 of
++%# the GNU General Public License. A copy of that license should have
++%# been provided with this software, but in any event can be snarfed
++%# from www.gnu.org.
++%#
++%# This work is distributed in the hope that it will be useful, but
++%# WITHOUT ANY WARRANTY; without even the implied warranty of
++%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++%# General Public License for more details.
++%#
++%# You should have received a copy of the GNU General Public License
++%# along with this program; if not, write to the Free Software
++%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++%# 02110-1301 or visit their web page on the internet at
++%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
++%#
++%#
++%# CONTRIBUTION SUBMISSION POLICY:
++%#
++%# (The following paragraph is not intended to limit the rights granted
++%# to you to modify and distribute this software under the terms of
++%# the GNU General Public License and is only of importance to you if
++%# you choose to contribute your changes and enhancements to the
++%# community by submitting them to Best Practical Solutions, LLC.)
++%#
++%# By intentionally submitting any modifications, corrections or
++%# derivatives to this work, or any other work intended for use with
++%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
++%# you are the copyright holder for those contributions and you grant
++%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
++%# royalty-free, perpetual, license to use, copy, create derivative
++%# works based on those contributions, and sublicense and distribute
++%# those contributions and any derivatives thereof.
++%#
++%# END BPS TAGGED BLOCK }}}
++
+<& /Elements/Header, Title => loc('My authentication tokens') &>
+<& /Elements/Tabs &>
+<& /Elements/ListActions, actions => \@results &>
2: e3979eb579 ! 2: a4767ecdf9 Make RT::Authen::Token behave like other parts of RT
@@ -1,18 +1,101 @@
Author: Craig <craig at bestpractical.com>
- Migrate to elevator theme
-
-diff --git a/share/html/Elements/AuthToken/CreateButton b/share/html/Elements/AuthToken/CreateButton
+ Make RT::Authen::Token behave like other parts of RT
+
+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
+
+diff --git a/lib/RT/Interface/Web/MenuBuilder.pm b/lib/RT/Interface/Web/MenuBuilder.pm
+--- a/lib/RT/Interface/Web/MenuBuilder.pm
++++ b/lib/RT/Interface/Web/MenuBuilder.pm
+@@
+ $page->child( history => title => loc('History'), path => "/Admin/Tools/ConfigHistory.html" );
+ }
+
++ if ( $request_path =~ m{^/Prefs/AuthTokens} ) {
++ $page->child( select_auth_token => title => loc('Select'), path => '/Prefs/AuthTokens.html');
++ $page->child( create_auth_token => title => loc('Create'),
++ raw_html => q[<a class="btn menu-item" href="#create-auth-token" data-toggle="modal" rel="modal:open">].loc("Create")."</a>"
++ );
++ }
++
+ # due to historical reasons of always having been in /Elements/Tabs
+ $HTML::Mason::Commands::m->callback( CallbackName => 'Privileged', Path => $request_path, Search_Args => $args, Has_Query => $has_query, ARGSRef => \%args, CallbackPage => '/Elements/Tabs' );
+ }
+@@
+ $page->child( keys => title => loc('Private keys'), path => "/Admin/Users/Keys.html?id=" . $id );
+ }
+ $page->child( 'summary' => title => loc('User Summary'), path => "/User/Summary.html?id=" . $id );
++
++ my $auth_tokens = $page->child(auth_tokens => title => loc('Auth Tokens'), path => '/Admin/Users/AuthTokens.html?id=' . $id);
++ $auth_tokens->child( select_auth_token => title => loc('Select'), path => '/Admin/Users/AuthTokens.html');
++ $auth_tokens->child( create_auth_token => title => loc('Create'),
++ raw_html => q[<a class="btn menu-item" href="#create-auth-token" data-toggle="modal" rel="modal:open">].loc("Create")."</a>"
++ );
+ }
+ }
+
+@@
+ $page->child( create => title => loc('Create'), path => "/Admin/Articles/Classes/Modify.html?Create=1" );
+ }
+ }
+-
+- my $request_path_token = $request_path =~ s!/{2,}!/!g;
+- if ( $request_path_token =~ m{^(/Admin/Users|/User/(Summary|History)\.html)} and $admin->child("users") ) {
+- if ( $HTML::Mason::Commands::DECODED_ARGS->{'id'} && $HTML::Mason::Commands::DECODED_ARGS->{'id'} =~ /^\d+$/ ) {
+- my $id = $HTML::Mason::Commands::DECODED_ARGS->{'id'};
+- my $obj = RT::User->new( $HTML::Mason::Commands::session{'CurrentUser'} );
+- $obj->Load($id);
+-
+- if ( $obj and $obj->id ) {
+- my $tabs = PageMenu();
+- $tabs->child(auth_tokens => title => loc('Auth Tokens'), path => '/Admin/Users/AuthTokens.html?id=' . $id);
+- }
+- }
+- }
+ }
+
+ sub BuildSelfServiceNav {
+
+diff --git a/share/html/Elements/AuthToken/CreateButton b/share/html/Admin/Users/AuthToken/Create.html
+similarity index 75%
+rename from share/html/Elements/AuthToken/CreateButton
+rename to share/html/Admin/Users/AuthToken/Create.html
--- a/share/html/Elements/AuthToken/CreateButton
-+++ b/share/html/Elements/AuthToken/CreateButton
-@@
--<%ARGS>
++++ b/share/html/Admin/Users/AuthToken/Create.html
+@@
+ %# those contributions and any derivatives thereof.
+ %#
+ %# END BPS TAGGED BLOCK }}}
++
++<& /Elements/AuthToken/Create, Owner => $UserObj->Id, %ARGS &>
++
+ <%ARGS>
-$Owner
-$ShowCreateForm => 0
-$CreateToken => 0
--</%ARGS>
--<%INIT>
--</%INIT>
++$id => undef
+ </%ARGS>
+ <%INIT>
++my @results;
++
++my $UserObj = RT::User->new( $session{'CurrentUser'} );
++$UserObj->Load( $id );
++unless ( $UserObj->id ) {
++ Abort( loc("Couldn't load user #[_1]", $id) );
++}
++$id = $ARGS{'id'} = $UserObj->id;
+ </%INIT>
-% if ($CreateToken) {
- <&| /Widgets/TitleBox, title => loc("Create Auth Token") &>
- <& /Elements/AuthToken/CreateResults, %ARGS &>
@@ -32,10 +115,306 @@
-</form>
-% }
+diff --git a/share/html/Admin/Users/AuthTokens.html b/share/html/Admin/Users/AuthTokens.html
+--- a/share/html/Admin/Users/AuthTokens.html
++++ b/share/html/Admin/Users/AuthTokens.html
+@@
+ <& /Elements/Tabs &>
+ <& /Elements/ListActions, actions => \@results &>
+
+-<div class="form-row">
+- <div class="auth-tokens 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/AuthTokens, Owner => $id, Path => '/Prefs/AuthTokens.html', %ARGS &>
+
+-<& /Elements/AuthToken/CreateButton, %ARGS, Owner => $UserObj->Id &>
+-<& /Elements/AuthToken/List, %ARGS, Owner => $UserObj->Id &>
+-</div>
+-
+-<%ARGS>
+-$id => undef
+-</%ARGS>
+ <%INIT>
+-my @results;
+-
+ my $UserObj = RT::User->new( $session{'CurrentUser'} );
+ $UserObj->Load( $id );
+ unless ( $UserObj->id ) {
+@@
+ }
+ $id = $ARGS{'id'} = $UserObj->id;
+ </%INIT>
++
++<%ARGS>
++$id => undef
++</%ARGS>
+
+diff --git a/share/html/Elements/AuthToken/AuthTokens b/share/html/Elements/AuthToken/AuthTokens
+new file mode 100644
+--- /dev/null
++++ b/share/html/Elements/AuthToken/AuthTokens
+@@
++%# BEGIN BPS TAGGED BLOCK {{{
++%#
++%# COPYRIGHT:
++%#
++%# This software is Copyright (c) 1996-2019 Best Practical Solutions, LLC
++%# <sales at bestpractical.com>
++%#
++%# (Except where explicitly superseded by other copyright notices)
++%#
++%#
++%# LICENSE:
++%#
++%# This work is made available to you under the terms of Version 2 of
++%# the GNU General Public License. A copy of that license should have
++%# been provided with this software, but in any event can be snarfed
++%# from www.gnu.org.
++%#
++%# This work is distributed in the hope that it will be useful, but
++%# WITHOUT ANY WARRANTY; without even the implied warranty of
++%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++%# General Public License for more details.
++%#
++%# You should have received a copy of the GNU General Public License
++%# along with this program; if not, write to the Free Software
++%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++%# 02110-1301 or visit their web page on the internet at
++%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
++%#
++%#
++%# CONTRIBUTION SUBMISSION POLICY:
++%#
++%# (The following paragraph is not intended to limit the rights granted
++%# to you to modify and distribute this software under the terms of
++%# the GNU General Public License and is only of importance to you if
++%# you choose to contribute your changes and enhancements to the
++%# community by submitting them to Best Practical Solutions, LLC.)
++%#
++%# By intentionally submitting any modifications, corrections or
++%# derivatives to this work, or any other work intended for use with
++%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
++%# you are the copyright holder for those contributions and you grant
++%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
++%# royalty-free, perpetual, license to use, copy, create derivative
++%# works based on those contributions, and sublicense and distribute
++%# those contributions and any derivatives thereof.
++%#
++%# END BPS TAGGED BLOCK }}}
++<& /Elements/ListActions, actions => \@results &>
++
++<div class="form-row">
++ <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>
++
++% if ( $Authstring ) {
++ <div class="modal authtoken-success" id="auth-token-auth-string">
++ <div class="modal-dialog modal-dialog-centered" role="document">
++ <div class="modal-content">
++ <div class="modal-header">
++ <&|/l,$Description &>This is your new authentication token. Treat it carefully like a password. Please save it now because you cannot access it again.</&>
++ <a id="auth-token-close-modal" href="javascript:void(0)" class="close" data-dismiss="modal" aria-label="Close">
++ <span aria-hidden="true">×</span>
++ </a>
++ </div>
++ <div class="col-12 authstring text-center">
++ <span><% $Authstring %></span>
++ </div>
++ </div>
++ </div>
++ </div>
++% }
++
++ <div class="col-12">
++ <& /Elements/AuthToken/Create, Path => $Path, Owner => $Owner &>
++ </div>
++
++ <div class="col-12">
++ <& /Elements/AuthToken/List, Path => $Path, Owner => $Owner &>
++ </div>
++</div>
++
++<%INIT>
++my @results;
++
++if ( $Update || $Revoke ) {
++ my $error = '';
++
++ my $token = RT::Authen::Token::AuthToken->new( $session{CurrentUser} );
++ $token->Load( $ARGS{'Token'} );
++ my ($ok, $msg);
++ if ( $Update ) {
++ if ( !length( $Description ) ) {
++ push @results, loc( "Description cannot be blank." );
++ }
++
++ if ( $Description ne $token->Description ) {
++ ($ok, $msg) = $token->SetDescription( $Description );
++ push @results, $msg;
++ }
++ }
++ elsif ($Revoke) {
++ ($ok, $msg) = $token->Delete;
++ push @results, $msg;
++ }
++}
++
++my ($authstring);
++if ( $CreateToken ) {
++ my $token = RT::Authen::Token::AuthToken->new( $session{CurrentUser} );
++
++ # Don't require password for systems with some form of federated auth
++ my %res = $session{'CurrentUser'}->CurrentUserRequireToSetPassword();
++
++ if ( !length( $Description ) ) {
++ push @results, loc("Description cannot be blank.");
++ }
++ elsif ( $res{'CanSet'} && !length( $ARGS{'Password'} ) ) {
++ push @results, loc("Please enter your current password.");
++ }
++ elsif ( $res{'CanSet'} && !$session{CurrentUser}->IsPassword($ARGS{'Password'} ) ) {
++ push @results, loc("Please enter your current password correctly.");
++ }
++ else {
++ ((my $ok), (my $msg), $Authstring) = $token->Create(
++ Owner => $Owner,
++ Description => $Description,
++ );
++ if ( $ok ) {
++ push @results, loc( "New token successfully created" );
++ }
++ else {
++ push @results, loc( "Something went wrong" );
++ }
++ }
++}
++</%INIT>
++
++<%ARGS>
++$Path
++$Owner
++$Update => 0
++$Revoke => 0
++$CreateToken => 0
++$Authstring => ''
++$Description => ''
++</%ARGS>
+
+diff --git a/share/html/Elements/AuthToken/Create b/share/html/Elements/AuthToken/Create
+new file mode 100644
+--- /dev/null
++++ b/share/html/Elements/AuthToken/Create
+@@
++%# BEGIN BPS TAGGED BLOCK {{{
++%#
++%# COPYRIGHT:
++%#
++%# This software is Copyright (c) 1996-2019 Best Practical Solutions, LLC
++%# <sales at bestpractical.com>
++%#
++%# (Except where explicitly superseded by other copyright notices)
++%#
++%#
++%# LICENSE:
++%#
++%# This work is made available to you under the terms of Version 2 of
++%# the GNU General Public License. A copy of that license should have
++%# been provided with this software, but in any event can be snarfed
++%# from www.gnu.org.
++%#
++%# This work is distributed in the hope that it will be useful, but
++%# WITHOUT ANY WARRANTY; without even the implied warranty of
++%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++%# General Public License for more details.
++%#
++%# You should have received a copy of the GNU General Public License
++%# along with this program; if not, write to the Free Software
++%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++%# 02110-1301 or visit their web page on the internet at
++%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
++%#
++%#
++%# CONTRIBUTION SUBMISSION POLICY:
++%#
++%# (The following paragraph is not intended to limit the rights granted
++%# to you to modify and distribute this software under the terms of
++%# the GNU General Public License and is only of importance to you if
++%# you choose to contribute your changes and enhancements to the
++%# community by submitting them to Best Practical Solutions, LLC.)
++%#
++%# By intentionally submitting any modifications, corrections or
++%# derivatives to this work, or any other work intended for use with
++%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
++%# you are the copyright holder for those contributions and you grant
++%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
++%# royalty-free, perpetual, license to use, copy, create derivative
++%# works based on those contributions, and sublicense and distribute
++%# those contributions and any derivatives thereof.
++%#
++%# END BPS TAGGED BLOCK }}}
++<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 id="auth-token-close-modal" 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" action="<% RT->Config->Get('WebPath') . $Path %>">
++ <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>
++% }
++ <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>
++ </form>
++ </div>
++ </div>
++ </div>
++</div>
++
++<%INIT>
++# Don't require password for systems with some form of federated auth
++my %res = $session{'CurrentUser'}->CurrentUserRequireToSetPassword();
++</%INIT>
++
++<%ARGS>
++$Path
++$Owner
++$Description => ''
++</%ARGS>
+
diff --git a/share/html/Elements/AuthToken/CreateForm b/share/html/Elements/AuthToken/CreateForm
--- a/share/html/Elements/AuthToken/CreateForm
+++ b/share/html/Elements/AuthToken/CreateForm
@@
+ %# END BPS TAGGED BLOCK }}}
<%ARGS>
$Owner
-$Error => ''
@@ -150,9 +529,16 @@
--- a/share/html/Elements/AuthToken/List
+++ b/share/html/Elements/AuthToken/List
@@
- my $tokens = RT::AuthTokens->new($session{CurrentUser});
- $tokens->LimitOwner(VALUE => $Owner);
- </%INIT>
+ %# those contributions and any derivatives thereof.
+ %#
+ %# END BPS TAGGED BLOCK }}}
+-<%ARGS>
+-$Owner
+-</%ARGS>
+-<%INIT>
+-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>
@@ -198,7 +584,7 @@
+ <& /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 %>">
++ <form class="authtoken-form" method="post" action="<% RT->Config->Get('WebPath') . $Path %>">
+ <div class="form-row">
+% if ($ARGS{id}) {
+ <input type="hidden" name="id" value="<% $ARGS{id} %>">
@@ -272,12 +658,23 @@
% }
</ul>
% }
+ </div>
++
++<%INIT>
++my $tokens = RT::Authen::Token::AuthTokens->new($session{CurrentUser});
++$tokens->LimitOwner(VALUE => $Owner);
++</%INIT>
++
++<%ARGS>
++$Owner
++$Path
++</%ARGS>
diff --git a/share/html/Elements/AuthToken/ModifyForm b/share/html/Elements/AuthToken/ModifyForm
--- a/share/html/Elements/AuthToken/ModifyForm
+++ b/share/html/Elements/AuthToken/ModifyForm
@@
- $TokenObj = RT::AuthToken->new($session{CurrentUser});
+ $TokenObj = RT::Authen::Token::AuthToken->new($session{CurrentUser});
$TokenObj->Load($Token);
}
-
@@ -408,45 +805,35 @@
--- a/share/html/Prefs/AuthTokens.html
+++ b/share/html/Prefs/AuthTokens.html
@@
- <& /Elements/ListActions, actions => \@results &>
-
- <div class="form-row">
+
+ <& /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>
+- <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>
+-</div>
++<& /Elements/AuthToken/AuthTokens, Owner => $owner, Path => '/Prefs/AuthTokens.html', %ARGS &>
<%INIT>
-
-diff --git a/share/static/css/elevator-light/rt-authen-token.css b/share/static/css/elevator-light/rt-authen-token.css
---- a/share/static/css/elevator-light/rt-authen-token.css
-+++ b/share/static/css/elevator-light/rt-authen-token.css
-@@
- float: left;
- }
-
-+.auth-token-messages {
-+ margin: 1rem 0rem 0rem 0px;
-+}
+-my @results;
+-my $UserObj = $session{'CurrentUser'}->UserObj;
++my $owner = $session{'CurrentUser'}->UserObj->Id;
+ </%INIT>
+
+diff --git a/share/static/images/loading.gif b/share/static/images/loading.gif
+deleted file mode 100644
+Binary files a/share/static/images/loading.gif and /dev/null differ
diff --git a/share/static/js/rt-authen-token.js b/share/static/js/rt-authen-token.js
--- a/share/static/js/rt-authen-token.js
@@ -471,49 +858,64 @@
- showModal(container.find('.authtoken-form-container').html());
- });
-
- var refreshTokenList = function () {
- var list = jQuery('.authtoken-list');
- jQuery.post(
-@@
-
- var submitForm = function (form, extraParams) {
- var payload = form.serializeArray();
-+ var name = extraParams[0].name;
-+
- if (extraParams) {
- Array.prototype.push.apply(payload, extraParams);
- }
-@@
- form.addClass('submitting');
- form.find('input').attr('disabled', true);
-
+- var refreshTokenList = function () {
+- var list = jQuery('.authtoken-list');
+- jQuery.post(
+- RT.Config.WebHomePath + "/Helpers/AuthToken/List",
+- list.data(),
+- function (data) {
+- list.replaceWith(data);
+- }
+- );
+- };
+-
+- var submitForm = function (form, extraParams) {
+- var payload = form.serializeArray();
+- if (extraParams) {
+- Array.prototype.push.apply(payload, extraParams);
+- }
+-
+- 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 {
+- }
+- else {
- jQuery('#body').append(html);
-+ jQuery('#auth-token-messages').replaceWith(html);
- }
- refreshTokenList();
- };
-@@
- data: payload,
- timeout: 30000, /* 30 seconds */
- success: function (data, status) {
+- }
+- refreshTokenList();
+- };
+-
+- jQuery.ajax({
+- method: 'POST',
+- url: form.data('ajax-url'),
+- 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>");
-
+- },
+- error: function (xhr, status, error) {
+- renderResult("<p>An error has occurred. Please refresh the page and try again.<p>");
+- }
+- });
+- };
+-
+- jQuery('body').on('click', '.authtoken-form button, .authtoken-form input[type=submit]', function (e) {
+- e.preventDefault();
+- var button = jQuery(this);
+-
+- var params = [{ name: button.attr('name'), value: button.attr('value') }];
+- submitForm(button.closest('form'), params);
+- });
+-
+- jQuery('body').on('submit', '.authtoken-form', function (e) {
+- e.preventDefault();
+- submitForm(jQuery(this));
+- });
++ jQuery('#auth-token-auth-string').modal('show');
+ });
+-
+
3: e7043c1549 < -: ------- Migrate Authen-Token code to work like other RT pages
4: 0f005b83ff ! 3: c41a3f2a71 Add documentation for using token auth
@@ -5,6 +5,16 @@
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>
@@ -45,7 +55,7 @@
+
=head1 DESCRIPTION
- This module adds the ability for users to generate and login with
+ Allow for users to generate and login with authentication tokens. Users
@@
database just like passwords, and so cannot be recovered after they are
generated.
@@ -55,3 +65,16 @@
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