added a public field to a project.
added a new mod_perl handler for simpler access control
This commit is contained in:
		| @ -1,7 +1,7 @@ | ||||
|  | ||||
| cfgdir=$(CFGDIR) | ||||
| cfg_DATA = codepot.ini codepot.mysql codepot.a2ldap | ||||
| cfg_SCRIPTS = start-commit pre-commit post-commit pre-revprop-change post-revprop-change | ||||
| cfg_SCRIPTS = start-commit pre-commit post-commit pre-revprop-change post-revprop-change access-normal.conf access-noanon.conf | ||||
|  | ||||
| EXTRA_DIST = $(cfg_DATA)  $(cfg_SCRIPTS) | ||||
|  | ||||
|  | ||||
| @ -46,10 +46,25 @@ | ||||
|  | ||||
| 	#Require ldap-group cn=users,ou=groups,dc=sample,dc=net | ||||
|  | ||||
| 	# allow anynymous for viewing and checking out | ||||
| 	# Enable find-grained access control using the access file. | ||||
| 	# The specified file must be located under the repository/conf subdirectory. | ||||
| 	# AuthzSVNRespsRelativeAccessFile requried subversion 1.7 or later. | ||||
| 	# If you're using a older version, there are no automatic repostory  | ||||
| 	# protection according to the project type (public/private) | ||||
| 	# You may have to use AuthzSVNAccessFile for manual control globally | ||||
| 	# in such a case. | ||||
| 	# AuthzSVNReposRelativeAccessFile access.conf | ||||
| 	# Satisfy All | ||||
|  | ||||
| 	# allow anynymous/guest for viewing and checking out | ||||
| 	<Limit GET HEAD OPTIONS REPORT PROPFIND> | ||||
| 		Allow from all | ||||
| 		#Satisfy any | ||||
| 		# Use 'Allow from all' to allow anonymous access. | ||||
| 		#Allow from all | ||||
|  | ||||
| 		# 'Required valid-user' is more strict in that it requires a valid | ||||
| 		# user name and password. You may create a guest account to supplement | ||||
| 		# anonymous access. | ||||
| 		Require valid-user | ||||
| 	</Limit> | ||||
|  | ||||
| 	# require authentication for other operations | ||||
|  | ||||
| @ -179,4 +179,3 @@ force_project_delete = "no" | ||||
| ; Leave this empty for the default footer message | ||||
| ;------------------------------------------------------------------------------ | ||||
| footer = "" | ||||
|  | ||||
|  | ||||
| @ -18,6 +18,7 @@ CREATE TABLE project ( | ||||
| 	summary     VARCHAR(255) NOT NULL, | ||||
| 	description TEXT NOT NULL, | ||||
| 	commitable  CHAR(1)      NOT NULL DEFAULT 'Y', | ||||
| 	public      CHAR(1)      NOT NULL DEFAULT 'Y', | ||||
|  | ||||
| 	createdon   DATETIME     NOT NULL, | ||||
| 	updatedon   DATETIME     NOT NULL, | ||||
| @ -38,7 +39,7 @@ CREATE TABLE project_membership ( | ||||
| CREATE TABLE wiki ( | ||||
| 	projectid  VARCHAR(32)   NOT NULL, | ||||
| 	name       VARCHAR(255)  NOT NULL, | ||||
| 	text	      TEXT          NOT NULL, | ||||
| 	text       TEXT          NOT NULL, | ||||
|  | ||||
| 	createdon  DATETIME      NOT NULL, | ||||
| 	updatedon  DATETIME      NOT NULL, | ||||
|  | ||||
							
								
								
									
										281
									
								
								codepot/etc/perl/Codepot/AccessHandler.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										281
									
								
								codepot/etc/perl/Codepot/AccessHandler.pm
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,281 @@ | ||||
| # | ||||
| # This file is not desinged to be used in conjuntion with other AAA providers. | ||||
| # This file requires to be used alone as shown below for apache httpd2.  | ||||
| # You may change AuthName or SVNParentPath. | ||||
| # | ||||
| # <Location "/svn"> | ||||
| #        DAV svn | ||||
| #        SVNParentPath "/var/lib/codepot/svnrepo" | ||||
| #        PerlAccessHandler Codepot::AccessHandler | ||||
| #        PerlAuthenHandler Codepot::AuthenHandler | ||||
| #        AuthType Basic | ||||
| #        AuthName "codepot" | ||||
| #        require valid-user | ||||
| # </Location> | ||||
| # | ||||
|  | ||||
| package Codepot::AccessHandler; | ||||
|  | ||||
| use strict; | ||||
| use warnings; | ||||
|  | ||||
| use Apache2::Access (); | ||||
| use Apache2::RequestUtil (); | ||||
| use Apache2::RequestRec (); | ||||
| use Apache2::Log; | ||||
| use APR::Table; | ||||
| use APR::Base64; | ||||
|  | ||||
| use Config::Simple; | ||||
| use Net::LDAP; | ||||
| use URI; | ||||
| use DBI; | ||||
|  | ||||
| use Apache2::Const -compile => qw(OK DECLINED FORBIDDEN HTTP_UNAUTHORIZED HTTP_INTERNAL_SERVER_ERROR PROXYREQ_PROXY); | ||||
|  | ||||
| sub get_config | ||||
| { | ||||
| 	my $cfg = new Config::Simple(); | ||||
|  | ||||
| 	if (!$cfg->read ('/etc/codepot/codepot.ini')) | ||||
| 	{ | ||||
| 		return undef; | ||||
| 	} | ||||
|  | ||||
| 	my $config = { | ||||
| 		ldap_server_uri => $cfg->param ("ldap_server_uri"), | ||||
| 		ldap_server_protocol_version => $cfg->param ("ldap_server_protocol_version"), | ||||
| 		ldap_auth_mode => $cfg->param ("ldap_auth_mode"), | ||||
| 		ldap_userid_format => $cfg->param ("ldap_userid_format"), | ||||
| 		ldap_password_format => $cfg->param ("ldap_password_format"), | ||||
| 		ldap_userid_admin_binddn => $cfg->param ("ldap_admin_binddn"), | ||||
| 		ldap_userid_admin_password => $cfg->param ("ldap_admin_password"), | ||||
| 		ldap_userid_search_base => $cfg->param ("ldap_userid_search_base"), | ||||
| 		ldap_userid_search_fitler => $cfg->param ("ldap_userid_search_filter"), | ||||
|  | ||||
| 		database_hostname => $cfg->param ("database_hostname"), | ||||
| 		database_username => $cfg->param ("database_username"), | ||||
| 		database_password => $cfg->param ("database_password"), | ||||
| 		database_name => $cfg->param ("database_name"), | ||||
| 		database_driver => $cfg->param ("database_driver"), | ||||
| 		database_prefix => $cfg->param ("database_prefix") | ||||
| 	}; | ||||
|  | ||||
| 	return $config; | ||||
| } | ||||
|  | ||||
|  | ||||
| sub format_string  | ||||
| { | ||||
| 	my ($fmt, $userid, $password) = @_; | ||||
|  | ||||
| 	my $out = $fmt; | ||||
| 	$out =~ s/\$\{userid\}/$userid/g; | ||||
| 	$out =~ s/\$\{password\}/$password/g; | ||||
|  | ||||
| 	return $out; | ||||
| } | ||||
|  | ||||
| sub authenticate  | ||||
| { | ||||
| 	my ($cfg, $userid, $password) = @_; | ||||
| 	my $binddn; | ||||
| 	my $passwd; | ||||
|  | ||||
| 	# get the next line removed once you implement the second mode | ||||
| 	if ($cfg->{ldap_auth_mode} == 2) { return -2; } | ||||
|  | ||||
| 	my $uri = URI->new ($cfg->{ldap_server_uri}); | ||||
| 	my $ldap = Net::LDAP->new ($uri->host,  | ||||
| 			scheme => $uri->scheme, | ||||
| 			port => $uri->port, | ||||
| 			version => $cfg->{ldap_server_protocol_version} | ||||
| 	); | ||||
| 	if (!defined($ldap)) | ||||
| 	{ | ||||
| 		# error | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if ($cfg->{ldap_auth_mode} == 2) | ||||
| 	{ | ||||
| 		# YET TO BE WRITTEN | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		$binddn = format_string ($cfg->{ldap_userid_format}, $userid, $password); | ||||
| 	} | ||||
|  | ||||
| 	$passwd = format_string ($cfg->{ldap_password_format}, $userid, $password); | ||||
| 	my $res = $ldap->bind ($binddn, password => $passwd); | ||||
|  | ||||
| 	print $res->code; | ||||
| 	print "\n"; | ||||
|  | ||||
| 	$ldap->unbind(); | ||||
| 	return ($res->code == 0)? 1: 0; | ||||
| } | ||||
|  | ||||
| sub open_database | ||||
| { | ||||
| 	my ($cfg) = @_; | ||||
|  | ||||
| 	my $dbtype = $cfg->{database_driver}; | ||||
| 	my $dbname = $cfg->{database_name}; | ||||
| 	my $dbhost = $cfg->{database_hostname}; | ||||
|  | ||||
| 	my $dbh = DBI->connect( | ||||
| 		"DBI:$dbtype:$dbname:$dbhost", | ||||
| 		$cfg->{database_username}, | ||||
| 		$cfg->{database_password}, | ||||
| 		{ RaiseError => 0, PrintError => 0, AutoCommit => 0 } | ||||
| 	); | ||||
|  | ||||
| 	return $dbh; | ||||
| } | ||||
|  | ||||
| sub close_database | ||||
| { | ||||
| 	my ($dbh) = @_; | ||||
| 	$dbh->disconnect (); | ||||
| } | ||||
|  | ||||
| sub is_project_member | ||||
| { | ||||
| 	my ($dbh, $prefix, $projectid, $userid) = @_; | ||||
|  | ||||
| 	my $query = $dbh->prepare ("SELECT projectid FROM ${prefix}project_membership WHERE userid=? AND projectid=?"); | ||||
| 	if (!$query || !$query->execute ($userid, $projectid)) | ||||
| 	{ | ||||
| 		return (-1, $dbh->errstr()); | ||||
| 	} | ||||
|  | ||||
| 	my @row = $query->fetchrow_array; | ||||
| 	return (((scalar(@row) > 0)? 1: 0), undef); | ||||
| } | ||||
|  | ||||
| sub is_project_public | ||||
| { | ||||
| 	my ($dbh, $prefix, $projectid) = @_; | ||||
|  | ||||
| 	my $query = $dbh->prepare ("SELECT public FROM ${prefix}project WHERE id=?"); | ||||
| 	if (!$query || !$query->execute ($projectid)) | ||||
| 	{ | ||||
| 		return (-1, $dbh->errstr()); | ||||
| 	} | ||||
|  | ||||
| 	my @row = $query->fetchrow_array; | ||||
| 	return (((scalar(@row) > 0 && $row[0] eq 'Y')? 1: 0), undef); | ||||
| } | ||||
|  | ||||
| sub __handler  | ||||
| { | ||||
| 	my ($r, $cfg, $dbh) = @_; | ||||
| 	my ($empty, $base, $repo, $dummy) = split ('/', $r->uri(), 4); | ||||
| 	my $method = uc($r->method()); | ||||
|  | ||||
| 	my $author; | ||||
| 	my $userid = undef; | ||||
| 	my $password = undef; | ||||
|  | ||||
| 	if ($r->proxyreq() == Apache2::Const::PROXYREQ_PROXY) | ||||
| 	{ | ||||
| 		$author = $r->headers_in->{'Proxy-Authorization'}; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		$author = $r->headers_in->{'Authorization'}; | ||||
| 	} | ||||
|  | ||||
| 	if (defined($author)) | ||||
| 	{ | ||||
| 		my ($rc, $pass) = $r->get_basic_auth_pw (); | ||||
| 		if ($rc != Apache2::Const::OK) { return $rc; } | ||||
|  | ||||
| 		#$author = APR::Base64::decode((split(/ /,$author))[1]); | ||||
| 		#($userid,$password) = split(/:/, $author); | ||||
|  | ||||
| 		$userid = $r->user(); | ||||
| 		$password = $pass; | ||||
| 	} | ||||
|  | ||||
| 	if (!defined($userid)) { $userid = ""; } | ||||
| 	if (!defined($password)) { $password = ""; } | ||||
|  | ||||
| 	if ($method eq "GET" || | ||||
| 	    $method eq "HEAD" || | ||||
| 	    $method eq "OPTIONS" || | ||||
| 	    $method eq "REPORT" || | ||||
| 	    $method eq "PROPFIND") | ||||
| 	{ | ||||
| 		my ($public, $errmsg) = is_project_public ($dbh, $cfg->{database_prefix}, $repo); | ||||
| 		if ($public <= -1) | ||||
| 		{ | ||||
| 			# failed to contact the authentication server | ||||
| 			$r->log_error ("Cannot check if a project is public - $errmsg"); | ||||
| 			return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR; | ||||
| 		} | ||||
| 		elsif ($public >= 1) | ||||
| 		{ | ||||
| 			return Apache2::Const::OK; | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	my $auth = authenticate ($cfg, $userid, $password); | ||||
| 	if ($auth <= -1) | ||||
| 	{ | ||||
| 		# failed to contact the authentication server | ||||
| 		return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR; | ||||
| 	} | ||||
| 	elsif ($auth == 0) | ||||
| 	{ | ||||
| 		# authentication denied | ||||
| 		$r->note_basic_auth_failure (); | ||||
| 		return Apache2::Const::HTTP_UNAUTHORIZED; | ||||
| 	} | ||||
|  | ||||
| 	# authentication successful.  | ||||
| 	my ($member, $errmsg) = is_project_member ($dbh, $cfg->{database_prefix}, $repo, $userid); | ||||
| 	if ($member <= -1) | ||||
| 	{ | ||||
| 		$r->log_error ("Cannot check project membership - $errmsg"); | ||||
| 		return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR; | ||||
| 	} | ||||
| 	elsif ($member == 0) | ||||
| 	{ | ||||
| 		# access denined | ||||
| 		return Apache2::Const::FORBIDDEN; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		# the user is a member of project. access granted. | ||||
| 		return Apache2::Const::OK; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| sub handler: method | ||||
| { | ||||
| 	my ($class, $r) = @_; | ||||
| 	my $res; | ||||
| 	my $cfg; | ||||
|  | ||||
| 	$cfg = get_config ();  | ||||
| 	if (!defined($cfg)) | ||||
| 	{ | ||||
| 		$r->log_error ("Cannot load configuration"); | ||||
| 		return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR; | ||||
| 	} | ||||
|  | ||||
| 	my $dbh = open_database ($cfg); | ||||
| 	if (!defined($dbh)) | ||||
| 	{ | ||||
| 		$r->log_error ("Cannot open database"); | ||||
| 		return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR; | ||||
| 	} | ||||
|  | ||||
| 	$res = __handler ($r, $cfg, $dbh); | ||||
|  | ||||
| 	close_database ($dbh); | ||||
| 	return $res; | ||||
| } | ||||
| 1; | ||||
							
								
								
									
										12
									
								
								codepot/etc/perl/Codepot/AuthenHandler.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								codepot/etc/perl/Codepot/AuthenHandler.pm
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| package Codepot::AuthenHandler; | ||||
|  | ||||
| use strict; | ||||
| use warnings; | ||||
|  | ||||
| use Apache2::Const -compile => qw(OK DECLINED FORBIDDEN HTTP_UNAUTHORIZED  HTTP_INTERNAL_SERVER_ERROR); | ||||
|  | ||||
| sub handler: method | ||||
| { | ||||
|         return Apache2::Const::OK; | ||||
| } | ||||
| 1; | ||||
		Reference in New Issue
	
	Block a user