Geeks in the West Country

Alt.NET Bristol Beers #2

August 25, 2009 · 1 Comment

Alt.NET Bristol Beers #2 will take place at the Portcullis on Wednesday 16th September!

Following the success of the first evening, we’re sticking to the same venue and format (we’re assured there will be food this time!).

We’ll be voting for topics at 1845 and then we’ll have a round-table discussion over the topic of the day between 1900 and 2000, before more beer, food and chat until late.

Some of us will be at the Portcullis from 1800 if anybody wants to come over early.

Hope to see you all on the 16th!

For more information see our page on Ning.

→ 1 CommentCategories: Alt.NET

Alt.NET Bristol Ning

July 22, 2009 · Leave a Comment

Thanks to everybody who came to Alt.NET Bristol beers last night! All of us at Bluewire had a lot of fun and everybody I spoke to was keen to do it again, so I’ve created a Ning page for us. You should sign up now and keep an eye on it as that’s where we will announce details of the next event! Hope to see you all again in September :-)

→ Leave a CommentCategories: Alt.NET · Community
Tagged: ,

Alt.NET Bristol Beers #1 – Tuesday 21st July 2009

June 29, 2009 · 1 Comment

What: Alt.NET Beers!

When: Tuesday 21st July 2009

Where: Upstairs at The Portcullis, Clifton, Bristol, BS8 4LE

If spending an evening drinking beer and talking Alt.NET is your thing, then come along to the inaugural Alt.NET Bristol beers at the excellent Portcullis tavern in Clifton! Taking inspiration from the Alt.NET London beers, the format will be a mini openconference style session where everybody will get an opportunity to suggest and vote for the topic to be discussed.

If you’ve never attended a session like this before they are a lot of fun and a great way to share knowledge and experience!

The plan for the evening is:

18:00  – 18:45: Socialising and proposal of topics for discussion. Topics can be proposed by placing post-it notes on a topic wall. Before voting we will cluster similar topics together where it appears to make sense.

18:45 – 19:00: Vote for the topic of the day through a show of hands in two rounds.

19:00 – 20: 00 : 60-minute discussion around of the topic of the day. At the end of the discussion we will ask participants to fill in a wiki stating what they hoped to get out of the discussion and what they actually got out.

20:00 – late: Socialising, beers and debate!

The Portcullis has a great selection of beer and cheap food for those of us that require feeding. All of us at Bluewire look forward to seeing you there!

→ 1 CommentCategories: Alt.NET · Events
Tagged: , , ,

Got an invalid XDocument but can’t work out why?

June 15, 2009 · Leave a Comment

This could be the reason…

I uncovered what I suspect may be a .NET Framework bug the other day, when I attempted to validate an XDocument against an XML schema which contained abstract datatypes.  It seems that XDocument.Validate() is unable to resolve derived types properly – it claimed that the concrete type of an XML element was not valid according to its abstract type in the schema.

Only after a lot of checking and self-reassurance that my XDocument really should be valid, and after dragging two colleagues through the problem and having them agree that it should be working too, did I begin to suspect something may be more fundamentally wrong.

I found that Visual Studio’s inbuilt XML document validation did think the document was valid. I then found that if the XDocument were saved out to a string, and validated using another method, there was no validation error.

I explain the problem in depth here. There are some code snippets and a sample Visual Studio project of a simple test case which sandboxes the problem effectively.

→ Leave a CommentCategories: Microsoft
Tagged: , , ,

WPF designer gotcha when setting TextDecorations in triggers

April 16, 2008 · 2 Comments

I just came accross a nasty gotcha with the Visual Studio 2008 WPF designer (Cider). When setting the TextDecorations property for a control using a trigger, the following code will work at runtime, but the designer will complain with “Must specify both Property and Value for Setter. Error at object ‘System.Windows.Setter’, Line 1 Position 737″.

<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="contentSite" Property="TextDecorations" Value="Underline"/>
</Trigger>
</ControlTemplate.Triggers>

