mike-obrien.net Resume Blog Labs
Thursday, December 27, 2007

The following is a step by step installation of Subversion over Apache and SSL authenticating through an Active Directory server or local server accounts. BTW, I'm by no means an Apache guru so please leave a comment if I'm missing anything. And thanks to a bunch of people who I cant remember who posted info on the web that helped in compiling these steps! :)

  1. Install the latest CollabNet Win32 distribution found here.
    1. Make sure that only the Apache (MOD_DAV_SVN) component is checked.
      image
    2. Set the Apache configuration. You can set an arbitrary http port for now; it will change when SSL is setup.  Also remember to check the “Install Apache … as a Windows Service” checkbox. The other two options should be set accordingly.
      image
  2. Create a test repository
    1. Open a command prompt and run the following command from the CollabNet installation folder (C:\Program Files\CollabNet Subversion Server\) to create a test repository:
      svnadmin create d:\temp\Repos\mysweetapp
  3. Test Connectivity
    1. Start the Apache service; it should be called Apache2.
    2. Browse to the test repository at http://localhost:1984/mysweetapp with a Subversion client and create a folder to verify that everything is setup correctly.
  4. Install and Configure the SSPI module
    1. Download the SSPI module from here. You will want to match the major and minor Apache build with the version number trailing the SSPI module version number. For example mod_auth_sspi-1.0.4-2.0.58.zip would be for Apache 2.0.x and mod_auth_sspi-1.0.4-2.2.2.zip would be for Apache 2.2.x (Thanks to Dan Switzer for pointing this out, I totally missed that!). After unzipping the contents if the zip, copy the mod_auth_sspi.so (In the bin folder) into the Apache modules folder (C:\Program Files\CollabNet Subversion Server\httpd\modules).
    2. Open the httpd.conf file in the Apache configuration folder (C:\Program Files\CollabNet Subversion Server\httpd\conf)
    3. Add the following line to (Or uncomment it in) the Apache configuration file (httpd.conf) in the LoadModule section:
      LoadModule sspi_auth_module modules/mod_auth_sspi.so
    4. Add the following settings, under “# Active Directory Auth”, to the location section. Be sure to specify the SSPIDomain which can be an AD domain or the local server name. If it is the local server name the local user accounts will be used to authenticate. You can use this option if there is no AD server.
           <Location />
                DAV svn
                SVNParentPath D:/Temp/Repos
       
                # Active Directory Auth
                AuthName "SVN Server"
                AuthType SSPI
                SSPIAuth On
                SSPIAuthoritative On
                SSPIDomain localhost
                SSPIOfferBasic on
                Require valid-user
           </Location>
    5. Restart the Apache2 service after the httpd.conf file has been saved.
    6. Perform the test noted in step #3 to test connectivity, this time logging in with a user from the domain specified above.
    7. Note that in TortoiseSVN  you can check the “Save Authentication” checkbox to avoid having to repeatedly enter your credentials:
      image
  5. Configure SSL
    1. Create the Certificate
      1. Create an OpenSSL configuration file under the Apache bin folder (C:\Program Files\CollabNet Subversion Server\httpd\bin) called openssl.conf and set its contents as follows:
             [ v3_ca ]
             subjectKeyIdentifier = hash
             authorityKeyIdentifier = keyid:always,issuer:always
             basicConstraints = CA:true
             [ req ]
             default_bits  = 1024
             default_keyfile  = svnserver.key
             distinguished_name = req_distinguished_name
             attributes  = req_attributes
             x509_extensions = v3_ca 
             string_mask  = nombstr
             [ req_distinguished_name ] 
             commonName  = Common Name
             commonName_default = My Server Name
             [ req_attributes ]
      2. Open up a command prompt in the Apache bin folder (C:\Program Files\CollabNet Subversion Server\httpd\bin).
      3. Run the following command to generate the private key and certificate request files. Be sure to enter the ip address or DNS name of the server when prompted for the common name. Also remember the pass phrase you entered as it will be required for the following step. This will create a svnserver.csr and svnserver.key file in the Apache bin folder.
              openssl req -config openssl.conf -new -out svnserver.csr
        image
      4. Remove the passphrase from the private key with the following command. Enter the passphrase you specified in the last step.
             openssl rsa -in svnserver.key -out svnserver.key
        image
      5. Create the self signed certificate with the following command. The following command sets the certificate expiration to 20 years.
             openssl x509 -in svnserver.csr -out svnserver.cert -req -signkey svnserver.key -days 7300
        image
      6. Delete the svnserver.csr in the Apache bin folder.
      7. Copy the svnserver.key and svnserver.cert from the Apache bin folder to the Apache conf folder.
    2. Open the httpd.conf file in the Apache configuration folder (C:\Program Files\CollabNet Subversion Server\httpd\conf).
    3. Change the listen port to 443:
           Listen 443
    4. Change the server name to include the SSL port, 443:
           ServerName localhost:443
    5. Uncomment or add the load module directive for mod_ssl:
           LoadModule ssl_module modules/mod_ssl.so
    6. Create or overwrite the following IfModule section so that it appears as follows:
           <IfModule mod_ssl.c>
                  SSLEngine on
       
                  SSLRandomSeed startup   builtin
                  SSLRandomSeed connect   builtin
                  SSLPassPhraseDialog     builtin
                  SSLSessionCache         dbm:logs/ssl_scache
                  SSLSessionCacheTimeout  300
                  SSLMutex                default
                  SSLCertificateFile      conf\svnserver.cert
                  SSLCertificateKeyFile   conf\svnserver.key 
            </IfModule>
    7. Restart the Apache2 service.
    8. Browse to https://localhost/mysweetapp and create a folder to test the configuration.
    9. Note that in TortoiseSVN you can permanently accept the certificate when this dialog appears. It is warning you that the issuer is not a trusted root authority.
      image
