shibboleth-dev - Re: More defined custom extensions mechanism
Subject: Shibboleth Developers
List archive
- From: Ian Young <>
- To: Tom Scavo <>
- Cc: Chad La Joie <>, Shibboleth Developers <>
- Subject: Re: More defined custom extensions mechanism
- Date: Sat, 09 Jul 2005 15:59:43 +0100
Tom Scavo wrote:
You're idea is intriguing, Ian.
Here's my idea in concrete terms, as three patches against the current CVS head.
patch1.txt alters the IdP configuration file schema to allow any number of <Plugin> elements at the end. Each one must have name (random string you can use to refer to the plugin in code) and implementation (class name) attributes, but can have any other attributes and any content model; it's up to the plugin to decode those.
patch2.txt is applied to the idp directory. Most of the workings are in PluginCollection.java, which is mainly a knock-off of ProtocolHandlerFactory.java. There is some bridging code in IdPProtocolSupport.java and some code to pick up the Plugin elements in IdPResponder.java.
A plugin class has to have a null constructor. If it also implements the (pre-existing) PluggableConfigurationComponent interface, the instance is passed the <Plugin> element to configure itself with.
I've included an example plugin as TestPlugin.java, and there is a second hunk of changes in IdPResponder which demonstrates accessing a plugin from code. Neither of these are really part of what would want to be checked in; they are just here as targets for discussion.
Finally, patch3.txt is applied to the idp.xml and shows what the configuration code looks like.
I've played around with this a bit, and I still quite like it. If something along these lines were part of the base distribution, I could certainly implement my NAT stuff on top of it with minimal additional patching (when combined with Chad's new extension system).
Comments, anyone?
-- Ian
Index: dist.idp.xml
===================================================================
RCS file: /home/cvs/shibboleth/shibboleth/java/src/conf/dist.idp.xml,v
retrieving revision 1.9
diff -u -r1.9 dist.idp.xml
--- dist.idp.xml 8 Jul 2005 21:03:17 -0000 1.9
+++ dist.idp.xml 9 Jul 2005 14:18:02 -0000
@@ -117,5 +117,12 @@
<!--
<MetadataProvider
type="edu.internet2.middleware.shibboleth.metadata.provider.XMLMetadata"
uri="$SHIB_HOME$/etc/IQ-metadata.xml"/> -->
+
+ <!-- example generic plugins -->
+ <Plugin name="my.plugin"
implementation="edu.internet2.middleware.shibboleth.TestPlugin" foo="bar">
+ <SomeConfiguration>text</SomeConfiguration>
+ </Plugin>
+ <Plugin name="boring.plugin" implementation="java.util.Date"/>
+
</IdPConfig>
Index: shibboleth-idpconfig-1.0.xsd
===================================================================
RCS file:
/home/cvs/shibboleth/shibboleth/java/src/schemas/shibboleth-idpconfig-1.0.xsd,v
retrieving revision 1.18
diff -u -r1.18 shibboleth-idpconfig-1.0.xsd
--- shibboleth-idpconfig-1.0.xsd 1 Jul 2005 21:12:39 -0000 1.18
+++ shibboleth-idpconfig-1.0.xsd 9 Jul 2005 14:17:21 -0000
@@ -130,6 +130,16 @@
<xs:anyAttribute
namespace="##any" processContents="lax"/>
</xs:complexType>
</xs:element>
+ <xs:element name="Plugin"
minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:any
namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute
name="implementation" type="xs:string" use="required" />
+ <xs:attribute
name="name" type="xs:string" use="required" />
+ <xs:anyAttribute
namespace="##any" processContents="lax"/>
+ </xs:complexType>
+ </xs:element>
</xs:sequence>
<xs:attribute name="resolverConfig"
type="xs:string" use="optional" default="/conf/resolver.xml"/>
<xs:attribute name="AAUrl" type="xs:anyURI"
use="optional"/>
Index: IdPProtocolSupport.java
===================================================================
RCS file:
/home/cvs/shibboleth/shibboleth/java/src/edu/internet2/middleware/shibboleth/idp/IdPProtocolSupport.java,v
retrieving revision 1.16
diff -u -r1.16 IdPProtocolSupport.java
--- IdPProtocolSupport.java 20 Jun 2005 20:22:48 -0000 1.16
+++ IdPProtocolSupport.java 9 Jul 2005 14:34:34 -0000
@@ -71,6 +71,7 @@
private ArtifactMapper artifactMapper;
private Semaphore throttle;
private Trust trust = new ShibbolethTrust();
+ private PluginCollection plugins = new PluginCollection();
IdPProtocolSupport(IdPConfig config, Logger transactionLog,
NameMapper nameMapper, ServiceProviderMapper spMapper,
ArpEngine arpEngine, AttributeResolver resolver,
ArtifactMapper artifactMapper)
@@ -179,6 +180,15 @@
}
}
+
+ public Object getPlugin(String name) {
+ return plugins.get(name);
+ }
+
+ public void addPlugin(Element element) throws
ShibbolethConfigurationException {
+ plugins.add(element);
+ }
+
public int providerCount() {
return metadata.size();
Index: IdPResponder.java
===================================================================
RCS file:
/home/cvs/shibboleth/shibboleth/java/src/edu/internet2/middleware/shibboleth/idp/IdPResponder.java,v
retrieving revision 1.38
diff -u -r1.38 IdPResponder.java
--- IdPResponder.java 8 Jul 2005 17:41:58 -0000 1.38
+++ IdPResponder.java 9 Jul 2005 14:34:35 -0000
@@ -228,6 +228,13 @@
throw new
ShibbolethConfigurationException("Could not load SAML metadata.");
}
+ // Load generic plugins
+ itemElements =
idPConfig.getDocumentElement().getElementsByTagNameNS(IdPConfig.configNameSpace,
+ "Plugin");
+ for (int i = 0; i < itemElements.getLength(); i++) {
+ protocolSupport.addPlugin((Element)
itemElements.item(i));
+ }
+
log.info("Identity Provider initialization
complete.");
} catch (ShibbolethConfigurationException ae) {
@@ -252,6 +259,23 @@
MDC.put("remoteAddr", request.getRemoteAddr());
log.debug("Received a request via GET for location (" +
request.getRequestURL() + ").");
+ /*
+ * Example code using plugins... not part of the
implementation.
+ */
+ Object plugged = protocolSupport.getPlugin("my.plugin");
+ if (plugged instanceof TestPlugin) {
+ ((TestPlugin)plugged).sayHowdy();
+ }
+ plugged = protocolSupport.getPlugin("boring.plugin");
+ if (plugged != null)
+ log.info("boring plugin says: " + plugged);
+ plugged = protocolSupport.getPlugin("missing.plugin");
+ if (plugged != null) {
+ log.info("missing plugin says: " + plugged);
+ } else {
+ log.info("missing plugin is missing");
+ }
+
try {
IdPProtocolHandler activeHandler =
lookupProtocolHandler(request);
// Pass request to the appropriate handler
Index: PluginCollection.java
===================================================================
RCS file: PluginCollection.java
diff -N PluginCollection.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ PluginCollection.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,105 @@
+/*
+ * Copyright [2005] [University Corporation for Advanced Internet
Development, Inc.]
+ *
+ * Licensed 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 edu.internet2.middleware.shibboleth.idp;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Element;
+
+import
edu.internet2.middleware.shibboleth.common.PluggableConfigurationComponent;
+import
edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
+
+/**
+ * Collection class for loading generic plugin implementations based on XML
configuration.
+ *
+ * @author Ian Young, after Walter Hoehn
+ */
+public class PluginCollection {
+
+ private static Logger log =
Logger.getLogger(PluginCollection.class.getName());
+ private Map/*<String, Object>*/ plugins = new HashMap();
+
+ public Object get(String name) {
+ return plugins.get(name);
+ }
+
+ public void add(Element config) throws
ShibbolethConfigurationException {
+ String name = config.getAttribute("name");
+ if (name == null || name.equals("")) {
+ log.error("No plugin name specified. Attribute
(name) is "
+ + "required with element <Plugin/>.");
+ throw new ShibbolethConfigurationException("Invalid
configuration data supplied.");
+ }
+
+ String implementation = config.getAttribute("implementation");
+ if (implementation == null || implementation.equals("")) {
+ log.error("No plugin implementation specified.
Attribute (implementation) is "
+ + "required with element <Plugin/>.");
+ throw new ShibbolethConfigurationException("Invalid
configuration data supplied.");
+
+ } else {
+
+ log.info("Loading plugin \"" + name + "\"
implementation=" + implementation);
+ try {
+ Class implClass =
Class.forName(implementation);
+ Constructor constructor =
implClass.getConstructor(new Class[]{});
+ Object rawImpl = constructor.newInstance(new
Object[]{});
+
+ /*
+ * If the object is initializable, pass it
the element.
+ * If not, don't bother.
+ */
+ if (rawImpl instanceof
PluggableConfigurationComponent) {
+
((PluggableConfigurationComponent)rawImpl).initialize(config);
+ }
+
+ /*
+ * Register this plugin.
+ */
+ plugins.put(name, rawImpl);
+
+ } catch (ClassNotFoundException e) {
+ log.error("Invalid configuration, supplied
implementation class for the plugin "
+ + "could not be found: " +
e.getMessage());
+ throw new
ShibbolethConfigurationException("Invalid configuration data supplied.");
+
+ } catch (NoSuchMethodException e) {
+ log.error("Invalid configuration, supplied
implementation class for the plugin is "
+ + "not valid. A DOM Element
constructor is required: " + e.getMessage());
+ throw new
ShibbolethConfigurationException("Invalid configuration data supplied.");
+
+ } catch (InvocationTargetException e) {
+ Throwable cause = e.getCause();
+ if (cause != null) {
+ log.error(cause.getMessage());
+ }
+ log.error("Invalid configuration, supplied
implementation class for the plugin"
+ + " could not be loaded: " +
e.getMessage());
+ throw new
ShibbolethConfigurationException("Invalid configuration data supplied.");
+ } catch (Exception e) {
+ log.error("Invalid configuration, supplied
implementation class for the plugin"
+ + " could not be loaded: " +
e.getMessage());
+ throw new
ShibbolethConfigurationException("Invalid configuration data supplied.");
+ }
+ }
+ }
+
+}
Index: TestPlugin.java
===================================================================
RCS file: TestPlugin.java
diff -N TestPlugin.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ TestPlugin.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,22 @@
+package edu.internet2.middleware.shibboleth.idp;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Element;
+
+import
edu.internet2.middleware.shibboleth.common.PluggableConfigurationComponent;
+
+public class TestPlugin implements PluggableConfigurationComponent {
+
+ private static Logger log =
Logger.getLogger(TestPlugin.class.getName());
+ private String foo = "(unset)";
+
+ public void initialize(Element config) {
+ foo = config.getAttribute("foo");
+ if (foo == null || foo.equals("")) foo = "(missing)";
+ log.info("test plugin initialized, foo='" + foo + "'");
+ }
+
+ public void sayHowdy() {
+ log.info("plugin says howdy: '" + foo + "'");
+ }
+}
- Re: More defined custom extensions mechanism, (continued)
- Re: More defined custom extensions mechanism, Walter Hoehn, 07/06/2005
- Re: More defined custom extensions mechanism, Tom Scavo, 07/06/2005
- Re: More defined custom extensions mechanism, Walter Hoehn, 07/06/2005
- Re: More defined custom extensions mechanism, Tom Scavo, 07/06/2005
- Re: More defined custom extensions mechanism, Chad La Joie, 07/06/2005
- RE: More defined custom extensions mechanism, Scott Cantor, 07/06/2005
- Re: More defined custom extensions mechanism, Ian Young, 07/08/2005
- Re: More defined custom extensions mechanism, Tom Scavo, 07/08/2005
- Re: More defined custom extensions mechanism, Ian Young, 07/08/2005
- Re: More defined custom extensions mechanism, Ian Young, 07/09/2005
- RE: More defined custom extensions mechanism, Scott Cantor, 07/09/2005
- Re: More defined custom extensions mechanism, Ian Young, 07/09/2005
- RE: More defined custom extensions mechanism, Scott Cantor, 07/09/2005
- Re: More defined custom extensions mechanism, Ian Young, 07/11/2005
- RE: More defined custom extensions mechanism, Scott Cantor, 07/11/2005
- Re: More defined custom extensions mechanism, Ian Young, 07/11/2005
- RE: More defined custom extensions mechanism, Scott Cantor, 07/11/2005
- Re: More defined custom extensions mechanism, Brent Putman, 07/08/2005
Archive powered by MHonArc 2.6.16.