To prevent the designer complaining, you have to use the full syntax for setting TextDecorations, as below:

<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="contentSite" Property="TextDecorations">
<Setter.Value>
<TextDecorationCollection>
<TextDecoration Location="Underline" />
</TextDecorationCollection>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>

This seems to keep the designer happy and behaves the same at runtime as the first example – looks like there’s a bug in the converter for TextDecorations somewhere that’s causing this…

→ 2 CommentsCategories: Microsoft
Tagged: , , , ,

JSUnit MSBuild task

January 30, 2008 · Leave a Comment

This is just a quick post to describe how to use the JSUnit MSBuild task (which you can download here). JSUnit currently ships with JUnit fixtures and ant wrappers to call these – this is essentially an MSBuild task wrapper around the StandaloneTest JUnit fixture (and so requires Java as well). Also there are a few things to bear in mind if you use this in a continuous integration scenario, namely that the process will need to fire up your browser of choice and so will need to interact with the desktop, and that with the current state of JSUnit it is best to access the test runner / pages over http (instead of using file://). Don’t forget you can’t mix and match file: and http: otherwise you’ll get x-site scripting errors in certain browsers.

Anyhoo, to use the task, first include it in your build file like so:

<import project="$(MSBuildJSUnitTasksPath)\MSBuild.JSUnit.Tasks.Targets"></import>

I’ve previously defined the MSBuildJSUnitTasksPath property to point to the directory where the MSBuild.JSUnit.Tasks.Targets and MSBuild.JSUnit.Tasks.dll are located. Having imported the targets you can then call the task using:

<StandaloneTest
JSUnitDir="$(JSUnitDir)"
TestRunnerLocation="http://localhost/JsUnit/TestRunner.html"
TestsPageLocation="http://localhost/TestPages/Foo.html"
LogsDirectory="$(JSUnitLogDir)"
Port="3333"
BrowserFileNames="c:\program files\Internet Explorer\iexplore.exe"
ContinueOnError="true">
<Output TaskParameter="TestsFailed" PropertyName="JSUnit_Failed" />

<Output TaskParameter="TestsPassed" PropertyName="JSUnit_Passed" />
<Output TaskParameter="TestsRun" PropertyName="JSUnit_Run" />
</StandaloneTest>

A few things are going on here. This task will attempt to call the JUnit test provided by JSUnit. This fires up a results server on port 3333 and then loads IE with the specified test runner / test page causing the results to be submitted to the results server and an xml report generated. This report will be placed in the location specified by LogsDirectory along with an HTML report generated by the MSBuild task. The output parameters capture the test statistics if you need to use them later (e.g. for TeamCity reporting :-) ) but remember these only work if the tests succeed (hence the ContinueOnError=”true”). You can then cause the build to fail by looking at the output parameter if you need to.

→ Leave a CommentCategories: JSUnit · Microsoft · msbuild
Tagged:

TeamCity MSBuild tasks

January 24, 2008 · 8 Comments

For our latest product, we’ve switched over from CC.NET to the excellent TeamCity continuous integration server from JetBrains, which, as of version 3, is free for small projects like ours. One of the nice aspects of TC is that it’s very easy to publish data from your build (such as number of unit test passes / failures) so that it gets picked up by the TC server.

To help us along, we’ve written a few simple MSBuild tasks which do just that. We’ve created a sourceforge project for them, but until that’s activated, you can download them here.

There are currently 3 tasks:

MSBuild.TeamCity.Tasks.TeamCityAppendStatusText

Appends text to be displayed in the build status when the build is complete – e.g. “Tests Passed: 3, Tests Failed: 1″

Example usage:

<TeamCityAppendStatusText TeamCityInfoPath="$(teamcity_build_checkoutDir)\teamcity-info.xml" Value="Tests Passed: 3" />
<TeamCityAppendStatusText
TeamCityInfoPath="$(teamcity_build_checkoutDir)\teamcity-info.xml" Value="Tests Failed: 1" />