Thursday, December 27, 2007 2:27:11 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
Thursday, December 20, 2007

You know what language I'll be coding in on Caturday? lolcode!

kthxbye

Thursday, December 20, 2007 2:20:38 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 

MathTV is posting videos on YouTube (Teasers for their service). There are over 60 so far on a number of different topics. MathTV also has an online subscription for $35 a year which gives you access to hundreds of videos. I like that they are under 10 minutes each and the instructor does a great job of explaining the material.

Thursday, December 20, 2007 3:15:46 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
Tuesday, December 18, 2007

The following JavaScript class enables you to get the expanded coefficients of a binomial raised to a particular power. Pass in the power and it will return an array of coefficients. For example, passing in a power of 6 returns {1, 6, 15, 20, 15, 6, 1}. This is also a row in Pascal's Triangle. It's using the following formula to calculate the coefficients, where n is the the power the binomial is raised to and k is the term position (0 to n).

Here is the class (PascalsTriangle.js):

function PascalsTriangle()
{
    this.GetExpandedBinomialCoefficients = function(power)
    {
        var coefficients = new Array(power);

        for (var index = 0; index <= power; index++)
        {
            coefficients[index] = this.GetExpandedBinomialCoefficient(power, index);
        }

        return coefficients;
    }

    this.GetExpandedBinomialCoefficient = function(power, term)
    {
        return this.GetFactorial(power) / (this.GetFactorial(term) * this.GetFactorial(power - term));
    }

    this.GetFactorial = function(value)
    {
        if (value <= 1)
            return 1;
        else
            return value * this.GetFactorial(value - 1);
    }
}

The class can be used as follows:

var pascalsTriangle = new PascalsTriangle();
var coefficients = pascalsTriangle.GetExpandedBinomialCoefficients(6);
alert(coefficients.join(' '));

This video covers Pascal's Triangle...

Tuesday, December 18, 2007 3:03:17 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
Wednesday, December 05, 2007

...and your 100% sure your xpath is correct. It's probably that there is a namespace defined. All you need to do is define the namespace under the xmlpoke element and prefix your element names with the namespace prefix. Check it:

web.config:

<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
  <appSettings>
    <add key="SomeSetting" value="" />
  </appSettings>
</configuration>

NAnt:

<project name="YadaYadaYada" default="default">
    <target name="default">
        <xmlpoke
             file="D:\Temp\web.config"
             xpath="/ns:configuration/ns:appSettings/ns:add[@key='SomeSetting']/@value"
             value="SomeValue">
                  <namespaces>
                      <namespace prefix="ns" uri="
http://schemas.microsoft.com/.NetConfiguration/v2.0" />
                  </namespaces>

         </xmlpoke>
   </target>
