directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kayyag...@apache.org
Subject svn commit: r1443107 [3/6] - in /directory/apacheds/trunk: interceptor-kerberos/src/main/java/org/apache/directory/server/core/kerberos/ kerberos-codec/ kerberos-codec/src/main/java/org/apache/directory/server/kerberos/changepwd/ kerberos-codec/src/mai...
Date Wed, 06 Feb 2013 18:19:39 GMT
Added: directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/KerberosConfig.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/KerberosConfig.java?rev=1443107&view=auto
==============================================================================
--- directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/KerberosConfig.java (added)
+++ directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/KerberosConfig.java Wed Feb  6 18:19:36 2013
@@ -0,0 +1,433 @@
+package org.apache.directory.server.kerberos;
+
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.security.auth.kerberos.KerberosPrincipal;
+
+import org.apache.directory.server.constants.ServerDNConstants;
+import org.apache.directory.shared.kerberos.KerberosUtils;
+import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
+import org.apache.directory.shared.kerberos.codec.types.PrincipalNameType;
+
+
+public class KerberosConfig
+{
+
+    /** The default kdc service principal */
+    public static final String DEFAULT_PRINCIPAL = "krbtgt/EXAMPLE.COM@EXAMPLE.COM";
+    
+    /** The default kdc realm */
+    public static final String DEFAULT_REALM = "EXAMPLE.COM";
+    
+    /** The default allowable clockskew */
+    public static final long DEFAULT_ALLOWABLE_CLOCKSKEW = 5 * 60000;
+    
+    /** The default for allowing empty addresses */
+    public static final boolean DEFAULT_EMPTY_ADDRESSES_ALLOWED = true;
+    
+    /** The default for requiring encrypted timestamps */
+    public static final boolean DEFAULT_PA_ENC_TIMESTAMP_REQUIRED = true;
+    
+    /** The default for the maximum ticket lifetime */
+    public static final int DEFAULT_TGS_MAXIMUM_TICKET_LIFETIME = 60000 * 1440;
+    
+    /** The default for the minimum ticket lifetime, 4 minutes */
+    public static final int DEFAULT_TGS_MINIMUM_TICKET_LIFETIME = 60000 * 4;
+    
+    /** The default for the maximum renewable lifetime */
+    public static final int DEFAULT_TGS_MAXIMUM_RENEWABLE_LIFETIME = 60000 * 10080;
+    
+    /** The default for allowing forwardable tickets */
+    public static final boolean DEFAULT_TGS_FORWARDABLE_ALLOWED = true;
+    
+    /** The default for allowing proxiable tickets */
+    public static final boolean DEFAULT_TGS_PROXIABLE_ALLOWED = true;
+    
+    /** The default for allowing postdated tickets */
+    public static final boolean DEFAULT_TGS_POSTDATED_ALLOWED = true;
+    
+    /** The default for allowing renewable tickets */
+    public static final boolean DEFAULT_TGS_RENEWABLE_ALLOWED = true;
+    
+    /** The default for verifying the body checksum */
+    public static final boolean DEFAULT_VERIFY_BODY_CHECKSUM = true;
+    
+    /** The default encryption types */
+    public static final String[] DEFAULT_ENCRYPTION_TYPES = new String[]
+        { "aes128-cts-hmac-sha1-96", "des-cbc-md5", "des3-cbc-sha1-kd" };
+    
+    /** The primary realm */
+    private String primaryRealm = KerberosConfig.DEFAULT_REALM;
+
+    /** The service principal name. */
+    private String servicePrincipal = KerberosConfig.DEFAULT_PRINCIPAL;
+
+    /** The allowable clock skew. */
+    private long allowableClockSkew = KerberosConfig.DEFAULT_ALLOWABLE_CLOCKSKEW;
+
+    /** Whether pre-authentication by encrypted timestamp is required. */
+    private boolean isPaEncTimestampRequired = KerberosConfig.DEFAULT_PA_ENC_TIMESTAMP_REQUIRED;
+
+    /** The maximum ticket lifetime. */
+    private long maximumTicketLifetime = KerberosConfig.DEFAULT_TGS_MAXIMUM_TICKET_LIFETIME;
+
+    /** The minimum ticket lifetime. */
+    private long minimumTicketLifetime = KerberosConfig.DEFAULT_TGS_MINIMUM_TICKET_LIFETIME;
+
+    /** The maximum renewable lifetime. */
+    private long maximumRenewableLifetime = KerberosConfig.DEFAULT_TGS_MAXIMUM_RENEWABLE_LIFETIME;
+
+    /** Whether empty addresses are allowed. */
+    private boolean isEmptyAddressesAllowed = KerberosConfig.DEFAULT_EMPTY_ADDRESSES_ALLOWED;
+
+    /** Whether forwardable addresses are allowed. */
+    private boolean isForwardableAllowed = KerberosConfig.DEFAULT_TGS_FORWARDABLE_ALLOWED;
+
+    /** Whether proxiable addresses are allowed. */
+    private boolean isProxiableAllowed = KerberosConfig.DEFAULT_TGS_PROXIABLE_ALLOWED;
+
+    /** Whether postdated tickets are allowed. */
+    private boolean isPostdatedAllowed = KerberosConfig.DEFAULT_TGS_POSTDATED_ALLOWED;
+
+    /** Whether renewable tickets are allowed. */
+    private boolean isRenewableAllowed = KerberosConfig.DEFAULT_TGS_RENEWABLE_ALLOWED;
+
+    /** Whether to verify the body checksum. */
+    private boolean isBodyChecksumVerified = KerberosConfig.DEFAULT_VERIFY_BODY_CHECKSUM;
+
+    /** The encryption types. */
+    private Set<EncryptionType> encryptionTypes;
+
+    /* cached kerberos/changepassword service principal */
+    private KerberosPrincipal srvPrincipal;
+    
+    private String searchBaseDn;
+    
+    public KerberosConfig()
+    {
+        setSearchBaseDn( ServerDNConstants.USER_EXAMPLE_COM_DN );
+        prepareEncryptionTypes();
+    }
+    
+    
+    /**
+     * Returns the allowable clock skew.
+     *
+     * @return The allowable clock skew.
+     */
+    public long getAllowableClockSkew()
+    {
+        return allowableClockSkew;
+    }
+
+
+    /**
+     * @return the isEmptyAddressesAllowed
+     */
+    public boolean isEmptyAddressesAllowed()
+    {
+        return isEmptyAddressesAllowed;
+    }
+
+
+    /**
+     * @return the isForwardableAllowed
+     */
+    public boolean isForwardableAllowed()
+    {
+        return isForwardableAllowed;
+    }
+
+
+    /**
+     * @return the isPostdatedAllowed
+     */
+    public boolean isPostdatedAllowed()
+    {
+        return isPostdatedAllowed;
+    }
+
+
+    /**
+     * @return the isProxiableAllowed
+     */
+    public boolean isProxiableAllowed()
+    {
+        return isProxiableAllowed;
+    }
+
+
+    /**
+     * @return the isRenewableAllowed
+     */
+    public boolean isRenewableAllowed()
+    {
+        return isRenewableAllowed;
+    }
+
+
+    /**
+     * @return the maximumRenewableLifetime
+     */
+    public long getMaximumRenewableLifetime()
+    {
+        return maximumRenewableLifetime;
+    }
+
+
+    /**
+     * @return the maximumTicketLifetime
+     */
+    public long getMaximumTicketLifetime()
+    {
+        return maximumTicketLifetime;
+    }
+
+
+    /**
+     * @param allowableClockSkew the allowableClockSkew to set
+     */
+    public void setAllowableClockSkew( long allowableClockSkew )
+    {
+        this.allowableClockSkew = allowableClockSkew;
+    }
+
+
+    /**
+     * Initialize the encryptionTypes set
+     * 
+     * @param encryptionTypes the encryptionTypes to set
+     */
+    public void setEncryptionTypes( EncryptionType[] encryptionTypes )
+    {
+        if ( encryptionTypes != null )
+        {
+            this.encryptionTypes.clear();
+
+            for ( EncryptionType encryptionType : encryptionTypes )
+            {
+                this.encryptionTypes.add( encryptionType );
+            }
+        }
+        
+        this.encryptionTypes = KerberosUtils.orderEtypesByStrength( this.encryptionTypes );
+    }
+
+
+    /**
+     * Initialize the encryptionTypes set
+     * 
+     * @param encryptionTypes the encryptionTypes to set
+     */
+    public void setEncryptionTypes( Set<EncryptionType> encryptionTypes )
+    {
+        this.encryptionTypes = KerberosUtils.orderEtypesByStrength( encryptionTypes );
+    }
+
+
+    /**
+     * @param isEmptyAddressesAllowed the isEmptyAddressesAllowed to set
+     */
+    public void setEmptyAddressesAllowed( boolean isEmptyAddressesAllowed )
+    {
+        this.isEmptyAddressesAllowed = isEmptyAddressesAllowed;
+    }
+
+
+    /**
+     * @param isForwardableAllowed the isForwardableAllowed to set
+     */
+    public void setForwardableAllowed( boolean isForwardableAllowed )
+    {
+        this.isForwardableAllowed = isForwardableAllowed;
+    }
+
+
+    /**
+     * @param isPaEncTimestampRequired the isPaEncTimestampRequired to set
+     */
+    public void setPaEncTimestampRequired( boolean isPaEncTimestampRequired )
+    {
+        this.isPaEncTimestampRequired = isPaEncTimestampRequired;
+    }
+
+
+    /**
+     * @param isPostdatedAllowed the isPostdatedAllowed to set
+     */
+    public void setPostdatedAllowed( boolean isPostdatedAllowed )
+    {
+        this.isPostdatedAllowed = isPostdatedAllowed;
+    }
+
+
+    /**
+     * @param isProxiableAllowed the isProxiableAllowed to set
+     */
+    public void setProxiableAllowed( boolean isProxiableAllowed )
+    {
+        this.isProxiableAllowed = isProxiableAllowed;
+    }
+
+
+    /**
+     * @param isRenewableAllowed the isRenewableAllowed to set
+     */
+    public void setRenewableAllowed( boolean isRenewableAllowed )
+    {
+        this.isRenewableAllowed = isRenewableAllowed;
+    }
+
+
+    /**
+     * @param kdcPrincipal the kdcPrincipal to set
+     */
+    public void setServicePrincipal( String kdcPrincipal )
+    {
+        this.servicePrincipal = kdcPrincipal;
+    }
+
+
+    /**
+     * @param maximumRenewableLifetime the maximumRenewableLifetime to set
+     */
+    public void setMaximumRenewableLifetime( long maximumRenewableLifetime )
+    {
+        this.maximumRenewableLifetime = maximumRenewableLifetime;
+    }
+
+
+    /**
+     * @param maximumTicketLifetime the maximumTicketLifetime to set
+     */
+    public void setMaximumTicketLifetime( long maximumTicketLifetime )
+    {
+        this.maximumTicketLifetime = maximumTicketLifetime;
+    }
+
+
+    /**
+     * @param primaryRealm the primaryRealm to set
+     */
+    public void setPrimaryRealm( String primaryRealm )
+    {
+        this.primaryRealm = primaryRealm;
+    }
+
+
+    /**
+     * Returns the primary realm.
+     *
+     * @return The primary realm.
+     */
+    public String getPrimaryRealm()
+    {
+        return primaryRealm;
+    }
+
+
+    /**
+     * Returns the service principal for this KDC/changepwd service.
+     *
+     * @return The service principal for this KDC/changepwd service.
+     */
+    public KerberosPrincipal getServicePrincipal()
+    {
+        if( srvPrincipal == null )
+        {
+            srvPrincipal = new KerberosPrincipal( servicePrincipal, PrincipalNameType.KRB_NT_SRV_INST.getValue() );
+        }
+        
+        return srvPrincipal;
+    }
+
+
+    /**
+     * Returns the encryption types.
+     *
+     * @return The encryption types.
+     */
+    public Set<EncryptionType> getEncryptionTypes()
+    {
+        return encryptionTypes;
+    }
+
+
+    /**
+     * Returns whether pre-authentication by encrypted timestamp is required.
+     *
+     * @return Whether pre-authentication by encrypted timestamp is required.
+     */
+    public boolean isPaEncTimestampRequired()
+    {
+        return isPaEncTimestampRequired;
+    }
+
+
+    /**
+     * @return the isBodyChecksumVerified
+     */
+    public boolean isBodyChecksumVerified()
+    {
+        return isBodyChecksumVerified;
+    }
+
+
+    /**
+     * @param isBodyChecksumVerified the isBodyChecksumVerified to set
+     */
+    public void setBodyChecksumVerified( boolean isBodyChecksumVerified )
+    {
+        this.isBodyChecksumVerified = isBodyChecksumVerified;
+    }
+
+    
+    public String getSearchBaseDn()
+    {
+        return searchBaseDn;
+    }
+
+
+    public void setSearchBaseDn( String searchBaseDn )
+    {
+        this.searchBaseDn = searchBaseDn;
+    }
+
+    
+    public long getMinimumTicketLifetime()
+    {
+        return minimumTicketLifetime;
+    }
+
+
+    public void setMinimumTicketLifetime( long minimumTicketLifetime )
+    {
+        this.minimumTicketLifetime = minimumTicketLifetime;
+    }
+
+
+    /**
+     * Construct an HashSet containing the default encryption types
+     */
+    private void prepareEncryptionTypes()
+    {
+        String[] encryptionTypeStrings = KerberosConfig.DEFAULT_ENCRYPTION_TYPES;
+
+        encryptionTypes = new HashSet<EncryptionType>();
+
+        for ( String enc : encryptionTypeStrings )
+        {
+            for ( EncryptionType type : EncryptionType.getEncryptionTypes() )
+            {
+                if ( type.getName().equalsIgnoreCase( enc ) )
+                {
+                    encryptionTypes.add( type );
+                }
+            }
+        }
+        
+        encryptionTypes = KerberosUtils.orderEtypesByStrength( encryptionTypes );
+    }
+}

