import org.opensaml.SAMLAssertion;
import org.opensaml.SAMLAttribute;
import org.opensaml.SAMLAttributeStatement;
+import org.opensaml.SAMLException;
import org.opensaml.SAMLObject;
import org.opensaml.artifact.Artifact;
import org.w3c.dom.Document;
import x0.maceShibbolethTargetConfig1.PathDocument.Path;
import x0.maceShibbolethTargetConfig1.SHIREDocument.SHIRE;
import x0.maceShibbolethTargetConfig1.ShibbolethTargetConfigDocument.ShibbolethTargetConfig;
-import edu.internet2.middleware.shibboleth.common.AAP;
-import edu.internet2.middleware.shibboleth.common.AttributeRule;
+import edu.internet2.middleware.shibboleth.aap.AAP;
+import edu.internet2.middleware.shibboleth.aap.AttributeRule;
import edu.internet2.middleware.shibboleth.common.Credentials;
import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
import edu.internet2.middleware.shibboleth.common.XML;
* Empty SAML elements get removed from the assertion.
* This can yield an AttributeAssertion with no attributes.
*
- * @param entity Origin site that sent the assertion
* @param assertion SAML Attribute Assertion
+ * @param role Role that issued the assertion
+ * @throws SAMLException Raised if assertion is mangled beyond repair
*/
- void applyAAP(EntityDescriptor entity, SAMLAssertion assertion) {
+ void applyAAP(SAMLAssertion assertion, RoleDescriptor role) throws SAMLException {
// Foreach AAP in the collection
AAP[] providers = getAAPProviders();
+ if (providers.length == 0) {
+ log.info("no filters specified, accepting entire assertion");
+ return;
+ }
for (int i=0;i<providers.length;i++) {
AAP aap = providers[i];
- if (aap.isAnyAttribute())
+ if (aap.anyAttribute()) {
+ log.info("any attribute enabled, accepting entire assertion");
continue;
-
- // Foreach Statement in the Assertion
- Iterator statements = assertion.getStatements();
- int istatement=0;
- while (statements.hasNext()) {
- Object statement = statements.next();
- if (statement instanceof SAMLAttributeStatement) {
- SAMLAttributeStatement attributeStatement =
- (SAMLAttributeStatement) statement;
-
- // Foreach Attribute in the AttributeStatement
- Iterator attributes = attributeStatement.getAttributes();
- int iattribute=0;
- while (attributes.hasNext()) {
- SAMLAttribute attribute =
- (SAMLAttribute) attributes.next();
- String name = attribute.getName();
- String namespace = attribute.getNamespace();
- AttributeRule rule = aap.lookup(name,namespace);
- if (rule==null) {
- // TODO Not sure, but code appears to keep unknown attributes
- log.warn("No rule found for attribute "+name);
- iattribute++;
- continue;
- }
- rule.apply(entity,attribute);
- if (!attribute.getValues().hasNext())
- attributeStatement.removeAttribute(iattribute);
- else
- iattribute++;
-
- }
- if (!attributeStatement.getAttributes().hasNext())
- assertion.removeStatement(istatement);
- else
- istatement++;
- } else {
- istatement++;
+ }
+ }
+
+ // Foreach Statement in the Assertion
+ Iterator statements = assertion.getStatements();
+ int istatement=0;
+ while (statements.hasNext()) {
+ Object statement = statements.next();
+ if (statement instanceof SAMLAttributeStatement) {
+ SAMLAttributeStatement attributeStatement = (SAMLAttributeStatement) statement;
+
+ // Check each attribute, applying any matching rules.
+ Iterator attributes = attributeStatement.getAttributes();
+ int iattribute=0;
+ while (attributes.hasNext()) {
+ SAMLAttribute attribute = (SAMLAttribute) attributes.next();
+ boolean ruleFound = false;
+ for (int i=0;i<providers.length;i++) {
+ AttributeRule rule = providers[i].lookup(attribute.getName(),attribute.getNamespace());
+ if (rule!=null) {
+ ruleFound = true;
+ try {
+ rule.apply(attribute,role);
+ }
+ catch (SAMLException ex) {
+ log.info("no values remain, removing attribute");
+ attributeStatement.removeAttribute(iattribute--);
+ break;
+ }
+ }
+ }
+ if (!ruleFound) {
+ log.warn("no rule found for attribute (" + attribute.getName() + "), filtering it out");
+ attributeStatement.removeAttribute(iattribute--);
+ }
+ iattribute++;
+ }
+
+ try {
+ attributeStatement.checkValidity();
+ istatement++;
+ }
+ catch (SAMLException ex) {
+ // The statement is now defunct.
+ log.info("no attributes remain, removing statement");
+ assertion.removeStatement(istatement);
}
}
}
- }
+
+ // Now see if we trashed it irrevocably.
+ assertion.checkValidity();
+ }
/**
*/
package edu.internet2.middleware.shibboleth.serviceprovider;
-import java.util.HashMap;
import java.util.Iterator;
-import java.util.Map;
-import java.util.regex.Pattern;
import org.apache.log4j.Logger;
-import org.apache.xmlbeans.XmlException;
-import org.opensaml.SAMLAttribute;
+import org.opensaml.SAMLException;
-import x0.maceShibboleth1.AttributeAcceptancePolicyDocument;
-import x0.maceShibboleth1.AttributeRuleType;
-import x0.maceShibboleth1.AttributeRuleValueType;
-import x0.maceShibboleth1.AttributeAcceptancePolicyDocument.AttributeAcceptancePolicy;
-import x0.maceShibboleth1.SiteRuleDocument.SiteRule;
-import x0.maceShibboleth1.SiteRuleType.Scope;
-import x0.maceShibboleth1.SiteRuleType;
-import edu.internet2.middleware.shibboleth.common.AAP;
-import edu.internet2.middleware.shibboleth.common.AttributeRule;
-import edu.internet2.middleware.shibboleth.metadata.EntityDescriptor;
+import edu.internet2.middleware.shibboleth.aap.provider.XMLAAPProvider;
+import edu.internet2.middleware.shibboleth.aap.AAP;
+import edu.internet2.middleware.shibboleth.aap.AttributeRule;
+import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
+
+import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
PluggableConfigurationComponent {
private static Logger log = Logger.getLogger(XMLAAPImpl.class);
+ XMLAAPProvider realObject = null;
- private boolean anyAttribute=false;
- private AttributeRule[] attributeRules;
-
-
- public void initialize(Node dom)
- throws XmlException {
- AttributeAcceptancePolicyDocument bean = AttributeAcceptancePolicyDocument.Factory.parse(dom);
- AttributeAcceptancePolicy aapbean = bean.getAttributeAcceptancePolicy();
- if (null!=aapbean.getAnyAttribute())
- anyAttribute=true; // There is an anyAttribute element
-
- AttributeRuleType[] rulebeans = aapbean.getAttributeRuleArray();
- attributeRules = new AttributeRule[rulebeans.length];
- for (int i=0;i<rulebeans.length;i++) {
- attributeRules[i]=new XMLAttributeRuleImpl(rulebeans[i]);
- }
- }
-
+ public void initialize(Node dom) throws ShibbolethConfigurationException {
+ try {
+ // Assuming this just gets a DOM tree containing the AAP,
+ // hopefully this will "just work".
+ realObject =
+ new edu.internet2.middleware.shibboleth.aap.provider.XMLAAPProvider(
+ (dom instanceof Element) ? (Element)dom : ((dom instanceof Document) ? ((Document)dom).getDocumentElement() : null)
+ );
+ }
+ catch (SAMLException e) {
+ throw new ShibbolethConfigurationException("Exception initializing AAP: " + e);
+ }
+ }
- public boolean isAnyAttribute() {
- return anyAttribute;
- }
-
- // The lookup could use a Map, but the array is not expected to
- // be long, and there are three keys to process. We can add a
- // Map later if needed.
+ public boolean anyAttribute() {
+ return realObject.anyAttribute();
+ }
- public AttributeRule lookup(String attrName, String attrNamespace) {
- for (int i=0;i<attributeRules.length;i++) {
- AttributeRule attributeRule = attributeRules[i];
- String name = attributeRule.getName();
- String namespace = attributeRule.getNamespace();
- if (name!=null &&
- name.equals(attrName)) {
- if (attrNamespace==null ||
- (namespace!=null &&
- namespace.equals(attrNamespace)))
- return attributeRule;
- }
- }
- return null;
+ public AttributeRule lookup(String name, String namespace) {
+ return realObject.lookup(name,namespace);
}
public AttributeRule lookup(String alias) {
- for (int i=0;i<attributeRules.length;i++) {
- AttributeRule attributeRule = attributeRules[i];
- if (attributeRule.getAlias().equals(alias))
- return attributeRule;
- }
- return null;
+ return realObject.lookup(alias);
}
- public AttributeRule[] getAttributeRules() {
- return attributeRules;
+ public Iterator getAttributeRules() {
+ return realObject.getAttributeRules();
}
-
- /**
- * Implement the ...commmon.AttributeRules interface by wrapping the XMLBean
- *
- * @author Howard Gilbert
- */
- public class XMLAttributeRuleImpl implements AttributeRule {
-
- AttributeRuleType bean;
- Map /*<Entityname-String,SiteRule>*/ siteMap = new HashMap();
-
- XMLAttributeRuleImpl(AttributeRuleType bean) {
- this.bean=bean;
- SiteRule[] siteRules = bean.getSiteRuleArray();
- for (int i=0;i<siteRules.length;i++) {
- SiteRule siteRule = siteRules[i];
- String entityName = siteRule.getName();
- siteMap.put(entityName,siteRule);
- }
- }
-
- public String getName() {
- return bean.getName();
- }
-
- public String getNamespace() {
- return bean.getNamespace();
- }
-
- public String getAlias() {
- return bean.getAlias();
- }
-
- public String getHeader() {
- return bean.getHeader();
- }
-
- /**
- * Apply this AttributeRule to values of a SAMLAttribute
- */
- public void apply(EntityDescriptor originSite, SAMLAttribute attribute) {
- Iterator values = attribute.getValues();
- int i=0;
- while(values.hasNext()) {
- Element valueElement = (Element) values.next();
- if (!acceptableValue(originSite,valueElement)||
- !scopeCheck(originSite,valueElement)) {
- attribute.removeValue(i);
- } else {
- i++;
- }
- }
- }
-
-
-
- /**
- * Apply an array of Scope elements to a SAML scope attribute.
- *
- * <p>Scope rules can accept or reject their matches.
- * Any match to a rejection is immediately fatal. Otherwise,
- * there must have been one accept by the end of the scan.</p>
- *
- * <p>The return is a three state Boolean object. A Boolean(false)
- * is a rejection. A Boolean(true) is a tentative approval. A
- * null is neutral (no rejection, but no match).
- */
- private Boolean applyScopeRules(Scope[] scopeArray, String scopeAttribute) {
- Boolean decision = null;
-
- for (int i=0;i<scopeArray.length;i++) {
- Scope scoperule = scopeArray[i];
-
- boolean accept = scoperule.getAccept();
- int type = scoperule.getType().intValue();
- String value = scoperule.getStringValue();
-
- switch (type) {
- case AttributeRuleValueType.INT_REGEXP:
- if (Pattern.matches(scopeAttribute,value)) {
- if (accept && decision==null)
- decision=Boolean.TRUE; // Tentative approval
- else
- return Boolean.FALSE; // Deny immediate
- }
- break;
- case AttributeRuleValueType.INT_XPATH:
- log.warn("implementation does not support XPath value rules");
- break;
- default:
- if (scopeAttribute.equals(value)) {
- if (accept && decision==null)
- decision=Boolean.TRUE; // Tentative approval
- else
- return Boolean.FALSE; // Deny immediate
- }
- break;
- }
- }
- return decision;
-
- }
-
- /**
- * Apply AnySite scope rules, then rules for Origin site.
- *
- * @param originSite Metadata for origin site
- * @param ele SAML attribute value
- * @return true if OK, false if failed test
- */
- private boolean scopeCheck(EntityDescriptor originSite, Element ele) {
-
- String scopeAttribute = ele.getAttributeNS(null,"Scope");
- if (scopeAttribute==null ||
- scopeAttribute.length()==0)
- return true; // Nothing to verify, so its OK
-
- Boolean anypermit = null; // null is neutral on decision
- Boolean sitepermit = null;
-
- // AnySite scope test
- Scope[] scopeArray = bean.getAnySite().getScopeArray();
- anypermit = applyScopeRules(scopeArray,scopeAttribute);
- if (anypermit!=null && // if null (neutral) fall through
- !anypermit.booleanValue()) // if tentative true, fall through
- return false; // Boolean(false) is immediate deny
-
- // Now find origin site rule, if present
- String os = originSite.getId();
- SiteRule siteRule = (SiteRule) siteMap.get(os);
-
- if (siteRule!=null) {
- scopeArray = siteRule.getScopeArray();
- sitepermit = applyScopeRules(scopeArray,scopeAttribute);
- if (sitepermit!=null &&
- !sitepermit.booleanValue())
- return false;
- }
-
- // Now, since any Boolean(false) would have generated a
- // rejection, any non-null value is a Boolean(true).
- // Accept if either found an accept
- return anypermit!=null || sitepermit!=null;
- }
-
- /**
- * Determine if SAML value matches any Value rule in list
- *
- * @param values Value rules from AAP
- * @param node SAML value
- * @return
- */
- private boolean checkForMatchingValue(SiteRuleType.Value[] values, Node node) {
- String nodeValue = node.getNodeValue();
- for (int i=0;i<values.length;i++) {
- SiteRuleType.Value value = values[i];
- String valueContents = value.getStringValue();
- switch (value.getType().intValue()) {
- case AttributeRuleValueType.INT_REGEXP:
- if (Pattern.matches(valueContents,nodeValue))
- return true;
- break;
- case AttributeRuleValueType.INT_XPATH:
- //log.warn("implementation does not support XPath value rules");
- break;
- default:
- if (nodeValue.equals(valueContents))
- return true;
- break;
- }
- }
- return false;
-
- }
-
-
- /**
- * Apply AnySite Value rules, then rules for Origin site
- * @param originSite Metadata for Origin site
- * @param ele SAML Attribute value
- * @return true to continue with scope check, false to reject now
- */
- private boolean acceptableValue(EntityDescriptor originSite, Element ele) {
-
- // any site, any value
- if (bean.getAnySite().getAnyValue()!=null)
- return true;
-
- Node node = ele.getFirstChild();
- boolean simple = node.getNodeType()==Node.TEXT_NODE;
-
- // any site, specific value
- if (simple) {
- SiteRuleType.Value[] values = bean.getAnySite().getValueArray();
- if (checkForMatchingValue(values,node))
- return true;
- }
-
- // Specific site
- String os = originSite.getId();
- SiteRule siteRule = (SiteRule) siteMap.get(os);
- if (siteRule==null) {
- log.warn("Site "+os+" not found in ruleset "+this.getName());
- return false;
- }
- if (siteRule.getAnyValue()!=null) {
- return true;
- }
- SiteRuleType.Value[] values = siteRule.getValueArray();
- if (checkForMatchingValue(values,node))
- return true;
-
- return false;
- }
- }
-
-
- /**
- * @return
- */
public String getSchemaPathname() {
return null;
}