</project>

Wednesday, December 05, 2007 8:00:25 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
Tuesday, November 27, 2007

Testing for the existence of a folder with NAnt is pretty simple. The only caveat is that you reference parameters without the ${} qualifier. You can also concatenate strings, building the path dynamically...

<property name="RootPath" value="D:\Temp" />
<property name="RelativePath" value="SomeFolder" />

<target name="default">

   <if test="${directory::exists(RootPath + '\' + SomeFolder)}">
      <echo message="${RootPath}\${SomeFolder} exists!"/>
   </if>

   <if test="${not(directory::exists(RootPath + '\' + SomeFolder))}">
      <echo message="${RootPath}\${SomeFolder} does not exist!"/>
   </if>

</target>

As a side note; if you plan on passing a path into an exec as a parameter remember to quote it with the &quot; HTML entity:

<exec program="${Subversion}">
    <arg value="update &quot;${RootPath}\${SomeFolder}&quot;" />
</exec>
 

Tuesday, November 27, 2007 5:43:06 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 

NAnt scripts can get cluttered with configuration values. One way to clean this up is to create properties that are used throughout the script. Although, you could take this a step further and store NAnt script configuration values in an Xml file. I like this approach because it creates a clear separation between the script and modifiable parameters. For example lets say we have an Xml configuration file called Build.config that contains paths:

<?xml version="1.0"?>
<buildConfiguration>
    <paths>
        <path name="SubversionPath" value="C:\Program Files\CollabNet Subversion Server\svn.exe" />
    </paths>
</buildConfiguration>

Our NAnt script could then load these paths into parameters in an "init" target. All other targets could then depend on this "init" target.

<?xml version="1.0"?>
<project name="Build" default="default">

    <property name="SubversionPath" value="" />
    <target name="init">
        <xmlpeek

              file="Build.config"
              xpath="/buildConfiguration/paths/path[@name = 'SubversionPath']/@value"
              property="SubversionPath"/>
     </target>

     <target name="default" depends="init">
         <echo message="${SubversionPath}" />

     </target>
</project>

image

Tuesday, November 27, 2007 5:09:38 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 

If you don't appreciate the Automatic Update service automatically rebooting your box after new updates are installed (Who would??), then simply run gpedit.msc to start the Group Policy editor and modify the following policies :

image

Tuesday, November 27, 2007 4:11:14 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
Monday, November 26, 2007

Passing parameters to a NAnt script from CruiseControl.NET is pretty simple. Basically you pass name/value pairs with the -D command line argument in the buildArgs element. Values with spaces need to be wrapped with double quotes. The following CC.NET configuration file illustrates this:

<cruisecontrol>
     <project>
          ...
          <tasks>
               <nant>
                    <executable>C:\Program Files\nant-0.85\bin\NAnt.exe</executable>
                    <baseDirectory>F:\Build\BabelFish2.0\WorkingFolder</baseDirectory>
                    <buildArgs>-D:param1=somevalue -D:param2="some other value"</buildArgs>
                    <nologo>true</nologo>
                    <buildFile>Source/Build/Build.nant</buildFile>
                    <targetList>
                         <target>default</target>
                    </targetList>
                    <buildTimeoutSeconds>2400</buildTimeoutSeconds>
               </nant>
          </tasks>
          ...
     </project>
</cruisecontrol>

The target NAnt script need only reference the properties as follows:

<project name="YadaYadaYada" default="default">
  <target name="default">
   
<echo message="Param 1=${param1}, Param 2=${param2}"/>
  </target>
</project>

image

Monday, November 26, 2007 10:32:34 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 

I've tried playing with custom configurations (Outside the stock Debug/Release configurations) in the past and found it confusing. So today I tried it again and had much better success. One thing that had me confused is the relationship between Solution level configuration and Project level configuration. What I didn't realize is that they are all completely separate entities... The "Debug" configuration in SolutionA is different from the "Debug" configuration in ProjectA. The "Debug" configuration in ProjectA is different from the "Debug" configuration in ProjectB. They all just happen to have the same name for consistency (Which is where my confusion began; guess I should have read the manual...). Although they are different entities, project level configurations can be mapped to a solution level configuration.