Added: directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/ChangePasswordServer.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/ChangePasswordServer.java?rev=1443107&view=auto
==============================================================================
--- directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/ChangePasswordServer.java (added)
+++ directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/ChangePasswordServer.java Wed Feb  6 18:19:36 2013
@@ -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.apache.directory.server.kerberos.changepwd;
+
+
+import java.io.IOException;
+
+import net.sf.ehcache.Cache;
+
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.server.kerberos.ChangePasswordConfig;
+import org.apache.directory.server.kerberos.changepwd.protocol.ChangePasswordProtocolHandler;
+import org.apache.directory.server.kerberos.kdc.DirectoryPrincipalStore;
+import org.apache.directory.server.kerberos.shared.replay.ReplayCache;
+import org.apache.directory.server.kerberos.shared.replay.ReplayCacheImpl;
+import org.apache.directory.server.kerberos.shared.store.PrincipalStore;
+import org.apache.directory.server.protocol.shared.DirectoryBackedService;
+import org.apache.directory.server.protocol.shared.transport.TcpTransport;
+import org.apache.directory.server.protocol.shared.transport.Transport;
+import org.apache.directory.server.protocol.shared.transport.UdpTransport;
+import org.apache.mina.core.service.IoAcceptor;
+import org.apache.mina.transport.socket.DatagramSessionConfig;
+import org.apache.mina.transport.socket.SocketAcceptor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Contains the configuration parameters for the Change Password protocol provider.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ChangePasswordServer extends DirectoryBackedService
+{
+    /** logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( ChangePasswordServer.class.getName() );
+
+    /** The default change password port. */
+    private static final int DEFAULT_IP_PORT = 464;
+
+    /** The default change password password policy for password length. */
+    public static final int DEFAULT_PASSWORD_LENGTH = 6;
+
+    /** The default change password password policy for category count. */
+    public static final int DEFAULT_CATEGORY_COUNT = 3;
+
+    /** The default change password password policy for token size. */
+    public static final int DEFAULT_TOKEN_SIZE = 3;
+
+    private ChangePasswordConfig config;
+
+    /** the cache used for storing change password requests */
+    private ReplayCache replayCache;
+
+    /**
+     * Creates a new instance of ChangePasswordConfiguration.
+     */
+    public ChangePasswordServer()
+    {
+        this( new ChangePasswordConfig() );
+    }
+
+    
+    public ChangePasswordServer( ChangePasswordConfig config )
+    {
+        this.config = config;
+    }
+
+    
+    /**
+     * @throws IOException if we cannot bind to the specified ports
+     */
+    public void start() throws IOException, LdapInvalidDnException
+    {
+        PrincipalStore store = new DirectoryPrincipalStore( getDirectoryService(), new Dn(this.getSearchBaseDn())  );
+        
+        LOG.debug( "initializing the changepassword replay cache" );
+
+        Cache cache = getDirectoryService().getCacheService().getCache( "changePwdReplayCache" );
+        replayCache = new ReplayCacheImpl( cache );
+
+        for ( Transport transport:transports )
+        {
+            IoAcceptor acceptor = transport.getAcceptor();
+            
+            // Disable the disconnection of the clients on unbind
+            acceptor.setCloseOnDeactivation( false );
+            
+            if ( transport instanceof UdpTransport )
+            {
+                // Allow the port to be reused even if the socket is in TIME_WAIT state
+                ((DatagramSessionConfig)acceptor.getSessionConfig()).setReuseAddress( true );
+            }
+            else
+            {
+                // Allow the port to be reused even if the socket is in TIME_WAIT state
+                ((SocketAcceptor)acceptor).setReuseAddress( true );
+                
+                // No Nagle's algorithm
+                ((SocketAcceptor)acceptor).getSessionConfig().setTcpNoDelay( true );
+            }
+            
+            // Set the handler
+            acceptor.setHandler( new ChangePasswordProtocolHandler( this, store ) );
+            
+            // Bind
+            acceptor.bind();
+        }
+        
+        LOG.info( "ChangePassword service started." );
+        //System.out.println( "ChangePassword service started." );
+    }
+
+
+    public void stop()
+    {
+        for ( Transport transport :getTransports() )
+        {
+            IoAcceptor acceptor = transport.getAcceptor();
+            
+            if ( acceptor != null )
+            {
+                acceptor.dispose();
+            }
+        }
+
+        replayCache.clear();
+        
+        LOG.info( "ChangePassword service stopped." );
+        //System.out.println( "ChangePassword service stopped." );
+    }
+
+
+    /**
+     * @return the replayCache
+     */
+    public ReplayCache getReplayCache()
+    {
+        return replayCache;
+    }
+
+
+    public ChangePasswordConfig getConfig()
+    {
+        return config;
+    }
+
+    
+    public int getTcpPort()
+    {
+        for( Transport t : getTransports() )
+        {
+            if ( t instanceof TcpTransport )
+            {
+                return t.getPort();
+            }
+        }
+        
+        throw new IllegalStateException( "TCP transport is not enabled" );
+    }
+
+    
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+        
+        sb.append( "ChangePasswordServer[" ).append( getServiceName() ).append( "], listening on :" ).append( '\n' );
+        
+        if ( getTransports() != null )
+        {
+            for ( Transport transport:getTransports() )
+            {
+                sb.append( "    " ).append( transport ).append( '\n' );
+            }
+        }
+        
+        return sb.toString();
+    }
+}

