Skip to content
Jun 29 10

Welcome

by admin

Hi, I’m a developer working in the Java enterprise space in large. I currently work for Oxford University Computing Service on the Core User Directory project. Before that worked as a self-employed consultant for clients such as Cardiff University. On the side I develop code and write documentation for the Internet2 Grouper project. I’ve recently extended into mobile applications on Android devices, making use of sensor functionality (such as GPS) to develop extended functionality.

I’ve got 12 years of experience, during which time I’ve developed large and small applications. These include a University-wide identity management system and Cardiff University, which I designed, programmed, implemented and support. This includes server-to-server data connections for provisioning and a web front-end for management.

I mainly work with open source software, using it to provide very high quality functionality to customers at a low cost. Typically this involves the use of code from multiple open source projects, which need to be integrated both with each other and with proprietary components (such as an existing directory, operating system installation or database). I maintain two open source projects which I use extensively in my work – the Data Rules and Routing Engine and the Java LDAP List Server. I also contribute to the Internet2 Grouper Project, being a core developer with commit access to the source tree.

If you’re interested in anything I’m up to, please drop me a line.

Please use this form to send me a message, or email robATrobhebron.co.uk (address obfuscated to prevent harvesting)

Your Name (required)

Your Email (required)

Subject

Your Message

Apr 23 11

Transcoding AVCHD video to a format for editing

by Rob

I have a Canon HD digital camera. It records using the AVCHD format, saving content to .MTS files. I needed to find a way of editing these files – I use Kino, a simple video editor to do this. I first did this more than a year ago, and at that time Kino on Ubuntu had no support for AVCHD and so I had to transcode the video to import it. When I tried again today I found that Kino on Ubuntu 10.10 was able to import AVCHD, but at a poor level of quality. Camera zooms and leaves gently swaying in the breeze became jerky and blocky, so it was back to transcoding.

I tried a few different methods, using both ffmpeg and mencoder before settling on use of the hdffxrvt script. This transcodes to .mov files at a good level of quality. I could probably get it to transcode straight to .dv files, but I haven’t tried this.

In order to get hdffxrt to work on Ubuntu I had to rebuild ffmpeg as otherwise it complained that the FLAAC codec was not supported. I followed the instructions at https://wiki.ubuntu.com/ffmpeg to do this. These instructions are a bit out of date. I had to use the following configure command before building:

./configure --enable-libdc1394 --enable-libdirac --enable-libfaac --enable-libfaad --enable-libfaadbin --enable-libgsm --enable-libmp3lame --enable-libopenjpeg --enable-librtmp --enable-libschroedinger --enable-libspeex --enable-libtheora --enable-libvorbis --enable-libvpx --enablapt-get source ffmpege-libx264 --enable-libxvid --enable-gpl --enable-nonfree

This enables more codecs than are needed, but I thought I’d go for a belt-and-braces approach. The full steps I took were:


apt-get source ffmpeg
cd ffmpeg-*/
./configure --enable-libdc1394 --enable-libdirac --enable-libfaac --enable-libfaad --enable-libfaadbin --enable-libgsm --enable-libmp3lame --enable-libopenjpeg --enable-librtmp --enable-libschroedinger --enable-libspeex --enable-libtheora --enable-libvorbis --enable-libvpx --enablapt-get source ffmpege-libx264 --enable-libxvid --enable-gpl --enable-nonfree

At this point I had to install the -dev packages of any missing codecs. The configure script tells you what's missing and you can install them from apt using apt-search followed by apt-get install . Once the configure script completed without error I finished the ffmpeg build with:


make
sudo checkinstall -D make install

This installed the ffmpeg binary into /usr/local/bin. I then edited the hdffxrvt script to set the value of the FFMPEG script to point to /usr/local/bin/ffmpeg

At this point I could transcode happily using


cd
hdffxrvt

Apr 22 11

Observations on the W3C UK Office Launch event

by Rob

I was fortunate enough to attend the W3C-UK Office Launch event last Monday (18th April). It being about 200 metres from my office certainly helped in my decision to go!

