Return-Path: Delivered-To: apmail-directory-commits-archive@www.apache.org Received: (qmail 85656 invoked from network); 29 Oct 2007 18:06:29 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 29 Oct 2007 18:06:29 -0000 Received: (qmail 24073 invoked by uid 500); 29 Oct 2007 18:05:17 -0000 Delivered-To: apmail-directory-commits-archive@directory.apache.org Received: (qmail 24031 invoked by uid 500); 29 Oct 2007 18:05:17 -0000 Mailing-List: contact commits-help@directory.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@directory.apache.org Delivered-To: mailing list commits@directory.apache.org Received: (qmail 24017 invoked by uid 99); 29 Oct 2007 18:05:17 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 29 Oct 2007 11:05:17 -0700 X-ASF-Spam-Status: No, hits=-100.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 29 Oct 2007 18:05:29 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id E82351A9832; Mon, 29 Oct 2007 11:05:08 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r589775 - in /directory/apacheds/branches/bigbang/kerberos-shared/src: main/java/org/apache/directory/server/kerberos/shared/replay/ test/java/org/apache/directory/server/kerberos/shared/replay/ Date: Mon, 29 Oct 2007 18:05:02 -0000 To: commits@directory.apache.org From: elecharny@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20071029180508.E82351A9832@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: elecharny Date: Mon Oct 29 11:04:59 2007 New Revision: 589775 URL: http://svn.apache.org/viewvc?rev=589775&view=rev Log: Refactored the replay cache : - we now use a thread to clean the cache - the entries are stored into a hashMap to speedup the cleaning - the key is the clientprincipal - for each clientPrincipal, we store a list of entries - when the cleaning thread is running, we remove from the beginning of the list all the timed out entries Added: directory/apacheds/branches/bigbang/kerberos-shared/src/test/java/org/apache/directory/server/kerberos/shared/replay/ directory/apacheds/branches/bigbang/kerberos-shared/src/test/java/org/apache/directory/server/kerberos/shared/replay/InMemoryReplayCacheTest.java Modified: directory/apacheds/branches/bigbang/kerberos-shared/src/main/java/org/apache/directory/server/kerberos/shared/replay/InMemoryReplayCache.java directory/apacheds/branches/bigbang/kerberos-shared/src/main/java/org/apache/directory/server/kerberos/shared/replay/ReplayCache.java Modified: directory/apacheds/branches/bigbang/kerberos-shared/src/main/java/org/apache/directory/server/kerberos/shared/replay/InMemoryReplayCache.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/kerberos-shared/src/main/java/org/apache/directory/server/kerberos/shared/replay/InMemoryReplayCache.java?rev=589775&r1=589774&r2=589775&view=diff ============================================================================== --- directory/apacheds/branches/bigbang/kerberos-shared/src/main/java/org/apache/directory/server/kerberos/shared/replay/InMemoryReplayCache.java (original) +++ directory/apacheds/branches/bigbang/kerberos-shared/src/main/java/org/apache/directory/server/kerberos/shared/replay/InMemoryReplayCache.java Mon Oct 29 11:04:59 2007 @@ -21,8 +21,11 @@ import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import javax.security.auth.kerberos.KerberosPrincipal; @@ -33,61 +36,37 @@ * "The replay cache will store at least the server name, along with the client name, * time, and microsecond fields from the recently-seen authenticators, and if a * matching tuple is found, the KRB_AP_ERR_REPEAT error is returned." + * + * We will store the entries using an HashMap which key will be the client + * principal, and we will store a list of entries for each client principal. + * + * A thread will run every N seconds to clean the cache from entries out of the + * clockSkew * * @author Apache Directory Project * @version $Rev$, $Date$ */ -public class InMemoryReplayCache implements ReplayCache +public class InMemoryReplayCache extends Thread implements ReplayCache { - private List list = new ArrayList(); - - private long clockSkew = 5 * KerberosTime.MINUTE; + /** Stores the entries in memory */ + private Map> cache = new HashMap>(); + /** default clock skew */ + private static final long DEFAULT_CLOCK_SKEW = 5 * KerberosTime.MINUTE; + + /** The clock skew */ + private long clockSkew = DEFAULT_CLOCK_SKEW; + + /** The default delay between each run of the cleaning process : 5 s */ + private static long DEFAULT_DELAY = 5 * 1000; + + /** The delay to wait between each cache cleaning */ + private long delay; /** - * Sets the clock skew. - * - * @param clockSkew + * A structure to hold an entry */ - public void setClockSkew( long clockSkew ) - { - this.clockSkew = clockSkew; - } - - - public synchronized boolean isReplay( KerberosPrincipal serverPrincipal, KerberosPrincipal clientPrincipal, - KerberosTime clientTime, int clientMicroSeconds ) - { - ReplayCacheEntry testEntry = new ReplayCacheEntry( serverPrincipal, clientPrincipal, clientTime, - clientMicroSeconds ); - - Iterator it = list.iterator(); - while ( it.hasNext() ) - { - ReplayCacheEntry entry = it.next(); - - if ( entry.equals( testEntry ) ) - { - return true; - } - - if ( entry.isOutsideClockSkew( clockSkew ) ) - { - it.remove(); - } - } - - return false; - } - - - public synchronized void save( KerberosPrincipal serverPrincipal, KerberosPrincipal clientPrincipal, - KerberosTime clientTime, int clientMicroSeconds ) - { - list.add( new ReplayCacheEntry( serverPrincipal, clientPrincipal, clientTime, clientMicroSeconds ) ); - } - - private class ReplayCacheEntry + public class ReplayCacheEntry { private KerberosPrincipal serverPrincipal; private KerberosPrincipal clientPrincipal; @@ -137,6 +116,200 @@ public boolean isOutsideClockSkew( long clockSkew ) { return !clientTime.isInClockSkew( clockSkew ); + } + } + + + /** + * Creates a new instance of InMemoryReplayCache. Sets the + * delay between each cleaning run to 5 seconds. + */ + public InMemoryReplayCache() + { + cache = new HashMap>(); + delay = DEFAULT_DELAY; + this.start(); + } + + + /** + * Creates a new instance of InMemoryReplayCache. Sets the + * delay between each cleaning run to 5 seconds. Sets the + * clockSkew to the given value + * + * @param clockSkew the allowed skew (milliseconds) + */ + public InMemoryReplayCache( long clockSkew ) + { + cache = new HashMap>(); + delay = DEFAULT_DELAY; + this.clockSkew = clockSkew; + this.start(); + } + + + /** + * Creates a new instance of InMemoryReplayCache. Sets the + * clockSkew to the given value, and set the cleaning thread + * kick off delay + * + * @param clockSkew the allowed skew (milliseconds) + * @param delay the interval between each run of the cache + * cleaning thread (milliseconds) + */ + public InMemoryReplayCache( long clockSkew, int delay ) + { + cache = new HashMap>(); + this.delay = (long)delay; + this.clockSkew = clockSkew; + this.start(); + } + + + /** + * Creates a new instance of InMemoryReplayCache. Sets the + * delay between each cleaning run to 5 seconds. Sets the + * cleaning thread kick off delay + * + * @param delay the interval between each run of the cache + * cleaning thread (milliseconds). + */ + public InMemoryReplayCache( int delay ) + { + cache = new HashMap>(); + this.delay = (long)delay; + this.clockSkew = DEFAULT_CLOCK_SKEW; + } + + + /** + * Sets the clock skew. + * + * @param clockSkew + */ + public void setClockSkew( long clockSkew ) + { + this.clockSkew = clockSkew; + } + + + /** + * Set the delay between each cleaning thread run. + * + * @param delay delay in milliseconds + */ + public void setDelay( long delay ) + { + this.delay = delay; + } + + /** + * Check if an entry is a replay or not. + */ + public synchronized boolean isReplay( KerberosPrincipal serverPrincipal, KerberosPrincipal clientPrincipal, + KerberosTime clientTime, int clientMicroSeconds ) + { + List entries = cache.get( clientPrincipal ); + + if ( ( entries == null ) || ( entries.size() == 0 ) ) + { + return false; + } + + for ( ReplayCacheEntry entry:entries ) + { + if ( serverPrincipal.equals( entry.serverPrincipal ) && + clientTime.equals( entry.clientTime ) && + (clientMicroSeconds == entry.clientMicroSeconds ) ) + { + return true; + } + } + + return false; + } + + + /** + * Add a new entry into the cache. A thread will clean all the timed out + * entries. + */ + public synchronized void save( KerberosPrincipal serverPrincipal, KerberosPrincipal clientPrincipal, + KerberosTime clientTime, int clientMicroSeconds ) + { + List entries = cache.get( clientPrincipal ); + + if ( entries == null ) + { + entries = new ArrayList(); + } + + entries.add( new ReplayCacheEntry( serverPrincipal, clientPrincipal, clientTime, clientMicroSeconds ) ); + + cache.put( clientPrincipal, entries ); + } + + + public Map> getCache() + { + return cache; + } + + /** + * A method to remove all the expired entries from the cache. + */ + private synchronized void cleanCache() + { + Collection> entryList = cache.values(); + + if ( ( entryList == null ) || ( entryList.size() == 0 ) ) + { + return; + } + + for ( List entries:entryList ) + { + if ( ( entries == null ) || ( entries.size() == 0 ) ) + { + continue; + } + + Iterator iterator = entries.iterator(); + + while ( iterator.hasNext() ) + { + ReplayCacheEntry entry = iterator.next(); + + if ( entry.isOutsideClockSkew( clockSkew ) ) + { + iterator.remove(); + } + else + { + break; + } + } + } + } + + + /** + * The cleaning thread. It runs every N seconds. + */ + public void run() + { + while ( true ) + { + try + { + Thread.sleep( delay ); + + cleanCache(); + } + catch ( InterruptedException ie ) + { + return; + } } } } Modified: directory/apacheds/branches/bigbang/kerberos-shared/src/main/java/org/apache/directory/server/kerberos/shared/replay/ReplayCache.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/kerberos-shared/src/main/java/org/apache/directory/server/kerberos/shared/replay/ReplayCache.java?rev=589775&r1=589774&r2=589775&view=diff ============================================================================== --- directory/apacheds/branches/bigbang/kerberos-shared/src/main/java/org/apache/directory/server/kerberos/shared/replay/ReplayCache.java (original) +++ directory/apacheds/branches/bigbang/kerberos-shared/src/main/java/org/apache/directory/server/kerberos/shared/replay/ReplayCache.java Mon Oct 29 11:04:59 2007 @@ -39,10 +39,10 @@ * Returns whether a request is a replay, based on the server principal, client * principal, time, and microseconds. * - * @param serverPrincipal - * @param clientPrincipal - * @param clientTime - * @param clientMicroSeconds + * @param serverPrincipal The server principal + * @param clientPrincipal The client principal + * @param clientTime The client time + * @param clientMicroSeconds The client microsecond * @return true if the request is a replay. */ boolean isReplay( KerberosPrincipal serverPrincipal, KerberosPrincipal clientPrincipal, KerberosTime clientTime, @@ -53,10 +53,10 @@ * Saves the server principal, client principal, time, and microseconds to * the replay cache. * - * @param serverPrincipal - * @param clientPrincipal - * @param clientTime - * @param clientMicroSeconds + * @param serverPrincipal The server principal + * @param clientPrincipal The client principal + * @param clientTime The client time + * @param clientMicroSeconds The client microsecond */ void save( KerberosPrincipal serverPrincipal, KerberosPrincipal clientPrincipal, KerberosTime clientTime, int clientMicroSeconds ); Added: directory/apacheds/branches/bigbang/kerberos-shared/src/test/java/org/apache/directory/server/kerberos/shared/replay/InMemoryReplayCacheTest.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/kerberos-shared/src/test/java/org/apache/directory/server/kerberos/shared/replay/InMemoryReplayCacheTest.java?rev=589775&view=auto ============================================================================== --- directory/apacheds/branches/bigbang/kerberos-shared/src/test/java/org/apache/directory/server/kerberos/shared/replay/InMemoryReplayCacheTest.java (added) +++ directory/apacheds/branches/bigbang/kerberos-shared/src/test/java/org/apache/directory/server/kerberos/shared/replay/InMemoryReplayCacheTest.java Mon Oct 29 11:04:59 2007 @@ -0,0 +1,131 @@ +/* + * 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.shared.replay; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.security.auth.kerberos.KerberosPrincipal; + +import org.apache.directory.server.kerberos.shared.messages.value.KerberosTime; +import org.apache.directory.server.kerberos.shared.messages.value.types.PrincipalNameType; +import org.apache.directory.server.kerberos.shared.replay.InMemoryReplayCache.ReplayCacheEntry; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * Test the InMemory replay cache + * + * @author Apache Directory Project + * @version $Rev: 542147 $, $Date: 2007-05-28 10:14:21 +0200 (Mon, 28 May 2007) $ + */ +public class InMemoryReplayCacheTest +{ + /** + * Test that the cache is working well. We will create a new entry + * every 20 ms, with 10 different serverPrincipals. + * + * After this period of time, we should only have 25 entries in the cache + */ + @Test + public void testCacheSetting() throws Exception + { + int delay = 500; + long clockSkew = 100; + + // Set a delay of 500 ms and a clock skew of 100 ms + InMemoryReplayCache cache = new InMemoryReplayCache( clockSkew, delay ); + + // Loop for 2 seconds, then check that the cache is clean + int i = 0; + int nbClient = 20; + int nbServer = 10; + + // Inject 100 entries, one every 20 ms + while ( i < 100 ) + { + KerberosPrincipal serverPrincipal = new KerberosPrincipal( "server" + i%nbServer + "@APACHE.ORG", PrincipalNameType.KRB_NT_PRINCIPAL.getOrdinal() ); + KerberosPrincipal clientPrincipal = new KerberosPrincipal( "client" + i%nbClient + "@APACHE.ORG", PrincipalNameType.KRB_NT_PRINCIPAL.getOrdinal() ); + + cache.save( serverPrincipal, clientPrincipal, new KerberosTime( System.currentTimeMillis() ), 0 ); + + Thread.sleep( 20 ); + i++; + } + + Map> map = cache.getCache(); + + // We should have 20 List of entries, as we have injected 20 different + // clientPrincipals + assertEquals( nbClient, map.size() ); + + int nbEntries = 0; + + // Loop into the cache to see how many entries we have + Collection> entryList = map.values(); + + for ( List entries:entryList ) + { + if ( ( entries == null ) || ( entries.size() == 0 ) ) + { + continue; + } + + Iterator iterator = entries.iterator(); + + while ( iterator.hasNext() ) + { + iterator.next(); + nbEntries ++; + } + } + + // We should have some + assertNotNull( nbEntries ); + + // Wait another delay, so that the cleaning thread will be kicked off + Thread.sleep( delay + 50 ); + + nbEntries = 0; + + for ( List entries:entryList ) + { + if ( ( entries == null ) || ( entries.size() == 0 ) ) + { + continue; + } + + Iterator iterator = entries.iterator(); + + while ( iterator.hasNext() ) + { + iterator.next(); + nbEntries ++; + } + } + + // We should not have anymore entry in the cache + assertEquals( 0, nbEntries ); + } +}