Added: directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/package-info.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/package-info.java?rev=1443107&view=auto
==============================================================================
--- directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/package-info.java (added)
+++ directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/package-info.java Wed Feb  6 18:19:36 2013
@@ -0,0 +1,29 @@
+/*
+ *  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. 
+ *  
+ */
+
+/**
+ * Provides the entry point to an instance of the
+ * {@link org.apache.directory.server.changepw.ChangePasswordServer},
+ * as well as support for configuration.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+
+package org.apache.directory.server.kerberos.changepwd;

Added: directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/protocol/ChangePasswordProtocolCodecFactory.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/protocol/ChangePasswordProtocolCodecFactory.java?rev=1443107&view=auto
==============================================================================
--- directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/protocol/ChangePasswordProtocolCodecFactory.java (added)
+++ directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/protocol/ChangePasswordProtocolCodecFactory.java Wed Feb  6 18:19:36 2013
@@ -0,0 +1,67 @@
+/*
+ *  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.apache.directory.server.kerberos.changepwd.protocol;
+
+
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.codec.ProtocolCodecFactory;
+import org.apache.mina.filter.codec.ProtocolDecoder;
+import org.apache.mina.filter.codec.ProtocolEncoder;
+
+
+/**
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ChangePasswordProtocolCodecFactory implements ProtocolCodecFactory
+{
+    private static final ChangePasswordProtocolCodecFactory INSTANCE = new ChangePasswordProtocolCodecFactory();
+
+
+    /**
+     * Returns the singleton instance of {@link ChangePasswordProtocolCodecFactory}.
+     *
+     * @return The singleton instance of {@link ChangePasswordProtocolCodecFactory}.
+     */
+    public static ChangePasswordProtocolCodecFactory getInstance()
+    {
+        return INSTANCE;
+    }
+
+
+    private ChangePasswordProtocolCodecFactory()
+    {
+        // Private constructor prevents instantiation outside this class.
+    }
+
+
+    public ProtocolEncoder getEncoder( IoSession session )
+    {
+        // Create a new encoder.
+        return new MinaChangePasswordEncoder();
+    }
+
+
+    public ProtocolDecoder getDecoder( IoSession session )
+    {
+        // Create a new decoder.
+        return new MinaChangePasswordDecoder();
+    }
+}