The event has a great deal packed into it and the content was of high quality. The overriding theme was that of (W3C) standards and how important they have been/are/will continue to be, with a strong sub theme of open-ness on a backdrop of social awareness. Having seen him speak I can see how Sir Tim Berners-Lee is the ideal figurehead for the W3C: you can’t help but take him seriously, but I doubt that any puffed-up business or political leader would feel threatened by him – an ideal combination!

I was surprised at who attended the event, perhaps because I expected it to be other people like me. In fact there were probably few techies there, and a large proportion of the audience appeared to be from the press. Reading the stories that have come out afterwards I’ve realised that it’s not so much the startling originality of the content that makes it newsworthy, but the fact that it was Tim Berners-Lee saying something vaguely controversial!

I have a few other observations:

  1. Membership of standards committees appears to be circular (the same people sit on numerous committees serially or, for all I know, simultaneously). I suppose this is a good thing as they will already know the ropes, but it could hold back new ideas and creativity.
  2. From my seat high up at the back I saw lots and lots of laptops, but only one iPad (the one that wouldn’t talk to the main screen). Is this because it’s a consumption device?
  3. Some people were manically tweeting/social networking/whatever during Tim Berners-Lee’s talk – I wonder how much they missed? The activity dwindled when his talk was over, so I guess people thought it more important to announce to friends/the world that they were there than to concentrate on the content. Is this an observation on social networking? I’m not sure
Mar 14 11

Testing Kerberos authentication with Apache Directory Server

by Rob

Testing Kerberos authentication with Apache Directory Server

I have a requirement to integrate with a Kerberos authentication architecture and wanted a Kerberos server to use for testing – ideally one that could be initialised by JUnit and so be used for Unit testing. Apache Directory Server seemed a likely candidate as it used only Java libraries. Here are notes on how I got it working:

I downloaded release 1.5.7 from http://http://directory.apache.org/, and followed instructions I found at http://http://directory.apache.org/apacheds/1.5/howto-do-sasl-gssapi-authentication-to-apacheds.html – I noticed that the configuration style was different to that in the documentation linked to on the Apache DS website, but the intention is similar. I found 3 things that were critical/missing:

  • I had to add encryption types to the kdcServer config to enable any form of authentication from either a java client or my Desktop (Debian stable).
  • Add 2 more properties to the kdcServer: paEncTimestampRequired=”false” to get around preauth errors; and bodyChecksumVerified=”false” to get around replay errors. I wouldn’t want to set either of these on a live KDC, but was OK for testing.
  • I found I had to use EXAMPLE.COM as the realm and ldap.example.com as the ldap host name, and I HAD to add ldap.example.com as the first line in my hosts file. This line looked like:

    10.0.0.121 ldap.example.com

    you should change 10.0.0.121 to your own IP Address. I’m sure it must be possible to use another realm and/or host, but I haven’t found the correct incantations yet.

My final, working server.conf file looked like:

<?xml version="1.0" encoding="UTF-8"?>

<!--
  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing,
  software distributed under the License is distributed on an
  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  KIND, either express or implied.  See the License for the
  specific language governing permissions and limitations
  under the License.
-->