The example below shows a possible configuration. The solution has 2 configurations: "PlanA" and "PlanB". The BLL project have 2 configurations: "Production" and "Staging". The UI project has 2 configurations: "Red" and "Blue". The "PlanA" solution configuration has the BLL project configuration set to "Staging" while the UI project configuration is set to "Red".

image

So basically the "PlanA" and "PlanB" solution configurations represent a specific combination of project configurations. When you build a solution with a specific solution level configuration it will know what project level configuration to use with each of the individual projects in the solution. "PlanA" would use "Staging" for the BLL and "Red" for the UI.

Another thing that got me is how to add/edit/remove the project level configurations. It's pretty simple; the solution level configuration dropdown (Shown in red above) has a "<New...>" and "<Edit..>" item that enables you to modify solution level configurations. Also each individual project has a configuration dropdown (Shown in blue and green above) that give you the same options for project specific configurations.

Another thing to remember is that when you add a new project, the Debug/Release solution configurations will be automatically re-added. So if you removed these earlier they will have to be removed again.

Oh, and one more thing. Website Projects (WSP) show up as having only one option for configuration and platform with no modification options (Shown in red below). This is because configurations do not apply to a WSP (Since it isnt really a project and does not have a project file). It's a little misleading that there is one item in the list as if its assigned to it. It should just be disabled IMO. In any event it can be ignored. If you want to configure build options for a WSP, create a corresponding Web Deployment Project (WDP). You can then create configurations on the WDP that apply to the the WSP.

image

Monday, November 26, 2007 9:31:44 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
Wednesday, November 21, 2007

** UPDATE ** A December 2007 CTP is available, more info here.

Looks like we will have to wait a couple of weeks for WDP support in Visual Studio 2008 as noted by Scott Guthrie:

"Two popular add-ins to Visual Studio are not yet available to download for the final VS 2008 release.  These are the Silverlight 1.1 Tools Alpha for Visual Studio and the Web Deployment Project add-in for Visual Studio. Our hope is to post updates to both of them to work with the final VS 2008 release in the next two weeks."

Wednesday, November 21, 2007 8:40:38 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 

Got VS2008 Team System up and running... Only issues I ran into were needing to update the .NET Compact Framework 2.0 to SP1 and reinstalling the .NET Framework 3.0 Redist (I had this installed but something got hosed so I had to reinstall it). I ran the beta versions on a VM so I didn't have to deal with issues resulting from uninstalling betas on my dev box. I'm really liking the VM approach for evaluation! 

Rick Strahl has some interesting comments on the VS2008 install here.

Wednesday, November 21, 2007 7:00:41 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
Wednesday, November 14, 2007

I guess this is a known issue with the following exception:

Unhandled Exception: System.IO.FileLoadException: Could not load file or assembly 'svcutil, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. Strong name validation failed. (Exception from HRESULT: 0x8013141A)
File name: 'svcutil, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' ---> System.Security.SecurityException: Strong name validation failed. (Exception from HRESULT: 0x8013141A)
The Zone of the assembly that failed was:
MyComputer

As a temporary fix you can mark the assembly to be skipped for strong name validation as follows:

sn.exe -Vr svcutil.exe

image

Wednesday, November 14, 2007 7:22:13 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 

Evidently the aspnet_compiler.exe does not care about .refresh files (From my tests and what I read on the internets). It would be nice if it did as it would reduce the steps needed to build a WSP (Web Site Project) on a build server. I ended up just manually copying the assemblies into the bin folder before the build as follows in this nant script:

<mkiisdir dirpath="..\BabelFish.ServiceHost.Web" vdirname="BabelFish.ServiceHost.Web" />

<copy todir="..\BabelFish.ServiceHost.Web\bin">
    <
fileset basedir="..\BabelFish.Services\bin">
        <
include name="*.dll" />
    </
fileset>
</
copy>

<exec program="C:\WINDOWS\Microsoft.NET\Framework\${framework.version}\aspnet_compiler.exe" useruntimeengine="true">
    <
arg value="-p" />
    <
arg value="..\BabelFish.ServiceHost.Web" />
    <
arg value="-v" />
    <
arg value="BabelFish.ServiceHost.Web" />
</
exec>

<deliisdir vdirname="BabelFish.ServiceHost.Web" />

Wednesday, November 14, 2007 6:33:25 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |