#!/usr/bin/perl
#
# Copyright 2006-2009 by Purdue Research Foundation, West Lafayette, IN 47906.
# All rights reserved.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License, version 2.1 as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
#
# gensvnapache
# Generate Apache Config for HUBzero SVN Projects

use strict;
use Net::LDAPS;
my $id;
my $name;
my $gidref;
my @gid;
my $dir;
my $svnroot;
my $svnurl;
my $i;
my $line;
my @dirlist;
my $sourcepublic;
my $is_there;
my $hubdir;
my $key;
my $value;
my %cfg;
my $type;

if($#ARGV != 2 && $#ARGV != 3) {
        print "Usage:  " . $0 . " svn_root_path svn_url_path hub_path [type]\n";
        exit(1);
}

$svnroot = shift();
$svnurl = shift();
$hubdir = shift();
$type = shift();

if(! -d $svnroot) {
        print "Error:  '" . $svnroot . "' is not a valid directory.\n";
        exit(2);
}

if (! -d $hubdir) {
        print "Error: '" . $hubdir . "' is not a valid directory.\n";
        exit(3);
}

###################### configuration scan (poor hack) ######################

open CONF1, "$hubdir/hubconfiguration.php" or die "Can't open hub configuration file: $!";
while (<CONF1>) { last if /^\s*class\s+HubConfig\s+\{\s*$/; }
while (<CONF1>) {
        last if /^\s*\}\s*$/;
        ($key, $value) = /^\s*var\s*\$(\w+)\s*=\s*"([^"\\]*(\\.[^"\\]*)*)"/;
        ($key, $value) = /^\s*var\s*\$(\w+)\s*=\s*'([^'\\]*(\\.[^'\\]*)*)'/ if ($key eq '');
        ($key, $value) = /^\s*var\s*\$(\w+)\s*\=\s*(\w+)\s*\;\s*$/ if ($key eq '');
        $cfg{$key} = $value;
}
close CONF1;

###################### end configuration scan ######################

###################### site parameterization ######################
my $ldapbase = $cfg{'hubLDAPBaseDN'};
my $admingid = "gid=apps,ou=groups," . $ldapbase;
my $ldaphost = $cfg{'hubLDAPMasterHost'};
my $ldapbinduser = $cfg{'hubLDAPSearchUserDN'};
my $ldapbindpass = $cfg{'hubLDAPSearchUserPW'};
$ldapbindpass =~ s/\\(\'|\"|\\)/$1/g;
###################### end site parameterization ######################

opendir(DIR, $svnroot);
@dirlist = readdir(DIR);
close(DIR);

print "#\n";
print "# Apache configuration for SVN repositories\n";
print "#\n";
print "# This file is generated automatically from LDAP.\n";
print "#      !!!  DO NOT MODIFY THIS FILE  !!!\n";
print "#\n";
print "\n";
foreach $dir (@dirlist) {
	if($dir ne "." && $dir ne ".." && $dir ne "config" && -d $svnroot.'/'.$dir) {
		$id = $dir;
		#if (($type == 'group') || ($type == 'infrastructure') || ($id =~ m/^group-/)) {
		if ($type eq 'group') {
			($name, $sourcepublic, $gidref) = ldapgrouplookup($id);

			if($name ne '') {
				@gid = @{$gidref};
				if($admingid) {
					$is_there = grep $_ eq $admingid, @gid;
					if(!$is_there) {
						push(@gid, $admingid);
					}
				}
				gensvnapachestanza($svnroot, $svnurl, $id, $name, $sourcepublic, @gid);
				print "\n";
			}
		} else {
			($name, $sourcepublic, $gidref) = ldaptoollookup($id . "_dev");
			if($name eq '') {
				($name, $sourcepublic, $gidref) = ldaptoollookup($id);
			}
			@gid = @{$gidref};
			if($admingid && ($type == 'tool' || $id =~ /^app-/)) {
				$is_there = grep $_ eq $admingid, @gid;
				if(!$is_there) {
					push(@gid, $admingid);
				}
			}
			gensvnapachestanza($svnroot, $svnurl, $id, $name, $sourcepublic, @gid);
			print "\n";
		}
	}
}


#function ldapgrouplookup(groupid)
sub ldapgrouplookup {
	my $id = shift();
	my $name;
	my $gid;
	my @gids;
	my $ldapconn;
	my $ldapfilter;
	my @ldapattrs;
	my @ldapentries;
	my $ldapentry;
	my $mesg;
	my @owners;
	my $owner;
	my $sourcepublic = 0;

	my $ldapgroupbase = "ou=projects," . $ldapbase;

	@gids = ();
	$name = "";
	$ldapconn = Net::LDAPS->new($ldaphost);
	if($ldapconn) {
		$mesg = $ldapconn->bind(dn=>$ldapbinduser, password=>$ldapbindpass, version=>3);
		if($mesg->is_error) {
			print "Error:  LDAP failed to bind\n";
		}
		else {
			@ldapattrs = ('cn', 'sourcePublic', 'owner');
			$id =~ s/^group-//;
			$ldapfilter = "(project=" . $id . ")";
			$mesg = $ldapconn->search(filter=>$ldapfilter, base=>$ldapgroupbase, attrs=>@ldapattrs);
			if(!$mesg->is_error) {
				@ldapentries = $mesg->entries;
				foreach $ldapentry (@ldapentries) {
					$name = $ldapentry->get_value('cn');
					if($ldapentry->get_value('sourcePublic') eq "TRUE") {
						$sourcepublic = 1;
					}
					@owners = $ldapentry->get_value('owner');
				}
			}
			foreach $owner (@owners) {
				push(@gids, $owner);
			}
			$ldapconn->unbind;
		}
	}
	return($name, $sourcepublic, \@gids);
}


#function ldaptoollookup(toolid)
sub ldaptoollookup {
	my $id = shift();
	my $name;
	my $gid;
	my @gids;
	my $ldapconn;
	my $ldapfilter;
	my @ldapattrs;
	my @ldapentries;
	my $ldapentry;
	my $mesg;
	my @owners;
	my $owner;
	my $sourcepublic = 0;

	my $ldaptoolbase = "ou=tools," . $ldapbase;

	@gids = ();
	$name = "";
	$ldapconn = Net::LDAPS->new($ldaphost);
	if($ldapconn) {
		$mesg = $ldapconn->bind(dn=>$ldapbinduser, password=>$ldapbindpass, version=>3);
		if($mesg->is_error) { 
			print "Error:  LDAP failed to bind\n";
		}
		else {
			@ldapattrs = ('cn', 'sourcePublic', 'owner');
			$id =~ s/^app-//;
			$ldapfilter = "(tool=" . $id . ")";
			$mesg = $ldapconn->search(filter=>$ldapfilter, base=>$ldaptoolbase, attrs=>@ldapattrs);
			if(!$mesg->is_error) {
				@ldapentries = $mesg->entries;
				foreach $ldapentry (@ldapentries) {
					$name = $ldapentry->get_value('cn');
					if($ldapentry->get_value('sourcePublic') eq "TRUE") {
						$sourcepublic = 1;
					}
					@owners = $ldapentry->get_value('owner');
				}
			}
			foreach $owner (@owners) {
				push(@gids, $owner);
			}
			$ldapconn->unbind;
		}
	}
	return($name, $sourcepublic, \@gids);
}


#function gensvnapachestanza(svnroot, projectid, projectname, sourcepublic, gid, [gid2, [gid3 ...]])
sub gensvnapachestanza {
	my $svnroot = shift();
	my $svnurl = shift();
	my $id = shift();
	my $name = shift();
	my $sourcepublic = shift();
	my @gid = ();
	while($#_ >= 0) {
		push(@gid, shift());
	}
	my $thisgid;

	$svnurl =~ s/\@PROJECT\@/$id/;

	print "<Location " . $svnurl . ">\n";
	print "\tDAV svn\n";
	print "\tSVNPath " . $svnroot . "/" . $id . "\n";
	print "\tAuthType Basic\n";
	print "\tAuthBasicProvider ldap\n";
	print "\tAuthName \"" . $name . " Subversion Repository\"\n";
	print "\tAuthzLDAPAuthoritative on\n";
	print "\tAuthLDAPBindDN \"" . $ldapbinduser . "\"\n";
	print "\tAuthLDAPBindPassword \"" . $ldapbindpass . "\"\n";
	print "\tAuthLDAPGroupAttributeIsDN on\n";
	print "\tAuthLDAPGroupAttribute owner\n";
	print "\tAuthLDAPGroupAttribute member\n";
	print "\tAuthLDAPURL " . $ldaphost . "/ou=users," . $ldapbase . "\n";
	if($sourcepublic > 0) {
		print "\t<LimitExcept GET PROPFIND OPTIONS REPORT>\n";
	}
	foreach $thisgid (@gid) {
		if($sourcepublic > 0) {
			print "\t";
		}
		print "\tRequire ldap-group " . $thisgid . "\n";
	}
	if($sourcepublic > 0) {
		print "\t</LimitExcept>\n";
	}
	print "</Location>\n";
}