<spring:beans xmlns="http://apacheds.org/config/1.5.7"
       xmlns:spring="http://xbean.apache.org/schemas/spring/1.0"
       xmlns:s="http://www.springframework.org/schema/beans">

  <defaultDirectoryService id="directoryService" instanceId="default"
                           replicaId="1"
                           workingDirectory="example.com"
                           allowAnonymousAccess="true"
                           accessControlEnabled="false"
                           denormalizeOpAttrsEnabled="false"
                           syncPeriodMillis="15000"
                           maxPDUSize="2000000">
    <systemPartition>
      <!-- use the following partitionConfiguration to override defaults for -->
      <!-- the system partition                                              -->
      <jdbmPartition id="system" cacheSize="100" suffix="ou=system" optimizerEnabled="true" syncOnWrite="true">
        <indexedAttributes>
          <jdbmIndex attributeId="1.3.6.1.4.1.18060.0.4.1.2.1" cacheSize="100"/>
          <jdbmIndex attributeId="1.3.6.1.4.1.18060.0.4.1.2.2" cacheSize="100"/>
          <jdbmIndex attributeId="1.3.6.1.4.1.18060.0.4.1.2.3" cacheSize="100"/>
          <jdbmIndex attributeId="1.3.6.1.4.1.18060.0.4.1.2.4" cacheSize="100"/>
          <jdbmIndex attributeId="1.3.6.1.4.1.18060.0.4.1.2.5" cacheSize="10"/>
          <jdbmIndex attributeId="1.3.6.1.4.1.18060.0.4.1.2.6" cacheSize="10"/>
          <jdbmIndex attributeId="1.3.6.1.4.1.18060.0.4.1.2.7" cacheSize="10"/>
          <jdbmIndex attributeId="ou" cacheSize="100"/>
          <jdbmIndex attributeId="uid" cacheSize="100"/>
          <jdbmIndex attributeId="objectClass" cacheSize="100"/>
        </indexedAttributes>
      </jdbmPartition>
    </systemPartition>

    <partitions>
      <!-- NOTE: when specifying new partitions you need not include those   -->
      <!-- attributes below with OID's which are the system indices, if left -->
      <!-- out they will be automatically configured for you with defaults.  -->
      <jdbmPartition id="example" cacheSize="100" suffix="dc=example,dc=com" optimizerEnabled="true"
                     syncOnWrite="true">
        <indexedAttributes>
          <jdbmIndex attributeId="1.3.6.1.4.1.18060.0.4.1.2.1" cacheSize="100"/>
          <jdbmIndex attributeId="1.3.6.1.4.1.18060.0.4.1.2.2" cacheSize="100"/>
          <jdbmIndex attributeId="1.3.6.1.4.1.18060.0.4.1.2.3" cacheSize="100"/>
          <jdbmIndex attributeId="1.3.6.1.4.1.18060.0.4.1.2.4" cacheSize="100"/>
          <jdbmIndex attributeId="1.3.6.1.4.1.18060.0.4.1.2.5" cacheSize="10"/>
          <jdbmIndex attributeId="1.3.6.1.4.1.18060.0.4.1.2.6" cacheSize="10"/>
          <jdbmIndex attributeId="1.3.6.1.4.1.18060.0.4.1.2.7" cacheSize="10"/>
          <jdbmIndex attributeId="dc" cacheSize="100"/>
          <jdbmIndex attributeId="ou" cacheSize="100"/>
          <jdbmIndex attributeId="krb5PrincipalName" cacheSize="100"/>
          <jdbmIndex attributeId="uid" cacheSize="100"/>
          <jdbmIndex attributeId="objectClass" cacheSize="100"/>
        </indexedAttributes>
      </jdbmPartition>
    </partitions>

    <interceptors>
      <normalizationInterceptor/>
      <authenticationInterceptor/>
      <referralInterceptor/>
      <aciAuthorizationInterceptor/>
      <defaultAuthorizationInterceptor/>
      <exceptionInterceptor/>
      <operationalAttributeInterceptor/>

      <!-- Uncomment to enable the password policy interceptor
      <passwordPolicyInterceptor/>-->
      <keyDerivationInterceptor/>

      <schemaInterceptor/>
      <subentryInterceptor/>
      <collectiveAttributeInterceptor/>
      <eventInterceptor/>
      <triggerInterceptor/>

      <!-- Uncomment to enable replication interceptor
      <replicationInterceptor>
        <configuration>
          <replicationConfiguration serverPort="10390" peerReplicas="instance_b@localhost:10392">
            <replicaId>
              <replicaId id="instance_a"/>
            </replicaId>
          </replicationConfiguration>
        </configuration>
      </replicationInterceptor>
      -->
    </interceptors>

    <!-- Uncomment to enable replication configuration -->
    <!--replicationConfiguration>
      <providers>
        <provider id="1 type="refreshAndPersist" timeLimit="1000" sizeLimit="1000">
          <url>
            ldap://ldap1.acme.com:10389/ou=data,dc=acme,dc=com?*, +?sub?(objectClass=*)
          </url>
          <connection bindMethod="simple">
            <principal>
              uid=admin,ou=system
            </principal>
            <credentials>secret</credentials>
          </bind>
        </provider>
        <provider id="2 type="refreshAndPersist" timeLimit="1000" sizeLimit="1000">
          <url>
            ldaps://ldap2.acme.com:10389/ou=data,dc=acme,dc=com?*, +?sub?(objectClass=*)
          </url>
          <connection bindMethod="simple">
            <principal>
              uid=admin,ou=system
            </principal>
            <credentials>secret</credentials>
          </bind>
        </provider>
      </providers>
    </replicationConfiguration-->

  </defaultDirectoryService>

  <!--
  +============================================================+
  | ChangePassword server configuration                        |
  +============================================================+
  -->
  <!--  missing  atou=users,ou=system
  <changePasswordServer id="changePasswordServer">
    <transports>
      <tcpTransport port="60464" nbThreads="2" backLog="50"/>
      <udpTransport port="60464" nbThreads="2" backLog="50"/>
    </transports>
    <directoryService>#directoryService</directoryService>
  </changePasswordServer>