Added: directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/protocol/ChangePasswordProtocolHandler.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/protocol/ChangePasswordProtocolHandler.java?rev=1443107&view=auto
==============================================================================
--- directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/protocol/ChangePasswordProtocolHandler.java (added)
+++ directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/protocol/ChangePasswordProtocolHandler.java Wed Feb  6 18:19:36 2013
@@ -0,0 +1,225 @@
+/*
+ *  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.apache.directory.server.kerberos.changepwd.protocol;
+
+
+import java.io.UnsupportedEncodingException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+
+import javax.security.auth.kerberos.KerberosPrincipal;
+
+import org.apache.directory.server.i18n.I18n;
+import org.apache.directory.server.kerberos.changepwd.ChangePasswordServer;
+import org.apache.directory.server.kerberos.changepwd.exceptions.ChangePasswdErrorType;
+import org.apache.directory.server.kerberos.changepwd.exceptions.ChangePasswordException;
+import org.apache.directory.server.kerberos.changepwd.messages.ChangePasswordError;
+import org.apache.directory.server.kerberos.changepwd.messages.ChangePasswordRequest;
+import org.apache.directory.server.kerberos.changepwd.service.ChangePasswordContext;
+import org.apache.directory.server.kerberos.changepwd.service.ChangePasswordService;
+import org.apache.directory.server.kerberos.shared.store.PrincipalStore;
+import org.apache.directory.shared.kerberos.KerberosTime;
+import org.apache.directory.shared.kerberos.components.PrincipalName;
+import org.apache.directory.shared.kerberos.exceptions.ErrorType;
+import org.apache.directory.shared.kerberos.exceptions.KerberosException;
+import org.apache.directory.shared.kerberos.messages.KrbError;
+import org.apache.mina.core.service.IoHandler;
+import org.apache.mina.core.session.IdleStatus;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.codec.ProtocolCodecFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ChangePasswordProtocolHandler implements IoHandler
+{
+    private static final Logger log = LoggerFactory.getLogger( ChangePasswordProtocolHandler.class );
+
+    private ChangePasswordServer server;
+    private PrincipalStore store;
+    private String contextKey = "context";
+
+
+    /**
+     * Creates a new instance of ChangePasswordProtocolHandler.
+     *
+     * @param config
+     * @param store
+     */
+    public ChangePasswordProtocolHandler( ChangePasswordServer config, PrincipalStore store )
+    {
+        this.server = config;
+        this.store = store;
+    }
+
+
+    public void sessionCreated( IoSession session ) throws Exception
+    {
+        if ( log.isDebugEnabled() )
+        {
+            log.debug( "{} CREATED:  {}", session.getRemoteAddress(), session.getTransportMetadata() );
+        }
+
+        session.getFilterChain().addFirst( "codec",
+            new ProtocolCodecFilter( ChangePasswordProtocolCodecFactory.getInstance() ) );
+    }
+
+
+    public void sessionOpened( IoSession session )
+    {
+        log.debug( "{} OPENED", session.getRemoteAddress() );
+    }
+
+
+    public void sessionClosed( IoSession session )
+    {
+        log.debug( "{} CLOSED", session.getRemoteAddress() );
+    }
+
+
+    public void sessionIdle( IoSession session, IdleStatus status )
+    {
+        log.debug( "{} IDLE ({})", session.getRemoteAddress(), status );
+    }
+
+
+    public void exceptionCaught( IoSession session, Throwable cause )
+    {
+        log.debug( session.getRemoteAddress() + " EXCEPTION", cause );
+        session.close( true );
+    }
+
+
+    public void messageReceived( IoSession session, Object message )
+    {
+        log.debug( "{} RCVD:  {}", session.getRemoteAddress(), message );
+
+        InetAddress clientAddress = ( ( InetSocketAddress ) session.getRemoteAddress() ).getAddress();
+        ChangePasswordRequest request = ( ChangePasswordRequest ) message;
+
+        try
+        {
+            ChangePasswordContext changepwContext = new ChangePasswordContext();
+            changepwContext.setConfig( server.getConfig() );
+            changepwContext.setStore( store );
+            changepwContext.setClientAddress( clientAddress );
+            changepwContext.setRequest( request );
+            changepwContext.setReplayCache( server.getReplayCache() );
+            session.setAttribute( getContextKey(), changepwContext );
+
+            ChangePasswordService.execute( session, changepwContext );
+
+            session.write( changepwContext.getReply() );
+        }
+        catch ( KerberosException ke )
+        {
+            if ( log.isDebugEnabled() )
+            {
+                log.warn( ke.getLocalizedMessage(), ke );
+            }
+            else
+            {
+                log.warn( ke.getLocalizedMessage() );
+            }
+
+            KrbError errorMessage = getErrorMessage( server.getConfig().getServicePrincipal(), ke );
+
+            session.write( new ChangePasswordError( request.getVersionNumber(), errorMessage ) );
+        }
+        catch ( Exception e )
+        {
+            log.error( I18n.err( I18n.ERR_152, e.getLocalizedMessage() ), e );
+
+            KrbError error = getErrorMessage( server.getConfig().getServicePrincipal(), new ChangePasswordException(
+                ChangePasswdErrorType.KRB5_KPASSWD_UNKNOWN_ERROR ) );
+            session.write( new ChangePasswordError( request.getVersionNumber(), error ) );
+        }
+    }
+
+
+    public void messageSent( IoSession session, Object message )
+    {
+        if ( log.isDebugEnabled() )
+        {
+            log.debug( "{} SENT:  {}", session.getRemoteAddress(), message );
+        }
+    }
+
+
+    protected String getContextKey()
+    {
+        return ( this.contextKey );
+    }
+
+
+    private KrbError getErrorMessage( KerberosPrincipal principal, KerberosException exception )
+    {
+        KrbError krbError = new KrbError();
+
+        KerberosTime now = new KerberosTime();
+
+        //FIXME not sure if this is the correct error to set for KrbError instance
+        // the correct change password protocol related error code is set in e-data anyway
+        krbError.setErrorCode( ErrorType.KRB_ERR_GENERIC );
+        krbError.setEText( exception.getLocalizedMessage() );
+        krbError.setSName( new PrincipalName( principal ) );
+        krbError.setSTime( now );
+        krbError.setSusec( 0 );
+        krbError.setEData( buildExplanatoryData( exception ) );
+
+        return krbError;
+    }
+
+
+    private byte[] buildExplanatoryData( KerberosException exception )
+    {
+        short resultCode = ( short ) exception.getErrorCode();
+
+        byte[] resultString =
+            { ( byte ) 0x00 };
+
+        if ( exception.getExplanatoryData() == null || exception.getExplanatoryData().length == 0 )
+        {
+            try
+            {
+                resultString = exception.getLocalizedMessage().getBytes( "UTF-8" );
+            }
+            catch ( UnsupportedEncodingException uee )
+            {
+                log.error( uee.getLocalizedMessage() );
+            }
+        }
+        else
+        {
+            resultString = exception.getExplanatoryData();
+        }
+
+        ByteBuffer byteBuffer = ByteBuffer.allocate( 2 + resultString.length );
+        byteBuffer.putShort( resultCode );
+        byteBuffer.put( resultString );
+
+        return byteBuffer.array();
+    }
+}

Added: directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/protocol/MinaChangePasswordDecoder.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/protocol/MinaChangePasswordDecoder.java?rev=1443107&view=auto
==============================================================================
--- directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/protocol/MinaChangePasswordDecoder.java (added)
+++ directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/protocol/MinaChangePasswordDecoder.java Wed Feb  6 18:19:36 2013
@@ -0,0 +1,79 @@
+/*
+ *  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.apache.directory.server.kerberos.changepwd.protocol;
+
+
+import org.apache.directory.server.i18n.I18n;
+import org.apache.directory.server.kerberos.changepwd.io.ChangePasswordDecoder;
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
+import org.apache.mina.filter.codec.ProtocolDecoderOutput;
+
+
+/**
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MinaChangePasswordDecoder extends CumulativeProtocolDecoder
+{
+    private int maxObjectSize = 16384; // 16KB
+
+
+    /**
+     * Returns the allowed maximum size of the object to be decoded.
+     * 
+     * @return The max object size.
+     */
+    public int getMaxObjectSize()
+    {
+        return maxObjectSize;
+    }
+
+
+    /**
+     * Sets the allowed maximum size of the object to be decoded.
+     * If the size of the object to be decoded exceeds this value, this
+     * decoder will throw a {@link IllegalArgumentException}.  The default
+     * value is <tt>16384</tt> (16KB).
+     * 
+     * @param maxObjectSize 
+     */
+    public void setMaxObjectSize( int maxObjectSize )
+    {
+        if ( maxObjectSize <= 0 )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_634, maxObjectSize ) );
+        }
+
+        this.maxObjectSize = maxObjectSize;
+    }
+
+
+    @Override
+    protected boolean doDecode( IoSession session, IoBuffer in, ProtocolDecoderOutput out ) throws Exception
+    {
+        boolean isTcp = !session.getTransportMetadata().isConnectionless();
+
+        out.write( ChangePasswordDecoder.decode( in.buf(), isTcp ) );
+
+        return true;
+    }
+}

