Pastebin
API
tools
faq
paste
Login
Sign up
Please fix the following errors:
New Paste
Syntax Highlighting
package RT::Authen::ExternalAuth; our $VERSION = '0.09'; =head1 NAME RT::Authen::ExternalAuth - RT Authentication using External Sources =head1 DESCRIPTION A complete package for adding external authentication mechanisms to RT. It currently supports LDAP via Net::LDAP and External Database authentication for any database with an installed DBI driver. It also allows for authenticating cookie information against an external database through the use of the RT-Authen-CookieAuth extension. MODIFIED IN 2011/10/01 By Luciano Silva - lucianoes at ufrgs dot br This version is only numeric UID LDAP. Use at your own risk. =begin testing ok(require RT::Authen::ExternalAuth); =end testing =cut use RT::Authen::ExternalAuth::LDAP; use RT::Authen::ExternalAuth::DBI; use strict; sub DoAuth { my ($session,$given_user,$given_pass) = @_; unless(defined($RT::ExternalAuthPriority)) { return (0, "ExternalAuthPriority not defined, please check your configuration file."); } my $no_info_check = 0; unless(defined($RT::ExternalInfoPriority)) { $RT::Logger->debug("ExternalInfoPriority not defined. User information (including user enabled/disabled cannot be externally-sourced"); $no_info_check = 1; } # This may be used by single sign-on (SSO) authentication mechanisms for bypassing a password check. my $pass_bypass = 0; my $success = 0; # Should have checked if user is already logged in before calling this function, # but just in case, we'll check too. return (0, "User already logged in!") if ($session->{'CurrentUser'} && $session->{'CurrentUser'}->Id); # We don't have a logged in user. Let's try all our available methods in order. # last if success, next if not. # Get the prioritised list of external authentication services my @auth_services = @$RT::ExternalAuthPriority; # For each of those services.. foreach my $service (@auth_services) { $pass_bypass = 0; # Get the full configuration for that service as a hashref my $config = $RT::ExternalSettings->{$service}; $RT::Logger->debug( "Attempting to use external auth service:", $service); # $username will be the final username we decide to check # This will not necessarily be $given_user my $username = undef; ############################################################# ####################### SSO Check ########################### ############################################################# if ($config->{'type'} eq 'cookie') { # Currently, Cookie authentication is our only SSO method $username = RT::Authen::ExternalAuth::DBI::GetCookieAuth($config); } ############################################################# # If $username is defined, we have a good SSO $username and can # safely bypass the password checking later on; primarily because # it's VERY unlikely we even have a password to check if an SSO succeeded. $pass_bypass = 0; if(defined($username)) { $RT::Logger->debug("Pass not going to be checked, attempting SSO"); $pass_bypass = 1; } else { # SSO failed and no $user was passed for a login attempt # We only don't return here because the next iteration could be an SSO attempt unless(defined($given_user)) { $RT::Logger->debug("SSO Failed and no user to test with. Nexting"); next; } # We don't have an SSO login, so we will be using the credentials given # on RT's login page to do our authentication. $username = $given_user; # Don't continue unless the service works. # next unless RT::Authen::ExternalAuth::TestConnection($config); # Don't continue unless the $username exists in the external service $RT::Logger->debug("Calling UserExists with \$username ($username) and \$service ($service)"); next unless RT::Authen::ExternalAuth::UserExists($username, $service); } #################################################################### ########## Load / Auto-Create ###################################### #################################################################### # We are now sure that we're talking about a valid RT user. # If the user already exists, load up their info. If they don't # then we need to create the user in RT. #MODIF my $MagicUid = "a"; #END_MODIF # Does user already exist internally to RT? $RT::Logger->debug("Auto-Create process, this is where the magic really happens!! Put the A letter befone the UID"); $session->{'CurrentUser'} = RT::CurrentUser->new(); $session->{'CurrentUser'}->Load($MagicUid . $username); #$session->{'CurrentUser'}->Load($username); # Unless we have loaded a valid user with a UserID create one. unless ($session->{'CurrentUser'}->Id) { my $UserObj = RT::User->new($RT::SystemUser); my ($val, $msg) = $UserObj->Create(%{ref($RT::AutoCreate) ? $RT::AutoCreate : {}}, Name => ("a" . $username), Gecos => $username, ); unless ($val) { $RT::Logger->error( "Couldn't create user $username: $msg" ); next; } $RT::Logger->info( "Autocreated external user", $UserObj->Name, "(", $UserObj->Id, ")"); $RT::Logger->debug("Loading new user (", $username, ") into current session"); $session->{'CurrentUser'}->Load("a" . $username); $RT::Logger->debug("Did the system load the the userseme with a ? Otherwise the next step will fail."); } #################################################################### ########## Authentication ########################################## #################################################################### # If we successfully used an SSO service, then authentication # succeeded. If we didn't then, success is determined by a password # test. $success = 0; if($pass_bypass) { $RT::Logger->debug("Password check bypassed due to SSO method being in use"); $success = 1; } else { $RT::Logger->debug("Password validation required for service - Executing..."); $success = RT::Authen::ExternalAuth::GetAuth($service,$username,$given_pass); } $RT::Logger->debug("Password Validation Check Result: ",$success); # If the password check succeeded then this is our authoritative service # and we proceed to user information update and login. last if $success; } # If we got here and don't have a user loaded we must have failed to # get a full, valid user from an authoritative external source. unless ($session->{'CurrentUser'} && $session->{'CurrentUser'}->Id) { delete $session->{'CurrentUser'}; return (0, "No User"); } unless($success) { delete $session->{'CurrentUser'}; return (0, "Password Invalid"); } # Otherwise we succeeded. $RT::Logger->debug("Authentication successful. Now updating user information and attempting login."); #################################################################################################### ############################### The following is auth-method agnostic ############################## #################################################################################################### # If we STILL have a completely valid RT user to play with... # and therefore password has been validated... if ($session->{'CurrentUser'} && $session->{'CurrentUser'}->Id) { # Even if we have JUST created the user in RT, we are going to # reload their information from an external source. This allows us # to be sure that the user the cookie gave us really does exist in # the database, but more importantly, UpdateFromExternal will check # whether the user is disabled or not which we have not been able to # do during auto-create # These are not currently used, but may be used in the future. my $info_updated = 0; my $info_updated_msg = "User info not updated"; unless($no_info_check) { # Note that UpdateUserInfo does not care how we authenticated the user # It will look up user info from whatever is specified in $RT::ExternalInfoPriority ($info_updated,$info_updated_msg) = RT::Authen::ExternalAuth::UpdateUserInfo($session->{'CurrentUser'}->Name); } # Now that we definitely have up-to-date user information, # if the user is disabled, kick them out. Now! if ($session->{'CurrentUser'}->UserObj->Disabled) { delete $session->{'CurrentUser'}; return (0, "User account disabled, login denied"); } } # If we **STILL** have a full user and the session hasn't already been deleted # This If/Else is logically unnecessary, but it doesn't hurt to leave it here # just in case. Especially to be a double-check to future modifications. if ($session->{'CurrentUser'} && $session->{'CurrentUser'}->Id) { $RT::Logger->info( "Successful login for", $session->{'CurrentUser'}->Name, "from", $ENV{'REMOTE_ADDR'}); # Do not delete the session. User stays logged in and # autohandler will not check the password again } else { # Make SURE the session is deleted. delete $session->{'CurrentUser'}; return (0, "Failed to authenticate externally"); # This will cause autohandler to request IsPassword # which will in turn call IsExternalPassword } return (1, "Successful login"); } sub UpdateUserInfo { my $username = shift; # Prepare for the worst... my $found = 0; my $updated = 0; my $msg = "User NOT updated"; my $user_disabled = RT::Authen::ExternalAuth::UserDisabled($username); my $UserObj = RT::User->new($RT::SystemUser); $UserObj->Load($username); # If user is disabled, set the RT::Principle to disabled and return out of the function. # I think it's a waste of time and energy to update a user's information if they are disabled # and it could be a security risk if they've updated their external information with some # carefully concocted code to try to break RT - worst case scenario, but they have been # denied access after all, don't take any chances. # If someone gives me a good enough reason to do it, # then I'll update all the info for disabled users if ($user_disabled) { # Make sure principle is disabled in RT my ($val, $message) = $UserObj->SetDisabled(1); # Log what has happened $RT::Logger->info("User marked as DISABLED (", $username, ") per External Service", "($val, $message)\n"); $msg = "User Disabled"; return ($updated, $msg); } # Make sure principle is not disabled in RT my ($val, $message) = $UserObj->SetDisabled(0); # Log what has happened $RT::Logger->info("User marked as ENABLED (", $username, ") per External Service", "($val, $message)\n"); # Update their info from external service using the username as the lookup key # CanonicalizeUserInfo will work out for itself which service to use # Passing it a service instead could break other RT code #MODIFICACAO - Incluido o substring no $username para remover o caracter a my %args = (Name => substr($username,1)); $UserObj->CanonicalizeUserInfo(\%args); # For each piece of information returned by CanonicalizeUserInfo, # run the Set method for that piece of info to change it for the user foreach my $key (sort(keys(%args))) { next unless $args{$key}; my $method = "Set$key"; # We do this on the UserObj from above, not self so that there # are no permission restrictions on setting information my ($method_success,$method_msg) = $UserObj->$method($args{$key}); # If your user information is not getting updated, # uncomment the following logging statements if ($method_success) { # At DEBUG level, log that method succeeded $RT::Logger->debug((caller(0))[3],"$method Succeeded. $method_msg"); } else { # At DEBUG level, log that method failed $RT::Logger->debug((caller(0))[3],"$method Failed. $method_msg"); } } # Confirm update success $updated = 1; $RT::Logger->debug( "UPDATED user (", $username, ") from External Service\n"); $msg = 'User updated'; return ($updated, $msg); } sub GetAuth { # Request a username/password check from the specified service # This is only valid for non-SSO services. my ($service,$username,$password) = @_; my $success = 0; # Get the full configuration for that service as a hashref my $config = $RT::ExternalSettings->{$service}; # And then act accordingly depending on what type of service it is. # Right now, there is only code for DBI and LDAP non-SSO services if ($config->{'type'} eq 'db') { $success = RT::Authen::ExternalAuth::DBI::GetAuth($service,$username,$password); $RT::Logger->debug("DBI password validation result:",$success); } elsif ($config->{'type'} eq 'ldap') { $success = RT::Authen::ExternalAuth::LDAP::GetAuth($service,$username,$password); $RT::Logger->debug("LDAP password validation result:",$success); } else { $RT::Logger->error("Invalid service type for GetAuth:",$service); } return $success; } sub UserExists { # Request a username/password check from the specified service # This is only valid for non-SSO services. # my $removemagic = substr($username, 1); # my ($removemagic,$service) = @_; my ($username,$service) = @_; my $success = 0; # Get the full configuration for that service as a hashref my $config = $RT::ExternalSettings->{$service}; # And then act accordingly depending on what type of service it is. # Right now, there is only code for DBI and LDAP non-SSO services if ($config->{'type'} eq 'db') { $success = RT::Authen::ExternalAuth::DBI::UserExists($username,$service); } elsif ($config->{'type'} eq 'ldap') { my $magicnewname = substr($username, '0', 8); my $username = $magicnewname; $success = RT::Authen::ExternalAuth::LDAP::UserExists($username,$service); } else { $RT::Logger->debug("Invalid service type for UserExists:",$service); } return $success; } sub UserDisabled { $RT::Logger->debug("Now is starting UserDisabled function"); my $username = shift; my $user_disabled = 0; my @info_services = $RT::ExternalInfoPriority ? @{$RT::ExternalInfoPriority} : undef; # For each named service in the list # Check to see if the user is found in the external service # If not found, jump to next service # If found, check to see if user is considered disabled by the service # Then update the user's info in RT and return foreach my $service (@info_services) { # Get the external config for this service as a hashref my $config = $RT::ExternalSettings->{$service}; # If the config doesn't exist, don't bother doing anything, skip to next in list. unless(defined($config)) { $RT::Logger->debug("You haven't defined a configuration for the service named \"", $service, "\" so I'm not going to try to get user information from it. Skipping..."); next; } # If it's a DBI config: if ($config->{'type'} eq 'db') { unless(RT::Authen::ExternalAuth::DBI::UserExists($username,$service)) { $RT::Logger->debug("User (", $username, ") doesn't exist in service (", $service, ") - Cannot update information - Skipping..."); next; } $user_disabled = RT::Authen::ExternalAuth::DBI::UserDisabled($username,$service); } elsif ($config->{'type'} eq 'ldap') { $RT::Logger->debug("Removing special character A from the username."); unless(RT::Authen::ExternalAuth::LDAP::UserExists(substr($username,1),$service)) { $RT::Logger->debug("User (", $username, ") doesn't exist in service (", $service, ") - Cannot update information - Skipping..."); next; } $RT::Logger->debug("New check on LDAP the username, but removing the special character A from the username."); $user_disabled = RT::Authen::ExternalAuth::LDAP::UserDisabled(substr($username,1),$service); } elsif ($config->{'type'} eq 'cookie') { RT::Logger->error("You cannot use SSO Cookies as an information service."); next; } else { # The type of external service doesn't currently have any methods associated with it. Or it's a typo. RT::Logger->error("Invalid type specification for config %config->{'name'}"); # Drop out to next service in list next; } } return $user_disabled; } sub CanonicalizeUserInfo { $RT::Logger->debug("Now is starting CanonicalizeUserInfo function"); # Careful, this $args hashref was given to RT::User::CanonicalizeUserInfo and # then transparently passed on to this function. The whole purpose is to update # the original hash as whatever passed it to RT::User is expecting to continue its # code with an update args hash. my $UserObj = shift; my $args = shift; my $found = 0; my %params = (Name => undef, EmailAddress => undef, RealName => undef); $RT::Logger->debug( (caller(0))[3], "called by", caller, "with:", join(", ", map {sprintf("%s: %s", $_, $args->{$_})} sort(keys(%$args)))); # Get the list of defined external services my @info_services = $RT::ExternalInfoPriority ? @{$RT::ExternalInfoPriority} : undef; # For each external service... foreach my $service (@info_services) { $RT::Logger->debug( "Attempting to get user info using this external service:", $service); # Get the config for the service so that we know what attrs we can canonicalize my $config = $RT::ExternalSettings->{$service}; if($config->{'type'} eq 'cookie'){ $RT::Logger->debug("You cannot use SSO cookies as an information service!"); next; } # For each attr we've been told to canonicalize in the match list foreach my $rt_attr (@{$config->{'attr_match_list'}}) { # Jump to the next attr in $args if this one isn't in the attr_match_list $RT::Logger->debug( "Attempting to use this canonicalization key:",$rt_attr); unless(defined($args->{$rt_attr})) { $RT::Logger->debug("This attribute (", $rt_attr, ") is null or incorrectly defined in the attr_map for this service (", $service, ")"); next; } # Else, use it as a canonicalization key and lookup the user info my $key = $config->{'attr_map'}->{$rt_attr}; my $value = $args->{$rt_attr}; # Check to see that the key being asked for is defined in the config's attr_map my $valid = 0; my ($attr_key, $attr_value); my $attr_map = $config->{'attr_map'}; while (($attr_key, $attr_value) = each %$attr_map) { $valid = 1 if ($key eq $attr_value); } unless ($valid){ $RT::Logger->debug( "This key (", $key, "is not a valid attribute key (", $service, ")"); next; } # Use an if/elsif structure to do a lookup with any custom code needed # for any given type of external service, or die if no code exists for # the service requested. if($config->{'type'} eq 'ldap'){ ($found, %params) = RT::Authen::ExternalAuth::LDAP::CanonicalizeUserInfo($service,$key,$value); } elsif ($config->{'type'} eq 'db') { ($found, %params) = RT::Authen::ExternalAuth::DBI::CanonicalizeUserInfo($service,$key,$value); } else { $RT::Logger->debug( (caller(0))[3], "does not consider", $service, "a valid information service"); } # Don't Check any more attributes last if $found; } # Don't Check any more services last if $found; } # If found, Canonicalize Email Address and # update the args hash that we were given the hashref for if ($found) { # It's important that we always have a canonical email address if ($params{'EmailAddress'}) { $params{'EmailAddress'} = $UserObj->CanonicalizeEmailAddress($params{'EmailAddress'}); } %$args = (%$args, %params); } $RT::Logger->info( (caller(0))[3], "returning", join(", ", map {sprintf("%s: %s", $_, $args->{$_})} sort(keys(%$args)))); ### HACK: The config var below is to overcome the (IMO) bug in ### RT::User::Create() which expects this function to always ### return true or rejects the user for creation. This should be ### a different config var (CreateUncanonicalizedUsers) and ### should be honored in RT::User::Create() return($found || $RT::AutoCreateNonExternalUsers); } { no warnings 'redefine'; *RT::User::CanonicalizeUserInfo = sub { my $self = shift; my $args = shift; return ( CanonicalizeUserInfo( $self, $args ) ); }; } 1;
Optional Paste Settings
Category:
None
Cryptocurrency
Cybersecurity
Fixit
Food
Gaming
Haiku
Help
History
Housing
Jokes
Legal
Money
Movies
Music
Pets
Photo
Science
Software
Source Code
Spirit
Sports
Travel
TV
Writing
Tags:
Syntax Highlighting:
None
Bash
C
C#
C++
CSS
HTML
JSON
Java
JavaScript
Lua
Markdown (PRO members only)
Objective C
PHP
Perl
Python
Ruby
Swift
4CS
6502 ACME Cross Assembler
6502 Kick Assembler
6502 TASM/64TASS
ABAP
AIMMS
ALGOL 68
APT Sources
ARM
ASM (NASM)
ASP
ActionScript
ActionScript 3
Ada
Apache Log
AppleScript
Arduino
Asymptote
AutoIt
Autohotkey
Avisynth
Awk
BASCOM AVR
BNF
BOO
Bash
Basic4GL
Batch
BibTeX
Blitz Basic
Blitz3D
BlitzMax
BrainFuck
C
C (WinAPI)
C Intermediate Language
C for Macs
C#
C++
C++ (WinAPI)
C++ (with Qt extensions)
C: Loadrunner
CAD DCL
CAD Lisp
CFDG
CMake
COBOL
CSS
Ceylon
ChaiScript
Chapel
Clojure
Clone C
Clone C++
CoffeeScript
ColdFusion
Cuesheet
D
DCL
DCPU-16
DCS
DIV
DOT
Dart
Delphi
Delphi Prism (Oxygene)
Diff
E
ECMAScript
EPC
Easytrieve
Eiffel
Email
Erlang
Euphoria
F#
FO Language
Falcon
Filemaker
Formula One
Fortran
FreeBasic
FreeSWITCH
GAMBAS
GDB
GDScript
Game Maker
Genero
Genie
GetText
Go
Godot GLSL
Groovy
GwBasic
HQ9 Plus
HTML
HTML 5
Haskell
Haxe
HicEst
IDL
INI file
INTERCAL
IO
ISPF Panel Definition
Icon
Inno Script
J
JCL
JSON
Java
Java 5
JavaScript
Julia
KSP (Kontakt Script)
KiXtart
Kotlin
LDIF
LLVM
LOL Code
LScript
Latex
Liberty BASIC
Linden Scripting
Lisp
Loco Basic
Logtalk
Lotus Formulas
Lotus Script
Lua
M68000 Assembler
MIX Assembler
MK-61/52
MPASM
MXML
MagikSF
Make
MapBasic
Markdown (PRO members only)
MatLab
Mercury
MetaPost
Modula 2
Modula 3
Motorola 68000 HiSoft Dev
MySQL
Nagios
NetRexx
Nginx
Nim
NullSoft Installer
OCaml
OCaml Brief
Oberon 2
Objeck Programming Langua
Objective C
Octave
Open Object Rexx
OpenBSD PACKET FILTER
OpenGL Shading
Openoffice BASIC
Oracle 11
Oracle 8
Oz
PARI/GP
PCRE
PHP
PHP Brief
PL/I
PL/SQL
POV-Ray
ParaSail
Pascal
Pawn
Per
Perl
Perl 6
Phix
Pic 16
Pike
Pixel Bender
PostScript
PostgreSQL
PowerBuilder
PowerShell
ProFTPd
Progress
Prolog
Properties
ProvideX
Puppet
PureBasic
PyCon
Python
Python for S60
QBasic
QML
R
RBScript
REBOL
REG
RPM Spec
Racket
Rails
Rexx
Robots
Roff Manpage
Ruby
Ruby Gnuplot
Rust
SAS
SCL
SPARK
SPARQL
SQF
SQL
SSH Config
Scala
Scheme
Scilab
SdlBasic
Smalltalk
Smarty
StandardML
StoneScript
SuperCollider
Swift
SystemVerilog
T-SQL
TCL
TeXgraph
Tera Term
TypeScript
TypoScript
UPC
Unicon
UnrealScript
Urbi
VB.NET
VBScript
VHDL
VIM
Vala
Vedit
VeriLog
Visual Pro Log
VisualBasic
VisualFoxPro
WHOIS
WhiteSpace
Winbatch
XBasic
XML
XPP
Xojo
Xorg Config
YAML
YARA
Z80 Assembler
ZXBasic
autoconf
jQuery
mIRC
newLISP
q/kdb+
thinBasic
Paste Expiration:
Never
Burn after read
10 Minutes
1 Hour
1 Day
1 Week
2 Weeks
1 Month
6 Months
1 Year
Paste Exposure:
Public
Unlisted
Private
Folder:
(members only)
Password
NEW
Enabled
Disabled
Burn after read
NEW
Paste Name / Title:
Create New Paste
Hello
Guest
Sign Up
or
Login
Sign in with Facebook
Sign in with Twitter
Sign in with Google
You are currently not logged in, this means you can not edit or delete anything you paste.
Sign Up
or
Login
Public Pastes
Free Crypto Method
CSS | 48 min ago | 0.72 KB
+12,000$ in 2 days
CSS | 48 min ago | 0.72 KB
Documents
48 min ago | 0.43 KB
Crypto admin access
48 min ago | 0.43 KB
Silk
56 min ago | 3.74 KB
fleet_agent
9 hours ago | 5.04 KB
Altur Song Lyrics
20 hours ago | 13.27 KB
CC:T GPS Beacon
1 day ago | 0.49 KB
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the
Cookies Policy
.
OK, I Understand
Not a member of Pastebin yet?
Sign Up
, it unlocks many cool features!