-->

  <!--
  +============================================================+
  | Kerberos server configuration                              |
  +============================================================+
  -->
  <!--  missing atou=users,ou=system
  <kdcServer id="kdcServer">
    <transports>
      <tcpTransport port="60088" nbThreads="4" backLog="50"/>
      <udpTransport port="60088" nbThreads="4" backLog="50"/>
    </transports>
    <directoryService>#directoryService</directoryService>
  </kdcServer>
-->

  <!--
  +============================================================+
  | NtpServer configuration                                    |
  +============================================================+
  -->
  <!--ntpServer>
    <transports>
      <tcpTransport port="60123"/>
      <udpTransport port="60123" nbThreads="1"/>
    </transports>
  </ntpServer-->

  <!--
  +============================================================+
  | DnsServer configuration                                    |
  +============================================================+
  -->
  <!--  missing atou=users,ou=system
  <dnsServer>
    <transports>
      <tcpTransport port="8053"/>
      <udpTransport port="8053"/>
    </transports>
    <directoryService>#directoryService</directoryService>
  </dnsServer>
-->

  <!--
  +============================================================+
  | LDAP Service configuration                                 |
  +============================================================+
  -->

  <ldapServer id="ldapServer"
            allowAnonymousAccess="false"
            saslHost="ldap.example.com"
            saslPrincipal="ldap/ldap.example.com@EXAMPLE.COM"
            searchBaseDn="ou=users,dc=example,dc=com"
            maxTimeLimit="15000"
            maxSizeLimit="1000">
    <transports>
      <tcpTransport address="ldap.example.com" port="10389" nbThreads="8" backLog="50" enableSSL="false"/>
      <tcpTransport address="ldap.example.com" port="10636" enableSSL="true"/>
    </transports>
    <directoryService>#directoryService</directoryService>
    <!-- The list of supported authentication mechanisms.                   -->
    <saslMechanismHandlers>
      <simpleMechanismHandler mech-name="SIMPLE"/>
      <cramMd5MechanismHandler mech-name="CRAM-MD5" />
      <digestMd5MechanismHandler mech-name="DIGEST-MD5" />
      <gssapiMechanismHandler mech-name="GSSAPI" />
      <ntlmMechanismHandler mech-name="NTLM" ntlmProviderFqcn="com.foo.Bar"/>
      <ntlmMechanismHandler mech-name="GSS-SPNEGO" ntlmProviderFqcn="com.foo.Bar"/>
    </saslMechanismHandlers>

    <!-- The realms serviced by this SASL host, used by DIGEST-MD5 and GSSAPI. -->
    <saslRealms>
      <s:value>EXAMPLE.COM</s:value>

    </saslRealms>

    <!-- the collection of extended operation handlers to install           -->
    <extendedOperationHandlers>
      <startTlsHandler/>
      <gracefulShutdownHandler/>
      <launchDiagnosticUiHandler/>
      <!-- The Stored Procedure Extended Operation is not stable yet and it may cause security risks.-->
      <!--storedProcedureExtendedOperationHandler/-->
    </extendedOperationHandlers>
  </ldapServer>

  <apacheDS id="apacheDS">
    <ldapServer>#ldapServer</ldapServer>
  </apacheDS>

  <!-- uncomment the below line to start the jetty(v6.1.14) http server
       This can be used to provide access to the data present in DIT via http
       using a web application
  -->
  <!--
   <httpServer id="httpServer" port="7009" >
   <webApps>
    <webApp warFile="/path/to/war/file" contextPath="/myApp"/>
   </webApps>
  </httpServer>
   -->

   <kdcServer id="kdcServer" enabled="true" searchBaseDn="ou=users,dc=example,dc=com" paEncTimestampRequired="false" bodyChecksumVerified="false">
      <!-- Whether to enable the Kerberos protocol.                           -->

      <!-- The port to run the Kerberos protocol on.                   -->
	<transports>
      <tcpTransport port="60088" nbThreads="4" backLog="50"/>
      <udpTransport port="60088" nbThreads="4" backLog="50"/>
    </transports>
	<spring:property name="encryptionTypes">
           <spring:set>
            <spring:value type="org.apache.directory.server.kerberos.shared.crypto.encryption.EncryptionType">DES3_CBC_SHA1</spring:value>
	    <spring:value type="org.apache.directory.server.kerberos.shared.crypto.encryption.EncryptionType">DES3_CBC_SHA1_KD</spring:value>
           </spring:set>
         </spring:property>
       <directoryService>#directoryService</directoryService>
   </kdcServer>
