Author: rhauch
Date: 2009-05-04 13:32:44 -0400 (Mon, 04 May 2009)
New Revision: 877
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.java
trunk/dna-jcr/src/test/resources/repositoryStubImpl.properties
Log:
DNA-371 No Default JAAS Implementation
Applied the patch, which improves ExecutionContext by allowing the creation of a context
using the username and password for JAAS authentication, and which changes JcrRepository
to use this approach when authenticating with SimpleCredentials. There still is no test
for this, but that should be added subsequently.
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java 2009-05-04
17:21:43 UTC (rev 876)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java 2009-05-04
17:32:44 UTC (rev 877)
@@ -23,10 +23,16 @@
*/
package org.jboss.dna.graph;
+import java.io.IOException;
import java.security.AccessControlContext;
import java.security.AccessController;
import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.TextOutputCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
@@ -413,11 +419,33 @@
*/
public ExecutionContext with( String name,
CallbackHandler callbackHandler ) throws LoginException
{
- return new ExecutionContext(this, new LoginContext(name, callbackHandler));
+ LoginContext loginContext = new LoginContext(name, callbackHandler);
+ loginContext.login();
+
+ return new ExecutionContext(this, loginContext);
}
/**
* Create an {@link ExecutionContext} that is the same as this context, but which
uses the supplied
+ * {@link Configuration#getAppConfigurationEntry(String) application configuration
name} and a {@link CallbackHandler JAAS
+ * callback handler} to create a new {@link LoginContext login context} with the
given user ID and password.
+ *
+ * @param name the name of the {@link Configuration#getAppConfigurationEntry(String)
JAAS application configuration name}
+ * @param userId the user ID to use for authentication
+ * @param password the password to use for authentication
+ * @return the execution context that is identical with this execution context, but
with a different security context; never
+ * null
+ * @throws LoginException if there <code>name</code> is invalid (or there
is no login context named "other"), or if the
+ * <code>callbackHandler</code> is null
+ */
+ public ExecutionContext with( String name,
+ String userId,
+ char[] password ) throws LoginException {
+ return this.with(name, new UserPasswordCallbackHandler(userId, password));
+ }
+
+ /**
+ * Create an {@link ExecutionContext} that is the same as this context, but which
uses the supplied
* {@link Configuration#getAppConfigurationEntry(String) application configuration
name}, a {@link Subject JAAS subject}, and
* a {@link CallbackHandler JAAS callback handler} (used to handle authentication
callbacks).
*
@@ -434,7 +462,10 @@
public ExecutionContext with( String name,
Subject subject,
CallbackHandler callbackHandler ) throws LoginException
{
- return new ExecutionContext(this, new LoginContext(name, subject,
callbackHandler));
+ LoginContext loginContext = new LoginContext(name, subject, callbackHandler);
+ loginContext.login();
+
+ return new ExecutionContext(this, loginContext);
}
/**
@@ -471,4 +502,82 @@
// namespaceRegistry.register("dnadtd",
"http://www.jboss.org/dna/dtd/1.0");
// namespaceRegistry.register("dnaxml",
"http://www.jboss.org/dna/xml/1.0");
}
+
+ /**
+ * A simple {@link CallbackHandler callback handler} implementation that attempts to
provide a user ID and password to any
+ * callbacks that it handles.
+ */
+ protected final class UserPasswordCallbackHandler implements CallbackHandler {
+
+ private static final boolean LOG_TO_CONSOLE = false;
+
+ private final String userId;
+ private final char[] password;
+
+ protected UserPasswordCallbackHandler( String userId,
+ char[] password ) {
+ this.userId = userId;
+ this.password = password;
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ *
+ * @see
javax.security.auth.callback.CallbackHandler#handle(javax.security.auth.callback.Callback[])
+ */
+ public void handle( Callback[] callbacks ) throws UnsupportedCallbackException,
IOException {
+ for (int i = 0; i < callbacks.length; i++) {
+ if (callbacks[i] instanceof TextOutputCallback) {
+
+ // display the message according to the specified type
+ TextOutputCallback toc = (TextOutputCallback)callbacks[i];
+ if (!LOG_TO_CONSOLE) {
+ continue;
+ }
+
+ switch (toc.getMessageType()) {
+ case TextOutputCallback.INFORMATION:
+ System.out.println(toc.getMessage());
+ break;
+ case TextOutputCallback.ERROR:
+ System.out.println("ERROR: " + toc.getMessage());
+ break;
+ case TextOutputCallback.WARNING:
+ System.out.println("WARNING: " +
toc.getMessage());
+ break;
+ default:
+ throw new IOException("Unsupported message type: "
+ toc.getMessageType());
+ }
+
+ } else if (callbacks[i] instanceof NameCallback) {
+
+ // prompt the user for a username
+ NameCallback nc = (NameCallback)callbacks[i];
+
+ if (LOG_TO_CONSOLE) {
+ // ignore the provided defaultName
+ System.out.print(nc.getPrompt());
+ System.out.flush();
+ }
+
+ nc.setName(this.userId);
+
+ } else if (callbacks[i] instanceof PasswordCallback) {
+
+ // prompt the user for sensitive information
+ PasswordCallback pc = (PasswordCallback)callbacks[i];
+ if (LOG_TO_CONSOLE) {
+ System.out.print(pc.getPrompt());
+ System.out.flush();
+ }
+ pc.setPassword(this.password);
+
+ } else {
+ throw new UnsupportedCallbackException(callbacks[i],
"Unrecognized Callback");
+ }
+ }
+
+ }
+ }
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.java 2009-05-04 17:21:43
UTC (rev 876)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.java 2009-05-04 17:32:44
UTC (rev 877)
@@ -36,6 +36,7 @@
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
+import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import net.jcip.annotations.ThreadSafe;
import org.jboss.dna.common.util.CheckArg;
@@ -84,6 +85,11 @@
* @see DefaultOptions#PROJECT_NODE_TYPES
*/
PROJECT_NODE_TYPES,
+ /**
+ * The {@link Configuration#getAppConfigurationEntry(String) JAAS application
configuration name} that specifies which
+ * login modules should be used to validate credentials.
+ */
+ JAAS_LOGIN_CONFIG_NAME,
}
/**
@@ -94,6 +100,11 @@
* The default value for the {@link Options#PROJECT_NODE_TYPES} option is
{@value} .
*/
public static final String PROJECT_NODE_TYPES = Boolean.FALSE.toString();
+
+ /**
+ * The default value for the {@link Options#JAAS_LOGIN_CONFIG_NAME} option is
{@value} .
+ */
+ public static final String JAAS_LOGIN_CONFIG_NAME = "dna-jcr";
}
/**
@@ -105,6 +116,7 @@
// Initialize the unmodifiable map of default options ...
EnumMap<Options, String> defaults = new EnumMap<Options,
String>(Options.class);
defaults.put(Options.PROJECT_NODE_TYPES, DefaultOptions.PROJECT_NODE_TYPES);
+ defaults.put(Options.JAAS_LOGIN_CONFIG_NAME,
DefaultOptions.JAAS_LOGIN_CONFIG_NAME);
DEFAULT_OPTIONS = Collections.<Options, String>unmodifiableMap(defaults);
}
@@ -291,7 +303,8 @@
*
* @throws IllegalArgumentException if <code>credentials</code> is not
<code>null</code> but:
* <ul>
- * <li>provides neither a <code>getLoginContext()</code>
nor a <code>getAccessControlContext()</code> method.</li>
+ * <li>provides neither a <code>getLoginContext()</code>
nor a <code>getAccessControlContext()</code> method and is
+ * not an instance of {@code SimpleCredentials}.</li>
* <li>provides a <code>getLoginContext()</code> method
that doesn't return a {@link LoginContext}.
* <li>provides a <code>getLoginContext()</code> method
that returns a <code>null</code> {@link LoginContext}.
* <li>does not provide a <code>getLoginContext()</code>
method, but provides a <code>getAccessControlContext()</code>
@@ -336,8 +349,16 @@
}
execContext = executionContext.create(accessControlContext);
} catch (NoSuchMethodException error2) {
- throw new
IllegalArgumentException(JcrI18n.credentialsMustProvideJaasMethod.text(credentials.getClass()),
- error2);
+ if (credentials instanceof SimpleCredentials) {
+ SimpleCredentials simple = (SimpleCredentials)credentials;
+ execContext =
executionContext.with(options.get(Options.JAAS_LOGIN_CONFIG_NAME),
+ simple.getUserID(),
+ simple.getPassword());
+ } else {
+ throw new IllegalArgumentException(
+
JcrI18n.credentialsMustProvideJaasMethod.text(credentials.getClass()),
+ error2);
+ }
}
}
} catch (RuntimeException error) {
Modified: trunk/dna-jcr/src/test/resources/repositoryStubImpl.properties
===================================================================
--- trunk/dna-jcr/src/test/resources/repositoryStubImpl.properties 2009-05-04 17:21:43 UTC
(rev 876)
+++ trunk/dna-jcr/src/test/resources/repositoryStubImpl.properties 2009-05-04 17:32:44 UTC
(rev 877)
@@ -42,4 +42,12 @@
javax.jcr.tck.NodeTest.testRemoveMandatoryNode.nodename3=dnatest\:mandatoryChild
javax.jcr.tck.NodeTest.testSaveContstraintViolationException.nodetype2=dnatest\:nodeWithMandatoryProperty
javax.jcr.tck.NodeOrderableChildNodesTest.testOrderBeforeUnsupportedRepositoryOperationException.nodetype2=dnatest\:unorderableUnstructured
-javax.jcr.tck.NodeOrderableChildNodesTest.testOrderBeforeUnsupportedRepositoryOperationException.nodetype3=dnatest\:unorderableUnstructured
\ No newline at end of file
+javax.jcr.tck.NodeOrderableChildNodesTest.testOrderBeforeUnsupportedRepositoryOperationException.nodetype3=dnatest\:unorderableUnstructured
+
+# Test users
+javax.jcr.tck.superuser.name=superuser
+javax.jcr.tck.superuser.pwd=superuser
+javax.jcr.tck.readwrite.name=readwrite
+javax.jcr.tck.readwrite.pwd=readwrite
+javax.jcr.tck.readonly.name=readonly
+javax.jcr.tck.readonly.pwd=readonly
\ No newline at end of file