directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From tbenn...@apache.org
Subject svn commit: r486187 [17/49] - in /directory/trunks/triplesec: ./ admin-api/ admin-api/src/ admin-api/src/main/ admin-api/src/main/java/ admin-api/src/main/java/org/ admin-api/src/main/java/org/safehaus/ admin-api/src/main/java/org/safehaus/triplesec/ a...
Date Tue, 12 Dec 2006 15:24:14 GMT
Added: directory/trunks/triplesec/main/pom.xml
URL: http://svn.apache.org/viewvc/directory/trunks/triplesec/main/pom.xml?view=auto&rev=486187
==============================================================================
--- directory/trunks/triplesec/main/pom.xml (added)
+++ directory/trunks/triplesec/main/pom.xml Tue Dec 12 07:23:31 2006
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  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. 
+-->
+<project>
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.safehaus.triplesec</groupId>
+    <artifactId>build</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>triplesec-main</artifactId>
+  <name>Triplesec Main</name>
+  <packaging>jar</packaging>  
+  <dependencies>
+    <dependency>
+      <groupId>${pom.groupId}</groupId>
+      <artifactId>triplesec-configuration-io</artifactId>
+      <version>${pom.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${pom.groupId}</groupId>
+      <artifactId>triplesec-configuration</artifactId>
+      <version>${pom.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${pom.groupId}</groupId>
+      <artifactId>triplesec-verifier</artifactId>
+      <version>${pom.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${pom.groupId}</groupId>
+      <artifactId>triplesec-otp</artifactId>
+      <version>${pom.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${pom.groupId}</groupId>
+      <artifactId>triplesec-testdata</artifactId>
+      <version>${pom.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-daemon</groupId>
+      <artifactId>commons-daemon</artifactId>
+      <version>1.0.1</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.directory.server</groupId>
+      <artifactId>apacheds-core-unit</artifactId>
+      <version>1.0-SNAPSHOT</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.directory.server</groupId>
+      <artifactId>apacheds-server-jndi</artifactId>
+      <version>1.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.directory.server</groupId>
+      <artifactId>apacheds-server-ssl</artifactId>
+      <version>1.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.directory.server</groupId>
+      <artifactId>apacheds-core</artifactId>
+      <version>1.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap</artifactId>
+      <version>0.9.5.3-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.directory.daemon</groupId>
+      <artifactId>daemon-bootstrappers</artifactId>
+      <version>1.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>jetty</groupId>
+      <artifactId>org.mortbay.jetty</artifactId>
+      <version>5.1.8</version>
+    </dependency>
+    <dependency>
+      <groupId>xerces</groupId>
+      <artifactId>xmlParserAPIs</artifactId>
+      <version>2.6.2</version>
+    </dependency>
+    <dependency>
+      <groupId>xerces</groupId>
+      <artifactId>xercesImpl</artifactId>
+      <version>2.0.2</version>
+    </dependency>
+    <dependency>
+      <groupId>tomcat</groupId>
+      <artifactId>servlet-api</artifactId>
+      <version>5.0.18</version>
+    </dependency>
+    <dependency>
+      <groupId>tomcat</groupId>
+      <artifactId>jsp-api</artifactId>
+      <version>5.0.18</version>
+    </dependency>
+    <dependency>
+      <groupId>tomcat</groupId>
+      <artifactId>jasper-runtime</artifactId>
+      <version>5.5.9</version>
+    </dependency>
+    <dependency>
+      <groupId>tomcat</groupId>
+      <artifactId>jasper-compiler</artifactId>
+      <version>5.5.9</version>
+    </dependency>
+    <dependency>
+      <groupId>tomcat</groupId>
+      <artifactId>jasper-compiler-jdt</artifactId>
+      <version>5.5.9</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-el</groupId>
+      <artifactId>commons-el</artifactId>
+      <version>1.0</version>
+    </dependency>
+    <dependency>
+      <groupId>ant</groupId>
+      <artifactId>ant</artifactId>
+      <version>1.6.5</version>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>nlog4j</artifactId>
+      <version>1.2.25</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>springframework</groupId>
+      <artifactId>spring-core</artifactId>
+      <version>1.2.6</version>
+    </dependency>
+    <dependency>
+      <groupId>springframework</groupId>
+      <artifactId>spring-beans</artifactId>
+      <version>1.2.6</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-logging</groupId>
+      <artifactId>commons-logging</artifactId>
+      <version>1.0.4</version>
+    </dependency>
+    <dependency>
+      <groupId>springframework</groupId>
+      <artifactId>spring-context</artifactId>
+      <version>1.2.6</version>
+    </dependency>
+  </dependencies>
+</project>

Added: directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/LoggingHotpMonitor.java
URL: http://svn.apache.org/viewvc/directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/LoggingHotpMonitor.java?view=auto&rev=486187
==============================================================================
--- directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/LoggingHotpMonitor.java (added)
+++ directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/LoggingHotpMonitor.java Tue Dec 12 07:23:31 2006
@@ -0,0 +1,140 @@
+/*
+ *  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. 
+ *  
+ */
+package org.safehaus.triplesec;
+
+
+import javax.security.auth.kerberos.KerberosPrincipal;
+
+import org.safehaus.triplesec.verifier.hotp.HotpMonitor;
+import org.safehaus.profile.ServerProfile;
+import org.safehaus.otp.ResynchParameters;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * A Log4J based logging HOTP verifier monitor.
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class LoggingHotpMonitor implements HotpMonitor
+{
+    /** underlying logger to use for logging events */
+    private final Log log;
+
+
+    public LoggingHotpMonitor( Log log )
+    {
+        if ( log == null )
+        {
+            this.log = LogFactory.getLog( "HotpMonitor" );
+
+            return;
+        }
+
+        this.log = log;
+    }
+
+
+    public LoggingHotpMonitor()
+    {
+        this.log = LogFactory.getLog( "HotpMonitor" );
+    }
+
+
+    public void verificationFailed( ServerProfile p, ResynchParameters params )
+    {
+        if ( log.isInfoEnabled() )
+        {
+            log.info( "verification failed for " + p + " with " + params );
+        }
+    }
+
+
+    public void initiatingResynch( ServerProfile p, ResynchParameters params )
+    {
+        if ( log.isInfoEnabled() )
+        {
+            log.info( "resynch initiated for " + p + " with " + params );
+        }
+    }
+
+
+    public void checkingLookahead( ServerProfile p, ResynchParameters params )
+    {
+        if ( log.isInfoEnabled() )
+        {
+            log.info( "checking lookahead for " + p + " with " + params );
+        }
+    }
+
+
+    public void integrityCheckFailed( ServerProfile p )
+    {
+        if ( log.isInfoEnabled() )
+        {
+            log.info( "integrity check failed for " + p );
+        }
+    }
+
+
+    public void resynchCompleted( ServerProfile p, ResynchParameters params )
+    {
+        if ( log.isInfoEnabled() )
+        {
+            log.info( "resynch completed for " + p + " with " + params );
+        }
+    }
+
+
+    public void resynchInProgress( ServerProfile p, ResynchParameters params )
+    {
+        if ( log.isInfoEnabled() )
+        {
+            log.info( "resynch in progress for " + p + " with " + params );
+        }
+    }
+
+
+    public void integrityCheckPassed( ServerProfile p )
+    {
+        if ( log.isDebugEnabled() )
+        {
+            log.debug( "verification passed for " + p );
+        }
+    }
+
+
+    public void accountLocked( ServerProfile p, ResynchParameters params )
+    {
+        log.warn( "account locked for " + p + " with " + params );
+    }
+
+
+    public void verifying( KerberosPrincipal principal )
+    {
+        if ( log.isDebugEnabled() )
+        {
+            log.debug( "attempting verification for " + principal );
+        }
+    }
+}

Added: directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/LoggingStoreMonitor.java
URL: http://svn.apache.org/viewvc/directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/LoggingStoreMonitor.java?view=auto&rev=486187
==============================================================================
--- directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/LoggingStoreMonitor.java (added)
+++ directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/LoggingStoreMonitor.java Tue Dec 12 07:23:31 2006
@@ -0,0 +1,200 @@
+/*
+ *  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. 
+ *  
+ */
+package org.safehaus.triplesec;
+
+
+import javax.naming.directory.Attributes;
+import javax.security.auth.kerberos.KerberosPrincipal;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.safehaus.profile.ServerProfile;
+import org.safehaus.triplesec.store.ServerProfileStore;
+import org.safehaus.triplesec.store.StoreMonitorAdapter;
+
+
+/**
+ * A log4j based logging StoreMonitor.
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class LoggingStoreMonitor extends StoreMonitorAdapter
+{
+    /** underlying logger used for logging store events */
+    private final Log log;
+
+
+    public LoggingStoreMonitor( Log log )
+    {
+        if ( log == null )
+        {
+            this.log = LogFactory.getLog( "StoreMonitor" );
+
+            return;
+        }
+
+        this.log = log;
+    }
+
+
+    public LoggingStoreMonitor()
+    {
+        this.log = LogFactory.getLog( "StoreMonitor" );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Callbacks
+    // ------------------------------------------------------------------------
+
+
+    public void profileAdded( ServerProfileStore store, ServerProfile profile )
+    {
+        if ( log.isDebugEnabled() )
+        {
+            log.debug( "store added profile " + profile.getUserId() + " to realm " + profile.getRealm() );
+        }
+    }
+
+
+    public void info( ServerProfileStore store, String s )
+    {
+        log.info( s );
+    }
+
+
+    public void profileImported( ServerProfileStore store, String dn, Attributes attributes )
+    {
+        if ( log.isInfoEnabled() )
+        {
+            log.info( "store imported profile - " + dn + " with attributes " + attributes );
+        }
+    }
+
+
+    public void profileNotImported( ServerProfileStore store, String dn, Attributes attributes )
+    {
+        if ( log.isInfoEnabled() )
+        {
+            log.info( "store did not imported profile - " + dn + " because it already existed" );
+        }
+    }
+
+
+    /*
+    public void profileDeleted( ServerProfileStore store, KerberosPrincipal principal, ServerProfile profile )
+    {
+        if ( log.isDebugEnabled() )
+        {
+            log.debug( "store deleted profile " + profile.getUserId() + " from realm " + profile.getRealm() );
+        }
+    }
+
+
+    public void profileAccessed( ServerProfileStore store, KerberosPrincipal principal, ServerProfile profile )
+    {
+        if ( log.isDebugEnabled() )
+        {
+            log.debug( "store accessed profile " + profile.getUserId() + " in realm " + profile.getRealm() );
+        }
+    }
+
+
+    public void profileUpdated( ServerProfileStore store, ServerProfile profile, ModificationItem[] mods )
+    {
+        String report = getModificationReport( mods );
+
+        log.info( "store updated profile " + profile.getUserId() + " in realm " + profile.getRealm() + ": " + report );
+    }
+
+
+    private String getModificationType( ModificationItem item )
+    {
+        switch( item.getModificationOp() )
+        {
+            case( DirContext.REMOVE_ATTRIBUTE ):
+
+                return "remove";
+
+            case( DirContext.REPLACE_ATTRIBUTE ):
+
+                return "replace";
+
+            case( DirContext.ADD_ATTRIBUTE ):
+
+                return "add";
+
+            default:
+                throw new IllegalArgumentException( "unknown mod type" );
+        }
+    }
+
+
+    private String getModificationReport( ModificationItem[] mods )
+    {
+        StringBuffer buf = new StringBuffer();
+
+        for ( int ii = 0; ii < mods.length; ii++ )
+        {
+            buf.append( "modop: " ).append( getModificationType( mods[ii] ) );
+
+            buf.append( "attribute: " ).append( mods[ii].getAttribute() );
+        }
+
+        return buf.toString();
+    }
+    */
+
+    public void storeInitialized( ServerProfileStore store )
+    {
+        log.info( "store initialized" );
+    }
+
+
+    public void storeFailure( ServerProfileStore store )
+    {
+        log.error( "store failed - no further info available" );
+    }
+
+
+    public void storeFailure( ServerProfileStore store, Throwable t )
+    {
+        log.error( "store failed - " + t.getMessage(), t );
+    }
+
+
+    public void storeFailure( ServerProfileStore store, KerberosPrincipal principal )
+    {
+        log.error( "store failed - operation for principal " + principal.getName() );
+    }
+
+
+    public void storeFailure( ServerProfileStore store, KerberosPrincipal principal, Throwable t )
+    {
+        log.error( "store failed - on principal " + principal.getName() + " - " + t.getMessage(), t );
+    }
+
+
+    public void storeFailure( ServerProfileStore store, KerberosPrincipal principal, String s )
+    {
+        log.error( "store failed - on principal " + principal.getName() + " - " + s );
+    }
+}

Added: directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/Service.java
URL: http://svn.apache.org/viewvc/directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/Service.java?view=auto&rev=486187
==============================================================================
--- directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/Service.java (added)
+++ directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/Service.java Tue Dec 12 07:23:31 2006
@@ -0,0 +1,597 @@
+/*
+ *  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. 
+ *  
+ */
+package org.safehaus.triplesec;
+
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.Properties;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import javax.security.auth.kerberos.KerberosPrincipal;
+
+import org.apache.directory.daemon.DaemonApplication;
+import org.apache.directory.daemon.InstallationLayout;
+import org.apache.directory.server.core.configuration.ShutdownConfiguration;
+import org.apache.directory.server.core.configuration.SyncConfiguration;
+import org.apache.directory.server.kerberos.sam.SamSubsystem;
+import org.apache.directory.shared.ldap.name.LdapDN;
+import org.apache.directory.shared.ldap.util.PropertiesUtils;
+
+import org.mortbay.http.SocketListener;
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.servlet.WebApplicationContext;
+
+import org.safehaus.profile.BaseServerProfileModifier;
+import org.safehaus.profile.ProfileTestData;
+import org.safehaus.profile.ServerProfile;
+import org.safehaus.triplesec.configuration.MutableTriplesecStartupConfiguration;
+import org.safehaus.triplesec.store.DefaultServerProfileStore;
+import org.safehaus.triplesec.store.ServerProfileStore;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.FileSystemXmlApplicationContext;
+
+
+/**
+ * The Triplesec service launched by daemons.
+ *
+ * @author <a href="mailto:akarasulu@safehaus.org">Alex Karasulu</a>
+ * @version $Rev$
+ */
+public class Service implements DaemonApplication
+{
+    /** this is the value the port override members have when they are not defined */
+    private static final int UNDEFINED_PORT_OVERRIDE = -2;
+    /** The period in milliseconds to wait before flushing db buffer cache */
+    private static final int SYNCPERIOD_MILLIS = 20000;
+    /** THe default port for the HTTP service */
+    private static final String HTTP_PORT_DEFAULT = "8383";
+
+    /** Setup a logger */
+    private static Logger log = LoggerFactory.getLogger( TriplesecUberjarMain.class );
+
+    /** The environment setting used to start the server */
+    private Properties env;
+    /** the time the server was started */
+    private long startTime;
+    /** a possible override port to use instead of what is present within the configuration */
+    private int httpPortOverride = UNDEFINED_PORT_OVERRIDE;
+    /** a possible override port to use instead of what is present within the configuration */
+    private int ldapPortOverride = UNDEFINED_PORT_OVERRIDE;
+    /** a possible override port to use instead of what is present within the configuration */
+    private int ldapsPortOverride = UNDEFINED_PORT_OVERRIDE;
+    /** a possible override port to use instead of what is present within the configuration */
+    private int krb5PortOverride = UNDEFINED_PORT_OVERRIDE;
+    /** a possible override port to use instead of what is present within the configuration */
+    private int changepwPortOverride = UNDEFINED_PORT_OVERRIDE;
+    /** a possible override port to use instead of what is present within the configuration */
+    private int ntpPortOverride = UNDEFINED_PORT_OVERRIDE;
+    /** embedded Jetty httpService */
+    private Server httpService;
+    /** setting to disable the shutdown hook for test cases: enabled by default */
+    private boolean enableShutdownHook = true;
+	/** setting to disable embedded HTTP web service: enabled by default */
+	private boolean enableHttpService = true;
+
+    private TriplesecInstallationLayout layout;
+    private Thread workerThread = null;
+    private SynchWorker worker = new SynchWorker();
+    private boolean startNoWait = false;
+    
+    
+    /**
+     * Sets the override port for the HTTP server.  If this value is set then the value is
+     * used for the HTTP server port instead of what is set within the configuration.
+     *
+     * @param httpPortOverride the HTTP port to use
+     */
+    public void setHttpPortOverride( int httpPortOverride )
+    {
+        this.httpPortOverride = httpPortOverride;
+    }
+
+
+    /**
+     * Sets the override port for the LDAP server.  If this value is set then the value is
+     * used for the LDAP server port instead of what is set within the configuration.
+     *
+     * @param ldapPortOverride the LDAP port to use
+     */
+    public void setLdapPortOverride( int ldapPortOverride )
+    {
+        this.ldapPortOverride = ldapPortOverride;
+    }
+
+
+    /**
+     * Sets the override port for the LDAPS server.  If this value is set then the value is
+     * used for the LDAPS server port instead of what is set within the configuration.
+     *
+     * @param ldapsPortOverride the LDAP port to use
+     */
+    public void setLdapsPortOverride( int ldapsPortOverride )
+    {
+        this.ldapsPortOverride = ldapsPortOverride;
+    }
+
+
+    /**
+     * Sets the override port for the Kerberos KDC.  If this value is set then the value is
+     * used for the KDC server port instead of what is set within the configuration.
+     *
+     * @param krb5PortOverride the Kerberos port to use
+     */
+    public void setKrb5PortOverride( int krb5PortOverride )
+    {
+        this.krb5PortOverride = krb5PortOverride;
+    }
+
+
+    /**
+     * Sets the override port for the Changepw Server.  If this value is set then the value is
+     * used for the Changepw server port instead of what is set within the configuration.
+     *
+     * @param changepwPortOverride the Changepw port to use
+     */
+    public void setChangepwPortOverride( int changepwPortOverride )
+    {
+        this.changepwPortOverride = changepwPortOverride;
+    }
+
+
+    /**
+     * Sets the override port for the NTP server.  If this value is set then the value is
+     * used for the NTP server port instead of what is set within the configuration.
+     *
+     * @param ntpPortOverride the NTP port to use
+     */
+    public void setNtpPortOverride( int ntpPortOverride )
+    {
+        this.ntpPortOverride = ntpPortOverride;
+    }
+
+    
+    private void configure( TriplesecInstallationLayout layout ) throws Exception
+    {
+        File configWebapp = new File( layout.getWebappsDirectory(), "config" );
+        File configured = new File( configWebapp, "configured" );
+        
+        // if the configuration application is not present then don't bother
+        if ( ! configWebapp.exists() )
+        {
+            return;
+        }
+
+        // if config app is present along with configured file inside then we exit too
+        if ( configured.exists() )
+        {
+            return;
+        }
+
+        // below here the server has not been configured and has the config app
+        httpService = new Server();
+        SocketListener listener = new SocketListener();
+        listener.setPort( Integer.parseInt( HTTP_PORT_DEFAULT ) );
+        httpService.addListener( listener );
+        httpService.addWebApplication( "config", configWebapp.getCanonicalPath() );
+        httpService.start();
+
+        // warn to let user know server is waiting and to make sure user sees the message
+        if ( log.isWarnEnabled() )
+        {
+            log.warn( "Waiting for admin to configure the server on port " + HTTP_PORT_DEFAULT );
+        }
+        
+        // waits until the webapp places a 'configured' file after the user completes configuration
+        while ( ! configured.exists() )
+        {
+            // check every second and a half for the directory's presence
+            Thread.sleep( 1500 );
+        }
+        
+        if ( log.isInfoEnabled() )
+        {
+            log.info( "Configuration stage completed ... starting normal initialization" );
+        }
+
+        httpService.stop();
+        httpService.destroy();
+        httpService = null;
+    }
+    
+
+    public void init( InstallationLayout installationLayout, String[] args ) throws Exception
+    {
+        MutableTriplesecStartupConfiguration cfg;
+
+        log.debug( "init(InstallationLayout,String[]) called" );
+        
+        if ( ! ( installationLayout instanceof TriplesecInstallationLayout ) )
+        {
+            layout = new TriplesecInstallationLayout ( installationLayout.getBaseDirectory() );
+        }
+        else
+        {
+            layout = ( TriplesecInstallationLayout ) installationLayout;
+        }
+
+        configure( layout );
+        startTime = System.currentTimeMillis();
+        
+        if ( layout != null )
+        {
+            log.info( "server: loading settings from ", layout.getConfigurationFile() );
+            ApplicationContext factory = null;
+            factory = new FileSystemXmlApplicationContext( layout.getConfigurationFile().toURL().toString() );
+            cfg = ( MutableTriplesecStartupConfiguration ) factory.getBean( "configuration" );
+            env = ( Properties ) factory.getBean( "environment" );
+        }
+        else if ( args.length > 0 && new File( args[0] ).exists() ) // hack that takes server.xml file argument
+        {
+            log.info( "server: loading settings from ", args[0] );
+            ApplicationContext factory = null;
+            factory = new FileSystemXmlApplicationContext( new File( args[0] ).toURL().toString() );
+            cfg = ( MutableTriplesecStartupConfiguration ) factory.getBean( "configuration" );
+            env = ( Properties ) factory.getBean( "environment" );
+        }
+        else
+        {
+            throw new Exception( "Can't figure out where to fine my installation." ); 
+        }
+
+        cfg.setShutdownHookEnabled( enableShutdownHook );
+		cfg.setEnableHttp( enableHttpService );
+        cfg.setLdifDirectory( layout.getConfigurationDirectory().getAbsoluteFile() );
+
+        if ( httpPortOverride != UNDEFINED_PORT_OVERRIDE )
+        {
+            cfg.setHttpPort( httpPortOverride );
+        }
+
+        if ( ldapPortOverride != UNDEFINED_PORT_OVERRIDE )
+        {
+            cfg.setLdapPort( ldapPortOverride );
+        }
+
+        if ( ldapsPortOverride != UNDEFINED_PORT_OVERRIDE )
+        {
+            cfg.setLdapsPort( ldapsPortOverride );
+        }
+
+        if ( layout != null )
+        {
+            cfg.setWorkingDirectory( layout.getPartitionsDirectory() );
+        }
+
+        env.setProperty( Context.PROVIDER_URL, "ou=system" );
+        env.setProperty( Context.INITIAL_CONTEXT_FACTORY, TriplsecContextFactory.class.getName() );
+        env.putAll( cfg.toJndiEnvironment() );
+
+        if ( krb5PortOverride != UNDEFINED_PORT_OVERRIDE )
+        {
+            cfg.setEnableKerberos( true );
+            env.put( "kdc.ipPort", Integer.toString( krb5PortOverride ) );
+            env.put( "kdc.ipPort", Integer.toString( krb5PortOverride ) );
+        }
+
+        if ( changepwPortOverride != UNDEFINED_PORT_OVERRIDE )
+        {
+            cfg.setEnableChangePassword( true );
+            env.put( "changepw.ipPort", Integer.toString( changepwPortOverride ) );
+            env.put( "changepw.ipPort", Integer.toString( changepwPortOverride ) );
+        }
+
+        if ( ntpPortOverride != UNDEFINED_PORT_OVERRIDE )
+        {
+            cfg.setEnableNtp( true );
+            env.put( "ntp.ipPort", Integer.toString( ntpPortOverride ) );
+            env.put( "ntp.ipPort", Integer.toString( ntpPortOverride ) );
+        }
+
+        // -------------------------------------------------------------------
+        // Get and/or create the userContext where profiles are subordinates
+        // -------------------------------------------------------------------
+
+        DirContext userContext = null;
+        try
+        {
+            LdapDN dn = new LdapDN( env.getProperty( "safehaus.entry.basedn" ) );
+            dn.remove( dn.size() - 1 );
+            env.setProperty( Context.PROVIDER_URL, dn.toString() );
+            userContext = new InitialDirContext( env );
+        }
+        catch ( NamingException e )
+        {
+            e.printStackTrace();
+            System.exit( -5 );
+        }
+
+        // set the user context for the sam subsystem
+        SamSubsystem.getInstance().setUserContext( userContext, "ou=users" );
+
+        // setup demo profiles
+        try
+        {
+            if ( PropertiesUtils.get( env, "safehaus.load.testdata", true ) )
+            {
+                ServerProfileStore store;
+                store = new DefaultServerProfileStore( ( DirContext ) userContext.lookup( "ou=Users" ) );
+                addDemoProfiles( store, env.getProperty( "kdc.primary.realm" ) );
+            }
+        }
+        catch ( NamingException e )
+        {
+            e.printStackTrace();
+            System.exit( -7 );
+        }
+        
+        try
+        {
+            if ( cfg.isEnableHttp() )
+            {
+                setupHttpService( cfg.getHttpPort() );
+            }
+        }
+        catch ( Exception e )
+        {
+            e.printStackTrace();
+            System.exit( -8 );
+        }
+
+        workerThread = new Thread( worker, "SynchWorkerThread" );
+
+        if ( log.isInfoEnabled() )
+        {
+            log.info( "server: started in {} milliseconds", ( System.currentTimeMillis() - startTime ) + "" );
+        }
+    }
+    
+    
+    public void setupHttpService( int port ) throws Exception
+    {
+        httpService = new Server();
+        httpService.setStatsOn( true );
+        httpService.setTrace( true );
+        
+        log.warn( "Setting trace and stats to on for Jetty" );
+        
+        SocketListener listener = new SocketListener();
+        listener.setPort( port );
+        httpService.addListener( listener );
+        
+        File webappsDir = new File( layout.getBaseDirectory(), "webapps" );
+        File[] webapps = webappsDir.listFiles( new FileFilter() {
+            public boolean accept( File dir ) { return dir.isDirectory(); }
+        } );
+        
+        if ( webapps == null )
+        {
+            return;
+        }
+        
+        for ( int ii = 0; ii < webapps.length; ii++ )
+        {
+            WebApplicationContext appContext = null;
+            
+            if ( webapps[ii].getName().equals( "ROOT" ) )
+            {
+                appContext = httpService.addWebApplication( "/", webapps[ii].getCanonicalPath() );
+            }
+            else if ( webapps[ii].getName().equals( "config" ) )
+            {
+            	continue;
+            }
+            else
+            {
+                appContext = httpService.addWebApplication( webapps[ii].getName(), webapps[ii].getCanonicalPath() );
+            }
+            
+            appContext.setExtractWAR( true );
+            appContext.setMimeMapping( "jar", "application/java-archive" );
+            appContext.setMimeMapping( "jad", "text/vnd.sun.j2me.app-descriptor" );
+            appContext.setMimeMapping( "cod", "application/vnd.rim.cod"  );
+            appContext.setMimeMapping( "wml", "text/vnd.wap.wml" );
+            appContext.setMimeMapping( "wmls", "text/vnd.wap.wmlscript"  );
+            appContext.setMimeMapping( "wbxml", "application/vnd.wap.wbxml"  );
+            appContext.setMimeMapping( "wmlc", "application/vnd.wap.wmlc" );
+            appContext.setMimeMapping( "wmlsc", "application/vnd.wap.wmlscriptc" );
+        }
+        
+        //httpService.start();
+    }
+
+
+    public void destroy()
+    {
+        log.debug( "destroy() called" );
+    }
+
+
+    public void start()
+    {
+        try
+        {
+			if ( httpService != null )
+			{
+				httpService.start();
+			}
+        }
+        catch ( Exception e )
+        {
+            e.printStackTrace();
+            System.exit( -8 );
+        }
+        workerThread.start();
+        return;
+    }
+
+
+    public void stop( String[] args ) throws Exception
+    {
+
+        try
+        {
+			if ( httpService != null )
+			{
+				httpService.stop();
+				httpService.destroy();
+				httpService = null;
+			}
+        }
+        catch ( Exception e )
+        {
+            e.printStackTrace();
+        }
+		worker.stop = true;
+        synchronized ( worker.lock )
+        {
+            worker.lock.notify();
+        }
+
+        while ( startNoWait && workerThread.isAlive() )
+        {
+            log.info( "Waiting for SynchWorkerThread to die." );
+            workerThread.join( 500 );
+        }
+
+        env.putAll( new ShutdownConfiguration().toJndiEnvironment() );
+        new InitialDirContext( env );
+    }
+
+
+    /**
+     * Adds profile test/demo data which is also setup on the client
+     * application.
+     *
+     * @param store the store to add the test data to
+     * @throws NamingException on failures while adding test profiles
+     */
+    private static void addDemoProfiles( ServerProfileStore store, String realm ) throws NamingException
+    {
+        for ( int ii = 0; ii < ProfileTestData.PROFILES.length; ii++ )
+        {
+            ServerProfile profile = ProfileTestData.PROFILES[ii];
+            BaseServerProfileModifier modifier = new BaseServerProfileModifier();
+            modifier.setActivationKey( profile.getActivationKey() );
+            modifier.setFactor( profile.getFactor() );
+            modifier.setFailuresInEpoch( profile.getFailuresInEpoch() );
+            modifier.setInfo( profile.getInfo() );
+            modifier.setLabel( profile.getLabel() );
+            modifier.setPassword( profile.getPassword() );
+            modifier.setRealm( realm );
+            modifier.setResynchCount( profile.getResynchCount() );
+            modifier.setSecret( profile.getSecret() );
+            modifier.setTokenPin( profile.getTokenPin() );
+            modifier.setUserId( profile.getUserId() );
+            profile = modifier.getServerProfile();
+            String name = profile.getUserId() + "@" + realm;
+            KerberosPrincipal principal = new KerberosPrincipal( name );
+
+            if ( ! store.hasProfile( principal ) )
+            {
+                store.add( profile );
+            }
+        }
+    }
+
+
+    public void synch() throws Exception
+    {
+        env.putAll( new SyncConfiguration().toJndiEnvironment() );
+        new InitialDirContext( env );
+    }
+
+
+    class SynchWorker implements Runnable
+    {
+        Object lock = new Object();
+        boolean stop = false;
+
+
+        public void run()
+        {
+            while ( !stop )
+            {
+                synchronized ( lock )
+                {
+                    try
+                    {
+                        lock.wait( SYNCPERIOD_MILLIS );
+                    }
+                    catch ( InterruptedException e )
+                    {
+                        log.warn( "SynchWorker failed to wait on lock.", e );
+                    }
+                }
+
+                try
+                {
+                    synch();
+                }
+                catch ( Exception e )
+                {
+                    log.error( "SynchWorker failed to synch directory.", e );
+                }
+            }
+        }
+    }
+
+    public static final String BANNER = "           _                     _          ____  ____   \n"
+        + "          / \\   _ __   __ _  ___| |__   ___|  _ \\/ ___|  \n"
+        + "         / _ \\ | '_ \\ / _` |/ __| '_ \\ / _ \\ | | \\___ \\   \n"
+        + "        / ___ \\| |_) | (_| | (__| | | |  __/ |_| |___) |  \n"
+        + "       /_/   \\_\\ .__/ \\__,_|\\___|_| |_|\\___|____/|____/   \n"
+        + "               |_|                                                               \n";
+
+
+    public static void printBanner()
+    {
+        System.out.println( BANNER );
+    }
+
+
+    public void setEnableShutdownHook( boolean enableShutdownHook )
+    {
+        this.enableShutdownHook = enableShutdownHook;
+    }
+
+
+    public boolean isEnableShutdownHook()
+    {
+        return enableShutdownHook;
+    }
+
+	public void setEnableHttpService( boolean enableHttpService )
+	{
+		this.enableHttpService = enableHttpService;
+	}
+
+	public boolean isEnableHttpService()
+	{
+		return enableHttpService;
+	}
+}

Added: directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/TriplesecInstallationLayout.java
URL: http://svn.apache.org/viewvc/directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/TriplesecInstallationLayout.java?view=auto&rev=486187
==============================================================================
--- directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/TriplesecInstallationLayout.java (added)
+++ directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/TriplesecInstallationLayout.java Tue Dec 12 07:23:31 2006
@@ -0,0 +1,58 @@
+/*
+ *  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. 
+ *  
+ */
+package org.safehaus.triplesec;
+
+import java.io.File;
+
+import org.apache.directory.daemon.InstallationLayout;
+
+
+public class TriplesecInstallationLayout extends InstallationLayout
+{
+    public TriplesecInstallationLayout( File installBase )
+    {
+        super( installBase );
+    }
+
+
+    public TriplesecInstallationLayout( String installBase )
+    {
+        super( installBase );
+    }
+
+
+    public File getWebappsDirectory()
+    {
+        return getWebappsDirectory( "webapps" );
+    }
+
+
+    public File getWebappsDirectory( String webappsPath )
+    {
+        return new File( super.baseDirectory, webappsPath );
+    }
+
+
+    public void mkdirs()
+    {
+        super.mkdirs();
+        getWebappsDirectory().mkdirs();
+    }
+}

Added: directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/TriplesecUberjarMain.java
URL: http://svn.apache.org/viewvc/directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/TriplesecUberjarMain.java?view=auto&rev=486187
==============================================================================
--- directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/TriplesecUberjarMain.java (added)
+++ directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/TriplesecUberjarMain.java Tue Dec 12 07:23:31 2006
@@ -0,0 +1,61 @@
+/*
+ *  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. 
+ *  
+ */
+package org.safehaus.triplesec;
+
+import java.io.File;
+
+
+
+/**
+ * The main application entry point for Triplesec as a java application.
+ *
+ * @author <a href="mailto:akarasulu@safehaus.org">Alex Karasulu</a>
+ * @version $Rev$
+ */
+public class TriplesecUberjarMain
+{
+    /**
+     * Takes a single argument, the path to the installation home, which contains 
+     * the configuration to load with server startup settings.
+     *
+     * @param args the arguments
+     */
+    public static void main( String[] args ) throws Exception
+    {
+        Service server = new Service();
+
+        if ( args.length > 0 && new File( args[0] ).isDirectory() )
+        {
+            server.init( new TriplesecInstallationLayout( args[0] ), null );
+            server.start();
+        }
+        else if ( args.length > 0 && new File( args[0] ).isFile() )
+        {
+            server.init( null, args );
+            server.start();
+        }
+        else
+        {
+            server.init( null, null );
+            server.start();
+        }
+    }
+}
+

Added: directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/TriplsecContextFactory.java
URL: http://svn.apache.org/viewvc/directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/TriplsecContextFactory.java?view=auto&rev=486187
==============================================================================
--- directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/TriplsecContextFactory.java (added)
+++ directory/trunks/triplesec/main/src/main/java/org/safehaus/triplesec/TriplsecContextFactory.java Tue Dec 12 07:23:31 2006
@@ -0,0 +1,48 @@
+/*
+ *  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. 
+ *  
+ */
+package org.safehaus.triplesec;
+
+
+import org.apache.directory.server.jndi.ServerContextFactory;
+import org.apache.directory.server.core.DirectoryService;
+
+import javax.naming.NamingException;
+
+
+/**
+ * Nothing for now.
+ *
+ * @author <a href="mailto:akarasulu@safehaus.org">Alex Karasulu</a>
+ * @version $Rev$
+ */
+public class TriplsecContextFactory extends ServerContextFactory
+{
+
+    public void afterStartup( DirectoryService service ) throws NamingException
+    {
+        super.afterStartup( service );
+    }
+
+
+    public void afterShutdown( DirectoryService service )
+    {
+        super.afterShutdown( service );
+    }
+}

Added: directory/trunks/triplesec/main/src/test/org/safehaus/triplesec/ConfigurationTest.java
URL: http://svn.apache.org/viewvc/directory/trunks/triplesec/main/src/test/org/safehaus/triplesec/ConfigurationTest.java?view=auto&rev=486187
==============================================================================
--- directory/trunks/triplesec/main/src/test/org/safehaus/triplesec/ConfigurationTest.java (added)
+++ directory/trunks/triplesec/main/src/test/org/safehaus/triplesec/ConfigurationTest.java Tue Dec 12 07:23:31 2006
@@ -0,0 +1,259 @@
+/*
+ *  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. 
+ *  
+ */
+package org.safehaus.triplesec;
+
+import java.io.File;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+
+import org.apache.ldap.common.berlib.asn1.SnickersProvider;
+import org.apache.ldap.server.configuration.DirectoryPartitionConfiguration;
+import org.apache.ldap.server.configuration.ServerStartupConfiguration;
+import org.apache.ldap.server.jndi.ServerContextFactory;
+import org.apache.ldap.server.schema.bootstrap.ApacheSchema;
+import org.apache.ldap.server.schema.bootstrap.CoreSchema;
+import org.apache.ldap.server.schema.bootstrap.CosineSchema;
+import org.apache.ldap.server.schema.bootstrap.InetorgpersonSchema;
+import org.apache.ldap.server.schema.bootstrap.Krb5kdcSchema;
+import org.apache.ldap.server.schema.bootstrap.SystemSchema;
+import org.safehaus.triplesec.store.ProfileObjectFactory;
+import org.safehaus.triplesec.store.ProfileStateFactory;
+import org.safehaus.triplesec.verifier.hotp.DefaultHotpSamVerifier;
+import org.safehaus.triplesec.store.schema.SafehausSchema;
+import junit.framework.TestCase;
+
+public class ConfigurationTest extends TestCase
+{
+    private ConfigurationFactory factory;
+
+    private Hashtable env;
+
+    public void setUp()
+    {
+        factory = new ConfigurationFactory();
+
+        env = new Hashtable();
+        
+        // Put common properties
+        env.put( Configuration.KDC_PRIMARY_REALM, "EXAMPLE.COM" );
+        env.put( Configuration.KDC_PRINCIPAL, "krbtgt/EXAMPLE.COM@EXAMPLE.COM" );
+        env.put( Configuration.CHANGEPW_PRINCIPAL, "kadmin/changepw@EXAMPLE.COM" );
+    }
+    
+    public void testSufficientProperties()
+    {
+        factory.getInstance( env );
+    }
+    
+    public void testInsufficientProperties()
+    {
+        env.clear();
+        subTestInsufficientProperties();
+        
+        env.clear();
+        env.put( Configuration.KDC_PRIMARY_REALM, "EXAMPLE.COM" );
+        subTestInsufficientProperties();
+        
+        env.clear();
+        env.put( Configuration.KDC_PRIMARY_REALM, "EXAMPLE.COM" );
+        env.put( Configuration.KDC_PRINCIPAL, "krbtgt/EXAMPLE.COM@EXAMPLE.COM" );
+        subTestInsufficientProperties();
+    }
+
+    private void subTestInsufficientProperties()
+    {
+        try
+        {
+            env = factory.getInstance( env );
+            fail( "IllegalArgumentException must be thrown." );
+        }
+        catch( IllegalArgumentException e )
+        {
+            assertTrue( true );
+        }
+    }
+
+    public void testPreserveOriginalProperties()
+    {
+        env.put( "keyX", "valueY" );
+        env = factory.getInstance( env );
+        assertEquals( "valueY", env.get( "keyX" ) );
+    }
+    
+    public void testJndiProperties() throws Exception
+    {
+        env = factory.getInstance( env );
+        assertEquals( "dc=example,dc=com", env.get( Context.PROVIDER_URL ) );
+        assertEquals( "uid=admin,ou=system", env.get( Context.SECURITY_PRINCIPAL ) );
+        assertEquals( "simple", env.get( Context.SECURITY_AUTHENTICATION ) );
+        assertEquals( "secret", env.get( Context.SECURITY_CREDENTIALS ) );
+        assertEquals( ServerContextFactory.class.getName(), env.get( Context.INITIAL_CONTEXT_FACTORY ) );
+        assertEquals( ProfileStateFactory.class.getName(), env.get( Context.STATE_FACTORIES ) );
+        assertEquals( ProfileObjectFactory.class.getName(), env.get( Context.OBJECT_FACTORIES ) );
+
+        // Do additional tests
+        tearDown();
+        setUp();
+        
+        env.put( Configuration.KDC_PRIMARY_REALM, "GLEAMYNODE.NET" );
+        env = factory.getInstance( env );
+        assertEquals( "dc=gleamynode,dc=net", env.get( Context.PROVIDER_URL ) );
+    }
+    
+    public void testApacheDsProperties() throws NamingException
+    {
+        Hashtable env = factory.getInstance( this.env );
+
+        ServerStartupConfiguration cfg = ( ServerStartupConfiguration ) ServerStartupConfiguration.toConfiguration( env );
+
+        assertTrue( cfg.isEnableKerberos() );
+
+        Set partitions = cfg.getContextPartitionConfigurations();
+
+        assertEquals( 1, partitions.size() );
+
+        // let's test that all partition information is correct
+
+        DirectoryPartitionConfiguration partition = ( DirectoryPartitionConfiguration ) partitions.iterator().next();
+
+        assertEquals( "dc=example,dc=com", partition.getSuffix() );
+
+        assertTrue( partition.getIndexedAttributes().contains( "ou" ) );
+        assertTrue( partition.getIndexedAttributes().contains( "uid" ) );
+        assertTrue( partition.getIndexedAttributes().contains( "objectClass" ) );
+        assertTrue( partition.getIndexedAttributes().contains( "krb5PrincipalName" ) );
+        assertTrue( partition.getIndexedAttributes().contains( "safehausUid" ) );
+        assertTrue( partition.getIndexedAttributes().contains( "safehausRealm" ) );
+
+        assertEquals( "example", partition.getContextEntry().get( "dc" ).get() );
+
+        assertTrue( partition.getContextEntry().get( "objectClass" ).contains( "top" ) );
+        assertTrue( partition.getContextEntry().get( "objectClass" ).contains( "domain" ) );
+
+        assertEquals( env.get( Configuration.WORK_DIRECTORY ) +
+                      File.separator + "realms" + 
+                      File.separator + "example_com", cfg.getWorkingDirectory().getPath() );
+
+        assertEquals( SnickersProvider.class.getName(), env.get( Configuration.ASN1_BERLIB_PROVIDER ) );
+
+        assertTrue( cfg.isAllowAnonymousAccess() );
+        assertTrue( cfg.isEnableNetworking() );
+        
+        Set schemaTypes = new HashSet();
+        Iterator it = cfg.getBootstrapSchemas().iterator();
+        while( it.hasNext() )
+        {
+            schemaTypes.add( it.next().getClass() );
+        }
+        
+        assertTrue( schemaTypes.contains( SystemSchema.class ) );
+        assertTrue( schemaTypes.contains( ApacheSchema.class ) );
+        assertTrue( schemaTypes.contains( CoreSchema.class ) );
+        assertTrue( schemaTypes.contains( CosineSchema.class ) );
+        assertTrue( schemaTypes.contains( InetorgpersonSchema.class ) );
+        assertTrue( schemaTypes.contains( Krb5kdcSchema.class ) );
+        assertTrue( schemaTypes.contains( SafehausSchema.class ) );
+
+        assertEquals( 389, cfg.getLdapPort() );
+    }
+
+    public void testSafeHausProperties()
+    {
+        env = factory.getInstance( env );
+        assertEquals( ".." + File.separator + "var", env.get( Configuration.WORK_DIRECTORY ) );
+        assertEquals( "389", env.get( Configuration.LDAP_PORT ) );
+        assertEquals( LoggingHotpMonitor.class.getName(), env.get( Configuration.VERIFIER_MONITOR ) );
+        assertEquals( LoggingStoreMonitor.class.getName(), env.get( Configuration.STORE_MONITOR ) );
+        assertEquals( "true", env.get( Configuration.LOAD_TEST_DATA ) );
+        assertEquals( "ou=Users,dc=example,dc=com", env.get( Configuration.ENTRY_BASEDN ) );
+        assertEquals( ".." + File.separator + "conf" + File.separator + "server.ldif", env.get( Configuration.ENTRY_LDIF_FILE ) );
+    }
+    
+    public void testKerberosProperties()
+    {
+        env = factory.getInstance( env );
+        assertEquals( DefaultHotpSamVerifier.class.getName(), env.get( Configuration.KERBEROS_SAM_TYPE ) );
+    }
+    
+    public void testKdcProperties()
+    {
+        env = factory.getInstance( env );
+        assertEquals( "88", env.get( Configuration.KDC_DEFAULT_PORT ) );
+        assertEquals( ".." + File.separator + "conf" + File.separator + "server.ldif", env.get( Configuration.KDC_ENTRY_LDIF_FILE ) );
+        assertEquals( "ou=Users,dc=example,dc=com", env.get( Configuration.KDC_ENTRY_BASEDN ) );
+        assertEquals( "5", env.get( Configuration.KDC_ALLOWABLE_CLOCKSKEW ) );
+        assertEquals( "kerberoskeys.ser", env.get( Configuration.KDC_KEYS_LOCATION ) );
+        assertEquals( "des-cbc-md5 des3-cbc-sha1 des3-cbc-md5 " +
+                      "des-cbc-md4 des-cbc-crc",
+                      env.get( Configuration.KDC_ENCRYPTION_TYPES ) );
+        assertEquals( "true", env.get( Configuration.KDC_PA_ENC_TIMESTAMP_REQUIRED ) );
+    }
+    
+    public void testTgsProperties()
+    {
+        env = factory.getInstance( env );
+        assertEquals( "1440", env.get( Configuration.TGS_MAXIMUM_TICKET_LIFETIME ) );
+        assertEquals( "10080", env.get( Configuration.TGS_MAXIMUM_RENEWABLE_LIFETIME ) );
+        assertEquals( "true", env.get( Configuration.TGS_EMPTY_ADDRESSES_ALLOWED ) );
+        assertEquals( "true", env.get( Configuration.TGS_FORWARDABLE_ALLOWED ) );
+        assertEquals( "true", env.get( Configuration.TGS_PROXIABLE_ALLOWED ) );
+        assertEquals( "true", env.get( Configuration.TGS_POSTDATE_ALLOWED ) );
+        assertEquals( "true", env.get( Configuration.TGS_RENEWABLE_ALLOWED ) );
+    }
+    
+    public void testInducedProperties() throws Exception
+    {
+        env.put( Configuration.KDC_PRIMARY_REALM, "GLEAMYNODE.NET" );
+
+        env.put( Configuration.LDAP_PORT, "1024" );
+
+        env = factory.getInstance( env );
+
+        ServerStartupConfiguration cfg = ( ServerStartupConfiguration ) ServerStartupConfiguration.toConfiguration( env );
+
+        assertEquals( 1024, cfg.getLdapPort() );
+
+        assertEquals( env.get( Configuration.KDC_ENTRY_BASEDN ),
+                      env.get( Configuration.ENTRY_BASEDN ) );
+
+        assertEquals( env.get( Configuration.KDC_ENTRY_LDIF_FILE ),
+                      env.get( Configuration.ENTRY_LDIF_FILE ) );
+
+        assertTrue( cfg.isEnableNetworking() );
+
+        tearDown();
+
+        setUp();
+
+        // We don't need to do this anymore do we ???
+
+        env.put( Configuration.LDAP_PORT, "-1" );
+
+        env = factory.getInstance( env );
+        cfg = ( ServerStartupConfiguration ) ServerStartupConfiguration.toConfiguration( env );
+        
+        assertFalse( cfg.isEnableNetworking() );
+    }
+}

Added: directory/trunks/triplesec/main/src/test/resources/log4j.properties
URL: http://svn.apache.org/viewvc/directory/trunks/triplesec/main/src/test/resources/log4j.properties?view=auto&rev=486187
==============================================================================
--- directory/trunks/triplesec/main/src/test/resources/log4j.properties (added)
+++ directory/trunks/triplesec/main/src/test/resources/log4j.properties Tue Dec 12 07:23:31 2006
@@ -0,0 +1,6 @@
+log4j.rootCategory=ERROR, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c] - %m%n
+

Added: directory/trunks/triplesec/otp/pom.xml
URL: http://svn.apache.org/viewvc/directory/trunks/triplesec/otp/pom.xml?view=auto&rev=486187
==============================================================================
--- directory/trunks/triplesec/otp/pom.xml (added)
+++ directory/trunks/triplesec/otp/pom.xml Tue Dec 12 07:23:31 2006
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+
+  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. 
+  
+-->
+<project>
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.safehaus.triplesec</groupId>
+    <artifactId>build</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>triplesec-otp</artifactId>
+  <name>Triplesec OTP API</name>
+  <description>
+    One Time Password Algorithm API
+  </description>
+  <packaging>jar</packaging>  
+  <dependencies>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>triplesec-crypto</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+</project>

Added: directory/trunks/triplesec/otp/src/main/java/org/safehaus/otp/Base64.java
URL: http://svn.apache.org/viewvc/directory/trunks/triplesec/otp/src/main/java/org/safehaus/otp/Base64.java?view=auto&rev=486187
==============================================================================
--- directory/trunks/triplesec/otp/src/main/java/org/safehaus/otp/Base64.java (added)
+++ directory/trunks/triplesec/otp/src/main/java/org/safehaus/otp/Base64.java Tue Dec 12 07:23:31 2006
@@ -0,0 +1,211 @@
+/*
+ *  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. 
+ *  
+ */
+package org.safehaus.otp;
+
+
+/**
+ * Decoding/Encoding of base64 characters to raw bytes.
+ *
+ * @author <a href="mailto:akarasulu@safehaus.org">Alex Karasulu</a>
+ * @version $Rev$
+ */
+public class Base64
+{
+
+    /**
+     * passed data array.
+     *
+     * @param a_data the array of bytes to encode
+     * @return base64-coded character array.
+     */
+    public static char[] encode( byte[] a_data )
+    {
+        char [] l_out = new char[( ( a_data.length + 2 ) / 3 ) * 4];
+    
+        //
+        // 3 bytes encode to 4 chars.  Output is always an even
+        // multiple of 4 characters.
+        //
+        for ( int ii = 0, l_index = 0; ii < a_data.length;
+            ii += 3, l_index += 4 )
+        {
+            boolean l_quad = false;
+            boolean l_trip = false;
+    
+            int l_val = ( 0xFF & ( int ) a_data[ii] );
+            l_val <<= 8;
+            if ( ( ii + 1 ) < a_data.length ) 
+            {
+                l_val |= ( 0xFF & ( int ) a_data[ii + 1] );
+                l_trip = true;
+            }
+
+            l_val <<= 8;
+            if ( ( ii + 2 ) < a_data.length ) 
+            {
+                l_val |= ( 0xFF & ( int ) a_data[ ii + 2] );
+                l_quad = true;
+            }
+
+            l_out[l_index + 3] = 
+                s_alphabet[( l_quad ? ( l_val & 0x3F ) : 64 )];
+            l_val >>= 6;
+            l_out[l_index + 2] = 
+                s_alphabet[( l_trip ? ( l_val & 0x3F ) : 64 )];
+            l_val >>= 6;
+            l_out[l_index + 1] = s_alphabet[l_val & 0x3F];
+            l_val >>= 6;
+            l_out[l_index + 0] = s_alphabet[l_val & 0x3F];
+        }
+        return l_out;
+    }
+
+
+    /**
+    * Decodes a BASE-64 encoded stream to recover the original
+    * data. White space before and after will be trimmed away,
+    * but no other manipulation of the input will be performed.
+    *
+    * As of version 1.2 this method will properly handle input
+    * containing junk characters (newlines and the like) rather
+    * than throwing an error. It does this by pre-parsing the
+    * input and generating from that a count of VALID input
+    * characters.
+    *
+    * @param a_data data to decode.
+    * @return the decoded binary data.
+    */
+    public static byte[] decode( char[] a_data )
+    {
+        // as our input could contain non-BASE64 data (newlines,
+        // whitespace of any sort, whatever) we must first adjust
+        // our count of USABLE data so that...
+        // (a) we don't misallocate the output array, and
+        // (b) think that we miscalculated our data length
+        //     just because of extraneous throw-away junk
+    
+        int l_tempLen = a_data.length;
+        for ( int ii = 0; ii < a_data.length; ii++ )
+        {
+            if ( ( a_data[ii] > 255 ) || s_codes[ a_data[ii] ] < 0 ) 
+            {
+                --l_tempLen;  // ignore non-valid chars and padding
+            }
+        }
+        // calculate required length:
+        //  -- 3 bytes for every 4 valid base64 chars
+        //  -- plus 2 bytes if there are 3 extra base64 chars,
+        //     or plus 1 byte if there are 2 extra.
+    
+        int l_len = ( l_tempLen / 4 ) * 3;
+
+        if ( ( l_tempLen % 4 ) == 3 ) 
+        {
+            l_len += 2;
+        }
+
+        if ( ( l_tempLen % 4 ) == 2 ) 
+        {
+            l_len += 1;
+        }
+    
+        byte[] l_out = new byte[l_len];
+    
+    
+    
+        int l_shift = 0;   // # of excess bits stored in accum
+        int l_accum = 0;   // excess bits
+        int l_index = 0;
+    
+        // we now go through the entire array (NOT using the 'tempLen' value)
+        for ( int ii = 0; ii < a_data.length; ii++ ) 
+        {
+            int l_value = ( a_data[ii] > 255 ) ? -1 : 
+                s_codes[ a_data[ii] ];
+    
+            if ( l_value >= 0 )       // skip over non-code 
+            {       
+                l_accum <<= 6;       // bits shift up by 6 each time thru
+                l_shift += 6;        // loop, with new bits being put in
+                l_accum |= l_value;  // at the bottom. whenever there
+                if ( l_shift >= 8 )   // are 8 or more shifted in, write them 
+                {
+                    l_shift -= 8;    // out (from the top, leaving any excess
+                    l_out[l_index++] =  // at the bottom for next iteration.
+                        ( byte ) ( ( l_accum >> l_shift ) & 0xff );
+                }
+            }
+        // we will also have skipped processing a padding null byte ('=') here;
+        // these are used ONLY for padding to an even length and do not legally
+        // occur as encoded data. for this reason we can ignore the fact that
+        // no index++ operation occurs in that special case: the out[] array is
+        // initialized to all-zero bytes to start with and that works to our
+        // advantage in this combination.
+        }
+    
+        // if there is STILL something wrong we just have to throw up now!
+        if ( l_index != l_out.length ) 
+        {
+            StringBuffer buf = new StringBuffer();
+            buf.append( "Miscalculated data length (wrote " );
+            buf.append( l_index );
+            buf.append( " instead of " );
+            buf.append(l_out.length );
+            buf.append( ")" );
+            throw new Error( buf.toString() );
+        }
+    
+        return l_out;
+    }
+
+    /** code characters for values 0..63 */
+    private static char[] s_alphabet =
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
+            .toCharArray();
+    
+    /** lookup table for converting base64 characters to value in range 0..63 */
+    private static byte[] s_codes = new byte[256];
+
+    static {
+        for ( int ii = 0; ii < 256; ii++ ) 
+        {
+            s_codes[ii] = -1;
+        }
+
+        for ( int ii = 'A'; ii <= 'Z'; ii++ ) 
+        {
+            s_codes[ii] = ( byte ) ( ii - 'A' );
+        }
+
+        for ( int ii = 'a'; ii <= 'z'; ii++ ) 
+        {
+            s_codes[ii] = ( byte ) ( 26 + ii - 'a' );
+        }
+
+        for ( int ii = '0'; ii <= '9'; ii++ ) 
+        {
+            s_codes[ii] = ( byte ) ( 52 + ii - '0' );
+        }
+
+        s_codes['+'] = 62;
+        s_codes['/'] = 63;
+    }
+}
+

Added: directory/trunks/triplesec/otp/src/main/java/org/safehaus/otp/Hotp.java
URL: http://svn.apache.org/viewvc/directory/trunks/triplesec/otp/src/main/java/org/safehaus/otp/Hotp.java?view=auto&rev=486187
==============================================================================
--- directory/trunks/triplesec/otp/src/main/java/org/safehaus/otp/Hotp.java (added)
+++ directory/trunks/triplesec/otp/src/main/java/org/safehaus/otp/Hotp.java Tue Dec 12 07:23:31 2006
@@ -0,0 +1,137 @@
+/*
+ *  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. 
+ *  
+ */
+package org.safehaus.otp;
+
+
+import org.safehaus.crypto.HMac;
+import org.safehaus.crypto.SHA1Digest;
+import org.safehaus.crypto.KeyParameter;
+import org.safehaus.crypto.CipherParameters;
+
+
+/**
+ * Generates a one time password using HMAC-SHA1.  This OTP algorithm is
+ * described within an <a href="http://boxmanei.notlong.com/">ietf draft</a>.
+ *
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @version $Rev: 585 $
+ */
+public class Hotp
+{
+    private static final int[] DIGITS_POWER
+            = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
+
+    /** the default minimum size for the HOTP value */
+    private static final int MIN_DIGITS = 6;
+
+    /** the default maximum size for the HOTP value */
+    private static final int MAX_DIGITS = 10;
+
+
+    /**
+     * Generates an HOTP value using a shared secret (K), a counter for the
+     * moving factor (C), and a HOTP value size (Digits).
+     *
+     * @param secret the shared secret key known to the token and the validator
+     * @param counter the movign factor
+     * @param digits the number of digits to produce for the HOTP value which
+     * should be between the range of 6 to 10 inclusive
+     * @return the generated HOTP value according to the specification
+     */
+    public static String generate( byte[] secret, long counter, int digits )
+    {
+        StringBuffer result = new StringBuffer();
+
+        if ( MIN_DIGITS < digits || digits > MAX_DIGITS )
+        {
+            throw new IllegalArgumentException( "Number of digits not within range: "
+                + MIN_DIGITS + " < digits > " + MAX_DIGITS );
+        }
+
+        if ( secret == null || secret.length == 0 )
+        {
+            throw new IllegalArgumentException( "Shared secret shouldn't be null or empty" );
+        }
+
+        byte[] hash = stepOne( secret, counter );
+
+        // put selected bytes into result int
+        int offset = 0;
+        int binary = ( ( hash[offset] & 0x7f ) << 24 ) |
+                 ( ( hash[offset + 1] & 0xff ) << 16 ) |
+                 ( ( hash[offset + 2] & 0xff ) << 8 )  |
+                 (   hash[offset + 3] & 0xff );
+
+        int otp = binary % DIGITS_POWER[digits];
+        result.append( Integer.toString( otp ) );
+        while ( result.length() < digits )
+        {
+            result.insert( 0, "0" );
+        }
+        return result.toString();
+    }
+
+
+    /**
+     * The first step to generate the HMAC-SHA-1 value.
+     *
+     * @param secretKey the shared secret key
+     * @param counter the counter value (moving factor C)
+     * @return the 20 byte HMAC-SHA-1 value
+     */
+    static byte[] stepOne( byte[] secretKey, long counter )
+    {
+        HMac mac = new HMac( new SHA1Digest() );
+        byte[] value = new byte[mac.getMacSize()];
+        CipherParameters params = new KeyParameter( secretKey );
+        mac.init( params );
+        mac.update( getCounterBytes( counter ), 0, 8 );
+        mac.doFinal( value, 0 );
+        return value;
+    }
+
+
+    // -------------------------------------------------------------------------
+    // Utility Methods
+    // -------------------------------------------------------------------------
+
+
+    /**
+     * Calculates the 8 bytes for the long counter where the 8 most significant
+     * bits are in the first byte, then next 8 MSBs are in the second byte and
+     * so on.
+     *
+     * @param counter the long counter value (C)
+     * @return the byte array of length 8 representing the counter
+     */
+    static byte[] getCounterBytes( long counter )
+    {
+        byte[] counterBytes = new byte[8];
+        counterBytes[7] = ( byte ) counter;
+        counterBytes[6] = ( byte ) ( counter >> 8 );
+        counterBytes[5] = ( byte ) ( counter >> 16 );
+        counterBytes[4] = ( byte ) ( counter >> 24 );
+        counterBytes[3] = ( byte ) ( counter >> 32 );
+        counterBytes[2] = ( byte ) ( counter >> 40 );
+        counterBytes[1] = ( byte ) ( counter >> 48 );
+        counterBytes[0] = ( byte ) ( counter >> 56 );
+        return counterBytes;
+    }
+}

Added: directory/trunks/triplesec/otp/src/main/java/org/safehaus/otp/HotpAttributes.java
URL: http://svn.apache.org/viewvc/directory/trunks/triplesec/otp/src/main/java/org/safehaus/otp/HotpAttributes.java?view=auto&rev=486187
==============================================================================
--- directory/trunks/triplesec/otp/src/main/java/org/safehaus/otp/HotpAttributes.java (added)
+++ directory/trunks/triplesec/otp/src/main/java/org/safehaus/otp/HotpAttributes.java Tue Dec 12 07:23:31 2006
@@ -0,0 +1,151 @@
+/*
+ *  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. 
+ *  
+ */
+package org.safehaus.otp;
+
+
+/**
+ * Attributes use to calculate a HOTP value.
+ *
+ * @author <a href="mailto:akarasulu@safehaus.org">Alex Karasulu</a>
+ * @version $Rev$
+ */
+public final class HotpAttributes
+{
+    private static final int DEFAULT_SIZE = 6;
+
+    /** the shared secret key */
+    private final byte[] secret;
+    /** the moving factor */
+    private final long factor;
+    /** the size of the value to generate */
+    private final int size;
+
+
+    /**
+     * Creates a HotpAttributes object with all three attributes.
+     *
+     * @param factor the moving factor
+     * @param secret the shared secret
+     */
+    public HotpAttributes( long factor, byte[] secret )
+    {
+        this( DEFAULT_SIZE, factor, secret );
+    }
+
+
+    /**
+     * Creates a HotpAttributes object with all three attributes.
+     *
+     * @param size the size of the value to generate
+     * @param factor the moving factor
+     * @param secret the shared secret
+     */
+    public HotpAttributes( int size, long factor, byte[] secret )
+    {
+        if ( 6 > size || size > 10 )
+        {
+            StringBuffer buf = new StringBuffer();
+            buf.append( "expecting HOTP value size in range [6,10] but got " );
+            buf.append( size );
+            throw new IllegalArgumentException( buf.toString() );
+        }
+
+        this.size = size;
+        this.factor = factor;
+        this.secret = secret;
+    }
+
+
+    /**
+     * Gets the shared secret key.
+     *
+     * @return the shared secret key
+     */
+    public byte[] getSecret()
+    {
+        return secret;
+    }
+
+
+    /**
+     * Gets the moving factor.
+     *
+     * @return the moving factor
+     */
+    public long getFactor()
+    {
+        return factor;
+    }
+
+
+    /**
+     * Gets the size of the value to generate.
+     *
+     * @return the size of charactor in the generated OTP
+     */
+    public int getSize()
+    {
+        return size;
+    }
+
+
+    /**
+     * Checks to see that another HotpAttributes matches this one exactly.
+     *
+     * @param obj the other object to compare this HotpAttributes to
+     * @return true if the objects are the same for all components
+     */
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( ! ( obj instanceof HotpAttributes ) )
+        {
+            return false;
+        }
+
+        HotpAttributes other = ( HotpAttributes ) obj;
+        if ( other.getSize() != this.size )
+        {
+            return false;
+        }
+        if ( other.getFactor() != this.factor )
+        {
+            return false;
+        }
+        if ( other.getSecret().length != this.secret.length )
+        {
+            return false;
+        }
+
+        for ( int ii = 0; ii < this.secret.length; ii++ )
+        {
+            if ( this.secret[ii] != other.getSecret()[ii] )
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}

Added: directory/trunks/triplesec/otp/src/main/java/org/safehaus/otp/HotpAttributesCipher.java
URL: http://svn.apache.org/viewvc/directory/trunks/triplesec/otp/src/main/java/org/safehaus/otp/HotpAttributesCipher.java?view=auto&rev=486187
==============================================================================
--- directory/trunks/triplesec/otp/src/main/java/org/safehaus/otp/HotpAttributesCipher.java (added)
+++ directory/trunks/triplesec/otp/src/main/java/org/safehaus/otp/HotpAttributesCipher.java Tue Dec 12 07:23:31 2006
@@ -0,0 +1,254 @@
+/*
+ *  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. 
+ *  
+ */
+package org.safehaus.otp;
+
+
+import org.safehaus.crypto.BlockCipherWrapper;
+import org.safehaus.crypto.DESEngine;
+
+import java.io.UnsupportedEncodingException;
+
+
+/**
+ * Encypts and decrypts HOTP attributes.  HOTP attributes are stored as binary information
+ * using the following data structure.  The result is DES encrypted then base 64 encoded.
+ * <pre>
+ * [[f1 value][f2 value][hotp size][factor][length][secret]]
+ * where ...
+ * f1 value   = 8 bytes        = the hotp value generated using factor-1 (encoded long)
+ * f2 value   = 8 bytes        = the hotp value generated using factor-2 (encoded long)
+ * hotp size  = 1 byte         = the unsigned # of characters in HOTP value within range [6-10]
+ * factor     = 8 bytes        = the current moving factor
+ * length     = 1 byte         = the unsigned length of the shared secret field (max 256)
+ * secret     = length bytes   = the shared secret
+ * </pre>
+ *
+ * @author <a href="mailto:akarasulu@safehaus.org">Alex Karasulu</a>
+ * @version $Rev$
+ */
+public class HotpAttributesCipher
+{
+    /**
+     * Takes HotpAttributes and formats them into a byte[] after calculating f1, f2, hotpSize,
+     * factor, and length bytes.  This formated byte[] is then encrypted using the password and
+     * a block cipher.  The encrypted result is then Base64 encoded for handling as a printable
+     * String.
+     *
+     * @param password the key to use when encrypting the attributes
+     * @param attributes the HotpAttributes to encrypt
+     * @return the formated, then encrypted, then base64 encoded string
+     * @throws UnsupportedEncodingException if the UTF-8 character encoding is not supported
+     */
+    public static String encrypt( String password, HotpAttributes attributes )
+            throws UnsupportedEncodingException
+    {
+        // encode all the components of the HOTP binary record as specified above in the class level javadoc
+        byte[] f1 = encodeLong( Long.parseLong( Hotp.generate( attributes.getSecret(),
+                attributes.getFactor()-1, attributes.getSize() ) ) );
+        byte[] f2 = encodeLong( Long.parseLong( Hotp.generate( attributes.getSecret(),
+                attributes.getFactor()-2, attributes.getSize() ) ) );
+        byte hotpSize = encodeUnsignedByte( attributes.getSize() );
+        byte[] factor = encodeLong( attributes.getFactor() );
+        byte length = encodeUnsignedByte( attributes.getSecret().length );
+
+        // calculate and build the record by copying all components into their proper positions
+        int totalLength = f1.length + f2.length + 1 + factor.length + 1 + attributes.getSecret().length;
+        byte[] input = new byte[totalLength];
+        int pos = 0;
+
+        // copy the f1 bytes
+        System.arraycopy( f1, 0, input, pos, f1.length );
+        pos += f1.length;
+
+        // copy the f2 bytes
+        System.arraycopy( f2, 0, input, pos, f2.length );
+        pos += f2.length;
+
+        // copy the hotpSize byte
+        input[pos] = hotpSize;
+        pos++;
+
+        // copy the factor bytes
+        System.arraycopy( factor, 0, input, pos, factor.length );
+        pos += factor.length;
+
+        // copy the length bytes
+        input[pos] = length;
+        pos++;
+
+        // copy the secret bytes
+        System.arraycopy( attributes.getSecret(), 0, input, pos, attributes.getSecret().length );
+
+
+        // initialize the cipher engine and encrypt the record
+        BlockCipherWrapper engine = new BlockCipherWrapper( new DESEngine().getClass() );
+        byte[] encrypted = engine.encrypt( password, input );
+
+        // base64 encode the encrypted record and return the string
+        return new String( Base64.encode( encrypted ) );
+    }
+
+
+    /**
+     * Decrypts the encrypted HotpAtrributes using the provided password.  It first Base64 decodes
+     * the encrypted string into the encrypted byte array.  The encrypted array is then decrypted
+     * using a cypher engine.  The decrypted attributes are then decoded based on the format for
+     * the hotp attributes.  If any errors or inconsistancies are found while extracting parameters
+     * from the decrypted record, null is returned to denote the failure to decrypt.  Once all
+     * parameters are extracted.  The HOTP credentials are verified using the f1 and f2 parameters
+     * to check for integrity.
+     *
+     * @param password the password to use for decrypting the encrypted hotp attributes
+     * @param encrypted the attributes in that are encrypted, format encoded and base64 encoded
+     * @return a non-null HotpAttribute if the decryption succeed with verification, or null if it did not
+     * @throws UnsupportedEncodingException if the UTF-8 character encoding is not supported
+     */
+    public static HotpAttributes decrypt( String password, String encrypted ) throws UnsupportedEncodingException
+    {
+        // base 64 decode the input
+        byte[] input = Base64.decode( encrypted.toCharArray() );
+
+        // initialize the cipher wrapper and decrypt
+        BlockCipherWrapper engine = new BlockCipherWrapper( new DESEngine().getClass() );
+        byte[] decrypted = engine.decrypt( password, input );
+
+        // check that we have at least 19 bytes in the decrypted output if not return null for failure
+        if ( decrypted.length < 19 )
+        {
+            return null;
+        }
+
+        // get the f1 and f2 hotp values as longs for integrity verification
+        long f1 = decodeLong( decrypted, 0 );
+        long f2 = decodeLong( decrypted, 8 );
+
+        // get the hotpSize and make sure it's within a valid range if not return null for failure
+        int hotpSize = decodeUnsignedByte( decrypted[16] );
+        if ( 6 > hotpSize || hotpSize > 10 )
+        {
+            return null;
+        }
+
+        // get the moving factor value and the field for the length of the shared secret bytes
+        // determine if the length is valid, meaning that reading this length will not cause
+        // an index out of bounds exception by overrunning the size of the decrypted array
+        long factor = decodeLong( decrypted, 17 );
+        int secretLength = decodeUnsignedByte( decrypted[25] );
+        if ( secretLength + 26 >= decrypted.length )
+        {
+            return null;
+        }
+
+        // acquire the secret and begin verification to make sure decryption succeeded
+        byte[] secret = new byte[secretLength];
+        System.arraycopy( decrypted, 26, secret, 0, secretLength );
+        if ( f1 != Long.parseLong( Hotp.generate( secret, factor-1, hotpSize ) ) )
+        {
+            return null;
+        }
+        if ( f2 != Long.parseLong( Hotp.generate( secret, factor-2, hotpSize ) ) )
+        {
+            return null;
+        }
+
+        return new HotpAttributes( factor, secret );
+    }
+
+
+    /**
+     * Gets unsigned value of a byte as an int.
+     */
+    public static int decodeUnsignedByte( byte bite )
+    {
+        if ( bite > 0 )
+        {
+            return bite;
+        }
+
+        int value = 0;
+        value |= ( (int) bite ) & 0x000000ff;
+        return value;
+    }
+
+
+    /**
+     * Gets encoded byte value of a int as an unsigned bite.
+     */
+    public static byte encodeUnsignedByte( int unsignedByte )
+    {
+        if ( 0 > unsignedByte || unsignedByte > 255 )
+        {
+            StringBuffer buf = new StringBuffer();
+            buf.append( "unsignedByte are was " );
+            buf.append( unsignedByte );
+            buf.append( ": value must be in range [0-255]" );
+            throw new IllegalArgumentException( buf.toString() );
+        }
+
+        return ( byte ) unsignedByte;
+    }
+
+
+    /**
+     * Encodes a long into 8 bytes.
+     *
+     * @param source the long to encode
+     * @return the encoded 8 byte array
+     */
+    public static byte[] encodeLong( long source )
+    {
+        byte[] encoded = new byte[8];
+
+        encoded[7] = ( byte ) source;
+        encoded[6] = ( byte ) ( source >> 8 );
+        encoded[5] = ( byte ) ( source >> 16 );
+        encoded[4] = ( byte ) ( source >> 24 );
+        encoded[3] = ( byte ) ( source >> 32 );
+        encoded[2] = ( byte ) ( source >> 40 );
+        encoded[1] = ( byte ) ( source >> 48 );
+        encoded[0] = ( byte ) ( source >> 56 );
+
+        return encoded;
+    }
+
+
+    /**
+     * Decodes an 8 byte encoded long into a Java primitive long.
+     *
+     * @param bites the bytes containing the encoded long
+     * @param offset the offset from zero where the bytes begin
+     * @return the decoded primitive long
+     */
+    public static long decodeLong( byte[] bites, int offset )
+    {
+        long value = 0 ;
+
+        value |= ( ( (long) bites[offset] )   << 56 ) & 0xff00000000000000L;
+        value |= ( ( (long) bites[offset+1] ) << 48 ) & 0x00ff000000000000L;
+        value |= ( ( (long) bites[offset+2] ) << 40 ) & 0x0000ff0000000000L;
+        value |= ( ( (long) bites[offset+3] ) << 32 ) & 0x000000ff00000000L;
+        value |= ( ( (long) bites[offset+4] ) << 24 ) & 0x00000000ff000000L;
+        value |= ( ( (long) bites[offset+5] ) << 16 ) & 0x0000000000ff0000L;
+        value |= ( ( (long) bites[offset+6] ) << 8  ) & 0x000000000000ff00L;
+        value |=   ( (long) bites[offset+7] )         & 0x00000000000000ffL;
+
+        return value ;
+    }
+}



Mime
View raw message