</spring:beans>

I wanted to test using native Kerboros tool that I knew to work with the production Kerberos. I therefore created a krb5.conf file (/etc/krb5.conf on Linux), which looked like:

[libdefaults]
 default_realm = EXAMPLE.COM

[realms]
 EXAMPLE.COM = {
  kdc = ldap.example.com:60088
 }

[domain_realm]
 .example.com = EXAMPLE.COM
 example.com = EXAMPLE.COM

Having started Apache DS and loaded data (using ApacheDSStudio, ot ldapadd with uid=admin,ou=system secret credentials) from the following LDIF file:


dn: dc=example,dc=com
objectClass: dcObject
objectClass: organization
objectClass: top
dc: example
o: example.com

dn: ou=Users,dc=example,dc=com
objectClass: organizationalUnit
objectClass: top
ou: Users

dn: uid=hnelson,ou=Users,dc=example,dc=com
objectClass: top
objectClass: person
objectClass: inetOrgPerson
objectClass: krb5principal
objectClass: krb5kdcentry
cn: Horatio Nelson
sn: Nelson
uid: hnelson
userPassword: secret
krb5PrincipalName: hnelson@EXAMPLE.COM
krb5KeyVersionNumber: 0

dn: uid=krbtgt,ou=Users,dc=example,dc=com
objectClass: top
objectClass: person
objectClass: inetOrgPerson
objectClass: krb5principal
objectClass: krb5kdcentry
cn: KDC Service
sn: Service
uid: krbtgt
userPassword: secret
krb5PrincipalName: krbtgt/EXAMPLE.COM@EXAMPLE.COM
krb5KeyVersionNumber: 0

dn: uid=ldap,ou=Users,dc=example,dc=com
objectClass: top
objectClass: person
objectClass: inetOrgPerson
objectClass: krb5principal
objectClass: krb5kdcentry
cn: LDAP
sn: Service
uid: ldap
userPassword: randall
krb5PrincipalName: ldap/ldap.example.com@EXAMPLE.COM
krb5KeyVersionNumber: 0

I was able to test by running:

$kinit hnelson@EXAMPLE.COM
Password for hnelson@EXAMPLE.COM: secret

$klist

Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: hnelson@EXAMPLE.COM

Valid starting Expires Service principal
03/14/11 08:36:17 03/15/11 08:36:17 krbtgt/EXAMPLE.COM@EXAMPLE.COM

.. and check that an LDAP search against ApacheDS worked with GSSAPI auth with:


$ ldapsearch -H ldap://ldap.example.com:10389 -b "ou=users,dc=example,dc=com" "(uid=hnelson)" -Y GSSAPI -O "maxssf=0"
SASL/GSSAPI authentication started
SASL username: hnelson@EXAMPLE.COM
SASL SSF: 0
# extended LDIF
#
# LDAPv3
# base with scope subtree
# filter: (uid=hnelson)
# requesting: ALL
#