MSBuild.TeamCity.Tasks.TeamCityAddStatistic

Adds a build statistic that can be picked up for graphing by configuring TeamCity’s main-config.xml (see here).

Example usage:

<TeamCityAddStatistic TeamCityInfoPath="$(teamcity_build_checkoutDir)\teamcity-info.xml" Key="TestsPassed" Value="3" />
<TeamCityAddStatistic
TeamCityInfoPath="$(teamcity_build_checkoutDir)\teamcity-info.xml" Key="TestsFailed" Value="1" />

MSBuild.TeamCity.Tasks.TeamCityAddStatisticList

Variation on the above which allows you to add multiple statistics at once. Each key/ value pair is delimited by ‘;’

Example usage:

<TeamCityAddStatisticList TeamCityInfoPath="$(teamcity_build_checkoutDir)\teamcity-info.xml" KeyValuePairs="TestsPassed=3;TestsFailed=1" />

Thats pretty much it for now as  that’s all we’re using. I’ll post a follow up shortly to show how you can use these to pull in results from MbUnit tests.

If you missed the link above, you can download the tasks here.

→ 8 CommentsCategories: Microsoft
Tagged: , ,

Reverse-proxying with SSL

November 15, 2007 · Leave a Comment

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.

→ Leave a CommentCategories: Uncategorized

SVN and Active Directory

