summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEike Stepper2007-10-05 05:58:50 (EDT)
committerEike Stepper2007-10-05 05:58:50 (EDT)
commitbf69d8d826d3f0f8033d2ee3a0bd3324df5c1be5 (patch)
treed637fb93658a0809ae8bdcf74b947e7253c70641
parentf0a5fe13c95cb58611ce03c887111fe777b788d0 (diff)
downloadcdo-bf69d8d826d3f0f8033d2ee3a0bd3324df5c1be5.zip
cdo-bf69d8d826d3f0f8033d2ee3a0bd3324df5c1be5.tar.gz
cdo-bf69d8d826d3f0f8033d2ee3a0bd3324df5c1be5.tar.bz2
[205027] Implement challenge/response based negotiator
https://bugs.eclipse.org/bugs/show_bug.cgi?id=205027
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOStateMachine.java160
-rw-r--r--plugins/org.eclipse.net4j.tests/src/org/eclipse/net4j/util/tests/SecurityTest.java213
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/ChallengeNegotiator.java159
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/ChallengeResponseNegotiator.java146
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/NegotiationContext.java68
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/Negotiator.java114
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/ResponseNegotiator.java72
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/UserManagerNegotiator.java71
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/fsm/FiniteStateMachine.java117
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/IBufferReceiver.java21
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/IChallengeResponse.java22
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/INegotiationContext.java12
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/INegotiator.java2
13 files changed, 728 insertions, 449 deletions
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOStateMachine.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOStateMachine.java
index aa994c5..476ba6e 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOStateMachine.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOStateMachine.java
@@ -43,68 +43,68 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent
{
super(CDOState.class, CDOEvent.class);
- transit(CDOState.TRANSIENT, CDOEvent.ATTACH, new AttachTransition());
- transit(CDOState.TRANSIENT, CDOEvent.DETACH, FAIL);
- transit(CDOState.TRANSIENT, CDOEvent.READ, IGNORE);
- transit(CDOState.TRANSIENT, CDOEvent.WRITE, IGNORE);
- transit(CDOState.TRANSIENT, CDOEvent.COMMIT, FAIL);
- transit(CDOState.TRANSIENT, CDOEvent.ROLLBACK, FAIL);
- transit(CDOState.TRANSIENT, CDOEvent.INVALIDATE, FAIL);
- transit(CDOState.TRANSIENT, CDOEvent.FINALIZE_ATTACH, FAIL);
-
- transit(CDOState.PREPARED_ATTACH, CDOEvent.ATTACH, FAIL);
- transit(CDOState.PREPARED_ATTACH, CDOEvent.DETACH, FAIL);
- transit(CDOState.PREPARED_ATTACH, CDOEvent.READ, IGNORE);
- transit(CDOState.PREPARED_ATTACH, CDOEvent.WRITE, FAIL);
- transit(CDOState.PREPARED_ATTACH, CDOEvent.COMMIT, FAIL);
- transit(CDOState.PREPARED_ATTACH, CDOEvent.ROLLBACK, FAIL);
- transit(CDOState.PREPARED_ATTACH, CDOEvent.INVALIDATE, FAIL);
- transit(CDOState.PREPARED_ATTACH, CDOEvent.FINALIZE_ATTACH, new FinalizeAttachTransition());
-
- transit(CDOState.NEW, CDOEvent.ATTACH, FAIL);
- transit(CDOState.NEW, CDOEvent.DETACH, FAIL);
- transit(CDOState.NEW, CDOEvent.READ, IGNORE);
- transit(CDOState.NEW, CDOEvent.WRITE, IGNORE);
- transit(CDOState.NEW, CDOEvent.COMMIT, new CommitTransition());
- transit(CDOState.NEW, CDOEvent.ROLLBACK, FAIL);
- transit(CDOState.NEW, CDOEvent.INVALIDATE, FAIL);
- transit(CDOState.NEW, CDOEvent.FINALIZE_ATTACH, FAIL);
-
- transit(CDOState.CLEAN, CDOEvent.ATTACH, FAIL);
- transit(CDOState.CLEAN, CDOEvent.DETACH, FAIL);
- transit(CDOState.CLEAN, CDOEvent.READ, IGNORE);
- transit(CDOState.CLEAN, CDOEvent.WRITE, new WriteTransition());
- transit(CDOState.CLEAN, CDOEvent.COMMIT, FAIL);
- transit(CDOState.CLEAN, CDOEvent.ROLLBACK, FAIL);
- transit(CDOState.CLEAN, CDOEvent.INVALIDATE, new InvalidateTransition());
- transit(CDOState.CLEAN, CDOEvent.FINALIZE_ATTACH, FAIL);
-
- transit(CDOState.DIRTY, CDOEvent.ATTACH, FAIL);
- transit(CDOState.DIRTY, CDOEvent.DETACH, FAIL);
- transit(CDOState.DIRTY, CDOEvent.READ, IGNORE);
- transit(CDOState.DIRTY, CDOEvent.WRITE, IGNORE);
- transit(CDOState.DIRTY, CDOEvent.COMMIT, new CommitTransition());
- transit(CDOState.DIRTY, CDOEvent.ROLLBACK, FAIL);
- transit(CDOState.DIRTY, CDOEvent.INVALIDATE, FAIL);
- transit(CDOState.DIRTY, CDOEvent.FINALIZE_ATTACH, FAIL);
-
- transit(CDOState.PROXY, CDOEvent.ATTACH, new LoadResourceTransition());
- transit(CDOState.PROXY, CDOEvent.DETACH, new DetachTransition());
- transit(CDOState.PROXY, CDOEvent.READ, new LoadTransition(false));
- transit(CDOState.PROXY, CDOEvent.WRITE, new LoadTransition(true));
- transit(CDOState.PROXY, CDOEvent.COMMIT, FAIL);
- transit(CDOState.PROXY, CDOEvent.ROLLBACK, FAIL);
- transit(CDOState.PROXY, CDOEvent.INVALIDATE, IGNORE);
- transit(CDOState.PROXY, CDOEvent.FINALIZE_ATTACH, IGNORE);
-
- transit(CDOState.CONFLICT, CDOEvent.ATTACH, FAIL);
- transit(CDOState.CONFLICT, CDOEvent.DETACH, FAIL);
- transit(CDOState.CONFLICT, CDOEvent.READ, FAIL);
- transit(CDOState.CONFLICT, CDOEvent.WRITE, FAIL);
- transit(CDOState.CONFLICT, CDOEvent.COMMIT, FAIL);
- transit(CDOState.CONFLICT, CDOEvent.ROLLBACK, FAIL);
- transit(CDOState.CONFLICT, CDOEvent.INVALIDATE, FAIL);
- transit(CDOState.CONFLICT, CDOEvent.FINALIZE_ATTACH, FAIL);
+ init(CDOState.TRANSIENT, CDOEvent.ATTACH, new AttachTransition());
+ init(CDOState.TRANSIENT, CDOEvent.DETACH, FAIL);
+ init(CDOState.TRANSIENT, CDOEvent.READ, IGNORE);
+ init(CDOState.TRANSIENT, CDOEvent.WRITE, IGNORE);
+ init(CDOState.TRANSIENT, CDOEvent.COMMIT, FAIL);
+ init(CDOState.TRANSIENT, CDOEvent.ROLLBACK, FAIL);
+ init(CDOState.TRANSIENT, CDOEvent.INVALIDATE, FAIL);
+ init(CDOState.TRANSIENT, CDOEvent.FINALIZE_ATTACH, FAIL);
+
+ init(CDOState.PREPARED_ATTACH, CDOEvent.ATTACH, FAIL);
+ init(CDOState.PREPARED_ATTACH, CDOEvent.DETACH, FAIL);
+ init(CDOState.PREPARED_ATTACH, CDOEvent.READ, IGNORE);
+ init(CDOState.PREPARED_ATTACH, CDOEvent.WRITE, FAIL);
+ init(CDOState.PREPARED_ATTACH, CDOEvent.COMMIT, FAIL);
+ init(CDOState.PREPARED_ATTACH, CDOEvent.ROLLBACK, FAIL);
+ init(CDOState.PREPARED_ATTACH, CDOEvent.INVALIDATE, FAIL);
+ init(CDOState.PREPARED_ATTACH, CDOEvent.FINALIZE_ATTACH, new FinalizeAttachTransition());
+
+ init(CDOState.NEW, CDOEvent.ATTACH, FAIL);
+ init(CDOState.NEW, CDOEvent.DETACH, FAIL);
+ init(CDOState.NEW, CDOEvent.READ, IGNORE);
+ init(CDOState.NEW, CDOEvent.WRITE, IGNORE);
+ init(CDOState.NEW, CDOEvent.COMMIT, new CommitTransition());
+ init(CDOState.NEW, CDOEvent.ROLLBACK, FAIL);
+ init(CDOState.NEW, CDOEvent.INVALIDATE, FAIL);
+ init(CDOState.NEW, CDOEvent.FINALIZE_ATTACH, FAIL);
+
+ init(CDOState.CLEAN, CDOEvent.ATTACH, FAIL);
+ init(CDOState.CLEAN, CDOEvent.DETACH, FAIL);
+ init(CDOState.CLEAN, CDOEvent.READ, IGNORE);
+ init(CDOState.CLEAN, CDOEvent.WRITE, new WriteTransition());
+ init(CDOState.CLEAN, CDOEvent.COMMIT, FAIL);
+ init(CDOState.CLEAN, CDOEvent.ROLLBACK, FAIL);
+ init(CDOState.CLEAN, CDOEvent.INVALIDATE, new InvalidateTransition());
+ init(CDOState.CLEAN, CDOEvent.FINALIZE_ATTACH, FAIL);
+
+ init(CDOState.DIRTY, CDOEvent.ATTACH, FAIL);
+ init(CDOState.DIRTY, CDOEvent.DETACH, FAIL);
+ init(CDOState.DIRTY, CDOEvent.READ, IGNORE);
+ init(CDOState.DIRTY, CDOEvent.WRITE, IGNORE);
+ init(CDOState.DIRTY, CDOEvent.COMMIT, new CommitTransition());
+ init(CDOState.DIRTY, CDOEvent.ROLLBACK, FAIL);
+ init(CDOState.DIRTY, CDOEvent.INVALIDATE, FAIL);
+ init(CDOState.DIRTY, CDOEvent.FINALIZE_ATTACH, FAIL);
+
+ init(CDOState.PROXY, CDOEvent.ATTACH, new LoadResourceTransition());
+ init(CDOState.PROXY, CDOEvent.DETACH, new DetachTransition());
+ init(CDOState.PROXY, CDOEvent.READ, new LoadTransition(false));
+ init(CDOState.PROXY, CDOEvent.WRITE, new LoadTransition(true));
+ init(CDOState.PROXY, CDOEvent.COMMIT, FAIL);
+ init(CDOState.PROXY, CDOEvent.ROLLBACK, FAIL);
+ init(CDOState.PROXY, CDOEvent.INVALIDATE, IGNORE);
+ init(CDOState.PROXY, CDOEvent.FINALIZE_ATTACH, IGNORE);
+
+ init(CDOState.CONFLICT, CDOEvent.ATTACH, FAIL);
+ init(CDOState.CONFLICT, CDOEvent.DETACH, FAIL);
+ init(CDOState.CONFLICT, CDOEvent.READ, FAIL);
+ init(CDOState.CONFLICT, CDOEvent.WRITE, FAIL);
+ init(CDOState.CONFLICT, CDOEvent.COMMIT, FAIL);
+ init(CDOState.CONFLICT, CDOEvent.ROLLBACK, FAIL);
+ init(CDOState.CONFLICT, CDOEvent.INVALIDATE, FAIL);
+ init(CDOState.CONFLICT, CDOEvent.FINALIZE_ATTACH, FAIL);
}
public void attach(InternalCDOObject object, CDOResource resource, CDOViewImpl view)
@@ -164,6 +164,12 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent
return object.cdoState();
}
+ @Override
+ protected void setState(InternalCDOObject object, CDOState state)
+ {
+ object.cdoInternalSetState(state);
+ }
+
/**
* Removes clutter from the trace log
*/
@@ -198,8 +204,7 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent
/**
* @author Eike Stepper
*/
- private static final class AttachTransition implements
- ITransition<CDOState, CDOEvent, InternalCDOObject, ResourceAndView>
+ private final class AttachTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, ResourceAndView>
{
public void execute(InternalCDOObject object, CDOState state, CDOEvent event, ResourceAndView data)
{
@@ -211,7 +216,7 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent
object.cdoInternalSetID(id);
object.cdoInternalSetResource(data.resource);
object.cdoInternalSetView(data.view);
- object.cdoInternalSetState(CDOState.PREPARED_ATTACH);
+ changeState(object, CDOState.PREPARED_ATTACH);
// Create new revision
CDORevisionImpl revision = new CDORevisionImpl(revisionManager, (CDOClassImpl)object.cdoClass(), id);
@@ -235,14 +240,13 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent
/**
* @author Eike Stepper
*/
- private static final class FinalizeAttachTransition implements
- ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
+ private final class FinalizeAttachTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
{
public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object data)
{
CDOTransactionImpl transaction = (CDOTransactionImpl)object.cdoView();
object.cdoInternalPostAttach();
- object.cdoInternalSetState(CDOState.NEW);
+ changeState(object, CDOState.NEW);
// Finalize content tree
for (Iterator<?> it = FSMUtil.iterator(object.eContents(), transaction); it.hasNext();)
@@ -256,7 +260,7 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent
/**
* @author Eike Stepper
*/
- private static final class DetachTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
+ private final class DetachTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
{
public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object data)
{
@@ -268,7 +272,7 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent
/**
* @author Eike Stepper
*/
- private static final class CommitTransition implements
+ private final class CommitTransition implements
ITransition<CDOState, CDOEvent, InternalCDOObject, CommitTransactionResult>
{
public void execute(InternalCDOObject object, CDOState state, CDOEvent event, CommitTransactionResult data)
@@ -296,14 +300,14 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent
CDORevisionManagerImpl revisionManager = view.getSession().getRevisionManager();
revisionManager.addRevision(revision);
- object.cdoInternalSetState(CDOState.CLEAN);
+ changeState(object, CDOState.CLEAN);
}
}
/**
* @author Eike Stepper
*/
- private static final class WriteTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
+ private final class WriteTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
{
public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object data)
{
@@ -316,26 +320,26 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent
CDOTransactionImpl transaction = view.toTransaction();
transaction.registerDirty(object);
- object.cdoInternalSetState(CDOState.DIRTY);
+ changeState(object, CDOState.DIRTY);
}
}
/**
* @author Eike Stepper
*/
- private static final class InvalidateTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Long>
+ private final class InvalidateTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Long>
{
public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Long timeStamp)
{
((CDORevisionImpl)object.cdoRevision()).setRevised(timeStamp - 1);
- object.cdoInternalSetState(CDOState.PROXY);
+ changeState(object, CDOState.PROXY);
}
}
/**
* @author Eike Stepper
*/
- private static final class LoadTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
+ private final class LoadTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
{
private boolean forWrite;
@@ -350,7 +354,7 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent
CDOViewImpl view = (CDOViewImpl)object.cdoView();
CDORevisionImpl revision = view.getRevision(id);
object.cdoInternalSetRevision(revision);
- object.cdoInternalSetState(CDOState.CLEAN);
+ changeState(object, CDOState.CLEAN);
object.cdoInternalPostLoad();
if (forWrite)
@@ -363,7 +367,7 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent
/**
* @author Eike Stepper
*/
- private static final class LoadResourceTransition implements
+ private final class LoadResourceTransition implements
ITransition<CDOState, CDOEvent, InternalCDOObject, ResourceAndView>
{
public void execute(InternalCDOObject object, CDOState state, CDOEvent event, ResourceAndView data)
diff --git a/plugins/org.eclipse.net4j.tests/src/org/eclipse/net4j/util/tests/SecurityTest.java b/plugins/org.eclipse.net4j.tests/src/org/eclipse/net4j/util/tests/SecurityTest.java
index b2f1919..c7b2630 100644
--- a/plugins/org.eclipse.net4j.tests/src/org/eclipse/net4j/util/tests/SecurityTest.java
+++ b/plugins/org.eclipse.net4j.tests/src/org/eclipse/net4j/util/tests/SecurityTest.java
@@ -16,21 +16,30 @@ import org.eclipse.net4j.internal.util.security.PasswordCredentials;
import org.eclipse.net4j.internal.util.security.Randomizer;
import org.eclipse.net4j.internal.util.security.ResponseNegotiator;
import org.eclipse.net4j.internal.util.security.UserManager;
+import org.eclipse.net4j.util.WrappedException;
+import org.eclipse.net4j.util.security.IChallengeResponse;
import org.eclipse.net4j.util.security.ICredentials;
import org.eclipse.net4j.util.security.ICredentialsProvider;
import java.nio.ByteBuffer;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
/**
* @author Eike Stepper
*/
public class SecurityTest extends AbstractOMTest
{
+ private static final int TIMEOUT = 10000;
+
private static final String USER_ID = "stepper";
- private static final char[] PASSWORD = "eike2007".toCharArray();
+ private static final char[] PASSWORD1 = "eike2007".toCharArray();
+
+ private static final char[] PASSWORD2 = "invalid".toCharArray();
- private static final PasswordCredentials CREDENTIALS = new PasswordCredentials(USER_ID, PASSWORD);
+ private static final PasswordCredentials CREDENTIALS = new PasswordCredentials(USER_ID, PASSWORD1);
private ICredentialsProvider credentialsProvider = new ICredentialsProvider()
{
@@ -40,65 +49,179 @@ public class SecurityTest extends AbstractOMTest
}
};
- private Randomizer randomizer = new Randomizer();
+ public void testSuccess() throws Exception
+ {
+ // Prepare randomizer
+ Randomizer randomizer = new Randomizer();
+ randomizer.activate();
+
+ // Prepare user manager
+ UserManager userManager = new UserManager();
+ userManager.activate();
+ userManager.addUser(USER_ID, PASSWORD1);
+
+ // Create negotiation contexts
+ PeerNegotiationContext challengeContext = new PeerNegotiationContext();
+ PeerNegotiationContext responseContext = new PeerNegotiationContext();
+
+ // Prepare challenge context
+ challengeContext.setPeer(responseContext);
+ Thread challengeThread = new Thread(challengeContext, "challengeThread");
+ challengeThread.start();
- private UserManager userManager = new UserManager();
+ // Prepare response context
+ responseContext.setPeer(challengeContext);
+ Thread responseThread = new Thread(responseContext, "responseThread");
+ responseThread.start();
- private NegotiationContext challengeContext = new NegotiationContext()
+ // Prepare response negotiator
+ ResponseNegotiator responseNegotiator = new ResponseNegotiator();
+ responseNegotiator.setCredentialsProvider(credentialsProvider);
+ responseNegotiator.activate();
+ responseNegotiator.negotiate(responseContext, false);
+
+ // Prepare challenge negotiator
+ ChallengeNegotiator challengeNegotiator = new ChallengeNegotiator();
+ challengeNegotiator.setRandomizer(randomizer);
+ challengeNegotiator.setUserManager(userManager);
+ challengeNegotiator.activate();
+ challengeNegotiator.negotiate(challengeContext, true);
+
+ Enum<?> responseState = responseContext.waitUntilFinished(TIMEOUT);
+ assertEquals(IChallengeResponse.State.SUCCESS, responseState);
+
+ Enum<?> challengeState = challengeContext.waitUntilFinished(TIMEOUT);
+ assertEquals(IChallengeResponse.State.SUCCESS, challengeState);
+
+ challengeContext.deactivate();
+ responseContext.deactivate();
+ challengeNegotiator.deactivate();
+ responseNegotiator.deactivate();
+ userManager.deactivate();
+ randomizer.deactivate();
+ }
+
+ public void testFailure() throws Exception
{
- public void transmitBuffer(ByteBuffer buffer)
+ // Prepare randomizer
+ Randomizer randomizer = new Randomizer();
+ randomizer.activate();
+
+ // Prepare user manager
+ UserManager userManager = new UserManager();
+ userManager.activate();
+ userManager.addUser(USER_ID, PASSWORD2);
+
+ // Create negotiation contexts
+ PeerNegotiationContext challengeContext = new PeerNegotiationContext();
+ PeerNegotiationContext responseContext = new PeerNegotiationContext();
+
+ // Prepare challenge context
+ challengeContext.setPeer(responseContext);
+ Thread challengeThread = new Thread(challengeContext, "challengeThread");
+ challengeThread.start();
+
+ // Prepare response context
+ responseContext.setPeer(challengeContext);
+ Thread responseThread = new Thread(responseContext, "responseThread");
+ responseThread.start();
+
+ // Prepare response negotiator
+ ResponseNegotiator responseNegotiator = new ResponseNegotiator();
+ responseNegotiator.setCredentialsProvider(credentialsProvider);
+ responseNegotiator.activate();
+ responseNegotiator.negotiate(responseContext, false);
+
+ // Prepare challenge negotiator
+ ChallengeNegotiator challengeNegotiator = new ChallengeNegotiator();
+ challengeNegotiator.setRandomizer(randomizer);
+ challengeNegotiator.setUserManager(userManager);
+ challengeNegotiator.activate();
+ challengeNegotiator.negotiate(challengeContext, true);
+
+ Enum<?> responseState = responseContext.waitUntilFinished(TIMEOUT);
+ assertEquals(IChallengeResponse.State.FAILURE, responseState);
+
+ Enum<?> challengeState = challengeContext.waitUntilFinished(TIMEOUT);
+ assertEquals(IChallengeResponse.State.FAILURE, challengeState);
+
+ challengeContext.deactivate();
+ responseContext.deactivate();
+ challengeNegotiator.deactivate();
+ responseNegotiator.deactivate();
+ userManager.deactivate();
+ randomizer.deactivate();
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ private final class PeerNegotiationContext extends NegotiationContext implements Runnable
+ {
+ private PeerNegotiationContext peer;
+
+ private BlockingQueue<ByteBuffer> queue = new LinkedBlockingQueue<ByteBuffer>();
+
+ private boolean running;
+
+ public PeerNegotiationContext()
{
- buffer.flip();
- responseContext.getBufferReceiver().receiveBuffer(responseContext, buffer);
}
- };
- private NegotiationContext responseContext = new NegotiationContext()
- {
+ public PeerNegotiationContext getPeer()
+ {
+ return peer;
+ }
+
+ public void setPeer(PeerNegotiationContext peer)
+ {
+ this.peer = peer;
+ }
+
+ public ByteBuffer getBuffer()
+ {
+ return ByteBuffer.allocateDirect(4096);
+ }
+
public void transmitBuffer(ByteBuffer buffer)
{
buffer.flip();
- challengeContext.getBufferReceiver().receiveBuffer(challengeContext, buffer);
+ queue.add(buffer);
}
- };
- public void testNegotiation() throws Exception
- {
- randomizer.activate();
- userManager.activate();
- userManager.addUser(USER_ID, PASSWORD);
-
- ResponseNegotiator client = new ResponseNegotiator();
- client.setCredentialsProvider(credentialsProvider);
- client.activate();
+ public void deactivate()
+ {
+ running = false;
+ }
- new Thread()
+ public void run()
{
- @Override
- public void run()
+ running = true;
+ while (running)
{
- ChallengeNegotiator server = new ChallengeNegotiator();
- server.setRandomizer(randomizer);
- server.setUserManager(userManager);
- server.setTokenLength(1024);
-
- try
+ if (peer != null)
{
- server.activate();
- server.startNegotiation(challengeContext);
- NegotiationContext.State result = challengeContext.waitForResult(2000);
- System.out.println(result);
- }
- catch (Exception ex)
- {
- ex.printStackTrace();
- fail(ex.getMessage());
- }
- finally
- {
- server.deactivate();
+ Receiver receiver = peer.getReceiver();
+ if (receiver != null)
+ {
+ ByteBuffer buffer = null;
+
+ try
+ {
+ buffer = queue.poll(20, TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException ex)
+ {
+ throw WrappedException.wrap(ex);
+ }
+
+ if (buffer != null)
+ {
+ receiver.receiveBuffer(peer, buffer);
+ }
+ }
}
}
- }.start();
+ }
}
}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/ChallengeNegotiator.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/ChallengeNegotiator.java
index c41aeb8..f999b87 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/ChallengeNegotiator.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/ChallengeNegotiator.java
@@ -10,10 +10,9 @@
**************************************************************************/
package org.eclipse.net4j.internal.util.security;
-import org.eclipse.net4j.internal.util.bundle.OM;
-import org.eclipse.net4j.internal.util.om.trace.ContextTracer;
-import org.eclipse.net4j.util.security.IChallengeResponse;
+import org.eclipse.net4j.util.security.INegotiationContext;
import org.eclipse.net4j.util.security.IRandomizer;
+import org.eclipse.net4j.util.security.IUserManager;
import java.nio.ByteBuffer;
import java.util.Arrays;
@@ -21,21 +20,18 @@ import java.util.Arrays;
/**
* @author Eike Stepper
*/
-public class ChallengeNegotiator extends UserManagerNegotiator implements IChallengeResponse
+public class ChallengeNegotiator extends ChallengeResponseNegotiator
{
- public static final int DEFAULT_TOKEN_LENGTH = 128;
-
- private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, ChallengeNegotiator.class);
+ public static final int DEFAULT_TOKEN_LENGTH = 1024;
private int tokenLength = DEFAULT_TOKEN_LENGTH;
private IRandomizer randomizer;
- private transient byte[] randomToken;
+ private IUserManager userManager;
public ChallengeNegotiator()
{
- super(true);
}
public int getTokenLength()
@@ -58,101 +54,14 @@ public class ChallengeNegotiator extends UserManagerNegotiator implements IChall
this.randomizer = randomizer;
}
- @Override
- protected int negotiate(int phase, ByteBuffer buffer)
+ public IUserManager getUserManager()
{
- if (TRACER.isEnabled())
- {
- TRACER.format("Negotiating phase {0}", phase);
- }
-
- switch (phase)
- {
- case INITIAL:
- challenge();
- return PHASE_RESPONSE;
-
- case PHASE_RESPONSE:
- try
- {
- if (verifyResponse(buffer))
- {
- acknowledge(true);
- return SUCCESS;
- }
- else
- {
- return NEED_MORE_BUFFERS;
- }
- }
- catch (SecurityException ex)
- {
- acknowledge(false);
- return FAILURE;
- }
-
- case PHASE_ACKNOWLEDGE:
- break;
-
- default:
- break;
- }
- return 0;
+ return userManager;
}
- /**
- * Use {@link #getBuffer()} and {@link #transmitBuffer(ByteBuffer)} to send the challenge.
- */
- protected void challenge()
+ public void setUserManager(IUserManager userManager)
{
- if (TRACER.isEnabled()) TRACER.trace("Transmitting token");
- randomToken = createRandomToken();
- ByteBuffer buffer = getBuffer();
- buffer.putInt(randomToken.length);
- buffer.put(randomToken);
- transmitBuffer(buffer);
- }
-
- /**
- * Use the passed <code>ByteBuffer</code> to authenticate the user.
- *
- * @return <code>true</code> if authentication was successful, <code>false</code> if more buffers are needed.
- * @throws SecurityException
- * if authentication was not successful.
- */
- protected boolean verifyResponse(ByteBuffer buffer) throws SecurityException
- {
- if (TRACER.isEnabled()) TRACER.trace("Received cryptedToken");
- int size = buffer.getInt();
- byte[] cryptedTokenFromClient = new byte[size];
- buffer.get(cryptedTokenFromClient);
-
- if (TRACER.isEnabled()) TRACER.trace("Received userID");
- size = buffer.getInt();
- byte[] userIDBytes = new byte[size];
- buffer.get(userIDBytes);
-
- String userID = new String(userIDBytes);
- byte[] cryptedToken = encrypt(userID, randomToken);
-
- if (Arrays.equals(cryptedToken, cryptedTokenFromClient))
- {
- return true;
- }
-
- throw new SecurityException("User could not be authenticated: " + userID);
- }
-
- /**
- * Use {@link #getBuffer()} and {@link #transmitBuffer(ByteBuffer)} to send the acknowledgement. The default
- * implementation of this method jsut sends a buffer with <code>(byte)1</code> if <code>success == true</code> or
- * <code>(byte)0</code> if <code>success == false</code>.
- */
- protected void acknowledge(boolean success)
- {
- ByteBuffer buffer = getBuffer();
- buffer.put(success ? ACKNOWLEDGE_SUCCESS : ACKNOWLEDGE_FAILURE);
- transmitBuffer(buffer);
+ this.userManager = userManager;
}
@Override
@@ -168,6 +77,11 @@ public class ChallengeNegotiator extends UserManagerNegotiator implements IChall
{
throw new IllegalStateException("randomizer == null");
}
+
+ if (userManager == null)
+ {
+ throw new IllegalStateException("userManager == null");
+ }
}
protected byte[] createRandomToken()
@@ -176,4 +90,49 @@ public class ChallengeNegotiator extends UserManagerNegotiator implements IChall
randomizer.nextBytes(token);
return token;
}
+
+ protected byte[] encryptToken(String userID, byte[] token) throws SecurityException
+ {
+ return userManager.encrypt(userID, token, getAlgorithmName());
+ }
+
+ @Override
+ protected void createChallenge(INegotiationContext context, ByteBuffer challenge)
+ {
+ // Create and remember a random token
+ byte[] randomToken = createRandomToken();
+ context.setInfo(randomToken);
+
+ // Set the token into challenge
+ challenge.putInt(randomToken.length);
+ challenge.put(randomToken);
+ }
+
+ @Override
+ protected void handleChallenge(INegotiationContext context, ByteBuffer challenge, ByteBuffer response)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected boolean handleResponse(INegotiationContext context, ByteBuffer response)
+ {
+ // Get remembered random token
+ byte[] randomToken = (byte[])context.getInfo();
+
+ // Get crypted token from response
+ int size = response.getInt();
+ byte[] responseToken = new byte[size];
+ response.get(responseToken);
+
+ // Get userID from response
+ size = response.getInt();
+ byte[] userIDBytes = new byte[size];
+ response.get(userIDBytes);
+ String userID = new String(userIDBytes);
+
+ // Encrypt the remembered token and compare to crypted token from response
+ byte[] cryptedToken = encryptToken(userID, randomToken);
+ return Arrays.equals(responseToken, cryptedToken);
+ }
}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/ChallengeResponseNegotiator.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/ChallengeResponseNegotiator.java
new file mode 100644
index 0000000..16c2ad5
--- /dev/null
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/ChallengeResponseNegotiator.java
@@ -0,0 +1,146 @@
+/***************************************************************************
+ * Copyright (c) 2004 - 2007 Eike Stepper, Germany.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ **************************************************************************/
+package org.eclipse.net4j.internal.util.security;
+
+import org.eclipse.net4j.util.fsm.ITransition;
+import org.eclipse.net4j.util.security.IChallengeResponse;
+import org.eclipse.net4j.util.security.INegotiationContext;
+import org.eclipse.net4j.util.security.SecurityUtil;
+
+import java.nio.ByteBuffer;
+
+/**
+ * @author Eike Stepper
+ */
+public abstract class ChallengeResponseNegotiator extends
+ Negotiator<IChallengeResponse.State, IChallengeResponse.Event> implements IChallengeResponse
+{
+ public static final String DEFAULT_ALGORITHM_NAME = SecurityUtil.PBE_WITH_MD5_AND_DES;
+
+ private String algorithmName = DEFAULT_ALGORITHM_NAME;
+
+ public ChallengeResponseNegotiator()
+ {
+ super(State.class, Event.class, State.INITIAL, State.SUCCESS, State.FAILURE, Event.START, Event.BUFFER);
+
+ init(State.INITIAL, Event.START, new Transition()
+ {
+ @Override
+ protected void execute(INegotiationContext context, ByteBuffer buffer)
+ {
+ // Create and transmit challenge
+ ByteBuffer challenge = context.getBuffer();
+ createChallenge(context, challenge);
+ context.transmitBuffer(challenge);
+
+ // Set context state
+ changeState(context, State.CHALLENGE);
+ }
+ });
+
+ init(State.INITIAL, Event.BUFFER, new Transition()
+ {
+ @Override
+ protected void execute(INegotiationContext context, ByteBuffer challenge)
+ {
+ // Handle challenge and transmit response
+ ByteBuffer response = context.getBuffer();
+ handleChallenge(context, challenge, response);
+ context.transmitBuffer(response);
+
+ // Set context state
+ changeState(context, State.RESPONSE);
+ }
+ });
+
+ init(State.CHALLENGE, Event.BUFFER, new Transition()
+ {
+ @Override
+ protected void execute(INegotiationContext context, ByteBuffer response)
+ {
+ // Handle response
+ boolean success = handleResponse(context, response);
+
+ // Transmit acknowledgement
+ ByteBuffer acknowledgement = context.getBuffer();
+ acknowledgement.put(success ? ACKNOWLEDGE_SUCCESS : ACKNOWLEDGE_FAILURE);
+ context.transmitBuffer(acknowledgement);
+
+ // Set context state
+ changeState(context, success ? State.SUCCESS : State.FAILURE);
+ }
+ });
+
+ init(State.RESPONSE, Event.BUFFER, new Transition()
+ {
+ @Override
+ protected void execute(INegotiationContext context, ByteBuffer acknowledgement)
+ {
+ // Handle acknowledgement
+ boolean success = acknowledgement.get() == ACKNOWLEDGE_SUCCESS;
+
+ // Set context state
+ changeState(context, success ? State.SUCCESS : State.FAILURE);
+ }
+ });
+ }
+
+ public String getAlgorithmName()
+ {
+ return algorithmName;
+ }
+
+ public void setAlgorithmName(String algorithmName)
+ {
+ this.algorithmName = algorithmName;
+ }
+
+ @Override
+ protected void doBeforeActivate() throws Exception
+ {
+ super.doBeforeActivate();
+ if (algorithmName == null)
+ {
+ throw new IllegalStateException("algorithmName == null");
+ }
+ }
+
+ @Override
+ protected State getState(INegotiationContext subject)
+ {
+ return (State)subject.getState();
+ }
+
+ @Override
+ protected void setState(INegotiationContext subject, State state)
+ {
+ subject.setState(state);
+ }
+
+ protected abstract void createChallenge(INegotiationContext context, ByteBuffer challenge);
+
+ protected abstract void handleChallenge(INegotiationContext context, ByteBuffer challenge, ByteBuffer response);
+
+ protected abstract boolean handleResponse(INegotiationContext context, ByteBuffer response);
+
+ /**
+ * @author Eike Stepper
+ */
+ protected abstract class Transition implements ITransition<State, Event, INegotiationContext, ByteBuffer>
+ {
+ public final void execute(INegotiationContext context, State state, Event event, ByteBuffer buffer)
+ {
+ execute(context, buffer);
+ }
+
+ protected abstract void execute(INegotiationContext context, ByteBuffer buffer);
+ }
+}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/NegotiationContext.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/NegotiationContext.java
index 3048a5f..2b20700 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/NegotiationContext.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/NegotiationContext.java
@@ -10,10 +10,9 @@
**************************************************************************/
package org.eclipse.net4j.internal.util.security;
-import org.eclipse.net4j.util.security.IBufferReceiver;
+import org.eclipse.net4j.util.WrappedException;
import org.eclipse.net4j.util.security.INegotiationContext;
-import java.nio.ByteBuffer;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -22,74 +21,83 @@ import java.util.concurrent.TimeUnit;
*/
public abstract class NegotiationContext implements INegotiationContext
{
- private IBufferReceiver bufferReceiver;
+ private Receiver receiver;
- private State state = State.ONGOING;
+ private Enum<?> state;
- private CountDownLatch ongoingLatch = new CountDownLatch(1);
+ private Object info;
+
+ private CountDownLatch finishedLatch = new CountDownLatch(1);
public NegotiationContext()
{
}
- public IBufferReceiver getBufferReceiver()
+ public Receiver getReceiver()
{
- return bufferReceiver;
+ return receiver;
}
- public void setBufferReceiver(IBufferReceiver bufferReceiver)
+ public void setReceiver(Receiver receiver)
{
- this.bufferReceiver = bufferReceiver;
+ this.receiver = receiver;
}
- public State getState()
+ public Enum<?> getState()
{
return state;
}
- public ByteBuffer getBuffer()
+ public void setState(Enum<?> state)
{
- return ByteBuffer.allocateDirect(4096);
+ this.state = state;
}
- public void negotiationSuccess()
+ public Object getInfo()
{
- state = State.SUCCESS;
- ongoingLatch.countDown();
+ return info;
}
- public void negotiationFailure()
+ public void setInfo(Object info)
{
- state = State.FAILURE;
- ongoingLatch.countDown();
+ this.info = info;
}
- public State waitForResult(long timeout)
+ public void setFinished(boolean success)
{
+ if (finishedLatch != null)
+ {
+ finishedLatch.countDown();
+ }
+ }
+
+ public Enum<?> waitUntilFinished(long timeout)
+ {
+ if (finishedLatch == null)
+ {
+ throw new IllegalStateException("finishedLatch == null");
+ }
+
try
{
if (timeout == -1)
{
- ongoingLatch.await();
+ finishedLatch.await();
}
else
{
- ongoingLatch.await(timeout, TimeUnit.MILLISECONDS);
+ finishedLatch.await(timeout, TimeUnit.MILLISECONDS);
}
}
catch (InterruptedException ex)
{
- state = State.INTERRUPTED;
+ throw WrappedException.wrap(ex);
+ }
+ finally
+ {
+ finishedLatch = null;
}
return state;
}
-
- /**
- * @author Eike Stepper
- */
- public static enum State
- {
- ONGOING, SUCCESS, FAILURE, INTERRUPTED;
- }
}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/Negotiator.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/Negotiator.java
index 64733b0..e1c99ae 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/Negotiator.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/Negotiator.java
@@ -10,8 +10,7 @@
**************************************************************************/
package org.eclipse.net4j.internal.util.security;
-import org.eclipse.net4j.internal.util.lifecycle.Lifecycle;
-import org.eclipse.net4j.util.security.IBufferReceiver;
+import org.eclipse.net4j.util.fsm.FiniteStateMachine;
import org.eclipse.net4j.util.security.INegotiationContext;
import org.eclipse.net4j.util.security.INegotiator;
@@ -20,99 +19,90 @@ import java.nio.ByteBuffer;
/**
* @author Eike Stepper
*/
-public abstract class Negotiator extends Lifecycle implements INegotiator, IBufferReceiver
+public abstract class Negotiator<STATE extends Enum<?>, EVENT extends Enum<?>> extends
+ FiniteStateMachine<STATE, EVENT, INegotiationContext> implements INegotiator, INegotiationContext.Receiver
{
- public static final int INITIAL = 0;
+ private STATE initialState;
- public static final int SUCCESS = -1;
+ private STATE successState;
- public static final int FAILURE = -2;
+ private STATE failureState;
- public static final int NEED_MORE_BUFFERS = -3;
+ private EVENT startEvent;
- private int phase = INITIAL;
+ private EVENT bufferEvent;
- private boolean initiator;
+ public Negotiator(Class<STATE> stateEnum, Class<EVENT> eventEnum, STATE initialState, STATE successState,
+ STATE failureState, EVENT startEvent, EVENT bufferEvent)
+ {
+ super(stateEnum, eventEnum);
- private INegotiationContext context;
+ if (initialState == null) throw new IllegalStateException("initialState == null");
+ if (successState == null) throw new IllegalStateException("successState == null");
+ if (failureState == null) throw new IllegalStateException("failureState == null");
+ if (startEvent == null) throw new IllegalStateException("startEvent == null");
+ if (bufferEvent == null) throw new IllegalStateException("bufferEvent == null");
+
+ this.initialState = initialState;
+ this.successState = successState;
+ this.failureState = failureState;
+ this.startEvent = startEvent;
+ this.bufferEvent = bufferEvent;
- public Negotiator(boolean initiator)
- {
- this.initiator = initiator;
}
- public int getPhase()
+ public STATE getInitialState()
{
- return phase;
+ return initialState;
}
- public boolean isInitiator()
+ public STATE getSuccessState()
{
- return initiator;
+ return successState;
}
- public void startNegotiation(INegotiationContext context)
+ public STATE getFailureState()
{
- this.context = context;
- context.setBufferReceiver(this);
- if (initiator)
- {
- doNegotiation(null);
- }
+ return failureState;
}
- public void receiveBuffer(INegotiationContext context, ByteBuffer buffer)
+ public EVENT getBufferEvent()
{
- checkContext();
-
- try
- {
- doNegotiation(buffer);
- }
- catch (SecurityException ex)
- {
- context.negotiationFailure();
- }
+ return bufferEvent;
}
- protected void doNegotiation(ByteBuffer buffer)
+ public EVENT getStartEvent()
{
- int result = negotiate(phase, buffer);
- switch (result)
- {
- case SUCCESS:
- context.negotiationSuccess();
- break;
- case FAILURE:
- context.negotiationSuccess();
- break;
- case NEED_MORE_BUFFERS:
- break;
- default:
- phase = result;
- break;
- }
+ return startEvent;
}
- protected abstract int negotiate(int phase, ByteBuffer buffer);
-
- protected ByteBuffer getBuffer()
+ public void negotiate(INegotiationContext context, boolean initiator)
{
- checkContext();
- return context.getBuffer();
+ context.setReceiver(this);
+ context.setState(initialState);
+ if (initiator)
+ {
+ process(context, startEvent, null);
+ postProcess(context);
+ }
}
- protected void transmitBuffer(ByteBuffer buffer)
+ public void receiveBuffer(INegotiationContext context, ByteBuffer buffer)
{
- checkContext();
- context.transmitBuffer(buffer);
+ process(context, bufferEvent, buffer);
+ postProcess(context);
}
- private void checkContext()
+ protected void postProcess(INegotiationContext context)
{
- if (context == null)
+ Enum<?> state = context.getState();
+ if (state == successState)
+ {
+ context.setFinished(true);
+ }
+ else if (state == failureState)
{
- throw new IllegalStateException("context == null");
+ context.setFinished(false);
}
}
}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/ResponseNegotiator.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/ResponseNegotiator.java
index 46bde97..1c79f0c 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/ResponseNegotiator.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/ResponseNegotiator.java
@@ -10,25 +10,21 @@
**************************************************************************/
package org.eclipse.net4j.internal.util.security;
-import org.eclipse.net4j.internal.util.bundle.OM;
-import org.eclipse.net4j.internal.util.om.trace.ContextTracer;
-import org.eclipse.net4j.util.security.IChallengeResponse;
import org.eclipse.net4j.util.security.ICredentialsProvider;
+import org.eclipse.net4j.util.security.INegotiationContext;
+import org.eclipse.net4j.util.security.SecurityUtil;
import java.nio.ByteBuffer;
/**
* @author Eike Stepper
*/
-public class ResponseNegotiator extends Negotiator implements IChallengeResponse
+public class ResponseNegotiator extends ChallengeResponseNegotiator
{
- private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, ResponseNegotiator.class);
-
private ICredentialsProvider credentialsProvider;
public ResponseNegotiator()
{
- super(false);
}
public ICredentialsProvider getCredentialsProvider()
@@ -42,36 +38,62 @@ public class ResponseNegotiator extends Negotiator implements IChallengeResponse
}
@Override
- protected int negotiate(int phase, ByteBuffer buffer)
+ protected void doBeforeActivate() throws Exception
{
- if (TRACER.isEnabled())
+ super.doBeforeActivate();
+ if (credentialsProvider == null)
{
- TRACER.format("Negotiating phase {0}", phase);
+ throw new IllegalStateException("credentialsProvider == null");
}
+ }
- switch (phase)
- {
- case INITIAL:
- return PHASE_RESPONSE;
+ @Override
+ protected void createChallenge(INegotiationContext context, ByteBuffer challenge)
+ {
+ throw new UnsupportedOperationException();
+ }
- case PHASE_RESPONSE:
- case PHASE_ACKNOWLEDGE:
- break;
+ @Override
+ protected void handleChallenge(INegotiationContext context, ByteBuffer challenge, ByteBuffer response)
+ {
+ // Get random token from challenge
+ int size = challenge.getInt();
+ byte[] randomToken = new byte[size];
+ challenge.get(randomToken);
- default:
- break;
- }
+ // Get credentials and encrypt token
+ PasswordCredentials credentials = (PasswordCredentials)credentialsProvider.getCredentials();
- return 0;
+ // Set crypted token into response
+ byte[] cryptedToken = encryptToken(credentials.getPassword(), randomToken);
+ response.putInt(cryptedToken.length);
+ response.put(cryptedToken);
+
+ // Set userID into response
+ byte[] userID = credentials.getUserID().getBytes();
+ response.putInt(userID.length);
+ response.put(userID);
}
@Override
- protected void doBeforeActivate() throws Exception
+ protected boolean handleResponse(INegotiationContext context, ByteBuffer response)
{
- super.doBeforeActivate();
- if (credentialsProvider == null)
+ throw new UnsupportedOperationException();
+ }
+
+ protected byte[] encryptToken(char[] password, byte[] token)
+ {
+ try
{
- throw new IllegalStateException("credentialsProvider == null");
+ return SecurityUtil.encrypt(token, password, getAlgorithmName());
+ }
+ catch (RuntimeException ex)
+ {
+ throw ex;
+ }
+ catch (Exception ex)
+ {
+ throw new SecurityException(ex);
}
}
}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/UserManagerNegotiator.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/UserManagerNegotiator.java
deleted file mode 100644
index 5fa6b00..0000000
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/security/UserManagerNegotiator.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/***************************************************************************
- * Copyright (c) 2004 - 2007 Eike Stepper, Germany.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Eike Stepper - initial API and implementation
- **************************************************************************/
-package org.eclipse.net4j.internal.util.security;
-
-import org.eclipse.net4j.util.security.IUserManager;
-import org.eclipse.net4j.util.security.SecurityUtil;
-
-/**
- * @author Eike Stepper
- */
-public abstract class UserManagerNegotiator extends Negotiator
-{
- public static final String DEFAULT_ALGORITHM_NAME = SecurityUtil.PBE_WITH_MD5_AND_DES;
-
- private String algorithmName = DEFAULT_ALGORITHM_NAME;
-
- private IUserManager userManager;
-
- public UserManagerNegotiator(boolean starter)
- {
- super(starter);
- }
-
- public String getAlgorithmName()
- {
- return algorithmName;
- }
-
- public void setAlgorithmName(String algorithmName)
- {
- this.algorithmName = algorithmName;
- }
-
- public IUserManager getUserManager()
- {
- return userManager;
- }
-
- public void setUserManager(IUserManager userManager)
- {
- this.userManager = userManager;
- }
-
- protected byte[] encrypt(String userID, byte[] data) throws SecurityException
- {
- return userManager.encrypt(userID, data, algorithmName);
- }
-
- @Override
- protected void doBeforeActivate() throws Exception
- {
- super.doBeforeActivate();
- if (algorithmName == null)
- {
- throw new IllegalStateException("algorithmName == null");
- }
-
- if (userManager == null)
- {
- throw new IllegalStateException("userManager == null");
- }
- }
-}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/fsm/FiniteStateMachine.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/fsm/FiniteStateMachine.java
index d406080..9eec10d 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/fsm/FiniteStateMachine.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/fsm/FiniteStateMachine.java
@@ -1,14 +1,17 @@
package org.eclipse.net4j.util.fsm;
import org.eclipse.net4j.internal.util.bundle.OM;
+import org.eclipse.net4j.internal.util.lifecycle.Lifecycle;
import org.eclipse.net4j.internal.util.om.trace.ContextTracer;
+import org.eclipse.net4j.util.event.IEvent;
+import org.eclipse.net4j.util.event.INotifier;
import java.text.MessageFormat;
/**
* @author Eike Stepper
*/
-public abstract class FiniteStateMachine<STATE extends Enum<?>, EVENT extends Enum<?>, SUBJECT>
+public abstract class FiniteStateMachine<STATE extends Enum<?>, EVENT extends Enum<?>, SUBJECT> extends Lifecycle
{
@SuppressWarnings("unchecked")
public static final ITransition IGNORE = new IgnoreTransition();
@@ -36,12 +39,12 @@ public abstract class FiniteStateMachine<STATE extends Enum<?>, EVENT extends En
states = stateEnum.getEnumConstants();
events = eventEnum.getEnumConstants();
transitions = new ITransition[states.length][events.length];
- transitAll(defaultTransition);
+ initAll(defaultTransition);
}
public FiniteStateMachine(Class<STATE> stateEnum, Class<EVENT> eventEnum)
{
- this(stateEnum, eventEnum, IGNORE);
+ this(stateEnum, eventEnum, FAIL);
}
public final STATE[] getStates()
@@ -61,7 +64,12 @@ public abstract class FiniteStateMachine<STATE extends Enum<?>, EVENT extends En
return transitions[s][e];
}
- public final void transit(STATE state, EVENT event, ITransition<STATE, EVENT, SUBJECT, ?> transition)
+ public final void init(STATE state, EVENT event, STATE targetState)
+ {
+ init(state, event, new ChangeStateTransition(targetState));
+ }
+
+ public final void init(STATE state, EVENT event, ITransition<STATE, EVENT, SUBJECT, ?> transition)
{
checkTransition(transition);
int s = state.ordinal();
@@ -69,7 +77,12 @@ public abstract class FiniteStateMachine<STATE extends Enum<?>, EVENT extends En
transitions[s][e] = transition;
}
- public final void transitEvents(STATE state, ITransition<STATE, EVENT, SUBJECT, ?> transition)
+ public final void initEvents(STATE state, STATE targetState)
+ {
+ initEvents(state, new ChangeStateTransition(targetState));
+ }
+
+ public final void initEvents(STATE state, ITransition<STATE, EVENT, SUBJECT, ?> transition)
{
checkTransition(transition);
int s = state.ordinal();
@@ -79,7 +92,12 @@ public abstract class FiniteStateMachine<STATE extends Enum<?>, EVENT extends En
}
}
- public final void transitStates(EVENT event, ITransition<STATE, EVENT, SUBJECT, ?> transition)
+ public final void initStates(EVENT event, STATE targetState)
+ {
+ initStates(event, new ChangeStateTransition(targetState));
+ }
+
+ public final void initStates(EVENT event, ITransition<STATE, EVENT, SUBJECT, ?> transition)
{
checkTransition(transition);
int e = event.ordinal();
@@ -89,7 +107,12 @@ public abstract class FiniteStateMachine<STATE extends Enum<?>, EVENT extends En
}
}
- public final void transitAll(ITransition<STATE, EVENT, SUBJECT, ?> transition)
+ public final void initAll(STATE targetState)
+ {
+ initAll(new ChangeStateTransition(targetState));
+ }
+
+ public final void initAll(ITransition<STATE, EVENT, SUBJECT, ?> transition)
{
checkTransition(transition);
for (int s = 0; s < states.length; s++)
@@ -156,6 +179,18 @@ public abstract class FiniteStateMachine<STATE extends Enum<?>, EVENT extends En
protected abstract STATE getState(SUBJECT subject);
+ protected abstract void setState(SUBJECT subject, STATE state);
+
+ protected void changeState(SUBJECT subject, STATE state)
+ {
+ STATE oldState = getState(subject);
+ setState(subject, state);
+ if (oldState != state)
+ {
+ fireEvent(new StateChangedEvent(subject, oldState, state));
+ }
+ }
+
private void checkTransition(ITransition<STATE, EVENT, SUBJECT, ?> transition)
{
if (transition == null)
@@ -197,4 +232,72 @@ public abstract class FiniteStateMachine<STATE extends Enum<?>, EVENT extends En
return "FAIL";
}
}
+
+ /**
+ * @author Eike Stepper
+ */
+ public class ChangeStateTransition implements ITransition<STATE, EVENT, SUBJECT, Object>
+ {
+ private STATE targetState;
+
+ public ChangeStateTransition(STATE targetState)
+ {
+ this.targetState = targetState;
+ }
+
+ public STATE getTargetState()
+ {
+ return targetState;
+ }
+
+ public void execute(SUBJECT subject, STATE state, EVENT event, Object data)
+ {
+ changeState(subject, targetState);
+ }
+
+ @Override
+ public String toString()
+ {
+ return MessageFormat.format("CHANGE_STATE[{0}]", targetState);
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public class StateChangedEvent implements IEvent
+ {
+ private Object subject;
+
+ private Enum<?> oldState;
+
+ private Enum<?> newState;
+
+ public StateChangedEvent(Object subject, Enum<?> oldState, Enum<?> newState)
+ {
+ this.subject = subject;
+ this.oldState = oldState;
+ this.newState = newState;
+ }
+
+ public INotifier getSource()
+ {
+ return FiniteStateMachine.this;
+ }
+
+ public Object getSubject()
+ {
+ return subject;
+ }
+
+ public Enum<?> getOldState()
+ {
+ return oldState;
+ }
+
+ public Enum<?> getNewState()
+ {
+ return newState;
+ }
+ }
} \ No newline at end of file
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/IBufferReceiver.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/IBufferReceiver.java
deleted file mode 100644
index 06113dc..0000000
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/IBufferReceiver.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/***************************************************************************
- * Copyright (c) 2004 - 2007 Eike Stepper, Germany.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Eike Stepper - initial API and implementation
- **************************************************************************/
-package org.eclipse.net4j.util.security;
-
-import java.nio.ByteBuffer;
-
-/**
- * @author Eike Stepper
- */
-public interface IBufferReceiver
-{
- public void receiveBuffer(INegotiationContext context, ByteBuffer buffer);
-}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/IChallengeResponse.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/IChallengeResponse.java
index 8ada22e..157e619 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/IChallengeResponse.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/IChallengeResponse.java
@@ -15,13 +15,23 @@ package org.eclipse.net4j.util.security;
*/
public interface IChallengeResponse
{
- public static final int PHASE_CHALLENGE = 1;
-
- public static final int PHASE_RESPONSE = 2;
-
- public static final int PHASE_ACKNOWLEDGE = 3;
-
public static final byte ACKNOWLEDGE_SUCCESS = 1;
public static final byte ACKNOWLEDGE_FAILURE = 0;
+
+ /**
+ * @author Eike Stepper
+ */
+ public enum State
+ {
+ INITIAL, CHALLENGE, RESPONSE, SUCCESS, FAILURE
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public enum Event
+ {
+ START, BUFFER
+ }
}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/INegotiationContext.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/INegotiationContext.java
index 756544f..dca0282 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/INegotiationContext.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/INegotiationContext.java
@@ -21,11 +21,17 @@ public interface INegotiationContext
public void transmitBuffer(ByteBuffer buffer);
- public void setBufferReceiver(IBufferReceiver receiver);
+ public void setReceiver(Receiver receiver);
- public void negotiationSuccess();
+ public Enum<?> getState();
- public void negotiationFailure();
+ public void setState(Enum<?> state);
+
+ public void setFinished(boolean success);
+
+ public Object getInfo();
+
+ public void setInfo(Object info);
/**
* @author Eike Stepper
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/INegotiator.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/INegotiator.java
index eada3f0..1b81cdf 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/INegotiator.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/INegotiator.java
@@ -15,5 +15,5 @@ package org.eclipse.net4j.util.security;
*/
public interface INegotiator
{
- public void startNegotiation(INegotiationContext context);
+ public void negotiate(INegotiationContext context, boolean initiator);
}