# hnelson, Users, example.com
dn: uid=hnelson,ou=Users,dc=example,dc=com
uid: hnelson
sn: Nelson
krb5PrincipalName: hnelson@EXAMPLE.COM
userPassword:: c2VjcmV0
krb5Key:: MBGgAwIBA6EKBAj0pxNkimHOWw==
krb5Key:: MBmgAwIBEaESBBCtIUs4tp38yqzxXzRtQXuQ
krb5Key:: MBmgAwIBF6ESBBCHjYAUYGzaKWd6RO+hNT/H
krb5Key:: MCGgAwIBEKEaBBhXB84pUpIsHIy/Q8I9j4xenoz3XT5KXiU=
objectClass: organizationalPerson
objectClass: person
objectClass: krb5Principal
objectClass: inetOrgPerson
objectClass: krb5KDCEntry
objectClass: top
krb5KeyVersionNumber: 0
cn: Horatio Nelson

# search result
search: 4
result: 0 Success

# numResponses: 2
# numEntries: 1

I was now happy that I had a working KDC. Next, I wanted to test it with a keytab, using a Java client to query LDAP. A keytab is a file saved locally on a client that removes the need to enter a password – the keytab effectively contains the password. Normally keytabs are generated with a random password, but this is not yet supported by Apache DS, so I used steps from https://cwiki.apache.org/DIRxINTEROP/kerberos-authentication-to-openldap-using-apacheds.html to generate a keytab by a workaround method. – with some slight differences:

As root (so that I could save the keytab in the default place); note that I have changed the principal name, and the encryption type to be compatible with the server configuration:


$ ktutil
ktutil: addent -password -p hnelson@EXAMPLE.COM -k 1 -e des3-cbc-sha1
Password for ldap/ldap.example.com@EXAMPLE.COM: secret
ktutil: list
slot KVNO Principal
---- ---- ---------------------------------------------------------------------
1 1 hnelson@EXAMPLE.COM
ktutil: wkt /etc/krb5.key$ klist -5ke
Keytab name: FILE:/etc/krb5.keytab
KVNO Principal
---- --------------------------------------------------------------------------
1 ldap/ldap.example.com@EXAMPLE.COM (DES cbc mode with RSA-MD5)tab
ktutil: quit

I then inspected the keytab with:


$klist -5ke
Keytab name: WRFILE:/etc/krb5.keytab
KVNO Principal
---- --------------------------------------------------------------------------
255 hnelson@EXAMPLE.COM (Triple DES cbc mode with HMAC/sha1)

and tested it with:


$ kinit -k hnelson@EXAMPLE.COM

kinit returened no error message, so I inspected my cache with:


$klist -5fea
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: hnelson@EXAMPLE.COM

Valid starting Expires Service principal
03/14/11 07:43:24 03/15/11 07:43:24 krbtgt/EXAMPLE.COM@EXAMPLE.COM
Etype (skey, tkt): Triple DES cbc mode with HMAC/sha1, Triple DES cbc mode with HMAC/sha1
Addresses: (none)

Which told me that the keytab was fine. If you get an error message “Key table entry not found while getting initial credentials”, check that the encryption on your server and on your ktutil keytab request are the same.

Lastly, I tested with java, using the UnboundID client libraries (which I like for the failover connection pooling it provides). I used the following jaas.conf:

GSSAPIBindRequest {
  com.sun.security.auth.module.Krb5LoginModule required
  useKeyTab=TRUE
  keyTab="/etc/krb5.keytab"
  principal="hnelson@EXAMPLE.COM"
  useTicketCache=TRUE
  renewTGT=TRUE
  ticketCache="/tmp/ub-krb5.cache";
};

and the following simple java classes for testing:

import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.RoundRobinServerSet;

public class ConnectionPool {
	private RoundRobinServerSet failoverServerSet;
	public void initPool() {
		String[] addresses = { "ldap.example.com"};
		int[]    ports     = { 10389 };
		failoverServerSet = new RoundRobinServerSet(addresses, ports);

	}
	public LDAPConnection getConnection() {
		try {
			if(failoverServerSet==null) this.initPool();
			return failoverServerSet.getConnection();
		} catch (LDAPException e) {

			e.printStackTrace();
			return null;
		}
	}
}

