Hi all
(For those on -devel, this is essentially the same post as late last
week but with minor changes)
PAM - http://www.kernel.org/pub/linux/libs/pam/ - can authenticate
against a multitude of sources (backends) - an LDAP system, Active
Directory, Kerberos, local passwd/shadow files, a separate MySQL
instance... you name it, it's probably got a module for it somewhere.
This will allow RT admins to use a flexible authentication source
*without* having to modify RT beyond a couple of configuration options.
The changes made are principally to the "IsPassword" function in
lib/RT/CurrentUser.pm such that it can use PAM to check a password, can
use the RT database to check a password, or fall through from PAM to
database if PAM fails.
Additionally, if PAM succeeds and the RT database differs from that
password, there's the option to set the RT password (thus keeping them
in sync).
In combination, if the PAM source goes away, the system can still
authenticate against the RT database using the most recently successful
PAM password. It's possible to turn off the password change and fallback
options, too.
There are both changes to CurrentUser.pm and some additional sections to
RT_SiteConfig.pm. Some of the logging statements could be changed (it's
a bit verbose at the moment) but otherwise it's all as functional as it
can be.
The array defining modules (see below) currently contains one module
name - rt-krb5-auth - but can contain several in order to authenticate
against multiple backends.
NOTE: Any module name passed in this way containing the word "dummy" is
skipped - it's there purely for reference, to see that the code looped
as I wanted it to.
We now have this in production for our support staff within the
department and several other University departments without error.
The example pam.d file included here is for authentication against an
AD. You could just as easily test against the local system, or something
else, given the right config.
Please feel free to give this a try (where relevant). If anyone needs a
hand making PAM fire off against an AD, please feel free to contact me
off list - there's a bit of extra config to make Kerberos work properly.
Graeme
--
Graeme Fowler
Team Manager (ISSS), Computing Services
Loughborough University - http://www.lboro.ac.uk/
T: +44 1509 228226
--- /dev/null 2007-11-12 10:49:39.404763750 +0000
+++ /etc/pam.d/rt-krb5-auth 2007-11-28 09:49:14.000000000 +0000
@@ -0,0 +1,2 @@
+#%PAM-1.0
+auth required pam_krb5.so debug no_user_check
--- lib/RT/CurrentUser.pm 2007-04-24 18:21:42.000000000 +0100
+++ local/lib/RT/CurrentUser.pm 2007-11-28 09:47:50.000000000 +0000
@@ -294,9 +294,13 @@
=head2 IsPassword
-Takes a password as a string. Passes it off to IsPassword in this
-user's UserObj. If it is the user's password and the user isn't
-disabled, returns 1.
+Takes a password as a string. Either:
+ 1. Checks it against PAM if $RT::PamAuth is set.
+ - if $RT::PamFallbackToInternal is set and PAM fails, falls to step 2
+ - sets RT password if $RT::PamUpdateRTPassword is set
+ 2. Passes it off to IsPassword in this user's UserObj.
+
+If the password is validated and the user isn't disabled, returns 1.
Otherwise, returns undef.
@@ -305,7 +309,48 @@
sub IsPassword {
my $self = shift;
my $value = shift;
-
+
+ if ($RT::PamAuth) {
+ my $name = $self->UserObj->Name;
+
+ # First check that the user isn't disabled.
+ # There is no point authenticating if they are!
+
+ if ($self->PrincipalObj->Disabled) {
+ $RT::Logger->warning("User $name attempted PAM login but is disabled in RT database.");
+ return undef;
+ }
+
+ use Authen::PAM;
+ foreach my $pam_module (@$RT::PamAuthModules) {
+ $RT::Logger->debug("MODULE: " . $pam_module);
+ next if ($pam_module =~ /dummy/);
+ my $pam_conv_func = sub { my @res = (PAM_SUCCESS); unshift @res,$value and unshift @res, 0 while( shift @_ && shift @_ ); @res };
+ my( $res, $pamh, );
+ if( ( $res = pam_start( $pam_module, $name, $pam_conv_func,$pamh ) ) == PAM_SUCCESS
+ && ( $res = pam_authenticate( $pamh, 0 ) )== PAM_SUCCESS
+ && ( $res = pam_end( $pamh, 0 ) )== PAM_SUCCESS
+ ) {
+ # If $PamUpdateRTPassword is defined we need to set the RT password
+ # but only if the old RT password differs
+ if ($RT::PamUpdateRTPassword && (!$self->UserObj->IsPassword($value))) {
+ $RT::Logger->warning("Attempting to change RT password for $name");
+ my ( $val, $msg ) = $self->UserObj->SetPassword($value);
+ if ($val) {
+ $RT::Logger->warning("User $name RT password changed to PAM password on successful PAM login");
+ }
+ }
+ return ( 1 );
+ } else {
+ $RT::Logger->warning("User $name failed PAM authentication");
+ unless ($RT::PamFallbackToInternal) {
+ return ( 0 );
+ } else {
+ $RT::Logger->warning("User $name falling back to RT database authentication");
+ }
+ }
+ }
+ }
return ($self->UserObj->IsPassword($value));
}
--- etc/RT_SiteConfig.pm.pre-3.6.5 2007-11-29 17:32:46.000000000 +0000
+++ etc/RT_SiteConfig.pm 2007-11-28 09:38:38.000000000 +0000
@@ -316,6 +316,30 @@
Set($WebExternalAuto , undef);
+# --- BEGIN MODIFICATION ---
+# If $PamAuth is defined, RT will attempt to use a PAM module on this
+# server to authenticate against, for example, Active Directory or
+# an LDAP server. The config of the PAM module is outside the scope
+# of this documentation. The name(s) of the PAM modules are listed
+# in the array $PamAuthModules
+
+Set($PamAuth , 1 );
+Set($PamAuthModules, [ 'rt-krb5-auth' ]);
+
+# If $PamFallbackToInternal is defined, the password will be checked
+# against the RT internal database upon PAM auth failure. This permits
+# the use of RT when the external authentication source has "gone away".
+
+Set($PamFallbackToInternal , 1 );
+
+# If $PamUpdateRTPassword is defined, successful authentication against
+# the configured PAM module(s) will update the local RT user's password
+# in the database. This permits the use of RT with the same passwords
+# when the external authentication source has "gone away".
+
+Set($PamUpdateRTPassword, 1 );
+# --- END MODIFICATION ---
+
# $WebSessionClass is the class you wish to use for managing Sessions.
# It defaults to use your SQL database, but if you are using MySQL 3.x and
# plans to use non-ascii Queue names, uncomment and add this line to
_______________________________________________
http://lists.bestpractical.com/cgi-bin/mailman/listinfo/rt-users
SAVE THOUSANDS OF DOLLARS ON RT SUPPORT:
If you sign up for a new RT support contract before December 31, we'll take
up to 20 percent off the price. This sale won't last long, so get in touch
today.
Email us at [EMAIL PROTECTED] or call us at +1 617 812 0745.
Community help: http://wiki.bestpractical.com
Commercial support: [EMAIL PROTECTED]
Discover RT's hidden secrets with RT Essentials from O'Reilly Media.
Buy a copy at http://rtbook.bestpractical.com