Geeks in the West Country

Entries categorized as ‘Uncategorized’

Reverse-proxying with SSL

November 15, 2007 · No Comments

Apache does name-based virtual hosting, and it does proxying, and it does both quite nicely. Problem is, it won’t mix the former with SSL. This, to my mind, is a major failing. We know why it doesn’t do it: SSL is defined per virtual host, but the server must know to which host the client is talking before it can unwrap the SSL-wrapped channel to find out which host… yadda, yadda, open box with crowbar inside.

However, with a wildcard SSL certificate matching all virtual hosts on the server, it is perfectly possible to unwrap the channel before directing the traffic to a specific virtual host. This is an edge case, but a very valuable edge case which MS ISA Server supports just fine.

In short, it would be nice to be able to specify a server-wide SSL wildcard certificate that applied to all SSL virtual hosts and did not prevent name-based virtual hosting. I understand that this may be difficult with Apache’s current architecture (vhost dispatch handled early in the pipeline) but if time allows I may experiment with the source code.

A dedicated HTTP/S reverse-proxying gateway application could be very useful.

Categories: Uncategorized

SVN and Active Directory

November 13, 2007 · No Comments

Our old SVN/Trac system is getting a shakeup. We’re constructing a new wiki project for the next version of our product and this seemed like the ideal time to rearrange the furniture. Trac’s getting moved to an actual database (backing up an SQLite DB centrally was getting annoying) and SVN’s finally getting its own server. A properly-configured reverse proxy acting as gateway to all the services should eliminate differences between internal and external URLs for a given service. The whole shebang’s being moved to Ubuntu Linux 7.04 too, since NFSv4 is much nicer for running shared repos and Trac project dirs than Windows Networking, and although we’re not running redundant/load-balanced Trac servers yet it’s probably a good idea to think ahead.

Of course, the reason we used Windows Server originally was that we needed Active Directory integration for Trac and SVN, and the Apache SSPI module is not available on Linux. Group-based, per-directory access control is awkward even with that setup, but there’s a solution: using mod_authz_svn for access control and running a script to synchronise the module’s user file with Active Directory via LDAP. I wasn’t able to find such a script, but hacking one together didn’t take long:

#!/usr/bin/perl
use Net::LDAP;
# Domain name.
$ldap_domain = “<your domain name here>”;
# DN of the LDAP directory root.
# This can be generated from the domain name.
$ldap_root = “dc=”.$ldap_domain;
$ldap_root =~ s/\./,dc=/g;
# Domain Controllers. Replace these with the hostnames of your DCs.
@dcs = ( ‘dc1′, ‘dc2′ );
# DN of the LDAP directory base for our queries.
# eg. ‘ou=Users,dc=example,dc=net’, but we can plug in $ldap_root
# for the domain’s DN.
$ldap_base = “<your base DN here>,$ldap_root”;
# Authorisation of guest account used for queries.
$ldap_username = “<guest AD user DN here>”;
$ldap_password = “<guest AD user’s password here>”;
#====================================
# Connect and bind to LDAP server.
foreach (@dcs) {
$ldap = Net::LDAP->new(”$_.$ldap_domain”) and last;
}
$ldap or die “$@”;
$ldap->bind($ldap_username, password => $ldap_password) or die “$@”;
# Gets a group by cn.
sub resolve_group($)
{
my($name) = @_;
$mesg = $ldap->search(
base => $ldap_base,
filter => “(&(cn=$name)(objectClass=group))”,
sizelimit => 1
) or die “$@”;
return $mesg->entry(0);
}
# Gets sAMAccountName attribute from all member users of a group, descending
# recursively into member groups.
sub get_member_users($)
{
my($group) = @_;
@users = ();
foreach (@{$group->get_value(’member’, asref=>1)}) {
$mesg = $ldap->search(
base => $_,
filter => “(objectClass=*)”,
attrs => [ 'member', 'dn', 'sAMAccountName', 'objectClass' ]
);
$member = $mesg->entry(0);
@objectClass = @{$member->get_value(’objectClass’, asref=>1)};
if ( grep $_ eq “group”, @objectClass ) {
push @users, @{get_member_users($member)};
}
if ( grep $_ eq “user”, @objectClass ) {
push @users, @{$member->get_value(’sAMAccountName’, asref=>1)};
}
}
return @users;
}
sub get_users_in_group($)
{
my($groupName) = @_;
$group = resolve_group($groupName);
return keys %{{ map { lc $_ => 1 } get_member_users($group) }};
}
while (readline STDIN) {
if($_ =~ /\[(.*?)\]/) {
$section = $1;
} elsif($section eq “groups” and $_ =~ /^(.*?)\s*=/) {
@usernames = get_users_in_group($1);
$list = join ‘, ‘, @usernames;
$_ = “$1 = $list\n”;
}
print $_;
}
$ldap->unbind;

(Yes, Perl’s even nastier when the blog software strips out the indentation and blank lines…)

Download update-groups.pl.

Active Directory will not allow an LDAP client to operate against it anonymously, therefore you will have to provide a user DN and a password in plaintext in the script. Fortunately, the permissions required for this script to operate are minimal. Simply create a new user in the Directory, add it to Domain Guests, set Domain Guests as primary group, and remove from Domain Users. Assuming you haven’t granted extra privileges to Domain Guests, the script will get no more than it needs to operate.

Fill in the fields appropriately for your Active Directory and write a mod_authz_svn user file, eg.:

[groups]
Administrators =
[/]
* = r
Administrators = rw

When run against this, the Perl script will look up every group name specified in [groups], extract all the member user names from the Active Directory, and write out the new group definition. The script takes input on STDIN and generates output on STDOUT, so run something like the following as a cron job (adjust paths as necessary):

#!/bin/bash
cd /svn
cat security.conf | perl update-groups.pl > security.conf.new && mv security.conf.new security.conf

This will only replace the user file if the new one is generated without errors.

Of course, to authenticate HTTP access to the repo you will have to configure Apache to use LDAP appropriately too. Something like the following works:

<Location />
AuthLDAPURL “ldap://<your domain controllers here>/<full DN for LDAP base here>?sAMAccountName?sub?(objectClass=user)”
AuthLDAPBindDN “<guest AD user’s DN here>”
AuthLDAPBindPassword <guest AD user’s password here>”
AuthBasicProvider ldap
AuthUserFile /dev/null
AuthType Basic
AuthzLDAPAuthoritative off
AuthName “Repository”
Require valid-user
DAV svn
SVNParentPath /svn
AuthzSVNAccessFile /svn/security.conf
</Location>

As before, fix up paths and values as necessary. Something similar can be used for controlling access to Trac. Don’t forget to add the mod_authz_svn, mod_authnz_ldap and mod_ldap modules to your Apache configuration, depending on Linux distro and version.

Categories: Uncategorized

Christening the blog

May 3, 2007 · No Comments

So now we have a company blog (wooo!). We’ve been doing a lot of interesting technical work recently which it seems either nobody else is doing or nobody else is admitting to doing, se we thought we’d write about it! This also seems a good place to put some of the internal tools we use which might be useful to other people and to also share some of our thoughts about rich web applications in .NET.

We’re in a slightly strange space technically, since our applications are generally based on a Microsoft stack, yet we also get down and dirty with DHTML - a combination which can be quite powerful but also seems to have two very distinct communities (maybe this will change with ASP.NET AJAX and SilverLight but I think it will take time). Anyway, thats the inaugural blog post done - I hope by the time you read this there’ll be something more interesting here….

Categories: Uncategorized