You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2007/10/29 19:05:02 UTC
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/
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 <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
* @version $Rev$, $Date$
*/
-public class InMemoryReplayCache implements ReplayCache
+public class InMemoryReplayCache extends Thread implements ReplayCache
{
- private List<ReplayCacheEntry> list = new ArrayList<ReplayCacheEntry>();
-
- private long clockSkew = 5 * KerberosTime.MINUTE;
+ /** Stores the entries in memory */
+ private Map<KerberosPrincipal, List<ReplayCacheEntry>> cache = new HashMap<KerberosPrincipal, List<ReplayCacheEntry>>();
+ /** 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<ReplayCacheEntry> 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<KerberosPrincipal, List<ReplayCacheEntry>>();
+ 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<KerberosPrincipal, List<ReplayCacheEntry>>();
+ 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<KerberosPrincipal, List<ReplayCacheEntry>>();
+ 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<KerberosPrincipal, List<ReplayCacheEntry>>();
+ 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<ReplayCacheEntry> 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<ReplayCacheEntry> entries = cache.get( clientPrincipal );
+
+ if ( entries == null )
+ {
+ entries = new ArrayList<ReplayCacheEntry>();
+ }
+
+ entries.add( new ReplayCacheEntry( serverPrincipal, clientPrincipal, clientTime, clientMicroSeconds ) );
+
+ cache.put( clientPrincipal, entries );
+ }
+
+
+ public Map<KerberosPrincipal, List<ReplayCacheEntry>> getCache()
+ {
+ return cache;
+ }
+
+ /**
+ * A method to remove all the expired entries from the cache.
+ */
+ private synchronized void cleanCache()
+ {
+ Collection<List<ReplayCacheEntry>> entryList = cache.values();
+
+ if ( ( entryList == null ) || ( entryList.size() == 0 ) )
+ {
+ return;
+ }
+
+ for ( List<ReplayCacheEntry> entries:entryList )
+ {
+ if ( ( entries == null ) || ( entries.size() == 0 ) )
+ {
+ continue;
+ }
+
+ Iterator<ReplayCacheEntry> 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 <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @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<KerberosPrincipal, List<ReplayCacheEntry>> 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<List<ReplayCacheEntry>> entryList = map.values();
+
+ for ( List<ReplayCacheEntry> entries:entryList )
+ {
+ if ( ( entries == null ) || ( entries.size() == 0 ) )
+ {
+ continue;
+ }
+
+ Iterator<ReplayCacheEntry> 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<ReplayCacheEntry> entries:entryList )
+ {
+ if ( ( entries == null ) || ( entries.size() == 0 ) )
+ {
+ continue;
+ }
+
+ Iterator<ReplayCacheEntry> iterator = entries.iterator();
+
+ while ( iterator.hasNext() )
+ {
+ iterator.next();
+ nbEntries ++;
+ }
+ }
+
+ // We should not have anymore entry in the cache
+ assertEquals( 0, nbEntries );
+ }
+}