diff --git a/Redmine.pm b/Redmine.pm index a47f8b7..5f23bde 100644 --- a/Redmine.pm +++ b/Redmine.pm @@ -239,6 +239,12 @@ my @directives = ( args_how => TAKE1, errmsg => 'Indicate the type of Repository (Subversion or Git or None). This is used to properly detected write requests. Defaults to Subversion.', }, + { + name => 'RedmineSetUserAttributes', + req_override => OR_AUTHCFG, + args_how => FLAG, + errmsg => 'Sets firstname, lastname, email address to environment variables. Defaults to no.', + }, ); # Initialize defaults configuration @@ -263,6 +269,8 @@ sub DIR_CREATE { DenyAnonymous => 0, DenyNonMember => 0, SuperAdmin => 1, + SetUserAttributes => 0, + AttributesCacheCredsCount => 0, }, $class; } @@ -278,6 +286,7 @@ sub RedmineCacheCredsMaxAge { set_val('CacheCredsMaxAge', @_); } sub RedmineDenyAnonymous { set_val('DenyAnonymous', @_); } sub RedmineDenyNonMember { set_val('DenyNonMember', @_); } sub RedmineSuperAdmin { set_val('SuperAdmin', @_); } +sub RedmineSetUserAttributes { set_val('SetUserAttributes', @_); } sub RedmineDbWhereClause { my ($cfg, $parms, $arg) = @_; @@ -337,9 +346,15 @@ sub authen_handler { # Used cached credentials if possible my $cache_key = get_cache_key($r, $password); - if(defined $cache_key && cache_get($r, $cache_key)) { + my $cfg = get_config($r); + if(defined $cache_key && !$cfg->{SetUserAttributes} && cache_get($r, $cache_key)) { $r->log->debug("reusing cached credentials for user '", $r->user, "'"); $r->set_handlers(PerlAuthzHandler => undef); + attributes_cache_get($r, $cache_key); + + } elsif(defined $cache_key && $cfg->{SetUserAttributes} && cache_get($r, $cache_key) && attributes_cache_get($r, $cache_key)) { + $r->log->debug("reusing cached credentials for user '", $r->user, "' including attributes"); + $r->set_handlers(PerlAuthzHandler => undef); } else { # Else check them @@ -381,7 +396,7 @@ sub check_login { my ($r, $dbh, $password) = @_; my $user = $r->user; - my ($hashed_password, $status, $auth_source_id, $salt) = $dbh->selectrow_array('SELECT hashed_password, status, auth_source_id, salt FROM users WHERE login = ?', undef, $user) + my ($hashed_password, $status, $auth_source_id, $salt, $id, $firstname, $lastname) = $dbh->selectrow_array('SELECT hashed_password, status, auth_source_id, salt, id, firstname, lastname FROM users WHERE login = ?', undef, $user) or return (AUTH_REQUIRED, "unknown user '$user'"); # Check password @@ -424,6 +439,20 @@ sub check_login { # Password is ok, check if account if locked return (FORBIDDEN, "inactive account: '$user'") unless $status == 1; + my($email_address) = $dbh->selectrow_array( + "SELECT address + FROM email_addresses + WHERE email_addresses.user_id=? and is_default=1", + undef, + $id + ); + if (defined $email_address) { + $r->subprocess_env->set("REDMINE_DEFAULT_EMAIL_ADDRESS" => $email_address); + } else { + $r->subprocess_env->set("REDMINE_DEFAULT_EMAIL_ADDRESS" => ""); + } + $r->subprocess_env->set("REDMINE_FIRSTNAME" => $firstname); + $r->subprocess_env->set("REDMINE_LASTNAME" => $lastname); $r->log->debug("successfully authenticated as active redmine user '$user'"); # Everything's ok @@ -544,6 +573,7 @@ sub authz_handler { # Put successful credentials in cache if(my $cache_key = $r->pnotes("RedmineCacheKey")) { cache_set($r, $cache_key); + attributes_cache_set($r, $cache_key); } } else { @@ -617,7 +647,10 @@ sub connect_database { my $r = shift; my $cfg = get_config($r); - my $dbh = DBI->connect($cfg->{DSN}, $cfg->{DbUser}, $cfg->{DbPass}) + my $dbh = DBI->connect($cfg->{DSN}, $cfg->{DbUser}, $cfg->{DbPass}, { + pg_enable_utf8 => 1, + mysql_enable_utf8 => 1, + }) or $r->log->error("Connection to database failed: $DBI::errstr."); return $dbh; @@ -655,6 +688,30 @@ sub cache_get { return 1; } +sub attributes_cache_get { + my($r, $key) = @_; + + my $cfg = get_config($r); + return unless $cfg->{CacheCredsMax} && $cfg->{AttributesCacheCreds}; + + my $cache_text = $cfg->{AttributesCacheCreds}->get($key) + or return 0; + + $r->log->error("cache_text:$cache_text"); + my($time, $email_address, $firstname, $lastname) = split(":", $cache_text); + if($cfg->{CacheCredsMaxAge} && ($r->request_time - $time) > $cfg->{CacheCredsMaxAge}) { + $cfg->{AttributesCacheCreds}->unset($key); + $cfg->{AttributesCacheCredsCount}--; + return 0; + } + + $r->subprocess_env->set("REDMINE_DEFAULT_EMAIL_ADDRESS", $email_address . ""); + $r->subprocess_env->set("REDMINE_FIRSTNAME", $firstname . ""); + $r->subprocess_env->set("REDMINE_LASTNAME", $lastname . ""); + + return 1; +} + # put credentials in cache sub cache_set { my($r, $key) = @_; @@ -675,6 +732,30 @@ sub cache_set { $cfg->{CacheCredsCount}++; } +sub attributes_cache_set { + my($r, $key) = @_; + + my $cfg = get_config($r); + return unless $cfg->{CacheCredsMax}; + + unless($cfg->{AttributesCacheCreds}) { + $cfg->{AttributesCachePool} = APR::Pool->new; + $cfg->{AttributesCacheCreds} = APR::Table::make($cfg->{AttributesCachePool}, $cfg->{CacheCredsMax}); + } + + if($cfg->{AttributesCacheCredsCount} >= $cfg->{CacheCredsMax}) { + $cfg->{AttributesCacheCreds}->clear; + $cfg->{AttributesCacheCredsCount} = 0; + } + my $cache_text = join(":", $r->request_time, + $r->subprocess_env->get("REDMINE_DEFAULT_EMAIL_ADDRESS"), + $r->subprocess_env->get("REDMINE_FIRSTNAME"), + $r->subprocess_env->get("REDMINE_LASTNAME"), + ); + $cfg->{AttributesCacheCreds}->set($key, $cache_text); + $cfg->{AttributesCacheCredsCount}++; +} + 1;