Added: directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/protocol/MinaChangePasswordEncoder.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/protocol/MinaChangePasswordEncoder.java?rev=1443107&view=auto
==============================================================================
--- directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/protocol/MinaChangePasswordEncoder.java (added)
+++ directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/protocol/MinaChangePasswordEncoder.java Wed Feb  6 18:19:36 2013
@@ -0,0 +1,51 @@
+/*
+ *  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.apache.directory.server.kerberos.changepwd.protocol;
+
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.server.kerberos.changepwd.io.ChangePasswordEncoder;
+import org.apache.directory.server.kerberos.changepwd.messages.AbstractPasswordMessage;
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.codec.ProtocolEncoderAdapter;
+import org.apache.mina.filter.codec.ProtocolEncoderOutput;
+
+
+/**
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MinaChangePasswordEncoder extends ProtocolEncoderAdapter
+{
+    public void encode( IoSession session, Object message, ProtocolEncoderOutput out ) throws Exception
+    {
+        boolean isTcp = !session.getTransportMetadata().isConnectionless();
+        
+        ByteBuffer encodedByteBuf = ChangePasswordEncoder.encode( ( AbstractPasswordMessage ) message, isTcp );
+        
+        IoBuffer buf = IoBuffer.allocate( encodedByteBuf.remaining() );
+        buf.put( encodedByteBuf.array() );
+        buf.flip();
+        out.write( buf );
+    }
+}

Added: directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/protocol/package-info.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/protocol/package-info.java?rev=1443107&view=auto
==============================================================================
--- directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/protocol/package-info.java (added)
+++ directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/protocol/package-info.java Wed Feb  6 18:19:36 2013
@@ -0,0 +1,29 @@
+/*
+ *  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. 
+ *  
+ */
+
+/**
+ * Provides the {@link org.apache.mina.core.service.IoHandler} and associated
+ * {@link org.apache.mina.filter.codec.ProtocolCodecFactory} required
+ * to implement the Change Password Service with the MINA NIO framework.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+
+package org.apache.directory.server.kerberos.changepwd.protocol;

Added: directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/service/ChangePasswordContext.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/service/ChangePasswordContext.java?rev=1443107&view=auto
==============================================================================
--- directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/service/ChangePasswordContext.java (added)
+++ directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/service/ChangePasswordContext.java Wed Feb  6 18:19:36 2013
@@ -0,0 +1,260 @@
+/*
+ *  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.apache.directory.server.kerberos.changepwd.service;
+
+
+import java.net.InetAddress;
+
+import org.apache.directory.server.kerberos.ChangePasswordConfig;
+import org.apache.directory.server.kerberos.changepwd.messages.AbstractPasswordMessage;
+import org.apache.directory.server.kerberos.shared.crypto.encryption.CipherTextHandler;
+import org.apache.directory.server.kerberos.shared.replay.ReplayCache;
+import org.apache.directory.server.kerberos.shared.store.PrincipalStore;
+import org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntry;
+import org.apache.directory.shared.kerberos.messages.ApReq;
+import org.apache.directory.shared.kerberos.messages.Authenticator;
+import org.apache.directory.shared.kerberos.messages.ChangePasswdData;
+import org.apache.directory.shared.kerberos.messages.Ticket;
+
+
+/**
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ChangePasswordContext
+{
+    private ChangePasswordConfig config;
+    private PrincipalStore store;
+    private AbstractPasswordMessage request;
+    private AbstractPasswordMessage reply;
+    private InetAddress clientAddress;
+
+    private ApReq authHeader;
+    private Ticket ticket;
+    private Authenticator authenticator;
+    private PrincipalStoreEntry serverEntry;
+    private CipherTextHandler cipherTextHandler;
+    
+    private ReplayCache replayCache;
+
+    private ChangePasswdData passwordData;
+
+    /**
+     * @return Returns the serverEntry.
+     */
+    public PrincipalStoreEntry getServerEntry()
+    {
+        return serverEntry;
+    }
+
+
+    /**
+     * @param serverEntry The serverEntry to set.
+     */
+    public void setServerEntry( PrincipalStoreEntry serverEntry )
+    {
+        this.serverEntry = serverEntry;
+    }
+
+
+    /**
+     * @return gets the config.
+     */
+    public ChangePasswordConfig getConfig()
+    {
+        return config;
+    }
+
+
+    /**
+     * @param config The config to set.
+     */
+    public void setConfig( ChangePasswordConfig config )
+    {
+        this.config = config;
+    }
+
+
+    /**
+     * @return Returns the reply.
+     */
+    public AbstractPasswordMessage getReply()
+    {
+        return reply;
+    }
+
+
+    /**
+     * @param reply The reply to set.
+     */
+    public void setReply( AbstractPasswordMessage reply )
+    {
+        this.reply = reply;
+    }
+
+
+    /**
+     * @return Returns the request.
+     */
+    public AbstractPasswordMessage getRequest()
+    {
+        return request;
+    }
+
+
+    /**
+     * @param request The request to set.
+     */
+    public void setRequest( AbstractPasswordMessage request )
+    {
+        this.request = request;
+    }
+
+
+    /**
+     * @return Returns the store.
+     */
+    public PrincipalStore getStore()
+    {
+        return store;
+    }
+
+
+    /**
+     * @param store The store to set.
+     */
+    public void setStore( PrincipalStore store )
+    {
+        this.store = store;
+    }
+
+
+    /**
+     * @return Returns the {@link CipherTextHandler}.
+     */
+    public CipherTextHandler getCipherTextHandler()
+    {
+        return cipherTextHandler;
+    }
+
+
+    /**
+     * @param cipherTextHandler The {@link CipherTextHandler} to set.
+     */
+    public void setCipherTextHandler( CipherTextHandler cipherTextHandler )
+    {
+        this.cipherTextHandler = cipherTextHandler;
+    }
+
+
+    /**
+     * @return Returns the authenticator.
+     */
+    public Authenticator getAuthenticator()
+    {
+        return authenticator;
+    }
+
+
+    /**
+     * @param authenticator The authenticator to set.
+     */
+    public void setAuthenticator( Authenticator authenticator )
+    {
+        this.authenticator = authenticator;
+    }
+
+
+    /**
+     * @return Returns the authHeader.
+     */
+    public ApReq getAuthHeader()
+    {
+        return authHeader;
+    }
+
+
+    /**
+     * @param authHeader The authHeader to set.
+     */
+    public void setAuthHeader( ApReq authHeader )
+    {
+        this.authHeader = authHeader;
+    }
+
+
+    /**
+     * @return Returns the ticket.
+     */
+    public Ticket getTicket()
+    {
+        return ticket;
+    }
+
+
+    /**
+     * @param ticket The ticket to set.
+     */
+    public void setTicket( Ticket ticket )
+    {
+        this.ticket = ticket;
+    }
+
+
+    /**
+     * @return Returns the clientAddress.
+     */
+    public InetAddress getClientAddress()
+    {
+        return clientAddress;
+    }
+
+
+    /**
+     * @param clientAddress The clientAddress to set.
+     */
+    public void setClientAddress( InetAddress clientAddress )
+    {
+        this.clientAddress = clientAddress;
+    }
+
+
+    public ChangePasswdData getPasswordData()
+    {
+        return passwordData;
+    }
+
+
+    public void setChngPwdData( ChangePasswdData passwordData )
+    {
+        this.passwordData = passwordData;
+    }
+
+
+    public ReplayCache getReplayCache()
+    {
+        return replayCache;
+    }
+
+
+    public void setReplayCache( ReplayCache replayCache )
+    {
+        this.replayCache = replayCache;
+    }
+}