import com.unboundid.ldap.sdk.DereferencePolicy;
import com.unboundid.ldap.sdk.GSSAPIBindRequest;
import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.SearchRequest;
import com.unboundid.ldap.sdk.SearchResult;
import com.unboundid.ldap.sdk.SearchResultEntry;
import com.unboundid.ldap.sdk.SearchScope;

public class PoolSearch {

	/**
	 *
	 */
	private static final long serialVersionUID = -136285992856792691L;

	public static void main(String[] args) throws LDAPException, InterruptedException {
		ConnectionPool connectionPool = new ConnectionPool();
			LDAPConnection connection = connectionPool.getConnection();
						connection.bind(new GSSAPIBindRequest("","","",null,null,"/home/rob/downloads/apache/apacheds/javaClientAuth/jaas.conf"));
			String filter="(objectClass=*)";
			SearchRequest searchRequest = new SearchRequest("OU=users,DC=example,DC=com", SearchScope.SUB, DereferencePolicy.NEVER, 0, 0, false, filter, "uid");
			SearchResult searchResult = connection.search(searchRequest);
			int count=1;
			for (SearchResultEntry searchResultEntry : searchResult.getSearchEntries())  {
				System.out.println(searchResultEntry.getDN() + " " + searchResultEntry.getAttributeValue("uid"));
			}
			connection.close();
	}

}

Note that I used a method that specifies that jass.conf file as I found that UnBoundID does not respect the java.security.auth.login.config system parameter.

I initiated the search with:

java PoolSearch -Djava.security.krb5.conf=/etc/krb5.conf -Dsun.security.krb5.debug=false

This works, so I’m happy – up to a point. The final sticking point is that the hostname ldap.example.com must be added to the local hosts file as the first line. This isn’t ideal for unit tests as root access is required to do this.

Sep 14 10

Docs for MyLoc published

by Rob

Documentation for my Android App (MyLoc – personal) is now available at http://www.sharemail.com/mediawiki/index.php/MyLoc_-_personal

I’ve started working on the next edition, which will include web integration. I’m also investigating whether it’s possible to authenticate using a Goggle account without needing to ask the user for username/password. I’m aware this is possible with Android > 2.0, but I’m targeting 1.6 and so will need to dig a bit further.

Aug 29 10

MyLoc Android App published

by Rob

I’ve published my first Android App – MyLoc. It’s a more polished version of an app I wrote for myself to keep track of where I’ve been without needing to sign up for any service that would be storing my data.

The way it works is that it wakes up every so often, gets a GPS fix (or falls back to a network fix if GPS is unavailable) and sends an email with my location to one or more email addresses. This email can include a map (downloaded from Google Maps), and an approximate address (reverse geo-coded by Google). Retrieving the map, the address and sending emails is all done on the phone rather than by a webapp hosted on some server. The emails are sent through a Gmail account (which could be the user’s main Gmail account, or a secondary one). I chose Gmail because the vast majority of Android users are likely to have an account already, and so it would be easiest for the largest number of people.

The reason I designed it to work like this is that, while I’m interested in keeping track of where I’ve been, I don’t want to be running the GPS receiver all the time as it drains battery. Also, once set up I want it to be completely hands-off. I have it set to get my location and send emails every hour and this is fine for when I want to remind myself of where I’ve been. The delay between updates can be set to as little as 10 minutes.

I think people could find it useful:

  • As a reminder of where they’ve been
  • To let other people know progress on a trip, or in a sporting event (marathon, triathon etc)
  • As a safety net where I’m resposible for a group of people, sending out location to a trusted third party on a regular basis

I’m sure there are other uses, and I’m going to be adding functionality to it pretty regularly, so hopefully you’ll find a use for it.

Jun 30 10

Using passthrough preauth and LDAP groups for roles with Spring security

by Rob

I’ve recently been putting together some web applications whcih use Spring Workflow and Spring Security. I originally implemneted them without any external components, but I soon had a requirement to allow authentication to be handled by another service (the Shbboleth Apache module), while authorisation would continue to be handled by Spring security using LDAP groups. Below is a Spring Security configuration file that pulls all this together.

Note that Spring expects the REMOTE_USER username to come through in a request header, not an environment variable as Apache normally does. To do this you need to use mod_rewrite to inject the header using these directives:

