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