Merge pull request #2 from eisin/master
Use for content publishing, not for repository access
This commit is contained in:
		
						commit
						0cd05b468a
					
				
							
								
								
									
										12
									
								
								README.pod
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								README.pod
									
									
									
									
									
								
							@ -61,9 +61,9 @@ Authen::Simple::LDAP (and IO::Socket::SSL if LDAPS is used):
 | 
			
		||||
		# RedmineDbWhereClause "and members.role_id IN (1,2)"
 | 
			
		||||
 | 
			
		||||
		## SCM transport protocol, used to detecte write requests
 | 
			
		||||
		## Valid values: dav-svn, git-smart-http
 | 
			
		||||
		## Default: dav-svn
 | 
			
		||||
		# RedmineSCMProtocol dav-svn
 | 
			
		||||
		## Valid values: Subversion, Git, None
 | 
			
		||||
		## Default: Subversion
 | 
			
		||||
		# RedmineRepositoryType Subversion
 | 
			
		||||
 | 
			
		||||
		## Credentials cache size
 | 
			
		||||
		## Default: 0 (disabled)
 | 
			
		||||
@ -101,6 +101,10 @@ Authen::Simple::LDAP (and IO::Socket::SSL if LDAPS is used):
 | 
			
		||||
		## Default: On
 | 
			
		||||
		# RedmineSuperAdmin Off
 | 
			
		||||
 | 
			
		||||
		## Sets firstname, lastname, email address to environment variables.
 | 
			
		||||
		## Default: Off
 | 
			
		||||
		# RedmineSetUserAttributes Off
 | 
			
		||||
 | 
			
		||||
	</Location>
 | 
			
		||||
 | 
			
		||||
To be able to browse repository inside redmine, you must add something
 | 
			
		||||
@ -132,4 +136,6 @@ S<them :>
 | 
			
		||||
 | 
			
		||||
And you need to upgrade at least reposman.rb (after r860).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										116
									
								
								Redmine.pm
									
									
									
									
									
								
							
							
						
						
									
										116
									
								
								Redmine.pm
									
									
									
									
									
								
							@ -63,7 +63,7 @@ Authen::Simple::LDAP (and IO::Socket::SSL if LDAPS is used):
 | 
			
		||||
		# RedmineDbWhereClause "and members.role_id IN (1,2)"
 | 
			
		||||
 | 
			
		||||
		## SCM transport protocol, used to detecte write requests
 | 
			
		||||
		## Valid values: Subversion, Git
 | 
			
		||||
		## Valid values: Subversion, Git, None
 | 
			
		||||
		## Default: Subversion
 | 
			
		||||
		# RedmineRepositoryType Subversion
 | 
			
		||||
 | 
			
		||||
@ -237,7 +237,13 @@ my @directives = (
 | 
			
		||||
		name         => 'RedmineRepositoryType',
 | 
			
		||||
		req_override => OR_AUTHCFG,
 | 
			
		||||
		args_how     => TAKE1,
 | 
			
		||||
		errmsg       => 'Indicate the type of Repository (Subversion or Git). This is used to properly detected write requests. Defaults to Subversion.',
 | 
			
		||||
		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.',
 | 
			
		||||
	},
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@ -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) = @_;
 | 
			
		||||