RewriteEngine On
RewriteCond %{LA-U:REMOTE_USER} (.+)
RewriteRule .* – [E=RU:%1]
RequestHeader set REMOTE_USER %{RU}e

Spring config file

This config uses beans which ship with Spring Security 2.0.x.

<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:s=”http://www.springframework.org/schema/security”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.1.xsd”>

<s:http>

<s:intercept-url pattern=”/work/**” access=”ROLE_GROUPERUSERS,ROLE_GROUPERADMINS” />
<s:form-login login-page=’/login.html’/>

<s:anonymous />
<s:logout />
</s:http>

<!– Pre auth –>

<bean id=”siteminderFilter”>
<s:custom-filter position=”PRE_AUTH_FILTER” />
<property name=”principalRequestHeader” value=”REMOTE_USER”/>
<property name=”authenticationManager” ref=”authenticationManager” />
</bean>

<bean id=”preauthAuthProvider”>
<s:custom-authentication-provider />
<property name=”preAuthenticatedUserDetailsService”>
<bean id=”userDetailsServiceWrapper”>
<property name=”userDetailsService” ref=”ldapUserDetailsService”/>
</bean>
</property>
</bean>
<s:authentication-manager alias=”authenticationManager” />
<bean id=”ldapUserDetailsService”>
<constructor-arg index=”0″>
<ref local=”filterBasedLdapUserSearch”/>
</constructor-arg>
<constructor-arg index=”1″>
<ref local=”ldapGroupsPopulator”/>
</constructor-arg>
</bean>
<bean id=”filterBasedLdapUserSearch”>
<constructor-arg index=”0″>
<value>o=Accounts</value>
</constructor-arg>
<constructor-arg index=”1″>
<value>(cn={0})</value>
</constructor-arg>
<constructor-arg index=”2″>
<ref local=”contextSource”/>
</constructor-arg>
<property name=”searchSubtree” value=”true”/>
</bean>
<bean id=”ldapGroupsPopulator”>
<constructor-arg>
<ref bean=”contextSource”/>
</constructor-arg>
<constructor-arg>
<value>ou=Groups,o=Resources</value>
</constructor-arg>
<property name=”searchSubtree” value=”true”/>
<property name=”groupRoleAttribute” value=”cn”/>
<property name=”groupSearchFilter” value=”(member={0})”/>
<property name=”rolePrefix” value=”ROLE_”/>
</bean>

<bean id=”contextSource”>
<property name=”url” value=”ldap://127.0.0.1:389/”/>
<property name=”userDn” value=”cn=admin,o=users”/>
<property name=”password” value=”password”/>
</bean>
<!–  end preauth –>

</beans>

Jun 30 10

What is Identity Management?

by Rob

In the IT industry today, almost all the publicity in Identity Management revolves around the use that identity data is put to, be it to provide authentication to a partner in a federation; supply personal infomation that a person has stored with a third party; or any similar purpose.

However, this is only the second aspect of Identity Management.

The first (and most important) is collating your store of identity data and maintaining it to ensure it is both comprehensive and accurate. Only when this store is in a good state can the data safely be put to any meaningful use, <corny metaphor>otherwise it’s like building a house with no foundations … on sand</corny metaphor>.

It’s not as easy as it sounds, and even for a small company or organisation requires thought and administrative overhead.

Here are a few of my rules-of-thumb for sucessful identity management:

  • Be sure of your data before putting it to any use
  • Be ready to meet organisational hurdles as you work with data from existing systems
  • Be ready to spend 80% of your time on data issues
  • Create a common unique key for each user if one deasn’t already exist and propogate it to as many systems from which data is sourced as possible
  • Choose unique identifiers that will be used to match data from different sources carefully. A match much be as near foolproof as possible
  • Structure your identity store so that it makes sense to humans as well as to computers
  • Make sure the system is dynamic – even if you don’t need to work with data in real time now, you will probably need to in the future
  • Design security in from the beginning and make it as granular as possible
  • Desgin-in internal data integrity
  • Design-in scalability
  • Design-in as much flexibility as possible. Assume that what you think will never be required will be called for next week
  • Be ready for the organisation to start to rely on your identity data to an extent that you didn’t think possible