vgritsenko 2004/02/12 19:34:18
Modified: . status.xml
config web.xml
java/src/org/apache/xindice/client/xmldb/xmlrpc
CollectionImpl.java DatabaseImpl.java
tools/jetty/conf main.xml
Added: tools/jetty/conf realm.properties
Log:
Add support for server-level basic http authentication
Revision Changes Path
1.32 +3 -0 xml-xindice/status.xml
Index: status.xml
===================================================================
RCS file: /home/cvs/xml-xindice/status.xml,v
retrieving revision 1.31
retrieving revision 1.32
diff -u -r1.31 -r1.32
--- status.xml 12 Feb 2004 03:12:18 -0000 1.31
+++ status.xml 13 Feb 2004 03:34:17 -0000 1.32
@@ -70,6 +70,9 @@
<changes>
<release version="1.1b4-dev" date="February 11 2004">
<action dev="VG" type="update">
+ Xindice server and XML-RPC driver support basic HTTP
authentication.
+ </action>
+ <action dev="VG" type="update">
Xindice managed driver class renamed to DatabaseImpl and
supports
same configuration parameters as embedded driver.
Xindice managed driver supports multiple database instances.
1.11 +27 -2 xml-xindice/config/web.xml
Index: web.xml
===================================================================
RCS file: /home/cvs/xml-xindice/config/web.xml,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- web.xml 8 Feb 2004 01:11:34 -0000 1.10
+++ web.xml 13 Feb 2004 03:34:17 -0000 1.11
@@ -58,4 +58,29 @@
<servlet-name>xindice</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
+
+ <!--
+ - Security constraint on the Xindice WebApp allows to protect
+ - Xindice XML-RPC server with Basic HTTP Authentication.
+ -
+ - In addition to this configuration, servlet engine should have
+ - "xindice" realm configuration. For Jetty config, see
tools/jetty/main.xml
+ -
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Xindice Server</web-resource-name>
+ <url-pattern>/</url-pattern>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>xindice</role-name>
+ </auth-constraint>
+ </security-constraint>
+ <login-config>
+ <auth-method>BASIC</auth-method>
+ <realm-name>xindice</realm-name>
+ </login-config>
+ <security-role>
+ <role-name>xindice</role-name>
+ </security-role>
+ -->
</web-app>
1.44 +32 -60
xml-xindice/java/src/org/apache/xindice/client/xmldb/xmlrpc/CollectionImpl.java
Index: CollectionImpl.java
===================================================================
RCS file:
/home/cvs/xml-xindice/java/src/org/apache/xindice/client/xmldb/xmlrpc/CollectionImpl.java,v
retrieving revision 1.43
retrieving revision 1.44
diff -u -r1.43 -r1.44
--- CollectionImpl.java 8 Feb 2004 02:43:02 -0000 1.43
+++ CollectionImpl.java 13 Feb 2004 03:34:17 -0000 1.44
@@ -47,7 +47,6 @@
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.IOException;
import java.io.StringReader;
-import java.net.MalformedURLException;
import java.util.Hashtable;
import java.util.Vector;
import java.util.StringTokenizer;
@@ -65,16 +64,6 @@
private static final Log log = LogFactory.getLog(CollectionImpl.class);
/**
- * Host and port number of the database server
- */
- private String hostPort;
-
- /**
- * Location of the XML-RPC service in the web server
- */
- private String serviceLocation;
-
- /**
* The XML-RPC client stub, connected to the server
*/
private XmlRpcClient client = null;
@@ -83,53 +72,24 @@
* Creates new <code>CollectionImpl</code> instance representing
connection
* to server collection.
*
- * @param hostPort hostname and port number in <code>host:port</code>
format.
- * Port no is optional, in which case HTTP default is assumed.
- * @param serviceLocation is the path in the web server's namespace where
- * the XML-RPC service is mounted. It is <code>null</code> unless
- * the <code>service-location</code> property of
- * <code>org.apache.xindice.client.xmlrpc.DatabaseImpl</code>
- * is set.
+ * @param client XML-RPC client connected to the Xindice XML-RPC server.
* @param collPath is the name of the collection to open.
* @exception XMLDBException thrown if a connection could not be
established,
* because of URL syntax errors, or connection failure, or if
no
* collection with path <code>collPath</code> could be
located.
*/
- public CollectionImpl(String hostPort, String serviceLocation, String
collPath) throws XMLDBException {
+ public CollectionImpl(XmlRpcClient client, String collPath) throws
XMLDBException {
super(collPath);
+ this.client = client;
- this.hostPort = hostPort;
- this.serviceLocation = serviceLocation;
- String xmlRpcURL = "http://" + hostPort + serviceLocation;
- try {
- if (log.isDebugEnabled()) {
- log.debug("Using URL: '" + xmlRpcURL + "'");
- }
- client = new XmlRpcClient(xmlRpcURL);
-
- /* Just check the collection does actually exist */
- Hashtable params = new Hashtable();
- params.put(RPCDefaultMessage.COLLECTION, collPath);
- // TODO: In case of error get error code. Current XMLPRC does
not provide place for detailed error code.
- String exists = (String)
runRemoteCommand("GetCollectionConfiguration", params);
-
- if (!"yes".equals(exists)) {
- throw new XMLDBException(ErrorCodes.NO_SUCH_COLLECTION,
- "Collection not found: " +
collPath);
- }
- } catch (MalformedURLException e) {
- client = null;
- throw new XMLDBException(ErrorCodes.INVALID_URI, e);
- } catch (XMLDBException x) {
- throw x; // propagate any xmldb exception.
- } catch (IOException e) {
- client = null;
- throw new XMLDBException(ErrorCodes.UNKNOWN_ERROR,
FaultCodes.GEN_GENERAL_ERROR,
- "Cannot communicate with the server: "
+ xmlRpcURL, e);
- } catch (Exception e) {
- client = null;
- throw new XMLDBException(ErrorCodes.UNKNOWN_ERROR,
FaultCodes.JAVA_RUNTIME_ERROR,
- "Collection not found: " + collPath, e);
+ /* Just check the collection does actually exist */
+ Hashtable params = new Hashtable();
+ params.put(RPCDefaultMessage.COLLECTION, collPath);
+ String exists = (String)
runRemoteCommand("GetCollectionConfiguration", params);
+
+ if (!"yes".equals(exists)) {
+ throw new XMLDBException(ErrorCodes.NO_SUCH_COLLECTION,
+ "Collection not found: " + collPath);
}
}
@@ -141,16 +101,19 @@
* @return the return value from the server. Type of return value
depends on
* command.
*
- * @exception Exception thrown if XML-RPC reports an exception.
+ * @exception XMLDBException thrown if XML-RPC reports an exception.
*/
- private Object runRemoteCommand(String cmdName, Hashtable params) throws
Exception {
-
+ private Object runRemoteCommand(String cmdName, Hashtable params) throws
XMLDBException {
try {
params.put(RPCMessageInterface.MESSAGE_PARAM, cmdName);
Vector v = new Vector();
v.add(params);
return ((Hashtable) client.execute("run",
v)).get(RPCDefaultMessage.RESULT);
} catch (XmlRpcException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("Got XmlRpc exception running command " + cmdName,
e);
+ }
+
// HACK: Dirty hack to pass at least some diagnostic info
through XmlRpc
// See also RPCMessageInterface.run()
StringTokenizer st = new StringTokenizer(e.getMessage(), ":");
@@ -164,7 +127,12 @@
// Ignore
}
}
- throw e;
+
+ throw new XMLDBException(ErrorCodes.UNKNOWN_ERROR,
FaultCodes.GEN_GENERAL_ERROR,
+ "Failed to execute command '" + cmdName
+ "' on server: " + client.getURL() + ", message: " + e.getMessage(), e);
+ } catch (IOException e) {
+ throw new XMLDBException(ErrorCodes.UNKNOWN_ERROR,
FaultCodes.GEN_GENERAL_ERROR,
+ "Cannot communicate with the server: "
+ client.getURL(), e);
}
}
@@ -292,12 +260,16 @@
/* see superclass for documentation */
public boolean isOpen() {
+
return (client != null);
}
/* see superclass for documentation */
public String getURI() {
- return "xmldb:" + DatabaseImpl.DRIVER_NAME + "://" + hostPort +
collPath;
+
+ return "xmldb:" + DatabaseImpl.DRIVER_NAME + "://" +
+ client.getURL().getHost() + ':' + client.getURL().getPort() +
+ collPath;
}
/**
@@ -319,7 +291,7 @@
}
try {
- return new CollectionImpl(hostPort, serviceLocation, collPath +
"/" + name);
+ return new CollectionImpl(client, collPath + "/" + name);
} catch (XMLDBException e) {
if (e.errorCode == ErrorCodes.NO_SUCH_COLLECTION) {
@@ -393,7 +365,7 @@
}
try {
- return new CollectionImpl(hostPort, serviceLocation,
collPath.substring(0, collPath.lastIndexOf('/')));
+ return new CollectionImpl(client, collPath.substring(0,
collPath.lastIndexOf('/')));
} catch (XMLDBException e) {
if (e.errorCode == ErrorCodes.NO_SUCH_COLLECTION) {
// per getParentCollection contract, return null if no parent
1.22 +128 -38
xml-xindice/java/src/org/apache/xindice/client/xmldb/xmlrpc/DatabaseImpl.java
Index: DatabaseImpl.java
===================================================================
RCS file:
/home/cvs/xml-xindice/java/src/org/apache/xindice/client/xmldb/xmlrpc/DatabaseImpl.java,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -r1.21 -r1.22
--- DatabaseImpl.java 12 Feb 2004 13:11:06 -0000 1.21
+++ DatabaseImpl.java 13 Feb 2004 03:34:17 -0000 1.22
@@ -22,20 +22,36 @@
import org.apache.commons.logging.LogFactory;
import org.apache.xindice.client.xmldb.CommonConfigurable;
import org.apache.xmlrpc.XmlRpc;
+import org.apache.xmlrpc.XmlRpcClient;
import org.xmldb.api.base.Collection;
import org.xmldb.api.base.Database;
import org.xmldb.api.base.ErrorCodes;
import org.xmldb.api.base.XMLDBException;
+import java.net.MalformedURLException;
+
/**
- * implements XML:DB's <code>Database</code> interface using XML-RPC to
- * communicate with the Xindice server.
+ * Implements XML:DB's <code>Database</code> interface using XML-RPC to
communicate
+ * with the Xindice XML-RPC server. Usually, this class is not used
+ * directly, but [EMAIL PROTECTED]
org.apache.xindice.client.xmldb.DatabaseImpl} is used instead.
*
* Note this class is a database <em>driver</em>, and one class of this
database
- * could be used to connect to <em>many</em> different databases.
+ * could be used to connect to <em>many</em> different databases, on one or
+ * different Xindice XML-RPC servers.
+ *
+ * XML-RPC database driver uses following configuration parameters:
+ * <ul>
+ * <li><strong>service-location</strong>: Specifies path to the Xindice
server WebApp</li>
+ * <li><strong>xmlrpc-driver</strong>: Specifies name of the SAX parser to
use</li>
+ * <li><strong>xmlrpc-user</strong>: If server protected with HTTP Basic
Auth, specifies user name</li>
+ * <li><strong>xmlrpc-password</strong>: If server protected with HTTP Basic
Auth, specifies password</li>
+ * </ul>
+ *
+ * If one of these parameters is not specified, system properties will be
used.
*
* @author <a href="mailto:[EMAIL PROTECTED]">James Bates</a>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Vadim Gritsenko</a>
* @version CVS $Revision$, $Date$
*/
public class DatabaseImpl extends CommonConfigurable implements Database {
@@ -48,14 +64,14 @@
private static final String PROP_SERVICE_LOCATION = "service-location";
/**
- * Driver property name for the SAX parser xml-rpc will use.
+ * System property name for the service location
*/
- private static final String PROP_XMLRPC_DRIVER = "xmlrpc-driver";
+ private static final String SYSPROP_SERVICE_LOCATION =
"xindice.xmlrpc.service-location";
/**
- * System property name for the service location
+ * Driver property name for the SAX parser xml-rpc will use.
*/
- private static final String SYSPROP_SERVICE_LOCATION =
"xindice.xmlrpc.service-location";
+ private static final String PROP_XMLRPC_DRIVER = "xmlrpc-driver";
/**
* System property name for the SAX parser xml-rpc will use in case
@@ -64,6 +80,28 @@
private static final String SYSPROP_XMLRPC_DRIVER =
"xindice.xmlrpc.driver";
/**
+ * Driver property name for the basic authentication user name.
+ */
+ private static final String PROP_XMLRPC_USER = "xmlrpc-user";
+
+ /**
+ * System property name for the basic authentication user name in case
+ * there were no configuration property passed
+ */
+ private static final String SYSPROP_XMLRPC_USER = "xindice.xmlrpc.user";
+
+ /**
+ * Driver property name for the basic authentication password.
+ */
+ private static final String PROP_XMLRPC_PASSWORD = "xmlrpc-password";
+
+ /**
+ * System property name for the basic authentication password in case
+ * there were no configuration property passed
+ */
+ private static final String SYSPROP_XMLRPC_PASSWORD =
"xindice.xmlrpc.password";
+
+ /**
* Default value of the xmlrpc-driver property
*/
private static final String DEFAULT_XMLRPC_DRIVER = "xerces";
@@ -84,7 +122,7 @@
private static final String CONFORMANCE_LEVEL = "0";
/**
- * Ensures that XML-RPC initialized just once
+ * Ensures that XML-RPC static properties initialized just once
*/
private static boolean xmlRpcInitialized;
@@ -93,10 +131,14 @@
*/
private String serviceLocation;
+ private String basicUser;
+ private String basicPassword;
+
+
/**
* Create a new DatabaseImpl object.
*/
- public DatabaseImpl() throws XMLDBException {
+ public DatabaseImpl() {
super();
}
@@ -107,7 +149,7 @@
* @param config from which the initial parameters for this
* DatabaseImpl object are copied.
*/
- public DatabaseImpl(CommonConfigurable config) throws XMLDBException {
+ public DatabaseImpl(CommonConfigurable config) {
super(config);
}
@@ -129,8 +171,7 @@
}
/**
- * Initialize XML-RPC static properties: encoding, keep-alive, SAX
driver.
- * Initialize XML-RPC service location.
+ * Initialize XML-RPC library static properties: encoding, keep-alive,
SAX driver.
*
* @throws XMLDBException if specified (or default, if none specified)
SAX driver
* class could not be loaded
@@ -143,9 +184,10 @@
/*
* Determine the SAXparser the xmlrpc client will use.
+ *
* In priority order:
* DatabaseImpl xmlrpc-driver property
- * (passed in the xmlrpcDriver parameter)
+ * (passed in the xmlrpc-driver parameter)
* System property "xindice.xmlrpc.driver"
* Default value "xerces"
*/
@@ -170,34 +212,85 @@
xmlRpcInitialized = true;
}
+ }
+
+ /**
+ * Initialize XML-RPC service location, basic authentication.
+ * Create XML-RPC client.
+ *
+ * @param hostPort of the Xindice XML-RPC server
+ * @return XML-RPC client connected to the Xindice server
+ * @throws XMLDBException
+ */
+ private XmlRpcClient connect(String hostPort) throws XMLDBException {
+
+ // Initialize XML-RPC static properties
+ initialize();
- if (this.serviceLocation == null) {
- /*
- * Determine the path in the web server to the XML-RPC service.
- * In priority order:
- * DatabaseImpl service-location property
- * (passed in the serviceLocation parameter)
- * System property "xindice.xmlrpc.service-location"
- * Default value "/xindice/"
- */
- serviceLocation = getProperty(PROP_SERVICE_LOCATION);
+ synchronized (this) {
if (serviceLocation == null) {
- serviceLocation =
System.getProperty(SYSPROP_SERVICE_LOCATION);
+
+ /*
+ * Determine the path in the web server to the XML-RPC
service.
+ *
+ * In priority order:
+ * DatabaseImpl service-location property
+ * (passed in the serviceLocation parameter)
+ * System property "xindice.xmlrpc.service-location"
+ * Default value "/xindice/"
+ */
+ serviceLocation = getProperty(PROP_SERVICE_LOCATION);
if (serviceLocation == null) {
- serviceLocation = DEFAULT_SERVICE_LOCATION;
+ serviceLocation =
System.getProperty(SYSPROP_SERVICE_LOCATION);
+ if (serviceLocation == null) {
+ serviceLocation = DEFAULT_SERVICE_LOCATION;
+ }
}
- }
- if (!serviceLocation.startsWith("/")) {
- serviceLocation = "/" + serviceLocation;
- }
- if (!serviceLocation.endsWith("/")) {
- serviceLocation = serviceLocation + "/";
+ if (!serviceLocation.startsWith("/")) {
+ serviceLocation = "/" + serviceLocation;
+ }
+ if (!serviceLocation.endsWith("/")) {
+ serviceLocation = serviceLocation + "/";
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("Using Service Location: '" + serviceLocation
+ "'");
+ }
+
+ /*
+ * Determine basic authentication parameters
+ */
+ basicUser = getProperty(PROP_XMLRPC_USER);
+ if (basicUser == null) {
+ basicUser = System.getProperty(SYSPROP_XMLRPC_USER);
+ }
+
+ if (basicUser != null) {
+ basicPassword = getProperty(PROP_XMLRPC_PASSWORD);
+ if (basicPassword == null) {
+ basicPassword =
System.getProperty(SYSPROP_XMLRPC_PASSWORD);
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("Using Basic authentication. User: '" +
basicUser + "', password: '" + basicPassword + "'");
+ }
+ }
}
+ }
+
+ String xmlRpcURL = "http://" + hostPort + serviceLocation;
+ try {
if (log.isDebugEnabled()) {
- log.debug("Using Service Location: '" + serviceLocation +
"'");
+ log.debug("Using URI: '" + xmlRpcURL + "'");
}
+ XmlRpcClient client = new XmlRpcClient(xmlRpcURL);
+ if (basicUser != null) {
+ client.setBasicAuthentication(basicUser, basicPassword);
+ }
+ return client;
+ } catch (MalformedURLException e) {
+ throw new XMLDBException(ErrorCodes.INVALID_URI, e);
}
}
@@ -249,11 +342,8 @@
hostPort = "127.0.0.1:8888";
}
- // Init XML-RPC in case it is not initialized yet. Initialize
serviceLocation
- initialize();
-
try {
- return new CollectionImpl(hostPort, serviceLocation, collPath);
+ return new CollectionImpl(connect(hostPort), collPath);
} catch (XMLDBException e) {
if (e.errorCode == ErrorCodes.NO_SUCH_COLLECTION) {
// per getCollection contract, return null if not found
1.3 +13 -1 xml-xindice/tools/jetty/conf/main.xml
Index: main.xml
===================================================================
RCS file: /home/cvs/xml-xindice/tools/jetty/conf/main.xml,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- main.xml 4 Aug 2003 02:10:30 -0000 1.2
+++ main.xml 13 Feb 2004 03:34:18 -0000 1.3
@@ -27,6 +27,19 @@
</Arg>
</Call>
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+ <!-- Add and configure "xindice" user realm -->
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+ <Call name="addRealm">
+ <Arg>
+ <New class="org.mortbay.http.HashUserRealm">
+ <Arg>xindice</Arg>
+ <Arg><SystemProperty name="xindice.home"
default="."/>/tools/jetty/conf/realm.properties</Arg>
+ <Set name="Name">xindice</Set>
+ </New>
+ </Arg>
+ </Call>
+
<!-- =============================================================== -->
<!-- Configure the Contexts -->
<!-- =============================================================== -->
@@ -48,6 +61,5 @@
<Arg><SystemProperty name="webapp" default="."/></Arg>
<Set name="defaultsDescriptor">./tools/jetty/conf/webdefaults.xml</Set>
</Call>
-
</Configure>
1.1 xml-xindice/tools/jetty/conf/realm.properties
Index: realm.properties
===================================================================
#
# This is a HashUserRealm defining users passwords and roles.
# The format is
# <username>: <password>[,<rolename> ...]
#
# Passwords may be clear text, obfuscated or checksummed. The class
# org.mortbay.util.Password should be used to generate obfuscated
# passwords or password checksums
xindice: manager, xindice