@ -291,8 +300,10 @@ sub RedmineRepositoryType {
 | 
			
		||||
	$arg = trim($arg);
 | 
			
		||||
	if($arg eq 'Subversion' || $arg eq 'Git') {
 | 
			
		||||
		$cfg->{RepositoryType} = 'Repository::'.$arg;
 | 
			
		||||
	} elsif($arg eq 'None') {
 | 
			
		||||
		$cfg->{RepositoryType} = $arg;
 | 
			
		||||
	} else {
 | 
			
		||||
		die "Invalid RedmineRepositoryType value: $arg, choose either Subversion or Git !";
 | 
			
		||||
		die "Invalid RedmineRepositoryType value: $arg, choose either Subversion or Git or None !";
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -335,16 +346,21 @@ 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);
 | 
			
		||||
 | 
			
		||||
		} 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
 | 
			
		||||
			my $dbh = connect_database($r)
 | 
			
		||||
				or return SERVER_ERROR;
 | 
			
		||||
 | 
			
		||||
			($res, $reason) = check_login($r, $dbh, $password);
 | 
			
		||||
			($res, $reason) = check_login($r, $dbh, $password, $cfg);
 | 
			
		||||
			$dbh->disconnect();
 | 
			
		||||
 | 
			
		||||
			# Store the cache key for latter use
 | 
			
		||||
@ -376,10 +392,14 @@ sub authen_handler {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
sub check_login {
 | 
			
		||||
	my ($r, $dbh, $password) = @_;
 | 
			
		||||
	my ($r, $dbh, $password, $cfg) = @_;
 | 
			
		||||
	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, $email_address) =
 | 
			
		||||
		$dbh->selectrow_array('SELECT users.hashed_password, users.status, users.auth_source_id, users.salt, users.id, users.firstname, users.lastname, email_addresses.address
 | 
			
		||||
		FROM users
 | 
			
		||||
		LEFT JOIN email_addresses on (email_addresses.user_id=users.id and email_addresses.is_default=1)
 | 
			
		||||
		WHERE users.login = ?', undef, $user)
 | 
			
		||||
		or return (AUTH_REQUIRED, "unknown user '$user'");
 | 
			
		||||
 | 
			
		||||
	# Check password
 | 
			
		||||
@ -422,7 +442,16 @@ sub check_login {
 | 
			
		||||
	# Password is ok, check if account if locked
 | 
			
		||||
	return (FORBIDDEN, "inactive account: '$user'") unless $status == 1;
 | 
			
		||||
 | 
			
		||||
	$r->log->debug("successfully authenticated as active redmine user '$user'");
 | 
			
		||||
	if ($cfg->{SetUserAttributes}) {
 | 
			
		||||
		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
 | 
			
		||||
	return OK;
 | 
			
		||||
@ -449,7 +478,23 @@ sub authz_handler {
 | 
			
		||||
 | 
			
		||||
	my ($identifier, $project_id, $is_public, $status);
 | 
			
		||||
 | 
			
		||||
	if($identifier = $cfg->{Project}) {
 | 
			
		||||
	if($cfg->{RepositoryType} eq 'None') {
 | 
			
		||||
		$identifier = $cfg->{Project};
 | 
			
		||||
		if(!$cfg->{Project}) {
 | 
			
		||||
			return FORBIDDEN;
 | 
			
		||||
		}
 | 
			
		||||
		($project_id, $is_public, $status) = $dbh->selectrow_array(
 | 
			
		||||
			"SELECT p.id, p.is_public, p.status
 | 
			
		||||
			FROM projects p
 | 
			
		||||
			WHERE p.identifier = ?",
 | 
			
		||||
			undef, $identifier
 | 
			
		||||
		);
 | 
			
		||||
		unless(defined $project_id) {
 | 
			
		||||
			$r->log_reason("No matching project for ${identifier}");
 | 
			
		||||
			return NOT_FOUND;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	} elsif($identifier = $cfg->{Project}) {
 | 
			
		||||
		($project_id, $is_public, $status) = $dbh->selectrow_array(
 | 
			
		||||
			"SELECT p.id, p.is_public, p.status
 | 
			
		||||
			FROM projects p JOIN repositories r ON (p.id = r.project_id)
 | 
			
		||||
@ -530,6 +575,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 {
 | 
			
		||||
@ -603,7 +649,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;
 | 
			
		||||
@ -641,6 +690,29 @@ 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;
 | 
			
		||||
 | 
			
		||||
	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) = @_;
 | 
			
		||||
@ -661,6 +733,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;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user