November 13, 2007 · 3 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 warnings;
use strict;
use Net::LDAP;
sub resolve_group($);
sub get_member_users($);
sub get_users_in_group($);
# Domain name.
my $ldap_domain = "<your domain name here>";
# DN of the LDAP directory root.
my $ldap_root = "dc=".$ldap_domain;
$ldap_root =~ s/\./,dc=/g;
# Domain Controllers.
my @dcs = ( 'dc1', 'dc2' );
# DN of the LDAP directory base for our queries.
my $ldap_base = "<your base DN here>,$ldap_root";
# Authorisation of guest account used for queries.
my $ldap_username = "<guest AD user DN here>";
my $ldap_password = "<guest AD user's password here>";
#====================================
# Connect and bind to LDAP server.
my $ldap;
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) = @_;
my $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) = @_;
my @users = ();
my $members = $group->get_value('member', asref=>1);
foreach (@{$members}) {
my($mesg, $member, @objectClass);
$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) = @_;
my $group = resolve_group($groupName);
return keys %{{ map { lc $_ => 1 } get_member_users($group) }};
}
my($section, @usernames);
while (readline STDIN) {
if($_ =~ /\[(.*?)\]/) {
$section = $1;
} elsif($section eq "groups" and $_ =~ /^(.*?)\s*=/) {
@usernames = get_users_in_group($1);
my $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.

→ 3 CommentsCategories: Uncategorized

IIS6 doesn’t like NewSID

August 10, 2007 · 1 Comment

Our PowerShell-based VM building framework is still in use. This is because some of the components for the new system were sent First Class instead of Next Day, and got lost in the mail. In future I’ll be sure to demand Next Day delivery on everything.

So our test server still operates (or not) at the whim of a mess of scripts. This seems to be working out OK so far, although human intervention is required when the VM registration process fails to restart properly, ie. roughly once a week. At least the terminal server I set up lets me fix it from home before I leave for work in the morning, which means the server might actually be built and working by the time I arrive.

The original test server runs Windows XP, which is pretty much the minimum requirement for our product. Recently we ran into a bug that only appeared on Windows 2003, requiring a second test server running that OS. As I mentioned back in May, we use NewSID plus yet more Powershell to deploy images since it suits our system better than Sysprep.

NewSID is a great tool. It generates a new Security ID for the machine, updates the Registry and other system files accordingly, fixes the filesystem’s Access Control Lists to use the new SID, and reboots the machine. Unfortunately, it doesn’t update the IIS Metabase.

On Windows XP this is not an issue for us. IIS versions prior to 6 use only a single application pool and our product’s installer sets up all permissions appropriately anyway. On II6, however, our app pool identity is a member of IIS_WPG, the IIS Worker Process Group, and relies on that group’s permissions. NewSID leaves the old SID in the Metabase and doesn’t add the new one, effectively nuking IIS_WPG’s permissions on all IIS directories.

IIS7 doesn’t have this problem. It uses built-in NT accounts not dependent upon the machine or domain SID, making a clean IIS7 Metabase effectively immune to this sort of corruption. Once you start adding permission sets it’s a different story, but in most cases only a clean system would be the subject of NewSID.

The conventional workaround for the issue is to remove IIS prior to running NewSID and reinstall it afterwards. This is fine for manual setup but falls short in our situation. It is by all means possible to automate the addition and removal of Windows components with the ’sysocmgr’ command, but setting up the necessary answer files is tedious. I wanted a better way.

So I poked around in Powershell, made heavy use of Google, and wrote some exploratory C#. Through Directory Services the Metabase can be edited just like Active Directory. I wrote some code to look through all the Access Control Lists for entries with trustees in a given domain and replace the trustee with its equivalent in another domain. This was all done at the SID level; ‘equivalent’ trustees are considered to be those with the same RID, since NewSID does not change that. Trustees that mapped to known accounts are ignored, since they aren’t broken.

It took me a while to figure out why the ‘patched’ entries were being removed by the original version of the tool. It seems that the AccessControlEntry interface doesn’t like raw SIDs being put into its Trustee property. Resolving the SID to a human-readable account beforehand solved this problem.

The result is a tool called MetabaseACL, which takes a directory path as its first argument:

MetabaseACL "IIS://Localhost"

This will display all ACLs in the Metabase within the given path. To fix SIDs, it can be given the ‘fixup’ command:

MetabaseACL "IIS://Localhost" fixup <old SID> <new SID>

It doesn’t matter if the SIDs are specific NT accounts or domain/machine SIDs; only the domain info will be used.

This integrates nicely with the ‘newsid’ package our VM builder uses. The script which does the work now looks something like this:

if($env:COMPUTERNAME -eq $compName)
{
if(Test-Path "C:\Machine.sid")
{
$id = New-Object System.Security.Principal.NTAccount("Administrator");
$newSid = $id.Translate([System.Security.Principal.SecurityIdentifier]).AccountDomainSid.Value;
$oldSid = Get-Content "C:\Machine.sid";
MetabaseACL "IIS://Localhost" fixup $oldSid $newSid;
Remove-Item "C:\Machine.sid";
}
[We're done here. Call next script in the chain.]
}
else
{
net stop iisadmin /y ;
if(-not (Test-Path HKCU:/SOFTWARE/Sysinternals))
{
New-Item HKCU:/SOFTWARE/Sysinternals
}
# Record old Machine SID.
$id = New-Object System.Security.Principal.NTAccount("Administrator");
$sid = $id.Translate([System.Security.Principal.SecurityIdentifier]).AccountDomainSid.Value;
Set-Content "C:\Machine.sid" $sid;
# Prepare for NewSID.
$key = New-Item HKCU:/SOFTWARE/Sysinternals/NewSID;
$key.SetValue("EulaAccepted", 1);
$p = [diagnostics.process]::Start("newsid.exe", "/a ${compName}");
$p.WaitForExit();
}

This script is run when the VM image boots. First time through it will record its SID and run NewSID. On the second boot it will retrieve the old SID, get the new SID, run MetabaseACL to do the fixup, and call the next script in the image building procedure.

And so ends another adventure with VM image deployment. Judging by the number of forum topics I came across while googling for a solution to the IIS/NewSID problem, this new tool will prove useful to people besides me.

Download MetabaseACL

Zip file includes source code and binaries. Runs on WinXP and Win2003. I haven’t tried it on Vista but it should be fine.

→ 1 CommentCategories: PowerShell