Added the ability for the resolver to compute attribute values via scripts included...
authorwassa <wassa@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Wed, 24 May 2006 16:58:33 +0000 (16:58 +0000)
committerwassa <wassa@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Wed, 24 May 2006 16:58:33 +0000 (16:58 +0000)
git-svn-id: https://subversion.switch.ch/svn/shibboleth/java-idp/trunk@1945 ab3bd59b-922f-494d-bb5f-6f0a3c29deca

.classpath
src/conf/resolver.scriptlet.xml [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/aa/attrresolv/ResolutionPlugInFactory.java
src/edu/internet2/middleware/shibboleth/aa/attrresolv/provider/ScriptletAttributeDefinition.java [new file with mode: 0644]
src/schemas/shibboleth-resolver-1.0.xsd
webApplication/WEB-INF/lib/bsh-2.0b1.jar [new file with mode: 0644]

index 4d173ac..38d78de 100644 (file)
@@ -32,5 +32,6 @@
        <classpathentry kind="lib" path="testlib/nekohtml.jar"/>
        <classpathentry kind="lib" path="webApplication/WEB-INF/lib/commons-codec-1.3.jar"/>
        <classpathentry kind="lib" path="lib/commons-io-1.1.jar"/>
+       <classpathentry kind="lib" path="webApplication/WEB-INF/lib/bsh-2.0b1.jar"/>
        <classpathentry kind="output" path="webApplication/WEB-INF/classes"/>
 </classpath>
diff --git a/src/conf/resolver.scriptlet.xml b/src/conf/resolver.scriptlet.xml
new file mode 100644 (file)
index 0000000..96773f8
--- /dev/null
@@ -0,0 +1,20 @@
+<AttributeResolver xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:mace:shibboleth:resolver:1.0" xsi:schemaLocation="urn:mace:shibboleth:resolver:1.0 shibboleth-resolver-1.0.xsd">
+       
+       <SimpleAttributeDefinition id="urn:mace:dir:attribute-def:eduPersonEntitlement">
+               <DataConnectorDependency requires="echo"/>
+       </SimpleAttributeDefinition>
+       
+       <ScriptletAttributeDefinition id="urn:mace:dir:attribute-def:eduPersonAffiliation">
+               <DataConnectorDependency requires="echo"/>
+               <Scriptlet>
+                       Attributes attributes = dependencies.getConnectorResolution("echo");
+                       Attribute affiliation = attributes.get("eduPersonAffiliation");
+                       if (affiliation != null &amp;&amp; affiliation.size() > 0) {
+                               resolverAttribute.addValue(attributes.get("eduPersonAffiliation").get(0));
+                       }
+               </Scriptlet>
+       </ScriptletAttributeDefinition>
+       
+       <CustomDataConnector id="echo" class="edu.internet2.middleware.shibboleth.aa.attrresolv.provider.SampleConnector"/>
+
+</AttributeResolver>
index 3ae9b69..5db669b 100644 (file)
@@ -22,6 +22,7 @@ import edu.internet2.middleware.shibboleth.aa.attrresolv.provider.MappedAttribut
 import edu.internet2.middleware.shibboleth.aa.attrresolv.provider.PersistentIDAttributeDefinition;
 import edu.internet2.middleware.shibboleth.aa.attrresolv.provider.RegExAttributeDefinition;
 import edu.internet2.middleware.shibboleth.aa.attrresolv.provider.SAML2PersistentID;
+import edu.internet2.middleware.shibboleth.aa.attrresolv.provider.ScriptletAttributeDefinition;
 import edu.internet2.middleware.shibboleth.aa.attrresolv.provider.SimpleAttributeDefinition;
 import edu.internet2.middleware.shibboleth.aa.attrresolv.provider.StaticDataConnector;
 
@@ -60,6 +61,8 @@ public class ResolutionPlugInFactory {
                if (e.getTagName().equals("CompositeAttributeDefinition")) { return new CompositeAttributeDefinition(e); }
 
                if (e.getTagName().equals("MappedAttributeDefinition")) { return new MappedAttributeDefinition(e); }
+               
+               if (e.getTagName().equals("ScriptletAttributeDefinition")) { return new ScriptletAttributeDefinition(e); }
 
                log.error("Unrecognized PlugIn type: " + e.getTagName());
                throw new AttributeResolverException("Failed to initialize PlugIn.");
diff --git a/src/edu/internet2/middleware/shibboleth/aa/attrresolv/provider/ScriptletAttributeDefinition.java b/src/edu/internet2/middleware/shibboleth/aa/attrresolv/provider/ScriptletAttributeDefinition.java
new file mode 100644 (file)
index 0000000..c1c9385
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * 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.aa.attrresolv.provider;
+
+import java.security.Principal;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import bsh.EvalError;
+import bsh.Interpreter;
+import bsh.ParseException;
+import bsh.TargetError;
+import edu.internet2.middleware.shibboleth.aa.attrresolv.AttributeDefinitionPlugIn;
+import edu.internet2.middleware.shibboleth.aa.attrresolv.Dependencies;
+import edu.internet2.middleware.shibboleth.aa.attrresolv.ResolutionPlugInException;
+import edu.internet2.middleware.shibboleth.aa.attrresolv.ResolverAttribute;
+
+/**
+ * <code>AttributeDefinitionPlugIn</code> implementation that determines resolved values by evaluating a section of
+ * java code specified in the resolver configuration. The java code be placed inside of a <Scriptlet/> child element.
+ * 
+ * @author Walter Hoehn
+ */
+
+public class ScriptletAttributeDefinition extends BaseAttributeDefinition implements AttributeDefinitionPlugIn {
+
+       private String script;
+       private static Logger log = Logger.getLogger(ScriptletAttributeDefinition.class.getName());
+
+       public ScriptletAttributeDefinition(Element e) throws ResolutionPlugInException {
+
+               super(e);
+
+               NodeList scriptlets = e.getElementsByTagName("Scriptlet");
+
+               if (scriptlets.getLength() < 1) {
+                       log.error("The Scriptlet Attribute Definition requires a <Scriptlet/> element.");
+                       throw new ResolutionPlugInException("Unable to load Attribute Definition.");
+               }
+               if (scriptlets.getLength() > 1) {
+                       log.warn("Scriptlet Attribute Definition contained more than one scriptlet.  Ignoring all but the first.");
+               }
+
+               Node tnode = ((Element) scriptlets.item(0)).getFirstChild();
+               if (tnode != null && tnode.getNodeType() == Node.TEXT_NODE) {
+                       script = tnode.getNodeValue();
+               }
+
+               // Sanity check
+               if (script == null || script.equals("")) {
+                       log.error("The Scriptlet Attribute Definition requires a <Scriptlet/> element that "
+                                       + "contains java code.");
+                       throw new ResolutionPlugInException("Unable to load Attribute Definition.");
+               }
+               try {
+                       loadBshInterpreter().eval(script);
+
+                       // FUTURE It would be really nice if we could do a better job of checking for errors here
+               } catch (ParseException pe) {
+                       log.error("The code supplied in the <Scriptlet/> element cannot " + "be parsed by the interpreter: "
+                                       + pe.getMessage());
+                       throw new ResolutionPlugInException("Unable to load Attribute Definition.");
+
+               } catch (Exception ge) {
+                       // this is expected... probably a NullPointer. We just want to ensure that the script will parse
+               }
+
+       }
+
+       public void resolve(ResolverAttribute attribute, Principal principal, String requester, String responder,
+                       Dependencies depends) throws ResolutionPlugInException {
+
+               try {
+
+                       standardProcessing(attribute);
+
+                       Interpreter beanShellInterpreter = loadBshInterpreter();
+
+                       // Export accessible variables to the scriptlet
+                       beanShellInterpreter.set("resolverAttribute", attribute);
+                       beanShellInterpreter.set("principal", principal);
+                       beanShellInterpreter.set("requester", requester);
+                       beanShellInterpreter.set("responder", responder);
+                       beanShellInterpreter.set("dependencies", depends);
+                       beanShellInterpreter.set("log", log);
+
+                       // Run the scriptlet
+                       beanShellInterpreter.eval(script);
+
+                       attribute.setResolved();
+
+               } catch (EvalError e) {
+                       if (e instanceof TargetError) {
+                               if (((TargetError) e).getTarget() instanceof ResolutionPlugInException) { throw (ResolutionPlugInException) ((TargetError) e)
+                                               .getTarget(); }
+                       }
+                       log.error("Encountered an error while evaluating the Attribute Definition scriptlet: " + e.getMessage());
+                       throw new ResolutionPlugInException("Unable to determine attribute's values.");
+               }
+       }
+
+       private Interpreter loadBshInterpreter() {
+
+               Interpreter beanShellInterpreter = new Interpreter();
+
+               // Be friendy and import classes that will be needed in the scriptlet
+               beanShellInterpreter.getNameSpace().importClass(
+                               "edu.internet2.middleware.shibboleth.aa.attrresolv.ResolverAttribute");
+               beanShellInterpreter.getNameSpace().importClass(
+                               "edu.internet2.middleware.shibboleth.aa.attrresolv.Dependencies");
+               beanShellInterpreter.getNameSpace().importClass("org.apache.log4j.Logger");
+               beanShellInterpreter.getNameSpace().importClass(
+                               "edu.internet2.middleware.shibboleth.aa.attrresolv.ResolutionPlugInException");
+               beanShellInterpreter.getNameSpace().importClass("javax.naming.directory.Attributes");
+               beanShellInterpreter.getNameSpace().importClass("javax.naming.directory.Attribute");
+               beanShellInterpreter.getNameSpace().importClass(
+                               "edu.memphis.idmanagement.provisioning.ProvisioningEngineException");
+
+               // Import any pre-defined scriptlet commands
+               beanShellInterpreter.getNameSpace().importCommands(
+                               "edu.internet2.middleware.shibboleth.aa.attrresolv.provider.scriptlet");
+
+               return beanShellInterpreter;
+       }
+
+}
index 83b703a..c3dec2b 100644 (file)
                                                </xs:complexContent>
                                        </xs:complexType>
                                </xs:element>
+                               <xs:element name="ScriptletAttributeDefinition" minOccurs="0" maxOccurs="unbounded">
+                                       <xs:complexType>
+                                               <xs:complexContent>
+                                                       <xs:extension base="resolver:BaseAttributeDefinition">
+                                                               <xs:sequence>
+                                                                       <xs:element name="Scriptlet" type="xs:string" minOccurs="1" maxOccurs="1"/>
+                                                               </xs:sequence>
+                                                               <xs:attribute name="sourceName" type="xs:string" use="optional"/>
+                                                               <xs:attribute name="valueHandler" type="xs:string" use="optional"/>
+                                                       </xs:extension>
+                                               </xs:complexContent>
+                                       </xs:complexType>
+                               </xs:element>
                                <xs:element name="CustomAttributeDefinition" minOccurs="0" maxOccurs="unbounded">
                                        <xs:complexType>
                                                <xs:complexContent>
diff --git a/webApplication/WEB-INF/lib/bsh-2.0b1.jar b/webApplication/WEB-INF/lib/bsh-2.0b1.jar
new file mode 100644 (file)
index 0000000..c005694
Binary files /dev/null and b/webApplication/WEB-INF/lib/bsh-2.0b1.jar differ