Added: directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/service/ChangePasswordService.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/service/ChangePasswordService.java?rev=1443107&view=auto
==============================================================================
--- directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/service/ChangePasswordService.java (added)
+++ directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/service/ChangePasswordService.java Wed Feb  6 18:19:36 2013
@@ -0,0 +1,427 @@
+/*
+ *  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.apache.directory.server.kerberos.changepwd.service;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+
+import javax.security.auth.kerberos.KerberosPrincipal;
+
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.util.Strings;
+import org.apache.directory.server.i18n.I18n;
+import org.apache.directory.server.kerberos.ChangePasswordConfig;
+import org.apache.directory.server.kerberos.changepwd.exceptions.ChangePasswdErrorType;
+import org.apache.directory.server.kerberos.changepwd.exceptions.ChangePasswordException;
+import org.apache.directory.server.kerberos.changepwd.messages.AbstractPasswordMessage;
+import org.apache.directory.server.kerberos.changepwd.messages.ChangePasswordReply;
+import org.apache.directory.server.kerberos.changepwd.messages.ChangePasswordRequest;
+import org.apache.directory.server.kerberos.protocol.codec.KerberosDecoder;
+import org.apache.directory.server.kerberos.shared.crypto.encryption.CipherTextHandler;
+import org.apache.directory.server.kerberos.shared.crypto.encryption.KeyUsage;
+import org.apache.directory.server.kerberos.shared.replay.ReplayCache;
+import org.apache.directory.server.kerberos.shared.store.PrincipalStore;
+import org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntry;
+import org.apache.directory.shared.kerberos.KerberosUtils;
+import org.apache.directory.shared.kerberos.codec.changePwdData.ChangePasswdDataContainer;
+import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
+import org.apache.directory.shared.kerberos.codec.types.PrincipalNameType;
+import org.apache.directory.shared.kerberos.components.EncKrbPrivPart;
+import org.apache.directory.shared.kerberos.components.EncryptedData;
+import org.apache.directory.shared.kerberos.components.EncryptionKey;
+import org.apache.directory.shared.kerberos.components.HostAddress;
+import org.apache.directory.shared.kerberos.components.HostAddresses;
+import org.apache.directory.shared.kerberos.components.PrincipalName;
+import org.apache.directory.shared.kerberos.exceptions.ErrorType;
+import org.apache.directory.shared.kerberos.exceptions.KerberosException;
+import org.apache.directory.shared.kerberos.messages.ApRep;
+import org.apache.directory.shared.kerberos.messages.ApReq;
+import org.apache.directory.shared.kerberos.messages.Authenticator;
+import org.apache.directory.shared.kerberos.messages.ChangePasswdData;
+import org.apache.directory.shared.kerberos.messages.EncApRepPart;
+import org.apache.directory.shared.kerberos.messages.KrbPriv;
+import org.apache.directory.shared.kerberos.messages.Ticket;
+import org.apache.mina.core.session.IoSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ChangePasswordService
+{
+    /** the logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( ChangePasswordService.class );
+
+    private static final CipherTextHandler cipherTextHandler = new CipherTextHandler();
+
+    public static void execute( IoSession session, ChangePasswordContext changepwContext ) throws Exception
+    {
+        if ( LOG.isDebugEnabled() )
+        {
+            monitorRequest( changepwContext );
+        }
+        
+        configureChangePassword( changepwContext );
+        getAuthHeader( changepwContext );
+        verifyServiceTicket( changepwContext );
+        getServerEntry( changepwContext );
+        verifyServiceTicketAuthHeader( changepwContext );
+        extractPassword( changepwContext );
+        
+        if ( LOG.isDebugEnabled() )
+        {
+            monitorContext( changepwContext );
+        }
+        
+        processPasswordChange( changepwContext );
+        buildReply( changepwContext );
+        
+        if ( LOG.isDebugEnabled() )
+        {
+            monitorReply( changepwContext );
+        }
+    }
+    
+    
+    private static void processPasswordChange( ChangePasswordContext changepwContext ) throws KerberosException
+    {
+        PrincipalStore store = changepwContext.getStore();
+        Authenticator authenticator = changepwContext.getAuthenticator();
+        String newPassword = Strings.utf8ToString( changepwContext.getPasswordData().getNewPasswd() );
+        KerberosPrincipal byPrincipal = KerberosUtils.getKerberosPrincipal( 
+            authenticator.getCName(),
+            authenticator.getCRealm() );
+
+        KerberosPrincipal targetPrincipal = null;
+
+        PrincipalName targName = changepwContext.getPasswordData().getTargName();
+        
+        if ( targName != null )
+        {
+            targetPrincipal = new KerberosPrincipal( targName.getNameString(), PrincipalNameType.KRB_NT_PRINCIPAL.getValue() );
+        }
+        else
+        {
+            targetPrincipal = byPrincipal;
+        }
+        
+        // usec and seq-number must be present per MS but aren't in legacy kpasswd
+        // seq-number must have same value as authenticator
+        // ignore r-address
+
+        store.changePassword( byPrincipal, targetPrincipal, newPassword, changepwContext.getTicket().getEncTicketPart().getFlags().isInitial() );
+        LOG.debug( "Successfully modified password for {} BY {}.", targetPrincipal, byPrincipal );
+    }
+    
+    
+    private static void monitorRequest( ChangePasswordContext changepwContext ) throws KerberosException
+    {
+        try
+        {
+            ChangePasswordRequest request = ( ChangePasswordRequest ) changepwContext.getRequest();
+            short versionNumber = request.getVersionNumber();
+
+            StringBuffer sb = new StringBuffer();
+            sb.append( "Responding to change password request:" );
+            sb.append( "\n\t" + "versionNumber    " + versionNumber );
+
+            LOG.debug( sb.toString() );
+        }
+        catch ( Exception e )
+        {
+            // This is a monitor.  No exceptions should bubble up.
+            LOG.error( I18n.err( I18n.ERR_152 ), e );
+        }
+    }
+    
+    
+    private static void configureChangePassword( ChangePasswordContext changepwContext )
+    {
+        changepwContext.setCipherTextHandler( cipherTextHandler );
+    }
+    
+    
+    private static void getAuthHeader( ChangePasswordContext changepwContext ) throws KerberosException
+    {
+        ChangePasswordRequest request = ( ChangePasswordRequest ) changepwContext.getRequest();
+
+        short pvno = request.getVersionNumber();
+        
+        if ( ( pvno != AbstractPasswordMessage.PVNO ) && ( pvno != AbstractPasswordMessage.OLD_PVNO ) )
+        {
+            throw new ChangePasswordException( ChangePasswdErrorType.KRB5_KPASSWD_BAD_VERSION );
+        }
+
+        if ( request.getAuthHeader() == null || request.getAuthHeader().getTicket() == null )
+        {
+            throw new ChangePasswordException( ChangePasswdErrorType.KRB5_KPASSWD_AUTHERROR );
+        }
+
+        ApReq authHeader = request.getAuthHeader();
+        Ticket ticket = authHeader.getTicket();
+
+        changepwContext.setAuthHeader( authHeader );
+        changepwContext.setTicket( ticket );
+    }
+    
+    
+    private static void verifyServiceTicket( ChangePasswordContext changepwContext ) throws KerberosException
+    {
+        ChangePasswordConfig config = changepwContext.getConfig();
+        Ticket ticket = changepwContext.getTicket();
+        String primaryRealm = config.getPrimaryRealm();
+        KerberosPrincipal changepwPrincipal = config.getServicePrincipal();
+        KerberosPrincipal serverPrincipal = KerberosUtils.getKerberosPrincipal( ticket.getSName(), ticket.getRealm() ); 
+
+        // for some reason kpassword is setting the pricnipaltype value as 1 for ticket.getSName()
+        // hence changing to string based comparison for server and changepw principals
+        // instead of serverPrincipal.equals( changepwPrincipal )
+        if ( !ticket.getRealm().equals( primaryRealm ) || !serverPrincipal.getName().equals( changepwPrincipal.getName() ) )
+        {
+            throw new KerberosException( org.apache.directory.shared.kerberos.exceptions.ErrorType.KRB_AP_ERR_NOT_US );
+        }
+    }
+    
+    
+    private static void getServerEntry( ChangePasswordContext changepwContext ) throws KerberosException
+    {
+        Ticket ticket = changepwContext.getTicket();
+        KerberosPrincipal principal =  KerberosUtils.getKerberosPrincipal( ticket.getSName(), ticket.getRealm() );
+        PrincipalStore store = changepwContext.getStore();
+
+        changepwContext.setServerEntry( KerberosUtils.getEntry( principal, store, ErrorType.KDC_ERR_S_PRINCIPAL_UNKNOWN ) );
+    }
+    
+    
+    private static void verifyServiceTicketAuthHeader( ChangePasswordContext changepwContext ) throws KerberosException
+    {
+        ApReq authHeader = changepwContext.getAuthHeader();
+        Ticket ticket = changepwContext.getTicket();
+
+        EncryptionType encryptionType = ticket.getEncPart().getEType();
+        EncryptionKey serverKey = changepwContext.getServerEntry().getKeyMap().get( encryptionType );
+
+        long clockSkew = changepwContext.getConfig().getAllowableClockSkew();
+        ReplayCache replayCache = changepwContext.getReplayCache();
+        boolean emptyAddressesAllowed = changepwContext.getConfig().isEmptyAddressesAllowed();
+        InetAddress clientAddress = changepwContext.getClientAddress();
+        CipherTextHandler cipherTextHandler = changepwContext.getCipherTextHandler();
+
+        Authenticator authenticator = KerberosUtils.verifyAuthHeader( authHeader, ticket, serverKey, clockSkew, replayCache,
+            emptyAddressesAllowed, clientAddress, cipherTextHandler, KeyUsage.AP_REQ_AUTHNT_SESS_KEY, false );
+
+        changepwContext.setAuthenticator( authenticator );
+    }
+    
+    
+    private static void extractPassword( ChangePasswordContext changepwContext ) throws Exception
+    {
+        ChangePasswordRequest request = ( ChangePasswordRequest ) changepwContext.getRequest();
+        Authenticator authenticator = changepwContext.getAuthenticator();
+        CipherTextHandler cipherTextHandler = changepwContext.getCipherTextHandler();
+
+        // get the subsession key from the Authenticator
+        EncryptionKey subSessionKey = authenticator.getSubKey();
+
+        // decrypt the request's private message with the subsession key
+        EncryptedData encReqPrivPart = request.getPrivateMessage().getEncPart();
+
+        ChangePasswdData passwordData = null;
+        
+        try
+        {
+            byte[] decryptedData = cipherTextHandler.decrypt( subSessionKey, encReqPrivPart, KeyUsage.KRB_PRIV_ENC_PART_CHOSEN_KEY );
+            EncKrbPrivPart privatePart = KerberosDecoder.decodeEncKrbPrivPart( decryptedData );
+
+            if( authenticator.getSeqNumber() != privatePart.getSeqNumber() )
+            {
+                throw new ChangePasswordException( ChangePasswdErrorType.KRB5_KPASSWD_MALFORMED );    
+            }
+            
+            if ( request.getVersionNumber() == AbstractPasswordMessage.OLD_PVNO )
+            {
+                passwordData = new ChangePasswdData();
+                passwordData.setNewPasswd( privatePart.getUserData() );
+            }
+            else
+            {
+                Asn1Decoder passwordDecoder = new Asn1Decoder();
+                ByteBuffer stream = ByteBuffer.wrap( privatePart.getUserData() );
+                ChangePasswdDataContainer container = new ChangePasswdDataContainer( stream );
+                passwordDecoder.decode( stream, container );
+                passwordData = container.getChngPwdData();
+            }
+        }
+        catch ( KerberosException ke )
+        {
+            throw new ChangePasswordException( ChangePasswdErrorType.KRB5_KPASSWD_SOFTERROR, ke );
+        }
+
+        changepwContext.setChngPwdData( passwordData );
+    }
+
+    
+    private static void monitorContext( ChangePasswordContext changepwContext ) throws KerberosException
+    {
+        try
+        {
+            PrincipalStore store = changepwContext.getStore();
+            ApReq authHeader = changepwContext.getAuthHeader();
+            Ticket ticket = changepwContext.getTicket();
+            ReplayCache replayCache = changepwContext.getReplayCache();
+            long clockSkew = changepwContext.getConfig().getAllowableClockSkew();
+
+            Authenticator authenticator = changepwContext.getAuthenticator();
+            KerberosPrincipal clientPrincipal = KerberosUtils.getKerberosPrincipal( 
+                authenticator.getCName(), authenticator.getCRealm() );
+
+            InetAddress clientAddress = changepwContext.getClientAddress();
+            HostAddresses clientAddresses = ticket.getEncTicketPart().getClientAddresses();
+
+            boolean caddrContainsSender = false;
+
+            if ( ticket.getEncTicketPart().getClientAddresses() != null )
+            {
+                caddrContainsSender = ticket.getEncTicketPart().getClientAddresses().contains( new HostAddress( clientAddress ) );
+            }
+
+            StringBuffer sb = new StringBuffer();
+            sb.append( "Monitoring context:" );
+            sb.append( "\n\t" + "store                  " + store );
+            sb.append( "\n\t" + "authHeader             " + authHeader );
+            sb.append( "\n\t" + "ticket                 " + ticket );
+            sb.append( "\n\t" + "replayCache            " + replayCache );
+            sb.append( "\n\t" + "clockSkew              " + clockSkew );
+            sb.append( "\n\t" + "clientPrincipal        " + clientPrincipal );
+            sb.append( "\n\t" + "ChangePasswdData        " + changepwContext.getPasswordData() );
+            sb.append( "\n\t" + "clientAddress          " + clientAddress );
+            sb.append( "\n\t" + "clientAddresses        " + clientAddresses );
+            sb.append( "\n\t" + "caddr contains sender  " + caddrContainsSender );
+            sb.append( "\n\t" + "Ticket principal       " + ticket.getSName() );
+
+            PrincipalStoreEntry ticketPrincipal = changepwContext.getServerEntry();
+            
+            sb.append( "\n\t" + "cn                     " + ticketPrincipal.getCommonName() );
+            sb.append( "\n\t" + "realm                  " + ticketPrincipal.getRealmName() );
+            sb.append( "\n\t" + "Service principal      " + ticketPrincipal.getPrincipal() );
+            sb.append( "\n\t" + "SAM type               " + ticketPrincipal.getSamType() );
+
+            EncryptionType encryptionType = ticket.getEncPart().getEType();
+            int keyVersion = ticketPrincipal.getKeyMap().get( encryptionType ).getKeyVersion();
+            sb.append( "\n\t" + "Ticket key type        " + encryptionType );
+            sb.append( "\n\t" + "Service key version    " + keyVersion );
+
+            LOG.debug( sb.toString() );
+        }
+        catch ( Exception e )
+        {
+            // This is a monitor.  No exceptions should bubble up.
+            LOG.error( I18n.err( I18n.ERR_154 ), e );
+        }
+    }
+    
+    
+    private static void buildReply( ChangePasswordContext changepwContext ) throws KerberosException, UnknownHostException
+    {
+        Authenticator authenticator = changepwContext.getAuthenticator();
+        Ticket ticket = changepwContext.getTicket();
+        CipherTextHandler cipherTextHandler = changepwContext.getCipherTextHandler();
+
+        // begin building reply
+
+        // create priv message
+        // user-data component is short result code
+        EncKrbPrivPart privPart = new EncKrbPrivPart();
+        // first two bytes are the result code, rest is the string 'Password Changed' followed by a null char
+        byte[] resultCode =
+            { ( byte ) 0x00, ( byte ) 0x00, (byte)0x50, (byte)0x61, (byte)0x73, (byte)0x73, (byte)0x77, (byte)0x6F, (byte)0x72, (byte)0x64, (byte)0x20, (byte)0x63, (byte)0x68, (byte)0x61, (byte)0x6E, (byte)0x67, (byte)0x65, (byte)0x64, (byte)0x00 };
+        privPart.setUserData( resultCode );
+
+        privPart.setSenderAddress( new HostAddress( InetAddress.getLocalHost() ) );
+
+        // get the subsession key from the Authenticator
+        EncryptionKey subSessionKey = authenticator.getSubKey();
+
+        EncryptedData encPrivPart;
+
+        try
+        {
+            encPrivPart = cipherTextHandler.seal( subSessionKey, privPart, KeyUsage.KRB_PRIV_ENC_PART_CHOSEN_KEY );
+        }
+        catch ( KerberosException ke )
+        {
+            throw new ChangePasswordException( ChangePasswdErrorType.KRB5_KPASSWD_SOFTERROR, ke );
+        }
+
+        KrbPriv privateMessage = new KrbPriv();
+        privateMessage.setEncPart( encPrivPart );
+
+        // Begin AP_REP generation
+        EncApRepPart repPart = new EncApRepPart();
+        repPart.setCTime( authenticator.getCtime() );
+        repPart.setCusec( authenticator.getCusec() );
+        
+        if ( authenticator.getSeqNumber() != null )
+        {
+            repPart.setSeqNumber( authenticator.getSeqNumber() );
+        }
+        
+        repPart.setSubkey( subSessionKey );
+
+        EncryptedData encRepPart;
+
+        try
+        {
+            encRepPart = cipherTextHandler.seal( ticket.getEncTicketPart().getKey(), repPart, KeyUsage.AP_REP_ENC_PART_SESS_KEY );
+        }
+        catch ( KerberosException ke )
+        {
+            throw new ChangePasswordException( ChangePasswdErrorType.KRB5_KPASSWD_SOFTERROR, ke );
+        }
+
+        ApRep appReply = new ApRep();
+        appReply.setEncPart( encRepPart );
+
+        // return status message value object, the version number 
+        changepwContext.setReply( new ChangePasswordReply( AbstractPasswordMessage.OLD_PVNO, appReply, privateMessage ) );
+    }
+
+    
+    private static void monitorReply( ChangePasswordContext changepwContext ) throws KerberosException
+    {
+        try
+        {
+            ChangePasswordReply reply = ( ChangePasswordReply ) changepwContext.getReply();
+            ApRep appReply = reply.getApplicationReply();
+            KrbPriv priv = reply.getPrivateMessage();
+
+            StringBuilder sb = new StringBuilder();
+            sb.append( "Responding with change password reply:" );
+            sb.append( "\n\t" + "appReply               " + appReply );
+            sb.append( "\n\t" + "priv                   " + priv );
+
+            LOG.debug( sb.toString() );
+        }
+        catch ( Exception e )
+        {
+            // This is a monitor.  No exceptions should bubble up.
+            LOG.error( I18n.err( I18n.ERR_155 ), e );
+        }
+    }
+}

Added: directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/service/package-info.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/service/package-info.java?rev=1443107&view=auto
==============================================================================
--- directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/service/package-info.java (added)
+++ directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/changepwd/service/package-info.java Wed Feb  6 18:19:36 2013
@@ -0,0 +1,27 @@
+/*
+ *  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. 
+ *  
+ */
+
+/**
+ * Provides the Change Password Service.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+
+package org.apache.directory.server.kerberos.changepwd.service;

Added: directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/DirectoryPrincipalStore.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/DirectoryPrincipalStore.java?rev=1443107&view=auto
==============================================================================
--- directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/DirectoryPrincipalStore.java (added)
+++ directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/DirectoryPrincipalStore.java Wed Feb  6 18:19:36 2013
@@ -0,0 +1,148 @@
+/*
+ *   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.apache.directory.server.kerberos.kdc;
+
+
+import javax.security.auth.kerberos.KerberosPrincipal;
+
+import org.apache.directory.api.ldap.model.constants.AuthenticationLevel;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.DefaultModification;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.util.Strings;
+import org.apache.directory.server.constants.ServerDNConstants;
+import org.apache.directory.server.core.api.CoreSession;
+import org.apache.directory.server.core.api.DirectoryService;
+import org.apache.directory.server.core.api.LdapPrincipal;
+import org.apache.directory.server.core.shared.DefaultCoreSession;
+import org.apache.directory.server.kerberos.changepwd.exceptions.ChangePasswdErrorType;
+import org.apache.directory.server.kerberos.changepwd.exceptions.ChangePasswordException;
+import org.apache.directory.server.kerberos.shared.store.PrincipalStore;
+import org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntry;
+import org.apache.directory.server.protocol.shared.kerberos.GetPrincipal;
+import org.apache.directory.server.protocol.shared.kerberos.StoreUtils;
+import org.apache.directory.shared.kerberos.KerberosAttribute;
+
+
+/**
+ * A PrincipalStore backing entries in a DirectoryService.
+ * 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DirectoryPrincipalStore implements PrincipalStore
+{
+    /** The directory service backing store for this PrincipalStore. */
+    private final DirectoryService directoryService;
+    private final Dn searchBaseDn;
+    
+    private CoreSession adminSession;
+    
+    /**
+     * Creates a new instance of DirectoryPrincipalStore.
+     *
+     * @param directoryService backing store for this PrincipalStore
+     */
+    public DirectoryPrincipalStore( DirectoryService directoryService, Dn searchBaseDn )
+    {
+        this.directoryService = directoryService;
+        this.adminSession = directoryService.getAdminSession();
+        this.searchBaseDn = searchBaseDn;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void changePassword( KerberosPrincipal byPrincipal, KerberosPrincipal forPrincipal, String newPassword, boolean isInitialTicket ) throws ChangePasswordException
+    {
+        try
+        {
+            Entry ebyPrincipalEntry = null;
+            
+            ebyPrincipalEntry = StoreUtils.findPrincipalEntry( adminSession, searchBaseDn, byPrincipal.getName() );
+            
+            if( ebyPrincipalEntry == null )
+            {
+                throw new ChangePasswordException( ChangePasswdErrorType.KRB5_KPASSWD_HARDERROR, ( "No such principal " + byPrincipal ).getBytes() );
+            }
+            
+            SchemaManager schemaManager = directoryService.getSchemaManager();
+            
+            CoreSession bySession = null;
+         
+            boolean isAdmin = ebyPrincipalEntry.getDn().getNormName().equals( ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
+            
+            if ( !isInitialTicket && !isAdmin )
+            {
+                throw new ChangePasswordException( ChangePasswdErrorType.KRB5_KPASSWD_INITIAL_FLAG_NEEDED );
+            }
+
+            // if admin assign the admin session
+            if( isAdmin )
+            {
+                bySession = adminSession;
+            }
+            // otherwise create a new session for the user with 'byPrincipal' who is trying to change the password for 'forPrincipal' 
+            else
+            {
+                LdapPrincipal byLdapPrincipal = new LdapPrincipal( schemaManager, ebyPrincipalEntry.getDn(), AuthenticationLevel.SIMPLE );
+                
+                bySession = new DefaultCoreSession( byLdapPrincipal, directoryService );
+            }
+            
+            Attribute newPasswordAttribute = new DefaultAttribute(
+                schemaManager.lookupAttributeTypeRegistry( SchemaConstants.USER_PASSWORD_AT ), Strings.getBytesUtf8(newPassword) );
+            Modification passwordMod = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, newPasswordAttribute );
+            
+            Attribute principalAttribute = new DefaultAttribute( 
+                schemaManager.lookupAttributeTypeRegistry( KerberosAttribute.KRB5_PRINCIPAL_NAME_AT ), forPrincipal.getName() );
+            Modification principalMod = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, principalAttribute );
+            
+            Entry forPrincipalEntry = StoreUtils.findPrincipalEntry( bySession, searchBaseDn, forPrincipal.getName() );
+            
+            adminSession.modify( forPrincipalEntry.getDn(), passwordMod, principalMod );
+        }
+        catch( LdapException e )
+        {
+            throw new ChangePasswordException( ChangePasswdErrorType.KRB5_KPASSWD_ACCESSDENIED, e );            
+        }
+        catch( Exception e )
+        {
+            throw new ChangePasswordException( ChangePasswdErrorType.KRB5_KPASSWD_HARDERROR, e );            
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public PrincipalStoreEntry getPrincipal( KerberosPrincipal principal ) throws Exception
+    {
+        return ( PrincipalStoreEntry ) new GetPrincipal( principal ).execute( adminSession, searchBaseDn );
+    }
+}

Modified: directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/KdcContext.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/KdcContext.java?rev=1443107&r1=1443106&r2=1443107&view=diff
==============================================================================
--- directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/KdcContext.java (original)
+++ directory/apacheds/trunk/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/KdcContext.java Wed Feb  6 18:19:36 2013
@@ -22,7 +22,9 @@ package org.apache.directory.server.kerb
 
 import java.net.InetAddress;
 
+import org.apache.directory.server.kerberos.KerberosConfig;
 import org.apache.directory.server.kerberos.shared.crypto.encryption.CipherTextHandler;
+import org.apache.directory.server.kerberos.shared.replay.ReplayCache;
 import org.apache.directory.server.kerberos.shared.store.PrincipalStore;
 import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
 import org.apache.directory.shared.kerberos.components.KdcReq;
@@ -36,7 +38,7 @@ public class KdcContext
 {
     private static final long serialVersionUID = 6490030984626825108L;
 
-    private KdcServer config;
+    private KerberosConfig config;
     private PrincipalStore store;
     private KdcReq request;
     private KerberosMessage reply;
@@ -44,11 +46,13 @@ public class KdcContext
     private CipherTextHandler cipherTextHandler;
     private EncryptionType encryptionType;
 
+    /** the replay cache */
+    private ReplayCache replayCache;
 
     /**
      * @return Returns the config.
      */
-    public KdcServer getConfig()
+    public KerberosConfig getConfig()
     {
         return config;
     }
@@ -57,7 +61,7 @@ public class KdcContext
     /**
      * @param config The config to set.
      */
-    public void setConfig( KdcServer config )
+    public void setConfig( KerberosConfig config )
     {
         this.config = config;
     }
@@ -173,4 +177,24 @@ public class KdcContext
     {
         this.encryptionType = encryptionType;
     }
+    
+    
+    /**
+     * sets the replay cache
+     *
+     * @param replayCache
+     */
+    public void setReplayCache( ReplayCache replayCache )
+    {
+        this.replayCache = replayCache;
+    }
+
+
+    /**
+     * @return the replay cache
+     */
+    public ReplayCache getReplayCache()
+    {
+        return replayCache;
+    }
 }



Mime
View raw message