+++ /dev/null
-/*
- * 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.aap;
-
-import java.util.Iterator;
-
-/**
- * Interface to attribute acceptance policy
- *
- * @author Scott Cantor
- */
-public interface AAP {
-
- /**
- * Determine whether this policy does not impose any filtering rules
- *
- * @return true iff the policy does not contain any filtering rules
- */
- boolean anyAttribute();
-
- /**
- * Find a rule for the given SAML attribute
- *
- * @param name
- * The AttributeName
- * @param namespace
- * The AttributeNamespace
- * @return The applicable rule, if any
- */
- AttributeRule lookup(String name, String namespace);
-
- /**
- * Find a rule for the given shorthand attribute name
- *
- * @param alias
- * The shorthand name
- * @return The applicable rule, if any
- */
- AttributeRule lookup(String alias);
-
- /**
- * Get all of the rules contained in the policy
- *
- * @return The policy rules
- */
- Iterator /* <AttributeRule> */getAttributeRules();
-}
+++ /dev/null
-/*
- * 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.aap;
-
-import org.opensaml.SAMLAttribute;
-import org.opensaml.SAMLException;
-
-import edu.internet2.middleware.shibboleth.metadata.RoleDescriptor;
-
-/**
- * Specifies handling of a specific SAML attribute
- *
- * @author Scott Cantor
- */
-public interface AttributeRule {
-
- /**
- * Get the SAML name of the applicable attribute
- *
- * @return The AttributeName
- */
- String getName();
-
- /**
- * Get the SAML namespace of the applicable attribute
- *
- * @return The AttributeNamespace
- */
- String getNamespace();
-
- /**
- * Get the shorthand name of the attribute
- *
- * @return The shorthand name
- */
- String getAlias();
-
- /**
- * Get the name of the protocol-specific header to export the attribute into
- *
- * @return The header name
- */
- String getHeader();
-
- /**
- * Is value matching of this attribute case-sensitive?
- *
- * @return The case sensitivity of the values
- */
- boolean getCaseSensitive();
-
- /**
- * Is the attribute formally scoped?
- *
- * @return The scoped property
- */
- boolean getScoped();
-
- /**
- * Applies a rule to an attribute, taking into account the role in which the issuer was acting
- *
- * @param attribute
- * The attribute to apply the filtering rule to
- * @param role
- * The metadata role in which the attribute issuer is acting
- * @throws SAMLException
- * Raised if the attribute is no longer valid after the filtering process (generally if all values are
- * deleted)
- */
- void apply(SAMLAttribute attribute, RoleDescriptor role) throws SAMLException;
-}
+++ /dev/null
-/*
- * 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.aap.provider;
-
-import java.io.IOException;
-import java.util.Iterator;
-
-import org.apache.log4j.Logger;
-import org.opensaml.MalformedException;
-import org.opensaml.SAMLException;
-import org.opensaml.XML;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-
-import edu.internet2.middleware.shibboleth.aap.AAP;
-import edu.internet2.middleware.shibboleth.aap.AttributeRule;
-import edu.internet2.middleware.shibboleth.common.ResourceWatchdog;
-import edu.internet2.middleware.shibboleth.common.ResourceWatchdogExecutionException;
-import edu.internet2.middleware.shibboleth.common.ShibResource;
-import edu.internet2.middleware.shibboleth.common.ShibResource.ResourceNotAvailableException;
-import edu.internet2.middleware.shibboleth.xml.Parser;
-
-/**
- * @author Walter Hoehn (wassa@columbia.edu)
- */
-public class XMLAAP extends ResourceWatchdog implements AAP {
-
- private static Logger log = Logger.getLogger(XMLAAP.class.getName());
- private AAP currentAAP;
-
- public XMLAAP(Element configuration) throws MalformedException, ResourceNotAvailableException {
- this(configuration.getAttribute("uri"));
- }
-
- public XMLAAP(String sitesFileLocation) throws MalformedException, ResourceNotAvailableException {
- super(new ShibResource(sitesFileLocation, XMLAAP.class));
- try {
- InputSource src = new InputSource(resource.getInputStream());
- src.setSystemId(resource.getURL().toString());
- Document doc = Parser.loadDom(src,true);
- currentAAP = new XMLAAPProvider(doc.getDocumentElement());
- } catch (IOException e) {
- log.error("Encountered a problem reading AAP source: " + e);
- throw new MalformedException("Unable to read AAP: " + e);
- }
- catch (SAXException e) {
- log.error("Encountered a problem parsing AAP source: " + e);
- throw new MalformedException("Unable to read AAP: " + e);
- }
- catch (SAMLException e) {
- log.error("Encountered a problem processing AAP source: " + e);
- throw new MalformedException("Unable to read AAP: " + e);
- }
-
- //Start checking for AAP updates
- start();
-
- }
-
- public boolean anyAttribute() {
- synchronized (currentAAP) {
- return currentAAP.anyAttribute();
- }
- }
-
- public AttributeRule lookup(String name, String namespace) {
- synchronized (currentAAP) {
- return currentAAP.lookup(name,namespace);
- }
- }
-
- public AttributeRule lookup(String alias) {
- synchronized (currentAAP) {
- return currentAAP.lookup(alias);
- }
- }
-
- public Iterator getAttributeRules() {
- synchronized (currentAAP) {
- return currentAAP.getAttributeRules();
- }
- }
-
- protected void doOnChange() throws ResourceWatchdogExecutionException {
- AAP newAAP = null;
- Document newDoc = null;
-
- try {
- log.info("Detected a change in the AAP. Reloading from (" + resource.getURL().toString() + ").");
- newAAP = new XMLAAP(XML.parserPool.parse(resource.getInputStream()).getDocumentElement());
- }
- catch (IOException e) {
- log.error("Encountered an error retrieving updated AAP, continuing to use stale copy: " + e);
- return;
- }
- catch (SAXException e) {
- log.error("Encountered an error retrieving updated AAP, continuing to use stale copy: " + e);
- return;
- }
- catch (SAMLException e) {
- log.error("Encountered an error retrieving updated AAP, continuing to use stale copy: " + e);
- return;
- }
-
- if (newAAP != null) {
- synchronized (currentAAP) {
- currentAAP = newAAP;
- }
- }
- }
-}
+++ /dev/null
-/*
- * 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.aap.provider;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.SortedMap;
-import java.util.TreeMap;
-import java.util.regex.PatternSyntaxException;
-
-import org.apache.log4j.Logger;
-import org.opensaml.MalformedException;
-import org.opensaml.SAMLAttribute;
-import org.opensaml.SAMLException;
-import org.opensaml.XML;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import edu.internet2.middleware.shibboleth.aap.AAP;
-import edu.internet2.middleware.shibboleth.aap.AttributeRule;
-import edu.internet2.middleware.shibboleth.common.Constants;
-import edu.internet2.middleware.shibboleth.common.PluggableConfigurationComponent;
-import edu.internet2.middleware.shibboleth.metadata.EntitiesDescriptor;
-import edu.internet2.middleware.shibboleth.metadata.RoleDescriptor;
-import edu.internet2.middleware.shibboleth.metadata.ScopedRoleDescriptor;
-import edu.internet2.middleware.shibboleth.metadata.ScopedRoleDescriptor.Scope;
-
-public class XMLAAPProvider implements AAP, PluggableConfigurationComponent {
-
- private static Logger log = Logger.getLogger(XMLAAPProvider.class.getName());
- private SortedMap /* <String,AttributeRule> */ attrmap = new TreeMap();
- private SortedMap /* <String,AttributeRule> */ aliasmap = new TreeMap();
- private boolean anyAttribute = false;
-
- public XMLAAPProvider(Element e) throws MalformedException {
- initialize(e);
- }
-
- public XMLAAPProvider() {} // must call initialize
-
- public void initialize(Element e) throws MalformedException {
- if (!XML.isElementNamed(e,edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"AttributeAcceptancePolicy")) {
- log.error("Construction requires a valid AAP file: (shib:AttributeAcceptancePolicy as root element)");
- throw new MalformedException("Construction requires a valid AAP file: (shib:AttributeAcceptancePolicy as root element)");
- }
-
- // Check for AnyAttribute element.
- Element anyAttr = XML.getFirstChildElement(e,edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"AnyAttribute");
- if (anyAttr != null) {
- anyAttribute = true;
- log.warn("<AnyAttribute> found, will short-circuit all attribute value and scope filtering");
- }
-
- // Loop over the AttributeRule elements.
- NodeList nlist = e.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"AttributeRule");
- for (int i=0; i<nlist.getLength(); i++) {
- AttributeRule rule=new XMLAttributeRule((Element)(nlist.item(i)));
- String key = rule.getName() + "!!" + ((rule.getNamespace() != null) ? rule.getNamespace() : Constants.SHIB_ATTRIBUTE_NAMESPACE_URI);
- attrmap.put(key,rule);
- if (rule.getAlias() != null)
- aliasmap.put(rule.getAlias(),rule);
- }
- }
-
- class XMLAttributeRule implements AttributeRule {
-
- private String name = null;
- private String namespace = null;
- private String alias = null;
- private String header = null;
- private boolean caseSensitive = true;
- private boolean scoped = false;
- private SiteRule anySiteRule = new SiteRule();
- private Map /* <String,SiteRule> */ siteMap = new HashMap();
-
- class Rule {
- static final int LITERAL = 0;
- static final int REGEXP = 1;
- static final int XPATH = 2;
-
- Rule(int type, String expression) {
- this.type = type;
- this.expression = expression;
- }
- int type;
- String expression;
- }
-
- class SiteRule {
- boolean anyValue = false;
- ArrayList valueDenials = new ArrayList();
- ArrayList valueAccepts = new ArrayList();
- ArrayList scopeDenials = new ArrayList();
- ArrayList scopeAccepts = new ArrayList();
- }
-
- XMLAttributeRule(Element e) throws MalformedException {
- alias = XML.assign(e.getAttributeNS(null,"Alias"));
- header = XML.assign(e.getAttributeNS(null,"Header"));
- name = XML.assign(e.getAttributeNS(null,"Name"));
- namespace = XML.assign(e.getAttributeNS(null,"Namespace"));
- if (namespace == null)
- namespace = Constants.SHIB_ATTRIBUTE_NAMESPACE_URI;
-
- String flag=XML.assign(e.getAttributeNS(null,"Scoped"));
- scoped=(XML.safeCompare(flag,"1") || XML.safeCompare(flag,"true"));
- flag=XML.assign(e.getAttributeNS(null,"CaseSensitive"));
- caseSensitive=(XML.isEmpty(flag) || XML.safeCompare(flag,"1") || XML.safeCompare(flag,"true"));
-
- // Check for an AnySite rule.
- Element anysite = XML.getFirstChildElement(e);
- if (anysite != null && XML.isElementNamed(anysite,edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"AnySite")) {
- // Process Scope elements.
- NodeList vlist = anysite.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"Scope");
- for (int i=0; i < vlist.getLength(); i++) {
- scoped=true;
- Element se=(Element)vlist.item(i);
- Node valnode=se.getFirstChild();
- if (valnode != null && valnode.getNodeType()==Node.TEXT_NODE) {
- flag=XML.assign(se.getAttributeNS(null,"Accept"));
- if (XML.isEmpty(flag) || XML.safeCompare(flag,"1") || XML.safeCompare(flag,"true"))
- anySiteRule.scopeAccepts.add(new Rule(toValueType(se),valnode.getNodeValue()));
- else
- anySiteRule.scopeDenials.add(new Rule(toValueType(se),valnode.getNodeValue()));
- }
- }
-
- // Check for an AnyValue rule.
- vlist = anysite.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"AnyValue");
- if (vlist.getLength() > 0) {
- anySiteRule.anyValue=true;
- }
- else {
- // Process each Value element.
- vlist = anysite.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"Value");
- for (int j=0; j<vlist.getLength(); j++) {
- Element ve=(Element)vlist.item(j);
- Node valnode=ve.getFirstChild();
- if (valnode != null && valnode.getNodeType()==Node.TEXT_NODE) {
- flag=XML.assign(ve.getAttributeNS(null,"Accept"));
- if (XML.isEmpty(flag) || XML.safeCompare(flag,"1") || XML.safeCompare(flag,"true"))
- anySiteRule.valueAccepts.add(new Rule(toValueType(ve),valnode.getNodeValue()));
- else
- anySiteRule.valueDenials.add(new Rule(toValueType(ve),valnode.getNodeValue()));
- }
- }
- }
- }
-
- // Loop over the SiteRule elements.
- NodeList slist = e.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"SiteRule");
- for (int k=0; k<slist.getLength(); k++) {
- String srulename=((Element)slist.item(k)).getAttributeNS(null,"Name");
- SiteRule srule = new SiteRule();
- siteMap.put(srulename,srule);
-
- // Process Scope elements.
- NodeList vlist = ((Element)slist.item(k)).getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"Scope");
- for (int i=0; i<vlist.getLength(); i++) {
- scoped=true;
- Element se=(Element)vlist.item(i);
- Node valnode=se.getFirstChild();
- if (valnode != null && valnode.getNodeType()==Node.TEXT_NODE)
- {
- flag=XML.assign(se.getAttributeNS(null,"Accept"));
- if (XML.isEmpty(flag) || XML.safeCompare(flag,"1") || XML.safeCompare(flag,"true"))
- srule.scopeAccepts.add(new Rule(toValueType(se),valnode.getNodeValue()));
- else
- srule.scopeDenials.add(new Rule(toValueType(se),valnode.getNodeValue()));
- }
- }
-
- // Check for an AnyValue rule.
- vlist = ((Element)slist.item(k)).getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"AnyValue");
- if (vlist.getLength() > 0) {
- srule.anyValue=true;
- }
- else {
- // Process each Value element.
- vlist = ((Element)slist.item(k)).getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"Value");
- for (int j=0; j<vlist.getLength(); j++) {
- Element ve=(Element)vlist.item(j);
- Node valnode=ve.getFirstChild();
- if (valnode != null && valnode.getNodeType()==Node.TEXT_NODE) {
- flag=XML.assign(ve.getAttributeNS(null,"Accept"));
- if (XML.isEmpty(flag) || XML.safeCompare(flag,"1") || XML.safeCompare(flag,"true"))
- srule.valueAccepts.add(new Rule(toValueType(ve),valnode.getNodeValue()));
- else
- srule.valueDenials.add(new Rule(toValueType(ve),valnode.getNodeValue()));
- }
- }
- }
- }
- }
-
- private int toValueType(Element e) throws MalformedException {
- if (!e.hasAttributeNS(null,"Type") || XML.safeCompare("literal",e.getAttributeNS(null,"Type")))
- return Rule.LITERAL;
- else if (XML.safeCompare("regexp",e.getAttributeNS(null,"Type")))
- return Rule.REGEXP;
- else if (XML.safeCompare("xpath",e.getAttributeNS(null,"Type")))
- return Rule.XPATH;
- throw new MalformedException("Found an invalid value or scope rule type.");
- }
-
- public String getName() {
- return name;
- }
-
- public String getNamespace() {
- return namespace;
- }
-
- public String getAlias() {
- return alias;
- }
-
- public String getHeader() {
- return header;
- }
-
- public boolean getCaseSensitive() {
- return caseSensitive;
- }
-
- public boolean getScoped() {
- return scoped;
- }
-
- public void apply(SAMLAttribute attribute, RoleDescriptor role) throws SAMLException {
- ScopedRoleDescriptor scoper = ((role instanceof ScopedRoleDescriptor) ? (ScopedRoleDescriptor)role : null);
-
- // This is a little tricky because if we remove anything,
- // the NodeList is out of sync with the underlying object.
- // We have to maintain a separate index counter into the object.
- int index = 0;
- NodeList vals = attribute.getValueElements();
- for (int i=0; i < vals.getLength(); i++) {
- if (!accept((Element)vals.item(i),scoper))
- attribute.removeValue(index);
- else
- index++;
- }
- }
-
- boolean match(String exp, String test) {
- try {
- if (test.matches(exp))
- return true;
- }
- catch (PatternSyntaxException ex) {
- log.error("caught exception while parsing regular expression ()");
- }
- return false;
- }
-
- public boolean scopeCheck(Element e, ScopedRoleDescriptor role, Collection ruleStack) {
- // Are we scoped?
- String scope=XML.assign(e.getAttributeNS(null,"Scope"));
- if (scope == null) {
- // Are we allowed to be unscoped?
- if (scoped)
- log.warn("attribute (" + name + ") is scoped, no scope supplied, rejecting it");
- return !scoped;
- }
-
- // With the new algorithm, we evaluate each matching rule in sequence, separately.
- Iterator srules = ruleStack.iterator();
- while (srules.hasNext()) {
- SiteRule srule = (SiteRule)srules.next();
-
- // Now run any denials.
- Iterator denials = srule.scopeDenials.iterator();
- while (denials.hasNext()) {
- Rule denial = (Rule)denials.next();
- if ((denial.type==Rule.LITERAL && XML.safeCompare(denial.expression,scope)) ||
- (denial.type==Rule.REGEXP && match(denial.expression,scope))) {
- log.warn("attribute (" + name + ") scope {" + scope + "} denied by site rule, rejecting it");
- return false;
- }
- else if (denial.type==Rule.XPATH)
- log.warn("scope checking does not permit XPath rules");
- }
-
- // Now run any accepts.
- Iterator accepts = srule.scopeAccepts.iterator();
- while (accepts.hasNext()) {
- Rule accept = (Rule)accepts.next();
- if ((accept.type==Rule.LITERAL && XML.safeCompare(accept.expression,scope)) ||
- (accept.type==Rule.REGEXP && match(accept.expression,scope))) {
- log.debug("matching site rule, scope match");
- return true;
- }
- else if (accept.type==Rule.XPATH)
- log.warn("scope checking does not permit XPath rules");
- }
- }
-
- // If we still can't decide, defer to metadata.
- if (role != null) {
- Iterator scopes=role.getScopes();
- while (scopes.hasNext()) {
- ScopedRoleDescriptor.Scope p = (Scope)scopes.next();
- if ((p.regexp && match(p.scope,scope)) || XML.safeCompare(p.scope,scope)) {
- log.debug("scope match via site metadata");
- return true;
- }
- }
- }
-
- log.warn("attribute (" + name + ") scope {" + scope + "} not accepted");
- return false;
- }
-
- boolean accept(Element e, ScopedRoleDescriptor role) {
- log.debug("evaluating value for attribute (" + name + ") from site (" +
- ((role!=null) ? role.getEntityDescriptor().getId() : "<unspecified>") +
- ")");
-
- // This is a complete revamp. The "any" cases become a degenerate case, the "least-specific" matching rule.
- // The first step is to build a list of matching rules, most-specific to least-specific.
-
- ArrayList ruleStack = new ArrayList();
- if (role != null) {
- // Primary match is against entityID.
- SiteRule srule=(SiteRule)siteMap.get(role.getEntityDescriptor().getId());
- if (srule!=null)
- ruleStack.add(srule);
-
- // Secondary matches are on groups.
- EntitiesDescriptor group=role.getEntityDescriptor().getEntitiesDescriptor();
- while (group != null) {
- srule=(SiteRule)siteMap.get(group.getName());
- if (srule!=null)
- ruleStack.add(srule);
- group = group.getEntitiesDescriptor();
- }
- }
- // Tertiary match is the AnySite rule.
- ruleStack.add(anySiteRule);
-
- // Still don't support complex content models...
- Node n=e.getFirstChild();
- boolean bSimple=(n != null && n.getNodeType()==Node.TEXT_NODE);
-
- // With the new algorithm, we evaluate each matching rule in sequence, separately.
- Iterator srules = ruleStack.iterator();
- while (srules.hasNext()) {
- SiteRule srule = (SiteRule)srules.next();
-
- // Check for shortcut AnyValue blanket rule.
- if (srule.anyValue) {
- log.debug("matching site rule, any value match");
- return scopeCheck(e,role,ruleStack);
- }
-
- // Now run any denials.
- Iterator denials = srule.valueDenials.iterator();
- while (bSimple && denials.hasNext()) {
- Rule denial = (Rule)denials.next();
- switch (denial.type) {
- case Rule.LITERAL:
- if ((caseSensitive && !XML.safeCompare(denial.expression,n.getNodeValue())) ||
- (!caseSensitive && denial.expression.equalsIgnoreCase(n.getNodeValue()))) {
- log.warn("attribute (" + name + ") value explicitly denied by site rule, rejecting it");
- return false;
- }
- break;
-
- case Rule.REGEXP:
- if (match(denial.expression,n.getNodeValue())) {
- log.warn("attribute (" + name + ") value explicitly denied by site rule, rejecting it");
- return false;
- }
- break;
-
- case Rule.XPATH:
- log.warn("implementation does not support XPath value rules");
- break;
- }
- }
-
- // Now run any accepts.
- Iterator accepts = srule.valueAccepts.iterator();
- while (bSimple && accepts.hasNext()) {
- Rule accept = (Rule)accepts.next();
- switch (accept.type) {
- case Rule.LITERAL:
- if ((caseSensitive && !XML.safeCompare(accept.expression,n.getNodeValue())) ||
- (!caseSensitive && accept.expression.equalsIgnoreCase(n.getNodeValue()))) {
- log.debug("site rule, value match");
- return scopeCheck(e,role,ruleStack);
- }
- break;
-
- case Rule.REGEXP:
- if (match(accept.expression,n.getNodeValue())) {
- log.debug("site rule, value match");
- return scopeCheck(e,role,ruleStack);
- }
- break;
-
- case Rule.XPATH:
- log.warn("implementation does not support XPath value rules");
- break;
- }
- }
- }
-
- log.warn((bSimple ? "" : "complex ") + "attribute (" + name + ") value {" +
- n.getNodeValue() + ") could not be validated by policy, rejecting it"
- );
- return false;
- }
- }
-
- public boolean anyAttribute() {
- return anyAttribute;
- }
-
- public AttributeRule lookup(String name, String namespace) {
- if (namespace==null) {
- String keyGreaterEqual = (String) attrmap.tailMap(name).firstKey();
- if (keyGreaterEqual.startsWith(name+"!!")) {
- return (AttributeRule) attrmap.get(keyGreaterEqual);
- } else {
- return null;
- }
- }
- return (AttributeRule)attrmap.get(name + "!!" + namespace);
- }
-
- public AttributeRule lookup(String alias) {
- return (AttributeRule)aliasmap.get(alias);
- }
-
- public Iterator getAttributeRules() {
- return attrmap.values().iterator();
- }
-}
+++ /dev/null
-/*
- * 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.
- */
-
-/*
- * PluggableConfigurationComponent.java
- *
- * Classes that implement a Pluggable configuration service
- * must also implement this interface.
- *
- * After loading a class by passing the type= attribute to
- * Class.forName(), a specific sanity check can be performed
- * by verifying that the loaded class implements this interface.
- * This ensures that it really is a Plugin.
- *
- * The initialize() method is then called, passing a DOM
- * node that represents the configuration information for
- * the plugin, either as opaque inline XML or from a
- * loaded external file.
- *
- * Note: in earlier releases the DOM node was passed to
- * the constructor, but it is safer to support a default
- * (no argument) constructor and handle initialization though
- * an interface like this.
- *
- * Note: To be useful, the implementing class must also
- * implement some functional interface, such as Trust or
- * AAP. This interface just manages the load and initialization
- * part.
- *
- * For examples of use, see one of the builtin implementation
- * classes (XMLMetadataImpl, ...).
- */
-package edu.internet2.middleware.shibboleth.common;
-
-import org.opensaml.SAMLException;
-import org.w3c.dom.Element;
-
-public interface PluggableConfigurationComponent {
-
- public abstract void
- initialize(Element dom)
- throws
- SAMLException,
- ShibbolethConfigurationException; // for other problems
-
-}
\ No newline at end of file
+++ /dev/null
-/*
- * 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.common;
-
-import java.util.ArrayList;
-
-import org.apache.log4j.Logger;
-import org.opensaml.NoSuchProviderException;
-import org.opensaml.ReplayCache;
-import org.opensaml.SAMLBrowserProfile;
-import org.opensaml.SAMLBrowserProfileFactory;
-import org.opensaml.SAMLException;
-import org.opensaml.TrustException;
-import org.opensaml.SAMLBrowserProfile.ArtifactMapper;
-import org.opensaml.SAMLBrowserProfile.BrowserProfileRequest;
-import org.opensaml.SAMLBrowserProfile.BrowserProfileResponse;
-
-import edu.internet2.middleware.shibboleth.metadata.EntityDescriptor;
-import edu.internet2.middleware.shibboleth.metadata.IDPSSODescriptor;
-import edu.internet2.middleware.shibboleth.metadata.MetadataException;
-import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderConfig;
-import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderContext;
-import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderConfig.ApplicationInfo;
-
-/**
- * Basic Shibboleth POST browser profile implementation with basic support for signing
- *
- * @author Scott Cantor @created April 11, 2002
- */
-public class ShibBrowserProfile {
-
- private static Logger log = Logger.getLogger(ShibBrowserProfile.class.getName());
-
- /** Policy URIs to attach or check against */
- protected ArrayList policies = new ArrayList();
-
- protected SAMLBrowserProfile profile = SAMLBrowserProfileFactory.getInstance();
- private static ServiceProviderContext context = ServiceProviderContext.getInstance();
- private String applicationId = null;
-
- /**
- * Identify the <Application> from which to get plugins.
- *
- * @param applicationId
- */
- public ShibBrowserProfile(String applicationId) throws NoSuchProviderException {
- this.applicationId = applicationId;
- }
-
-
- /**
- * @see org.opensaml.SAMLBrowserProfile#receive(java.lang.StringBuffer, javax.servlet.http.HttpServletRequest, java.lang.String, int, org.opensaml.ReplayCache, org.opensaml.SAMLBrowserProfile.ArtifactMapper, int)
- */
- public BrowserProfileResponse receive(
- StringBuffer issuer,
- BrowserProfileRequest bpRequest,
- String recipient,
- ReplayCache replayCache,
- ArtifactMapper artifactMapper,
- int minorVersion
- ) throws SAMLException {
-
- String providerId = null;
- issuer.setLength(0);
-
- // Let SAML do all the decoding and parsing
- BrowserProfileResponse bpr = profile.receive(issuer, bpRequest, recipient, replayCache, artifactMapper, minorVersion);
-
- /*
- * Now find the Metadata for the Entity that send this assertion.
- * From the C++, look first for issuer, then namequalifier (for 1.1 compat.)
- */
- EntityDescriptor entity = null;
- String asn_issuer = bpr.assertion.getIssuer();
- String qualifier = bpr.authnStatement.getSubject().getNameIdentifier().getNameQualifier();
- ServiceProviderConfig config = context.getServiceProviderConfig();
- ApplicationInfo appinfo = config.getApplication(applicationId);
-
- entity = appinfo.lookup(asn_issuer);
- providerId=asn_issuer;
- if (entity==null) {
- providerId=qualifier;
- entity= appinfo.lookup(qualifier);
- }
- if (entity==null) {
- log.error("assertion issuer not found in metadata(Issuer ="+
- issuer+", NameQualifier="+qualifier);
- throw new MetadataException("ShibBrowserProfile.receive() metadata lookup failed, unable to process assertion");
- }
- issuer.append(providerId);
-
- IDPSSODescriptor role = entity.getIDPSSODescriptor(
- minorVersion==1?
- org.opensaml.XML.SAML11_PROTOCOL_ENUM :
- org.opensaml.XML.SAML10_PROTOCOL_ENUM
- );
-
- if (bpr.response.isSigned()) {
- boolean signatureValid = appinfo.validate(bpr.response,role);
- if (!signatureValid) {
- throw new TrustException("ShibBrowserProfile cannot validate signature on response from SSO");
- }
- }
- if (bpr.assertion.isSigned()) {
- boolean signatureValid = appinfo.validate(bpr.assertion,role);
- if (!signatureValid) {
- throw new TrustException("ShibBrowserProfile cannot validate signature on assertion from SSO");
- }
- }
-
- return bpr;
- }
-}
+++ /dev/null
-/*
- * 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.common;
-
-import java.util.Collection;
-
-import javax.xml.namespace.QName;
-import org.opensaml.SAMLException;
-import org.w3c.dom.Element;
-
-/**
- * Indicates that an error occurred before or during the processing of a SAML request/response exchange.
- * <P>
- *
- *
- *
- * @author Scott Cantor
- * @created November 17, 2001
- */
-public class UnsupportedProtocolException extends SAMLException implements Cloneable {
-
- /**
- * Creates a new UnsupportedProtocolException
- *
- * @param e
- * The root of a DOM tree
- * @exception SAMLException
- * Raised if an exception occurs while constructing the object.
- */
- protected UnsupportedProtocolException(Element e) throws SAMLException {
-
- super(e);
- }
-
- /**
- * Creates a new UnsupportedProtocolException
- *
- * @param msg
- * The detail message
- */
- public UnsupportedProtocolException(String msg) {
-
- super(msg);
- }
-
- /**
- * Creates a new UnsupportedProtocolException
- *
- * @param msg
- * The detail message
- * @param e
- * The exception to be wrapped in a UnsupportedProtocolException
- */
- public UnsupportedProtocolException(String msg, Exception e) {
-
- super(msg, e);
- }
-
- /**
- * Creates a new UnsupportedProtocolException
- *
- * @param codes
- * A collection of QNames
- * @param msg
- * The detail message
- */
- public UnsupportedProtocolException(Collection codes, String msg) {
-
- super(codes, msg);
- }
-
- /**
- * Creates a new UnsupportedProtocolException wrapping an existing exception
- * <p>
- *
- * The existing exception will be embedded in the new one, and its message will become the default message for the
- * UnsupportedProtocolException.
- * </p>
- *
- * @param codes
- * A collection of QNames
- * @param e
- * The exception to be wrapped in a UnsupportedProtocolException
- */
- public UnsupportedProtocolException(Collection codes, Exception e) {
-
- super(codes, e);
- }
-
- /**
- * Creates a new UnsupportedProtocolException from an existing exception.
- * <p>
- *
- * The existing exception will be embedded in the new one, but the new exception will have its own message.
- * </p>
- *
- * @param codes
- * A collection of QNames
- * @param msg
- * The detail message
- * @param e
- * The exception to be wrapped in a UnsupportedProtocolException
- */
- public UnsupportedProtocolException(Collection codes, String msg, Exception e) {
-
- super(codes, msg, e);
- }
-
- /**
- * Creates a new UnsupportedProtocolException
- *
- * @param code
- * A status code
- * @param msg
- * The detail message
- */
- public UnsupportedProtocolException(QName code, String msg) {
-
- super(code, msg);
- }
-
- /**
- * Creates a new UnsupportedProtocolException wrapping an existing exception
- * <p>
- *
- * The existing exception will be embedded in the new one, and its message will become the default message for the
- * UnsupportedProtocolException.
- * </p>
- *
- * @param code
- * A status code
- * @param e
- * The exception to be wrapped in a UnsupportedProtocolException
- */
- public UnsupportedProtocolException(QName code, Exception e) {
-
- super(code, e);
- }
-
- /**
- * Creates a new UnsupportedProtocolException from an existing exception.
- * <p>
- *
- * The existing exception will be embedded in the new one, but the new exception will have its own message.
- * </p>
- *
- * @param code
- * A status code
- * @param msg
- * The detail message
- * @param e
- * The exception to be wrapped in a UnsupportedProtocolException
- */
- public UnsupportedProtocolException(QName code, String msg, Exception e) {
-
- super(code, msg, e);
- }
-}
import org.w3c.dom.Element;
import org.w3c.dom.Node;
-import edu.internet2.middleware.shibboleth.common.PluggableConfigurationComponent;
import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
import edu.internet2.middleware.shibboleth.common.Trust;
import edu.internet2.middleware.shibboleth.metadata.EntitiesDescriptor;
*
* @author Walter Hoehn
*/
-public class ShibbolethTrust extends BasicTrust implements Trust, PluggableConfigurationComponent {
+public class ShibbolethTrust extends BasicTrust implements Trust {
private static Logger log = Logger.getLogger(ShibbolethTrust.class.getName());
private static final String CN_OID = "2.5.4.3";
import org.w3c.dom.NodeList;
import edu.internet2.middleware.shibboleth.common.Constants;
-import edu.internet2.middleware.shibboleth.common.PluggableConfigurationComponent;
import edu.internet2.middleware.shibboleth.metadata.*;
/**
* @author Scott Cantor
*/
-public class XMLMetadataProvider implements Metadata, PluggableConfigurationComponent {
+public class XMLMetadataProvider implements Metadata {
private static Logger log = Logger.getLogger(XMLMetadataProvider.class.getName());
private Map /* <String,ArrayList<EntityDescriptor> > */ sites = new HashMap();
+++ /dev/null
-/*
- * 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.
- */
-
-/*
- * AuthenticatonAssertionConsumerServlet
- *
- * The Shibboleth function previous known as the SHIRE.
- *
- * Authentication Assertion Consumer is the SAML 2.0 term for what the
- * SHIRE does. A SAML Assertion containing an Authentication statement
- * with the "principal" identifier value equal to the handle vended by
- * the Handle Server is received from the Browser. The Handle Server
- * generated a form, prefilled it with a Bin64 encoding of the SAML
- * statement, and included Javascript to automatically submit the form
- * to this URL.
- *
- * All HTTP, HTML, and servlet logic is localized to this layer of
- * modules. Any information must be extracted from the Servlet API
- * to be passed directly to Shibboleth.
- *
- * The work is done by a ShibPOSTProfile object. It takes the Bin64
- * encoded string, converts it to a SAMLObject, verifies structure,
- * and validates signatures.
- *
- * The resulting Authentication Assertion SAML statement is passed
- * to Session Manager to create a new session. This process feeds
- * back a session identifier that becomes the value of a Cookie sent
- * back to the Browser to track the session.
- *
- * If the decision is made to fetch attributes immediately, the
- * Session object can be passed to the static AttributeRequestor
- * service. It generates a ShibBinding, sends a request to the AA,
- * validates the response, applies AAP, and stores the resulting
- * SAML Attribute Assertion in the Session object.
- */
-package edu.internet2.middleware.shibboleth.serviceprovider;
-
-import java.io.IOException;
-import java.util.Iterator;
-
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.log4j.Logger;
-import org.opensaml.SAMLAssertion;
-import org.opensaml.SAMLAttributeStatement;
-import org.opensaml.SAMLAudienceRestrictionCondition;
-import org.opensaml.SAMLCondition;
-import org.opensaml.SAMLException;
-import org.opensaml.SAMLResponse;
-import org.opensaml.SAMLStatement;
-import org.opensaml.SAMLBrowserProfile.BrowserProfileRequest;
-import org.opensaml.SAMLBrowserProfile.BrowserProfileResponse;
-
-import edu.internet2.middleware.shibboleth.common.ShibBrowserProfile;
-import edu.internet2.middleware.shibboleth.metadata.MetadataException;
-import edu.internet2.middleware.shibboleth.resource.AuthenticationFilter;
-import edu.internet2.middleware.shibboleth.resource.FilterUtil;
-import edu.internet2.middleware.shibboleth.resource.FilterSupport.NewSessionData;
-import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderConfig.ApplicationInfo;
-
-/**
- * Process the Authentication Assertion POST data to create a Session.
- *
- * @author Howard Gilbert
- */
-public class AssertionConsumerServlet extends HttpServlet {
-
- // There is currently no reason for a Cookie from the SP
- // private static final String COOKIEPREFIX = "edu.internet2.middleware.shibboleth.session.";
-
- private static Logger log = Logger.getLogger(AssertionConsumerServlet.class.getName());
-
- private static ServiceProviderContext context = ServiceProviderContext.getInstance();
-
- // The query string parameter appended when Redirecting to the RM
- public static final String SESSIONPARM =
- "ShibbolethSessionId";
-
-
- public void init() throws ServletException {
- super.init();
- ServletContext servletContext = this.getServletContext();
-
- // Note: the ServletContext should have been initialized by the Listener
- ServletContextInitializer.initServiceProvider(servletContext);
-
- // Establish linkage between the SP context and the RM Filter class
- AuthenticationFilter.setFilterSupport(new FilterSupportImpl());
- }
-
-
-
- /**
- * Process the POST (or Artifact GET) from the Browser after SSO
- */
- public void doPost(
- HttpServletRequest request,
- HttpServletResponse response)
- {
-
- // Initialize Request level (ThreadLocal) tracking
- ServletContextInitializer.beginService(request,response);
-
- String contextPath = request.getContextPath();
- ServiceProviderConfig config = context.getServiceProviderConfig();
-
- String ipaddr = request.getRemoteAddr();
- String target = request.getParameter("TARGET");
-
- // Map the Resource URL into an <Application>
- String applicationId = config.mapRequest(target);
- ApplicationInfo appinfo = config.getApplication(applicationId);
- String handlerURL = request.getRequestURL().toString();
- String providerId = appinfo.getProviderId();
-
- log.debug("Authentication received from "+ipaddr+" for "+target+
- "(application:"+applicationId+") (Provider:"+providerId+")");
-
- try {
- NewSessionData data = new NewSessionData();
- FilterUtil.sessionDataFromRequest(data,request);
- data.applicationId = applicationId;
- data.handlerURL = handlerURL;
- data.providerId = providerId;
-
- String sessionId = createSessionFromData(data);
-
- // A cookie could be written here, but the browser
- // never comes back to the SP except with an assertion
- // and that produces a new session
-// String cookiename = COOKIEPREFIX+applicationId;
-// Cookie cookie = new Cookie(cookiename,sessionId);
-// response.addCookie(cookie);
-
- /*
- * Now Redirect the Browser
- */
- try {
- if (target.equals("SendAttributesBackToMe")) {
- // A diagnostic and maybe an API feature. Return the Attributes back to their owner.
- ServletOutputStream outputStream = response.getOutputStream();
- response.setContentType("text/xml");
- Session session = context.getSessionManager().findSession(sessionId,applicationId);
- SAMLResponse attributeResponse = session.getAttributeResponse();
- outputStream.print(attributeResponse.toString());
- } else {
- if (target.indexOf(':')>0) {
- // Ordinary URL target. Should not occur any more
- if (target.indexOf('?')>0)
- response.sendRedirect(target+"&"+SESSIONPARM+"="+sessionId);
- else
- response.sendRedirect(target+"?"+SESSIONPARM+"="+sessionId);
- } else {
- // Assume Target is SessionID of
- Session session =context.getSessionManager().findSession(sessionId, applicationId);
- if (session!=null) {
- String savedTarget = session.getSavedTargetURL();
- if (savedTarget!=null)
- target=savedTarget;
- }
- response.sendRedirect(target);
- }
- }
- } catch (IOException e) {
- // The Browser is gone
- }
- }
- catch (MetadataException e) {
- log.error("Authentication Assertion source not found in Metadata.");
- try {
- String msg = appinfo.getErrorsConfig().getMetadata();
- if (msg==null)
- msg=appinfo.getErrorsConfig().getSession();
- if (msg==null)
- msg=appinfo.getErrorsConfig().getShire();
- if (msg==null)
- msg="sessionError.html";
- if (msg.charAt(0)!='/')
- msg=contextPath+"/"+msg;
- response.sendRedirect(msg);
- } catch (IOException e1) {
- // Browser is gone
- }
- }
- catch (SAMLException e) {
- log.error("Authentication Assertion had invalid format.");
- try {
- String msg = appinfo.getErrorsConfig().getSession();
- if (msg==null)
- msg=appinfo.getErrorsConfig().getShire();
- if (msg==null)
- msg="sessionError.html";
- if (msg.charAt(0)!='/')
- msg=contextPath+"/"+msg;
- response.sendRedirect(msg);
- } catch (IOException e1) {
- // Browser is gone
- }
- }
- finally {
- // Detach ThreadLocal tracking block from the request thread
- // before returning to Web Server.
- ServletContextInitializer.finishService(request,response);
- }
- }
-
- /**
- * NewSessionData is created from the HttpServletRequest and
- * the SPConfig/Application. It can be POSTProfile or Artifact.
- * Create a Session object from it.
- *
- * <p>Note: This method can also be called from FilterSupport.</p>
- *
- * @return random key of Session
- * @throws SAMLException
- */
- public static
- String createSessionFromData(
- NewSessionData data
- )
- throws SAMLException {
- String sessionid=null;
- StringBuffer pproviderId = // Get back IdP Entity name from SAML
- new StringBuffer();
- ServiceProviderConfig config = context.getServiceProviderConfig();
- ApplicationInfo appinfo = config.getApplication(data.applicationId);
- String[] audienceArray = appinfo.getAudienceArray();
- String providerId = appinfo.getProviderId();
-
- // Set up Shibboleth layer to support SAML BrowserProfile
- ShibBrowserProfile profile = new ShibBrowserProfile(data.applicationId);
-
- // Create the Artifact processing Callback (that maps an Artifact
- // to the IdP Artifact resolver endpoint) just in case it is needed
- SPArtifactMapper mapper = new SPArtifactMapper(appinfo,config);
-
- // Build the SAML object that represents data extracted
- // from the FORM or QueryString parameters on the request.
- BrowserProfileRequest bpr = new BrowserProfileRequest();
- bpr.SAMLArt = data.SAMLArt;
- bpr.SAMLResponse = data.SAMLResponse;
-
- bpr.TARGET = data.target;
-
- // Process the encoded SAMLResponse or, if Artifact, fetch
- // a corresponding Response from the IdP.
- BrowserProfileResponse samldata = profile.receive(
- pproviderId,
- bpr,
- data.handlerURL,
- context.getReplayCache(),
- mapper,
- 1
- );
-
- // Check Assertions for restrictions
- Iterator conditions = samldata.assertion.getConditions();
- while (conditions.hasNext()) {
- SAMLCondition cond =
- (SAMLCondition)conditions.next();
-
- if (cond instanceof SAMLAudienceRestrictionCondition) {
- SAMLAudienceRestrictionCondition audienceCondition =
- (SAMLAudienceRestrictionCondition) cond;
- Iterator audiences = audienceCondition.getAudiences();
- if (audiences==null)
- continue; // probably invalid
- boolean matched = false;
- StringBuffer audienceTests = new StringBuffer();
- while (!matched && audiences.hasNext()) {
- String audienceString = (String) audiences.next();
- audienceTests.append(audienceString);
- audienceTests.append(' ');
- if (audienceString.equals(providerId)) {
- matched=true;
- }
- if (audienceArray!=null) {
- for (int i=0;i<audienceArray.length;i++) {
- if (audienceString.equals(audienceArray[i])) {
- matched=true;
- break;
- }
- }
- }
- }
- if (!matched) {
- log.error("Assertion restricted to "+audienceTests.toString());
- StringBuffer audienceBuffer = new StringBuffer("Did not match ");
- audienceBuffer.append(providerId);
- if (audienceArray!=null && audienceArray.length>0) {
- audienceBuffer.append(" or ");
- for (int i=0;i<audienceArray.length;i++) {
- audienceBuffer.append(audienceArray[i]);
- audienceBuffer.append(' ');
- }
- }
- log.error(audienceBuffer.toString());
- throw new SAMLException("Assertion failed audience restriction test.");
- }
- }
- }
-
- // Create a new Session object or fill in an existing emtpy
- // Session object with the values from this Assertion.
- SessionManager sessionManager = context.getSessionManager();
- String emptySessionId = null;
- if (data.target.indexOf(':')==-1) {
- // The Target can be a URL or an Empty SessionId
- emptySessionId = data.target;
- }
- sessionid = sessionManager.newSession(
- data.applicationId,
- data.ipaddr,
- pproviderId.toString(),
- samldata.assertion,
- samldata.authnStatement,
- emptySessionId);
-
- Session session = sessionManager.findSession(sessionid, data.applicationId);
-
- // Fetch attributes immediately (unless we already have them)
- checkForAttributePush(samldata, session);
- AttributeRequestor.fetchAttributes(session);
-
- return sessionid;
- }
-
-
- /**
- * Scan the POST data for Attribute Assertions. If any are found,
- * then attributes have been pushed and we don't need to go to
- * the AA to get them.
- * @param samldata The BrowserProfileResponse containing the SAMLResponse
- * @param session The Session just created
- */
- private static void checkForAttributePush(BrowserProfileResponse samldata, Session session) {
- SAMLResponse samlresponse = samldata.response;
- Iterator assertions = samlresponse.getAssertions();
- while (assertions.hasNext()) {
- SAMLAssertion assertion = (SAMLAssertion) assertions.next();
- Iterator statements = assertion.getStatements();
- while (statements.hasNext()) {
- SAMLStatement statement = (SAMLStatement) statements.next();
- if (statement instanceof SAMLAttributeStatement) {
- log.info("Found Attributes with Authenticaiton data (Attribute Push).");
- session.setAttributeResponse(samlresponse);
- // Note, the Attribute Statements have not been checked for
- // AAP or Signatures. AttributeRequestor will bypass calling
- // the AA and will reprocess the POST Response for Attributes.
- return;
- }
- }
- }
- }
-
-
- /**
- * The Artifact comes in a GET. However, the code for processing
- * the HttpServletRequest is the same for both methods.
- */
- protected void doGet(HttpServletRequest arg0, HttpServletResponse arg1)
- throws ServletException, IOException {
- log.debug("Received GET: "+ arg0.getQueryString());
- doPost(arg0,arg1);
- }
-
-
-}
+++ /dev/null
-/*
- * 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.
- */
-
-/*
- * AttributeRequestor.java
- *
- * Generate a SAMLRequest to the AA for Attributes, then process the
- * reply. In C++, this logic was InternalCCacheEntry::getNewResponse()
- * in shib-ccache.cpp.
- *
- * The User Authentication was previously processed by ShibPOSTProfile
- * and was stored by SessionManager in a Session object. Although the
- * attributes might be fetched immediately, that is a strategy issue.
- * In Java, we isolate the Attribute fetch in this separate module.
- *
- * The Session block retains a copy of the original SAMLStatement from
- * the POST, and it contains information about the remote Entity.
- * However, the POST came from the HS (or IIDPProvider if you want to
- * use SAML 2 terms), and this transaction has to go to the AA. So
- * Metadata must be used to obtain the AttributeAuthorityRole and its
- * associated Endpoint (URL).
- *
- * The ApplicationInfo object for the configured Application presents
- * a getAttributeDesignators method that can return a list of attributes
- * to specify in the request. However, I can find no configuration element
- * that corresponds to this, and no example logic. For now that method
- * returns an empty collection and no particular attributes are requested.
- *
- * The actual SSL session and exchange of data is performed by OpenSAML.
- * Our interface to SAML is through the separate ShibBind module. The
- * layers of processing and responsibilites need to be understood.
- *
- * ShibBind uses the Metadata for the User's ID Providing Entity to
- * locate the AttributeAuthorityRole and therefore the AA URL. This
- * is passed to OpenSAML along with the request. Upon return, if any
- * statements are signed it is the responsiblilty of ShibBind to call
- * the Trust implementations to validate the signatures.
- *
- * This module then checks, by calling the isSigned() property of
- * SAMLObjects, to make sure that everything that is supposed to be
- * signed actually was signed. ShibBind knows if a signature is valid,
- * but this module knows if a signature was requred. This module also
- * applies AAP to examine attributes and values and discard those that
- * the policy doesn't accept.
- *
- * Recovery Context: All exceptions handled and logged internally.
- */
-package edu.internet2.middleware.shibboleth.serviceprovider;
-
-import java.security.Key;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-
-import org.apache.log4j.Logger;
-import org.apache.xml.security.signature.XMLSignature;
-import org.opensaml.SAMLAssertion;
-import org.opensaml.SAMLAttributeQuery;
-import org.opensaml.SAMLAuthenticationStatement;
-import org.opensaml.SAMLException;
-import org.opensaml.SAMLRequest;
-import org.opensaml.SAMLResponse;
-import org.opensaml.SAMLSubject;
-import org.opensaml.XML;
-
-import edu.internet2.middleware.shibboleth.common.Credential;
-import edu.internet2.middleware.shibboleth.common.Credentials;
-import edu.internet2.middleware.shibboleth.metadata.AttributeAuthorityDescriptor;
-import edu.internet2.middleware.shibboleth.metadata.EntityDescriptor;
-import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderConfig.ApplicationInfo;
-
-/**
- * A static class with a static method. No objects are created
- *
- * @author Howard Gilbert
- */
-public class AttributeRequestor {
-
- private static Logger log = Logger.getLogger(AttributeRequestor.class);
- private static ServiceProviderContext context = ServiceProviderContext.getInstance();
-
- private AttributeRequestor() {} // Prevent instantiation
-
- /**
- * Request SAML Attribute response from AA (or process
- * Attributes previously presented through AttributePush).
- *
- * @param session Session object
- * @return true if Attributes successfully stored in the Session
- * @throws MetadataException If IdP has no configured AA
- * @throws SAMLException If there is a problem with the reply
- */
- static
- boolean // return false if attributes are not fetched
- fetchAttributes(
- Session session){
-
- log.debug("Fetching attributes for session "+session.getSessionId()+
- " from "+session.getEntityId());
-
- // Get local references to configuration objects
- ServiceProviderConfig config = context.getServiceProviderConfig();
- ApplicationInfo appinfo = config.getApplication(session.getApplicationId());
-
- SAMLResponse response = session.getAttributeResponse();
-
- // The Entity name was fed by by ShibPOSTProfile.accept(). Look it up in the
- // Metadata now and return the Entity object.
- EntityDescriptor entity = appinfo.lookup(session.getEntityId());
- if (entity==null) {
- log.error("Entity(Site) deleted from Metadata since authentication POST received: "+session.getEntityId());
- return false;
- }
-
- SAMLRequest request = null;
-
- // Find the Shibboleth protocol AA Role configured in the Metadat for this Entity.
- AttributeAuthorityDescriptor aa =
- entity.getAttributeAuthorityDescriptor(XML.SAML11_PROTOCOL_ENUM); // throws MetadataException
- if (aa==null) {
- log.error("No Attribute Authority in Metadata for ID="+entity.getId());
- return false;
- }
-
- // Were Attributes already Pushed?
- if (response==null) {
- // No, then build and issue the Attribute Query
- SAMLAttributeQuery query = null;
- SAMLSubject subject;
- try {
- // Get the POST data from the Session. It has the Subject and its source.
- SAMLAuthenticationStatement authenticationStatement = session.getAuthenticationStatement();
- if (authenticationStatement==null) {
- log.error("Session contains no Authentication Statement." );
- return false;
- }
- SAMLSubject subject2 = authenticationStatement.getSubject();
- if (subject2==null) {
- log.error("Session Authentication Statement contains no Subject." );
- return false;
- }
- subject = (SAMLSubject) subject2.clone();
- } catch (Exception e) {
- log.error("Unable to generate the query SAMLSubject from the Authenticaiton." );
- return false;
- }
- log.debug("Subject (Handle) is "+subject.getNameIdentifier());
-
-
-
-
- Collection attributeDesignators = appinfo.getAttributeDesignators();
- try {
- query =
- new SAMLAttributeQuery(
- subject, // Subject (i.e. Handle) from authentication
- appinfo.getProviderId(), // SP Entity name
- attributeDesignators // Attributes to request, null for everything
- );
-
- // Wrap the Query in a request
- request = new SAMLRequest(query);
- } catch (SAMLException e) {
- log.error("AttributeRequestor unable to build SAML Query for Session "+session.getSessionId());
- return false;
- }
-
- String credentialId = appinfo.getCredentialIdForEntity(entity);
- if (credentialId!=null)
- possiblySignRequest(config.getCredentials(), request, credentialId);
-
- // ShibBinding will extract URLs from the Metadata and build
- // parameters so SAML can create the session. It also interfaces
- // to Trust to verify that any signed objects have trusted signatures.
- try {
- ShibBinding binding = new ShibBinding(session.getApplicationId());
- response = binding.send(request,aa,null,null,appinfo);
- } catch (SAMLException e) {;} // response will be null
- if (response==null) {
- log.error("AttributeRequestor Query to remote AA returned no response from "+session.getEntityId());
- return false;
- }
- } else {
- // Attributes were already pushed (by POST or Artifact)
- log.info("Bypassing Attribute Query because Attributes already Pushed.");
- }
-
- // At this point we either have Attribute Assertions because
- // they were already there or because we fetched them from the AA
-
- // Check each assertion in the response.
- int acount = 0;
- Iterator assertions = response.getAssertions();
- ArrayList assertionList = new ArrayList();
- while (assertions.hasNext()) {
- assertionList.add(assertions.next());
- }
- assertions=assertionList.iterator();
- while (assertions.hasNext()) {
- SAMLAssertion assertion = (SAMLAssertion) assertions.next();
-// if (signedAssertions && !assertion.isSigned()) {
-// log.warn("AttributeRequestor has removed unsigned assertion from response from "+session.getEntityId());
-// response.removeAssertion(acount);
-// continue;
-// }
-
- try {
- appinfo.applyAAP(assertion,aa); // apply each AAP to this assertion
- acount++;
- }
- catch (SAMLException ex) {
- response.removeAssertion(acount); // AAP rejected all statements for this assertion
- }
- }
-
- // A response may end up with no attributes, but that is not an error.
- // Maybe there is just nothing important to say about this user.
-
- session.setAttributeResponse(response); // Save response in Session object
- return true;
- }
-
- /**
- * Given a credentialId from the CredentialUse/RelyingParty stuff,
- * find a corresponding Credential element and use its Key/Cert to
- * sign the Request.
- *
- * @oaran credentials Credentials object from config file
- * @param request SAML AA Query request
- * @param credentialId Siging Id from CredentialUse
- */
- static void possiblySignRequest(
- Credentials credentials,
- SAMLRequest request,
- String credentialId) {
-
-
- if (credentials==null) {
- log.error("No Credentials Element in SP Config file.");
- return;
- }
- Credential credential = credentials.getCredential(credentialId);
- if (credential==null) {
- log.error("No credential found for id "+credentialId);
- return;
- }
- Key key = credential.getPrivateKey();
- X509Certificate[] certificateChain = credential.getX509CertificateChain();
- try {
- request.sign(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1,key,Arrays.asList(certificateChain));
- log.debug("Attribute Request signed with "+credentialId);
- } catch (SAMLException e) {
- log.error("Unable to sign Attribute Request", e);
- }
- }
-
-}
+++ /dev/null
-/*
- * 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.serviceprovider;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-import javax.servlet.UnavailableException;
-
-import org.apache.log4j.ConsoleAppender;
-import org.apache.log4j.FileAppender;
-import org.apache.log4j.Layout;
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
-import org.apache.log4j.PatternLayout;
-import org.apache.xml.security.Init;
-
-import edu.internet2.middleware.commons.log4j.ThreadLocalAppender;
-
-/**
- * A ContextListener gets control from the Servlet Container before
- * any Servlets or Filters are loaded. It can perform the earliest
- * forms of initialization. Commonly, this is used to initialize log
- * files or container systems (such as Spring). Initialization can
- * done here or in the init routines of the Filters and individual
- * Servlets. It is better to do it here logic that is common to all
- * Servlets and Filters since you do not know what order they will
- * be loaded. It is generally a good idea to have one on spec so
- * that you can move logic around as needed.
- */
-public class ContextListener implements ServletContextListener {
-
- //TODO: Change before release
- private static final Level defaultLogLevel = Level.DEBUG;
-
- // Initialization, parsing files, and setting up
- public static final String SHIBBOLETH_INIT = "shibboleth.init";
- private static Logger initLogger = Logger.getLogger(SHIBBOLETH_INIT);
- private static Logger initLogger2 = Logger.getLogger("edu.internet2.middleware.shibboleth.xml");
-
- // Authentication and Attribute processing, including SAML, Trust,
- // Metadata, etc. Because the SP doesn't control all the code, it is
- // based on real classnames
- private static Logger clientLogger = Logger.getLogger("edu.internet2.middleware");
- private static Logger samlLogger = Logger.getLogger("org.opensaml");
-
- // Requests from the Resource Manager only touch the RequestMapper
- // and Session Cache
- public static final String SHIBBOLETH_SERVICE = "shibboleth.service";
- private static Logger serviceLogger = Logger.getLogger(SHIBBOLETH_SERVICE);
-
-
- public void contextInitialized(ServletContextEvent servletContextEvent) {
- ServletContext servletContext = servletContextEvent.getServletContext();
- Init.init(); // Let XML Security go first
-
-
- Layout initLayout = new PatternLayout("%d{HH:mm} %-5p %m%n");
-
- ThreadLocalAppender threadAppender = new ThreadLocalAppender();
- threadAppender.setLayout(initLayout);
- threadAppender.setName("ThreadAppender");
-
- ConsoleAppender consoleAppender= new ConsoleAppender(initLayout,ConsoleAppender.SYSTEM_OUT);
- consoleAppender.setName("SPConsoleAppender");
-
- clientLogger.addAppender(threadAppender);
- clientLogger.addAppender(consoleAppender);
- clientLogger.setLevel(defaultLogLevel);
-
- initLogger.addAppender(consoleAppender);
- initLogger.setLevel(defaultLogLevel);
-
- initLogger2.setLevel(defaultLogLevel);
-
- // The init log location is represented as a URL in the web.xml
- // We have to change this int a fully qualified path name
- String initLogUrl = servletContext.getInitParameter("InitializationLog");
- if (initLogUrl!=null)
- try {
- URI initLogURI = new URI(initLogUrl);
- File initLogFile = new File(initLogURI);
- String logname = initLogFile.getAbsolutePath();
- FileAppender initLogAppender = new FileAppender(initLayout,logname);
- initLogAppender.setName("SPInitLogFileAppender");
- initLogger.addAppender(initLogAppender);
- initLogger2.addAppender(initLogAppender);
- } catch (URISyntaxException e1) {
- servletContext.log("InitializationLog context parameter is not a valid URL", e1);
- } catch (IOException e1) {
- servletContext.log("InitializationLog context parameter does not point to a valid location",e1);
- }
-
-
- samlLogger.addAppender(threadAppender);
- samlLogger.addAppender(consoleAppender);
- samlLogger.setLevel(defaultLogLevel);
-
- serviceLogger.addAppender(consoleAppender);
- serviceLogger.setLevel(defaultLogLevel);
-
-
- try {
- ServletContextInitializer.initServiceProvider(servletContext);
- } catch (UnavailableException e) {
- // Do nothing now, Servlet will retry in a few milliseconds
- }
-
- }
-
- public void contextDestroyed(ServletContextEvent arg0) {
- // Nothing interesting happens at the end
- }
-
-}
+++ /dev/null
-/*
- * 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.
- */
-
-/*
- * FilterSupportImpl.java
- *
- * Provide access to the Filter to configuration information
- * and Session data.
- */
-package edu.internet2.middleware.shibboleth.serviceprovider;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import org.apache.log4j.Logger;
-import org.opensaml.SAMLException;
-
-import x0.maceShibbolethTargetConfig1.SessionInitiatorDocument.SessionInitiator;
-import x0.maceShibbolethTargetConfig1.SessionsDocument.Sessions;
-import x0Metadata.oasisNamesTcSAML2.IndexedEndpointType;
-
-import edu.internet2.middleware.shibboleth.aap.AAP;
-import edu.internet2.middleware.shibboleth.aap.AttributeRule;
-import edu.internet2.middleware.shibboleth.resource.FilterSupport;
-import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderConfig.ApplicationInfo;
-
-/**
- * This class provides the FilterSupport interface for Resource Managers.
- * It can be directly connected to RMs in the same JVM, or it can be
- * wrapped in a Remote or Web Service interface.
- *
- * @author Howard Gilbert
- */
-public class FilterSupportImpl implements FilterSupport {
-
- private static ServiceProviderContext context = ServiceProviderContext.getInstance();
- private static Logger log = Logger.getLogger(ContextListener.SHIBBOLETH_SERVICE);
-
- /**
- * The Resource has been mapped to an ApplicationId. This routine
- * builds a struct (public data field only serializable class)
- * that contains a subset of parameters extracted from the
- * Application(s) element, which has been turned into an
- * ApplicationInfo object in the config.
- *
- * @param applicationId select the SPConfig Application element
- * @return RMAppInfo structure
- */
- public RMAppInfo getRMAppInfo(String applicationId) {
- RMAppInfo rmdata = new RMAppInfo();
-
- ServiceProviderConfig config = context.getServiceProviderConfig();
-
- ApplicationInfo appinfo = config.getApplication(applicationId);
- Sessions appSessionValues = appinfo.getSessionsConfig();
-
- rmdata.applicationId = applicationId;
- rmdata.providerId = appinfo.getProviderId();
-
- // The deprecated ShireURL has a fully qualified URL
- // The new preferred syntax uses a prefix from HandlerURL
- // and a suffix from an AssertionConsumerService
- rmdata.handlerUrl = appSessionValues.getShireURL();
- if (rmdata.handlerUrl==null) {
- String handler = appSessionValues.getHandlerURL();
- if (handler!=null) {
- IndexedEndpointType[] assertionConsumerServiceArray =
- appSessionValues.getAssertionConsumerServiceArray();
- IndexedEndpointType assertionConsumerService = null;
- if (assertionConsumerServiceArray.length>0)
- assertionConsumerService = assertionConsumerServiceArray[0];
- for (int i=0;i<assertionConsumerServiceArray.length;i++) {
- if (assertionConsumerServiceArray[i].getIsDefault()) {
- assertionConsumerService = assertionConsumerServiceArray[i];
- }
- }
- String suffix = assertionConsumerService.getLocation();
- if (suffix!=null)
- rmdata.handlerUrl= handler+suffix;
- // Ideally, we should now check the generated URL against the
- // Metadata, but current practice doesn't guarantee that the
- // SP has a copy of its own Metadata declaration.
- }
-
- }
-
- // Again there is a deprecated attribute and some new structure
- rmdata.wayfUrl = appSessionValues.getWayfURL(); // deprecated
- SessionInitiator[] sessionInitiatorArray = appSessionValues.getSessionInitiatorArray();
- if (sessionInitiatorArray.length>0) {
- String temp = sessionInitiatorArray[0].getWayfURL();
- if (temp!=null)
- rmdata.wayfUrl = temp;
- }
-
- rmdata.cookieName = appSessionValues.getCookieName();
- rmdata.cookieProperties = appSessionValues.getCookieProps();
-
- /*
- * The mapping of long globally unique Attribute names
- * to shorter alias names and even dummy HTTP headers is done
- * in the AAP part of the configuration. Run through the AAP
- * blocks and turn this into a more usable pair of Maps keyed
- * by attributeid and returning the nickname or header name.
- */
- rmdata.headerToAttribute = new HashMap();
- rmdata.attributeToAlias = new HashMap();
- AAP[] providers = appinfo.getAAPProviders();
- for (int i=0;i<providers.length;i++) {
- AAP aap = providers[i];
- Iterator attributeRules = aap.getAttributeRules();
- while (attributeRules.hasNext()) {
- AttributeRule rule = (AttributeRule) attributeRules.next();
- String name = rule.getName();
- String alias = rule.getAlias();
- String header = rule.getHeader();
- if (header!=null && header.length()!=0)
- rmdata.headerToAttribute.put(header,name);
- if (alias!=null && alias.length()!=0)
- rmdata.attributeToAlias.put(name,alias);
- }
- }
-
-
- return rmdata;
- }
-
- /**
- * From the Session object, return a simple Map of Attributes
- * and values.
- *
- * @param sessionId
- * @param applicationId
- * @return Map of (attribute,value) pairs
- */
- public SessionInfo
- getSessionInfo(String sessionId, String applicationId) {
- SessionInfo sessionInfo = new SessionInfo();
- SessionManager sm = context.getSessionManager();
- Session session =
- sm.findSession(sessionId, applicationId);
- sessionInfo.savedTarget=session.getSavedTargetURL();
- if (session==null)
- sessionInfo.sessionStatus = SessionInfo.SESSION_NOT_FOUND;
- else if (!session.isInitialized())
- sessionInfo.sessionStatus = SessionInfo.SESSION_NOT_INITIALIZED;
- else if (!applicationId.equals(session.getApplicationId()))
- sessionInfo.sessionStatus = SessionInfo.SESSION_BAD_APPLICATIONID;
- else
- sessionInfo.attributes = SessionManager.mapAttributes(session);
- return sessionInfo;
- }
-
-
- /**
- * Process a POST or Artifact Assertion presented to the RM and
- * create a Session object from it.
- *
- * @param sessionData Assertion data
- * @return sessionId string
- */
- public String createSessionFromData(NewSessionData sessionData) {
- String sessionid;
- try {
- sessionid = AssertionConsumerServlet.createSessionFromData(sessionData);
- } catch (SAMLException e) {
- log.error("Invalid data submitted by RM "+e);
- return null;
- }
- log.info("Session created from data submitted by RM: "+sessionid);
- return sessionid;
- }
-
-
- /**
- * Create empty Session so SessionID can be written as a Cookie
- * before redirecting the Browser to the IDP.
- *
- * @param applicationId
- * @param url The real resource (Target) URL
- * @return SessionId of empty session
- */
- public String createEmptySession(String applicationId, String url) {
- SessionManager sessionManager = context.getSessionManager();
- String id = sessionManager.reserveSession(applicationId,url);
- return id;
- }
-
- /**
- * The RM presents its context which is then processed through
- * the RequestMap logic. A transformed verion of RequestMap that
- * contains only the subset of the data applicable to this RM
- * is returned in a format that is easy to serialize.
- */
- public RMConfigData getResourceManagerConfig(String contextRM) {
- ServiceProviderConfig config = context.getServiceProviderConfig();
-
- RMConfigData rmconfig = new RMConfigData();
-
- rmconfig.hostResolutions = config.contextResolutions(contextRM);
- return rmconfig;
- }
-
-}
+++ /dev/null
-/*
- * 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.
- */
-
-/*
- * RequestTracker.java
- *
- * An object representing a sanitized version of information
- * on the current request. Typically, data will be extracted
- * from the current HttpRequest and stored here. A reference to
- * the object is stored in a ThreadLocal field of the
- * ServiceProviderContext when a request arrives, and then the
- * reference is nulled before returning to the container.
- *
- * Thread local storage is somewhat expensive, though it gets
- * more efficient with each release. Therefore, a reference to
- * this object should be obtained once when needed and saved
- * in a local variable. Obviously, a reference must never be
- * saved in a field because the data here is thread-specific.
- */
-package edu.internet2.middleware.shibboleth.serviceprovider;
-
-/**
- * Hold information about the current request in a ThreadLocal object.
- *
- * <p>ServiceProviderContext context = ServiceProviderContext.getInstance();<br />
- * RequestTracker requestTracker = context.getRequestContext();</p>
- *
- * @author Howard Gilbert
- */
-public class RequestTracker {
-
- String ipaddr = null;
-
- public String getIpaddr() {
- return ipaddr;
- }
- public void setIpaddr(String ipaddr) {
- this.ipaddr = ipaddr;
- }
-}
+++ /dev/null
-/*
- * 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.
- */
-
-/*
- * SPArtifactMapper is a callback routine implementing a SAML
- * interface. It is based on the shib-target/ArtifactMapper.cpp
- * in the C++ code and shares a lot of logic with the
- * AttributeRequestor class with a little bit of ShibBinding thrown
- * in for good measure. This callback routine helps build and then
- * directs a request that presents an Artifact and
- * receives the Assertion that the Artifact represents.
- */
-package edu.internet2.middleware.shibboleth.serviceprovider;
-
-import java.util.Iterator;
-
-import org.apache.log4j.Logger;
-import org.opensaml.NoSuchProviderException;
-import org.opensaml.ProfileException;
-import org.opensaml.SAMLBinding;
-import org.opensaml.SAMLBindingFactory;
-import org.opensaml.SAMLException;
-import org.opensaml.SAMLRequest;
-import org.opensaml.SAMLResponse;
-import org.opensaml.SAMLSOAPHTTPBinding;
-import org.opensaml.UnsupportedExtensionException;
-import org.opensaml.SAMLBrowserProfile.ArtifactMapper;
-import org.opensaml.artifact.SAMLArtifact;
-import org.opensaml.artifact.SAMLArtifactType0001;
-import org.opensaml.artifact.SAMLArtifactType0002;
-
-import edu.internet2.middleware.shibboleth.common.Trust;
-import edu.internet2.middleware.shibboleth.metadata.Endpoint;
-import edu.internet2.middleware.shibboleth.metadata.EndpointManager;
-import edu.internet2.middleware.shibboleth.metadata.EntityDescriptor;
-import edu.internet2.middleware.shibboleth.metadata.IDPSSODescriptor;
-import edu.internet2.middleware.shibboleth.metadata.Metadata;
-import edu.internet2.middleware.shibboleth.metadata.MetadataException;
-import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderConfig.ApplicationInfo;
-
-/**
- * A callback class that SAML calls when processing an Artifact.
- * The Artifact references an Assertion being held by an IdP, but
- * SAML requires access to the Metadata and Trust services of Shibboleth
- * to locate the IdP Endpoint and generate a valid request to fetch it.
- * This class contains much in common with AttributeRequestor, but while
- * that class is static this must be an instance that captures state
- * (mostly the ApplicationInfo block of the Application to which the
- * Artifact was directed).
- * @author Howard Gilbert
- *
- */
-public class SPArtifactMapper implements ArtifactMapper {
-
- private static Logger log = Logger.getLogger(SPArtifactMapper.class.getName());
-
- // State variables set by constructor used by callback
- ApplicationInfo appinfo = null;
- ServiceProviderConfig config = null;
-
-
- /**
- * To create an instance of this object you must provide a snapshot
- * of the ServiceProviderConfig and the ApplicationInfo from the
- * Application element to which the Artifact is directed. We keep
- * this around as state until they are needed by the callback.
- * @param appinfo ApplicationInfo
- * @param config ServiceProviderConfig
- */
- public SPArtifactMapper(
- ApplicationInfo appinfo,
- ServiceProviderConfig config) {
- this.appinfo = appinfo;
- this.config = config;
- }
-
-
- /**
- * The Callback routine from SAML to direct a Request containing
- * the Artifact to the IdP.
- * @param request A SAMLRequest to resolve the Artifact
- * @return The SAMLResponse from the IdP
- * @throws SAMLException
- */
- public SAMLResponse resolve(SAMLRequest request)
- throws SAMLException {
- SAMLResponse response = null;
-
- // Ok, so what is this Artifact anyway
- Iterator artifacts = request.getArtifacts();
- if (!artifacts.hasNext())
- throw new SAMLException("SPArtifactMapper was passed no artifact.");
- EntityDescriptor entity = null;
- SAMLArtifact artifact = null;
- while (artifacts.hasNext()) {
- artifact = (SAMLArtifact)artifacts.next();
- entity = ((Metadata)appinfo).lookup(artifact);
- if (entity!=null)
- break;
- }
- if (entity==null) {
- throw new MetadataException("Unable to find Artifact issuer in Metadata.");
- }
- String entityId = entity.getId();
- log.info("Processing Artifact issued by "+entityId);
-
- IDPSSODescriptor idp = entity.getIDPSSODescriptor(
- request.getMinorVersion()==1?
- org.opensaml.XML.SAML11_PROTOCOL_ENUM :
- org.opensaml.XML.SAML10_PROTOCOL_ENUM
- );
- if (idp==null) {
- throw new MetadataException("Entity "+entityId+" has no usable IDPSSODescriptor.");
- }
-
-
- // Sign the Request if so configured
- String credentialId = appinfo.getCredentialIdForEntity(entity);
- if (credentialId!=null)
- AttributeRequestor.possiblySignRequest(config.getCredentials(), request, credentialId);
-
- //TODO: C++ code determines if the IdP is authenticated
- //boolean authenticated=false;
-
- if (artifact instanceof SAMLArtifactType0001) {
- // A Type1 Artifact takes any usable SOAP Endpoint
- EndpointManager endpointManager = idp.getArtifactResolutionServiceManager();
- Iterator endpoints = endpointManager.getEndpoints();
- while (endpoints.hasNext()) {
- // Search for an Endpoint with a SOAP Binding
- Endpoint endpoint = (Endpoint)endpoints.next();
- String binding = endpoint.getBinding();
- if (!binding.equals(SAMLBinding.SOAP))
- continue; // The C++ code is more elaborate here
-
- response = resolveArtifact(request, idp, endpoint);
- break; // Got response, stop scanning endpoints
- }
- } else if (artifact instanceof SAMLArtifactType0002) {
- // A Type2 Artifact carries an Endpoint location
- SAMLArtifactType0002 type2 = (SAMLArtifactType0002) artifact;
- EndpointManager endpointManager = idp.getArtifactResolutionServiceManager();
- Iterator endpoints = endpointManager.getEndpoints();
- while (endpoints.hasNext()) {
- // Search for an Endpoint matching the Artifact
- Endpoint endpoint = (Endpoint)endpoints.next();
- String binding = endpoint.getBinding();
- if (!binding.equals(SAMLBinding.SOAP))
- continue; // The C++ code is more elaborate here
- String location = endpoint.getLocation();
- if (!location.equals(type2.getSourceLocation()))
- continue;
-
- response = resolveArtifact(request, idp, endpoint);
- break; // Got response, stop scanning endpoints
- }
- } else {
- throw new UnsupportedExtensionException("Unrecognized Artifact type.");
- }
- if (response == null) {
- throw new MetadataException("Unable to locate acceptable binding/endpoint to resolve artifact.");
- }
- return response;
- }
-
- /**
- * Call back into SAML to transmit the Request to the IdP Enpoint
- * and get back the Response represented by the Artifact.
- * @param request A SAMLRequest containing the Artifact
- * @param idp The IdP entity
- * @param endpoint The IdP Endpoint
- * @return The SAMLResponse returned by the IdP
- * @throws NoSuchProviderException
- * @throws SAMLException
- * @throws ProfileException if the response has no assertions
- */
- private SAMLResponse resolveArtifact(SAMLRequest request, IDPSSODescriptor idp, Endpoint endpoint) throws NoSuchProviderException, SAMLException, ProfileException {
- SAMLResponse response;
- SAMLBinding sbinding = SAMLBindingFactory.getInstance(endpoint.getBinding());
- if (sbinding instanceof SAMLSOAPHTTPBinding) { // I shure hope so
- SAMLSOAPHTTPBinding httpbind = (SAMLSOAPHTTPBinding)sbinding;
- httpbind.addHook(new ShibHttpHook(idp,(Trust)appinfo));
- }
- response=sbinding.send(endpoint.getLocation(),request);
- if (!response.getAssertions().hasNext()) {
- throw new ProfileException("No SAML assertions returned in response to artifact profile request.");
- }
- return response;
- }
-
-}
+++ /dev/null
-/*
- * 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.
- */
-
-/*
- * ServiceProviderConfig.java
- *
- * A ServiceProviderConfig object holds an instance of the Shibboleth
- * configuration data from the main configuration file and from all
- * secondary files referenced by the main file.
- *
- * The configuration file is typically processed during Context
- * initialization. In a Servlet environment, this is done from
- * the ServletContextInitializer, while in JUnit testing it is
- * done during test setup (unless you are testing configuration
- * in which case it is part of the test itself). This occurs
- * during init() processing and is inheritly synchronized.
- *
- * Initialization is a two step process. First create an
- * instance of this class, then find a path to the configuration
- * file and call loadConfigObjects().
- *
- * In addition to the option of loading external classes that
- * implement one of the Plugin service interfaces by providing
- * the name of the class in the type= attribute of the Plugin
- * configuration XML, there is also a manual wiring interface.
- * Create an implimenting object yourself, then add it to the
- * configuration by passing an identifying URI and the object
- * to a addOrReplaceXXXImplementation() method.
- *
- * These wiring calls are agressive, while the XML is passive.
- * If the wiring call is made before loadConfigObject(), then
- * XML referencing this same URI will find that it has already
- * been loaded and use it. Alternately, if the call is made
- * after loadConfigObject() then the XML will have processed
- * the URI, loaded the file, and built an implimenting object.
- * However, the wiring call will replace that object with the
- * one provided in the call. Obviously making these calls
- * first will be slightly more efficient, and is necessary if
- * the XML configuration specifies URIs that will be provided
- * by the wiring call and are not represented by any actual file.
- *
- * After initialization completes, this object and its arrays
- * and collections should be structurally immutable. A map or
- * array should not be changed by adding or removing members.
- * Thus iteration over the collections can be unsynchronized.
- * The reference to a value in the map can be swapped for a
- * new object, because this doesn't effect iteration.
- *
- * Any method may obtain a copy of the current ServiceProviderConfig
- * object by calling ServiceProviderContext.getServiceProviderConfig().
- * This reference should only be held locally (for the duration
- * of the request). Should the entire Shibboleth configuration file
- * be reparsed (because of a dynamic update), then a new reference will
- * be stored in the SPContext. Picking up a new reference for each
- * request ensures that a program uses the latest configuration.
- *
- * When a secondary file (Metadata, Trust, AAP, etc.) is reloaded,
- * a new object is constructed for that interface and the entry in
- * the corresponding Map of providers of that interface is replaced.
- * Therefore, non-local variables must only store the URI for such
- * objects. A method can pass the URI to the Map lookup method and
- * obtain a local variable reference to the current implementing
- * object which can be used during the processing of the current
- * request.
- *
- * Note: The URI for a secondary file cannot change just by
- * reloading the file, but it can change if this main configuration
- * file object is rebuilt. Therefore, if an external object stores
- * a URI for a plugin object, it must be prepared for the Map lookup
- * to return null. This would indicate that the main configuration
- * file has been reloaded and the previously valid URI now no longer
- * points to any implementing object.
- *
- * XML configuration data is parsed into two formats. First, it
- * is processed by an ordinary JAXP XML parser into a W3C DOM format.
- * The parser may validate the XML against an XSD schema, but the
- * resulting DOM is "untyped". The XML becomes a tree of Element,
- * Attribute, and Text nodes. The program must still convert an
- * attribute or text string to a number, date, boolean, or any other
- * data type even through the XSD declares that it must be of that
- * type. The program must also search through the elements of the tree
- * to find specific names for expected contents.
- *
- * This module then subjects the DOM to a secondary parse through
- * some classes generated by compiling the XSD file with tools
- * provided by the Apache XML Bean project. This turns the valid
- * XML into strongly typed Java objects. A class is generated to
- * represent every data type defined in the XSD schemas. Attribute
- * values and child elements become properties of the objects of
- * these classes. The XMLBean objects simplify the configuration
- * logic.
- *
- * If the configuration file directly reflected the program logic,
- * the XML Bean classes would probably be enough. However, there
- * are two important considerations:
- *
- * First, the Metadata is in transition. Currently we support an
- * ad-hoc format defined by Shibboleth. However, it is expected
- * that this will change in the next release to support a new
- * standard accompanying SAML 2.0. The program logic anticipates
- * this change, and is largely designed around concepts and
- * structures of the new SAML standard. The actual configuration
- * file and XML Beans support the old format, which must be mapped
- * into this new structure.
- *
- * Second, secondary configuration elements (Credentials, Trust,
- * Metadata, AAP, etc.) are "Pluggable" components. There is a
- * built-in implementation of these services based on the XML
- * configuration described in the Shibboleth documentation.
- * However, the administrator can provide other classes that
- * implement the required interfaces by simply coding the class
- * name in the type= parameter of the XML element referencing the
- * plugin. In this case we don't know the format of the opaque
- * XML and simply pass it to the plugin.
- *
- *
- * Dependencies: Requires XML Beans and the generated classes.
- * Requires access to XSD schema files for configuration file formats.
- * Logic depends on the order of enums in the XSD files.
- *
- * Error Strategy: A failure parsing the main configuration file
- * prevents further processing. However, a problem parsing a plug-in
- * configuration file should be noted while processing continues.
- * This strategy reports all the errors in all the files to the log
- * rather than stopping at the first error.
- */
-
-package edu.internet2.middleware.shibboleth.serviceprovider;
-
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-import org.apache.log4j.Logger;
-import org.apache.log4j.PropertyConfigurator;
-import org.apache.xmlbeans.XmlException;
-import org.apache.xmlbeans.XmlOptions;
-import org.opensaml.SAMLAssertion;
-import org.opensaml.SAMLAttribute;
-import org.opensaml.SAMLAttributeStatement;
-import org.opensaml.SAMLException;
-import org.opensaml.SAMLSignedObject;
-import org.opensaml.artifact.Artifact;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.xml.sax.SAXException;
-
-import x0.maceShibbolethTargetConfig1.ApplicationDocument;
-import x0.maceShibbolethTargetConfig1.LocalConfigurationType;
-import x0.maceShibbolethTargetConfig1.PluggableType;
-import x0.maceShibbolethTargetConfig1.RequestMapDocument;
-import x0.maceShibbolethTargetConfig1.SPConfigDocument;
-import x0.maceShibbolethTargetConfig1.SPConfigType;
-import x0.maceShibbolethTargetConfig1.ShibbolethTargetConfigDocument;
-import x0.maceShibbolethTargetConfig1.ApplicationDocument.Application;
-import x0.maceShibbolethTargetConfig1.ApplicationsDocument.Applications;
-import x0.maceShibbolethTargetConfig1.CredentialUseDocument.CredentialUse;
-import x0.maceShibbolethTargetConfig1.CredentialUseDocument.CredentialUse.RelyingParty;
-import x0.maceShibbolethTargetConfig1.ErrorsDocument.Errors;
-import x0.maceShibbolethTargetConfig1.HostDocument.Host;
-import x0.maceShibbolethTargetConfig1.HostDocument.Host.Scheme.Enum;
-import x0.maceShibbolethTargetConfig1.PathDocument.Path;
-import x0.maceShibbolethTargetConfig1.SessionsDocument.Sessions;
-import edu.internet2.middleware.shibboleth.aap.AAP;
-import edu.internet2.middleware.shibboleth.aap.AttributeRule;
-import edu.internet2.middleware.shibboleth.aap.provider.XMLAAPProvider;
-import edu.internet2.middleware.shibboleth.common.Credentials;
-import edu.internet2.middleware.shibboleth.common.PluggableConfigurationComponent;
-import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
-import edu.internet2.middleware.shibboleth.common.Trust;
-import edu.internet2.middleware.shibboleth.common.provider.ShibbolethTrust;
-import edu.internet2.middleware.shibboleth.metadata.EntitiesDescriptor;
-import edu.internet2.middleware.shibboleth.metadata.EntityDescriptor;
-import edu.internet2.middleware.shibboleth.metadata.Metadata;
-import edu.internet2.middleware.shibboleth.metadata.RoleDescriptor;
-import edu.internet2.middleware.shibboleth.metadata.provider.XMLMetadataProvider;
-import edu.internet2.middleware.shibboleth.xml.Parser;
-import edu.internet2.middleware.shibboleth.resource.FilterSupport;
-import edu.internet2.middleware.shibboleth.resource.FilterSupport.RequestResolution;
-
-/**
- * Load the configuration files into objects, index them, and return them on request.
- *
- * <p>A new instance of the ServiceProviderConfig object can be created to
- * parse a new version of the configuration file. It can then be swapped
- * into the ServiceProviderContext reference and will be picked up by
- * subsequent requests.</p>
- *
- * @author Howard Gilbert
- */
-public class ServiceProviderConfig {
-
- // Map key prefix for inline plugin configuration elements
- private static final String INLINEURN = "urn:inlineBS:ID";
-
- private static Logger initlog = Logger.getLogger(ContextListener.SHIBBOLETH_INIT+".Config");
- private static Logger reqlog = Logger.getLogger(ServiceProviderConfig.class);
-
- private SPConfigType // The XMLBean from the main config file
- config = null;
-
-
- /*
- * The following Maps reference objects that implement a plugin
- * interface indexed by their URI. There are builtin objects
- * created from inline or external XML files, but external
- * objects implementing the interfaces may be injected by
- * calling the addOrReplaceXXX method. Public access to these
- * Maps is indirect, through methods the ApplicationInfo object
- * for a given configured or default application.
- */
-
- private Map/*<String, Metadata>*/ entityLocators =
- new TreeMap/*<String, Metadata>*/();
-
- public void addOrReplaceMetadataImplementor(String uri, Metadata m) {
- initlog.info("addOrReplaceMetadataImplementor " + uri+ " as "+m.getClass());
- entityLocators.put(uri, m);
- }
-
- public Metadata getMetadataImplementor(String uri) {
- return (Metadata)entityLocators.get(uri);
- }
-
- private Map/*<String, AAP>*/ attributePolicies =
- new TreeMap/*<String, AAP>*/();
-
- public void addOrReplaceAAPImplementor(String uri, AAP a) {
- initlog.info("addOrReplaceAAPImplementor " + uri+ " as "+a.getClass());
- attributePolicies.put(uri,a);
- }
-
- public AAP getAAPImplementor(String uri) {
- return (AAP) attributePolicies.get(uri);
- }
-
- private Map/*<String, Trust>*/ certificateValidators =
- new TreeMap/*<String, Trust>*/();
-
- public void addOrReplaceTrustImplementor(String uri, Trust t) {
- initlog.info("addOrReplaceTrustImplementor " + uri+ " as "+t.getClass());
- certificateValidators.put(uri,t);
- }
-
- public Trust getTrustImplementor(String uri) {
- return (Trust) certificateValidators.get(uri);
- }
-
- private Trust[] defaultTrust = {new ShibbolethTrust()};
-
- /*
- * Objects created from the <Application(s)> elements.
- * They manage collections of URI-Strings that index the
- * previous maps to return Metadata, Trust, and AAP info
- * applicable to this applicationId.
- */
- private Map/*<String, ApplicationInfo>*/ applications =
- new TreeMap/*<String, ApplicationInfo>*/();
-
- // Default application info from <Applications> element
- private ApplicationInfo defaultApplicationInfo = null;
-
- public ApplicationInfo getApplication(String applicationId) {
- ApplicationInfo app=null;
- app = (ApplicationInfo) applications.get(applicationId);
- if (app==null) // If no specific match, return default
- return defaultApplicationInfo;
- return app;
- }
-
-
- // Objects created from single configuration file elements
- private Credentials credentials = null;
- private RequestMapDocument.RequestMap requestMap = null;
-
-
- /*
- * A few constants
- */
-
- private static final String XMLTRUSTPROVIDERTYPE =
- "edu.internet2.middleware.shibboleth.common.provider.ShibbolethTrust";
- private static final String XMLAAPPROVIDERTYPE =
- "edu.internet2.middleware.shibboleth.aap.provider.XMLAAP";
- private static final String XMLFEDERATIONPROVIDERTYPE =
- "edu.internet2.middleware.shibboleth.metadata.provider.XMLMetadata";
- private static final String XMLREQUESTMAPPROVIDERTYPE =
- "edu.internet2.middleware.shibboleth.sp.provider.NativeRequestMapProvider";
-
- /**
- * The constructor prepares for, but does not parse the configuration.
- *
- * @throws ShibbolethConfigurationException
- * if XML Parser cannot be initialized (Classpath problem)
- */
- public ServiceProviderConfig() {
- }
-
- /**
- * loadConfigObjects must be called once to parse the configuration.
- *
- * <p>To reload a modified configuration file, create and load a second
- * object and swap the reference in the context object.</p>
- *
- * @param configFilePath URL or resource name of file
- * @return the DOM Document
- * @throws ShibbolethConfigurationException
- * if there was an error loading the file
- */
- public synchronized void loadConfigObjects(String configFilePath)
- throws ShibbolethConfigurationException {
-
- if (config!=null) {
- initlog.error("ServiceProviderConfig.loadConfigObjects may not be called twice for the same object.");
- throw new ShibbolethConfigurationException("Cannot reload configuration into same object.");
- }
-
- initlog.info("Loading SP configuration from "+configFilePath);
-
- Document configDoc;
- try {
- configDoc = Parser.loadDom(configFilePath, true);
- if (configDoc==null) {
- initlog.error("Cannot load configuration file from "+configFilePath);
- throw new ShibbolethConfigurationException("Cannot load configuration file from "+configFilePath);
- }
- } catch (SAMLException e) {
- throw new ShibbolethConfigurationException("Problem obtaining XML parser from SAML "+e.toString());
- } catch (IOException e) {
- throw new ShibbolethConfigurationException("Problem reading file parsing "+configFilePath, e);
- } catch (SAXException e) {
- throw new ShibbolethConfigurationException("Problem parsing XML in "+configFilePath, e);
- }
- loadConfigBean(configDoc);
-
- return;
- }
-
- public long getDefaultAttributeLifetime() {
- return config.getGlobal().getMemorySessionCache().getDefaultLifetime();
- }
-
- public long getAAConnectTimeout() {
- return config.getGlobal().getMemorySessionCache().getAAConnectTimeout();
- }
- public long getAATimeout() {
- return config.getGlobal().getMemorySessionCache().getAATimeout();
- }
-
-
- /**
- * The RequestMap in the SPConfig potentially contains data for many
- * contexts. Create a simpler to parse table with just elements for
- * one WebApp context. A HostResolution entry is provided for every
- * Host element (scheme,host,port) above the context, and a table
- * of subdirectory exceptions then provides overrides.
- *
- * @param context A simple context name such as "secure"
- * @return A collection of HostResolution structures
- */
- public List /*<HostResolutions*/ contextResolutions(String context) {
- List /*<HostResolutions*/ hostResolutions = new ArrayList();
-
- // Process each <Host> entry in the <RequestMap>
- Host[] hostArray = requestMap.getHostArray();
- for (int ihost=0;ihost<hostArray.length;ihost++) {
- Host host = hostArray[ihost];
-
- // Start with an empty subdirectory map
- TreeMap pathOverrides = new TreeMap();
-
- // Scheme must be http or https. If omitted, use both
- Enum scheme = host.getScheme();
- String schemeName = "http";
- if (scheme!=null) {
- // First do http, then later https will be added
- schemeName = scheme.toString();
- if (!schemeName.startsWith("http"))
- continue; // Don't deal with ftp, etc.
- }
-
- String hostName = host.getName();
- int hostport = host.isSetPort()?(int) host.getPort():-1;
- URL hosturl = null;
- try {
- hosturl = new URL(
- schemeName,
- hostName,
- hostport,
- "/"+context);
- } catch (MalformedURLException e) {
- continue;
- }
-
- // The <Host> element applicationId and other attributes
- // establish the default Resolution structure
- String hostElementAppid = host.getApplicationId();
- if (hostElementAppid==null)
- hostElementAppid="default";
- RequestResolution requestResolution = new RequestResolution(hostElementAppid);
- requestResolution.requiresSession = host.getRequireSession();
-
- // Unless, of course, the <Path> for the context overrides
- // the Host values
- Path[] pathArray = host.getPathArray();
- Path[] subdirectories = null;
- for (int i=0;i<pathArray.length;i++) {
- Path contextPath = pathArray[i];
- if (context.equals(contextPath.getName())) {
- // This list may be extended with other attributes
- if (contextPath.isSetApplicationId())
- requestResolution.applicationId = contextPath.getApplicationId();
- if (contextPath.isSetRequireSession())
- requestResolution.requiresSession = contextPath.getRequireSession();
- break;
- }
- }
-
- // Note, the Context does not have to be explicitly specified
- // in a Path. If omitted, then then the Host defaults apply
- // and there are no overrides.
-
- // Add the HostResolution struct to the table. Note that at
- // this time the pathOverrides table is empty and if one
- // <Host> generates both an http and https element then they
- // share the same pathOverrides table.
- hostResolutions.add(new FilterSupport.HostResolution(requestResolution,hosturl,pathOverrides) );
- if (scheme==null) {
- // If no scheme was specified, then create a second https URL
- URL cloneurl = null;
- try {
- cloneurl = new URL(
- "https",
- hostName,
- hostport,
- context);
- } catch (MalformedURLException e) {
- continue;
- }
- hostResolutions.add(new FilterSupport.HostResolution(requestResolution,cloneurl,pathOverrides) );
- }
-
- // Now if any <Path> elements are under the context <Path>
- // fill in the pathOverrides table.
- if (subdirectories!=null && subdirectories.length>0) {
- String prefix = "";
- buildPathExceptions(prefix, subdirectories, pathOverrides, requestResolution);
- }
-
- } // foreach host
-
- return hostResolutions;
- }
-
- /**
- * Recursive Method to drill down through the Path elements in the RequestMap
- * to create a mapping table of subdirectory paths to RequestResolutions
- * @param prefix starts out "" and then adds subdirectory levels
- * @param subdirectories Path elements from current scan depth in RequestMap XML
- * @param pathToResolution Accumulating the map
- * @param defaultResolution RequestResolution from parent element
- */
- private void buildPathExceptions(
- String prefix,
- Path[] subdirectories,
- TreeMap pathToResolution,
- RequestResolution defaultResolution) {
-
- // Run down the list of subdirectory elements
- for (int i = 0; i<subdirectories.length;i++) {
- Path subdirectory = subdirectories[i];
- // Generate the path prefix up to this point
- String fullpath =
- prefix.length()==0?
- subdirectory.getName():
- prefix+"/"+subdirectory.getName();
-
- // Now build the RequestResolution from parent plus any overrides
- RequestResolution newResolution =
- new RequestResolution(defaultResolution.applicationId);
- newResolution.requiresSession = defaultResolution.requiresSession;
- boolean nondefault = false;
-
- // Note that this list may be extended with additional attributes
- if (subdirectory.isSetApplicationId()) {
- newResolution.applicationId = subdirectory.getApplicationId();
- nondefault=true;
- }
- if (subdirectory.isSetRequireSession()) {
- newResolution.requiresSession = subdirectory.getRequireSession();
- nondefault=true;
- }
-
- // If there was an override, add a resolution element to the table.
- if (nondefault) {
- pathToResolution.put(fullpath,newResolution);
- }
-
- // Now see if there are any nested Path elements to process recursively
- Path[] pathArray = subdirectory.getPathArray();
- if (pathArray!=null && pathArray.length!=0) {
- buildPathExceptions(fullpath,pathArray,pathToResolution,newResolution);
- }
-
- }
- }
-
-
- /*
- * Given a URL, determine its ApplicationId from the RequestMap config.
- *
- * <p>Note: This is not a full implementation of all RequestMap
- * configuration options. Other functions will be added as needed.</p>
- */
- public String mapRequest(String urlreq) {
- String applicationId = "default";
- URL url;
-
- try {
- url = new URL(urlreq);
- } catch (MalformedURLException e) {
- return applicationId;
- }
-
- String urlscheme = url.getProtocol();
- String urlhostname = url.getHost();
- String urlpath = url.getPath();
- int urlport = url.getPort();
-
- // find Host entry for this virtual server
- Host[] hostArray = requestMap.getHostArray();
- for (int ihost=0;ihost<hostArray.length;ihost++) {
- Host host = hostArray[ihost];
- Enum scheme = host.getScheme();
- String hostName = host.getName();
- String hostApplicationId = host.getApplicationId();
- long hostport = host.getPort();
-
- if (scheme != null &&
- !urlscheme.equals(scheme.toString()))
- continue;
- if (!urlhostname.equals(hostName))
- continue;
- if (hostport!=0 &&
- urlport!=0 &&
- urlport!=hostport)
- continue;
-
- // find Path entry for this subdirectory
- Path[] pathArray = host.getPathArray();
- if (hostApplicationId!=null)
- applicationId=hostApplicationId;
- for (int i=0;i<pathArray.length;i++) {
- String dirname = pathArray[i].getName();
- if (urlpath.equals(dirname)||
- urlpath.startsWith(dirname+"/")){
- String pthid= pathArray[i].getApplicationId();
- if (pthid!=null)
- applicationId=pthid;
- }
- }
- }
-
- reqlog.debug("mapRequest mapped "+urlreq+" into "+applicationId);
- return applicationId;
- }
-
- /**
- * <p>Parse the main configuration file DOM into XML Bean</p>
- *
- * <p>Automatically load secondary configuration files designated
- * by URLs in the main configuration file</p>
- *
- * @throws ShibbolethConfigurationException
- */
- private void loadConfigBean(Document configDoc)
- throws ShibbolethConfigurationException {
- boolean anyError=false;
-
- Element documentElement = configDoc.getDocumentElement();
- // reprocess the already validated DOM to create a bean with typed fields
- // dump the trash (comments, processing instructions, extra whitespace)
- try {
- if (documentElement.getLocalName().equals("ShibbolethTargetConfig")) {
- initlog.debug("SP Configuration file is in 1.2 syntax.");
- ShibbolethTargetConfigDocument configBeanDoc;
- configBeanDoc = ShibbolethTargetConfigDocument.Factory.parse(configDoc,
- new XmlOptions().setLoadStripComments().setLoadStripProcinsts().setLoadStripWhitespace());
- config = configBeanDoc.getShibbolethTargetConfig();
- } else if (documentElement.getLocalName().equals("SPConfig")) {
- initlog.debug("SP Configuration file is in 1.3 syntax.");
- SPConfigDocument configBeanDoc;
- configBeanDoc = SPConfigDocument.Factory.parse(configDoc,
- new XmlOptions().setLoadStripComments().setLoadStripProcinsts().setLoadStripWhitespace());
- config = configBeanDoc.getSPConfig();
- } else {
- initlog.error("Root element not ShibbolethTargetConfig or SPConfig");
- throw new XmlException("Root element not ShibbolethTargetConfig or SPConfig");
- }
- } catch (XmlException e) {
- // Since the DOM was already validated against the schema, errors will not typically occur here
- initlog.error("Error while parsing shibboleth configuration");
- throw new ShibbolethConfigurationException("Error while parsing shibboleth configuration");
- }
-
- String loggerUrlString = config.getLogger();
- if (loggerUrlString!=null) {
- try {
- URL loggerURL = new URL(loggerUrlString);
- initlog.warn("logging is being reconfigured by "+ loggerUrlString);
- PropertyConfigurator.configure(loggerURL);
- } catch (MalformedURLException e) {
- // This error is not serious enough to prevent initialization
- initlog.error("Ignoring invalid value for logger attribute "+loggerUrlString );
- }
- }
-
- Applications apps = config.getApplications(); // <Applications>
-
-
-
- /*
- * Create an <Application> id "default" from <Applications>
- */
- ApplicationDocument defaultAppDoc =
- // Create a new XMLBeans "Document" level object
- ApplicationDocument.Factory.newInstance();
- ApplicationDocument.Application defaultApp =
- // Add an XMLBeans "root Element" object to the Document
- defaultAppDoc.addNewApplication();
- // set or copy over fields from unrelated Applications object
- defaultApp.setId("default");
- defaultApp.setAAPProviderArray(apps.getAAPProviderArray());
- defaultApp.setAttributeDesignatorArray(apps.getAttributeDesignatorArray());
- defaultApp.setAudienceArray(apps.getAudienceArray());
- defaultApp.setCredentialUse(apps.getCredentialUse());
- defaultApp.setErrors(apps.getErrors());
- defaultApp.setFederationProviderArray(apps.getFederationProviderArray());
- defaultApp.setMetadataProviderArray(apps.getMetadataProviderArray());
- defaultApp.setProviderId(apps.getProviderId());
- defaultApp.setSessions(apps.getSessions());
- defaultApp.setTrustProviderArray(apps.getTrustProviderArray());
-
- /*
- * Now process secondary files configured in the applications
- */
- anyError |= processApplication(defaultApp);
-
- Application[] apparray = apps.getApplicationArray();
- for (int i=0;i<apparray.length;i++){
- Application tempapp = apparray[i];
- applications.put(tempapp.getId(),tempapp);
- anyError |= processApplication(tempapp);
- }
-
- /*
- * Now process other secondary files
- */
- anyError |= processCredentials();
- anyError |= processPluggableRequestMapProvider();
-
- if (anyError) {
- initlog.error("SP Initialization terminated due to configuration errors");
- throw new ShibbolethConfigurationException("Errors processing configuration file, see log");
- }
- }
-
-
- /**
- * Routine to handle CredentialProvider
- *
- * <p>Note: This only handles in-line XML.
- * Also, Credentials was an existing IdP class, so it doesn't
- * implement the new PluggableConfigurationComponent interface and
- * can't be loaded by generic plugin support.
- * </p>
- */
- private boolean processCredentials() {
- boolean anyError=false;
- PluggableType[] pluggable = config.getCredentialsProviderArray();
- for (int i=0;i<pluggable.length;i++) {
- String pluggabletype = pluggable[i].getType();
- if (!pluggabletype.equals(
- "edu.internet2.middleware.shibboleth.common.Credentials")) {
- initlog.error("Unsupported CredentialsProvider type "+pluggabletype);
- anyError=true;
- continue;
- }
- PluggableType credentialsProvider = pluggable[i];
- Node fragment = credentialsProvider.newDomNode();
- // newDomNode returns the current node wrapped in a Fragment
- try {
- Node credentialsProviderNode = fragment.getFirstChild();
- Node credentialsNode=credentialsProviderNode.getFirstChild();
- credentials = new Credentials((Element)credentialsNode);
- } catch(Exception e) {
- initlog.error("Cannot process Credentials element of Shibboleth configuration",e);
- anyError=true;
- continue;
- }
- }
- return anyError;
- }
-
- /**
- * Find and load secondary configuration files referenced in an Application(s)
- *
- * @param app Application object
- * @throws ShibbolethConfigurationException
- */
- private boolean processApplication(Application app)
- throws ShibbolethConfigurationException {
-
- boolean anyError=false;
-
- String applicationId = app.getId();
-
- ApplicationInfo appinfo = new ApplicationInfo(app);
-
- anyError |= processPluggableMetadata(appinfo);
- anyError |= processPluggableAAPs(appinfo);
- anyError |= processPluggableTrusts(appinfo);
-
- applications.put(applicationId, appinfo);
-
- return anyError;
- }
-
- /**
- * Generic code to create an object of a Pluggable type that implements
- * a configuration interface.
- *
- * <p>The configuration schema defines "PluggableType" as a type of
- * XML element that has opaque contents and attributes "type" and
- * "uri". If the uri attribute is omitted, then the configuration
- * data is inline XML content. The XSD files typically define the
- * format of pluggable configuration elements, but without binding
- * them to the PluggableType element that may contain them.</p>
- *
- * <p>The implimentation of pluggable objects is provided by
- * external classes. There are "builtin" classes provided with
- * Shibboleth (XMLMetadataImpl, XMLTrustImpl, XMLAAPImpl) that
- * provide examples of how this is done. By design, others can
- * provide their own classes just by putting the class name as
- * the value of the type attribute.</p>
- *
- * <p>This routine handles the common setup. It creates objects
- * of one of the builtin types, or it uses Class.forName() to
- * access a user specified class. It then locates either the
- * inline XML elements or the external XML file. It passes the
- * XML to initialize the object. Finally, a reference to the
- * object is stored in the appropriate Map.</p>
- *
- * <p>The objects created implement two interfaces. Mostly they
- * implement a configuration interface (EntityDescriptor, Trust,
- * AAP, etc). However, for the purpose of this routine they also
- * must be declared to implement PluggableConfigurationComponent
- * and provide an initialize() method that parses a DOM Node
- * containing their root XML configuration element.</p>
- *
- * @param pluggable XMLBean for element defined in XSD to be of "PluggableType"
- * @param implclass java.lang.Class of Builtin implementation class
- * @param interfaceClass java.lang.Class of Interface
- * @param builtinName alias type to choose Builtin imlementation
- * @param uriMap ApplicationInfo Map for this interface
- * @return
- */
- private
- String
- processPluggable(
- PluggableType pluggable,
- Class implclass,
- Class interfaceClass,
- String builtinName,
- Map /*<String,PluggableConfigurationComponent>*/uriMap
- ) {
-
- String pluggabletype = pluggable.getType();
-
- if (!pluggabletype.equals(builtinName)) {
- // Not the builtin type, try to load user class by name
- initlog.info("loading user-specified pluggable class "+pluggabletype);
- try {
- implclass = Class.forName(pluggabletype);
- } catch (ClassNotFoundException e) {
- initlog.error("Type value "+pluggabletype+" not found as supplied Java class");
- return null;
- }
- if (!interfaceClass.isAssignableFrom(implclass)||
- !PluggableConfigurationComponent.class.isAssignableFrom(implclass)) {
- initlog.error(pluggabletype+" class does not support required interfaces.");
- return null;
- }
- }
-
- PluggableConfigurationComponent impl;
- try {
- impl = (PluggableConfigurationComponent) implclass.newInstance();
- } catch (Exception e) {
- initlog.error("Unable to instantiate "+pluggabletype);
- return null;
- }
-
- String uri = pluggable.getUri();
- if (uri==null) { // inline
-
- uri=genDummyUri();
- try {
- Node fragment = pluggable.newDomNode(); // XML-Fragment node
- Node pluggableNode = fragment.getFirstChild(); // PluggableType
- Element contentNode=(Element) pluggableNode.getFirstChild();// root element
- impl.initialize(contentNode);
- } catch (Exception e) {
- initlog.error("XML error " + e);
- return null;
- }
-
- } else { // external file
-
- if (uriMap.get(uri)!=null) { // Already parsed this file
- return "";
- }
-
- try {
- Document extdoc = Parser.loadDom(uri,true);
- if (extdoc==null)
- return null;
- impl.initialize(extdoc.getDocumentElement());
- } catch (Exception e) {
- initlog.error("XML error " + e);
- return null;
- }
- }
-
- uriMap.put(uri,impl);
- return uri;
- }
-
-
-
- /**
- * Handle the pluggable element that was called FederationProvider in 1.2 but
- * is called MetadataProvider in 1.3.
- */
- private boolean processPluggableMetadata(ApplicationInfo appinfo) {
- boolean anyError = false;
- PluggableType[] pluggable = appinfo.applicationConfig.getMetadataProviderArray();
- if (pluggable.length==0) {
- // If no entries under the new name, try the old name
- pluggable = appinfo.applicationConfig.getFederationProviderArray();
- }
- for (int i = 0;i<pluggable.length;i++) {
- String uri = processPluggable(pluggable[i],
- XMLMetadataProvider.class,
- Metadata.class,
- XMLFEDERATIONPROVIDERTYPE,
- entityLocators);
- if (uri==null)
- anyError=true;
- else if (uri.length()>0) {
- appinfo.addGroupUri(uri);
- }
- }
- return anyError;
- }
-
- /**
- * Reload XML Metadata configuration after file changed.
- * @param uri Path to Metadata XML configuration
- * @return true if file reloaded.
- */
- public boolean reloadFederation(String uri) {
- if (getMetadataImplementor(uri)!=null||
- uri.startsWith(INLINEURN))
- return false;
- try {
- Document sitedoc = Parser.loadDom(uri,true);
- if (sitedoc==null)
- return false;
- XMLMetadataProvider impl = new XMLMetadataProvider();
- impl.initialize(sitedoc.getDocumentElement());
- addOrReplaceMetadataImplementor(uri,impl);
- } catch (Exception e) {
- initlog.error("Error while parsing Metadata file "+uri);
- initlog.error("XML error " + e);
- return false;
- }
- return true;
- }
-
- /**
- * Handle an AAPProvider element with
- * type="edu.internet2.middleware.shibboleth.common.provider.XMLAAP"
- * @throws InternalConfigurationException
- */
- private boolean processPluggableAAPs(ApplicationInfo appinfo){
- boolean anyError=false;
- PluggableType[] pluggable = appinfo.applicationConfig.getAAPProviderArray();
- for (int i = 0;i<pluggable.length;i++) {
- String uri = processPluggable(pluggable[i],
- XMLAAPProvider.class,
- AAP.class,
- XMLAAPPROVIDERTYPE,
- attributePolicies);
- if (uri==null)
- anyError=true;
- else if (uri.length()>0) {
- appinfo.addAapUri(uri);
- }
- }
- return anyError;
- }
-
- /**
- * Reload XML AAP configuration after file changed.
- * @param uri AAP to Trust XML configuration
- * @return true if file reloaded.
- */
- public boolean reloadAAP(String uri) {
- if (getAAPImplementor(uri)!=null||
- uri.startsWith(INLINEURN))
- return false;
- try {
- Document aapdoc = Parser.loadDom(uri,true);
- if (aapdoc==null)
- return false;
- XMLAAPProvider impl = new XMLAAPProvider();
- impl.initialize(aapdoc.getDocumentElement());
- addOrReplaceAAPImplementor(uri,impl);
- } catch (Exception e) {
- initlog.error("Error while parsing AAP file "+uri);
- initlog.error("XML error " + e);
- return false;
- }
- return true;
- }
-
-
- /**
- * Handle a TrustProvider element with
- * type="edu.internet2.middleware.shibboleth.common.provider.XMLTrust"
- *
- * Note: This code builds the semantic structure of trust. That is, it knows
- * about certificates and keys. The actual logic of Trust (signature generation
- * and validation) is implemented in a peer object defined in the external
- * class XMLTrustImpl.
- *
- * @throws ShibbolethConfigurationException if X.509 certificate cannot be processed
- * @throws InternalConfigurationException
- */
- private boolean processPluggableTrusts(ApplicationInfo appinfo){
- boolean anyError=false;
- PluggableType[] pluggable = appinfo.applicationConfig.getTrustProviderArray();
- for (int i = 0;i<pluggable.length;i++) {
- String uri = processPluggable(pluggable[i],
- ShibbolethTrust.class,
- Trust.class,
- XMLTRUSTPROVIDERTYPE,
- certificateValidators);
- if (uri==null)
- anyError=true;
- else if (uri.length()>0) {
- appinfo.addTrustUri(uri);
- }
- }
- return anyError;
- }
-
-
-
- private boolean processPluggableRequestMapProvider(){
- LocalConfigurationType shire = config.getSHIRE();
- if (shire==null)
- shire = config.getLocal();
- if (shire==null) {
- initlog.error("No SHIRE or Local element.");
- return true;
- }
- PluggableType mapProvider = shire.getRequestMapProvider();
-
- String pluggabletype = mapProvider.getType();
- if (!pluggabletype.equals(XMLREQUESTMAPPROVIDERTYPE)) {
- initlog.error("Unsupported RequestMapProvider type "+pluggabletype);
- return true;
- }
-
- RequestMapDocument requestMapDoc = null;
- Document mapdoc = null;
- String uri = mapProvider.getUri();
-
- if (uri==null) { // inline
-
- uri=genDummyUri();
- try {
- Node fragment = mapProvider.newDomNode();
- Node pluggableNode = fragment.getFirstChild();
- Node contentNode=pluggableNode.getFirstChild();
-
- requestMapDoc = RequestMapDocument.Factory.parse(contentNode);
- } catch (Exception e) {
- initlog.error("Error while parsing inline RequestMap");
- initlog.error("XML error " + e);
- return true;
- }
-
- } else { // external file
- try {
- mapdoc = Parser.loadDom(uri,true);
- if (mapdoc==null)
- return true;
- requestMapDoc = RequestMapDocument.Factory.parse(mapdoc);
- } catch (Exception e) {
- initlog.error("Error while parsing RequestMap file "+uri);
- initlog.error("XML error " + e);
- return true;
- }
- }
-
- requestMap = requestMapDoc.getRequestMap();
- return false;
- }
-
-
- // Generate Map keys for inline plugin configuration Elements
- private int inlinenum = 1;
- private String genDummyUri() {
- return INLINEURN+Integer.toString(inlinenum++);
- }
-
-
-
-
-
-
- /**
- * ApplicationInfo represents the <Application(s)> object, its fields,
- * and the pluggable configuration elements under it.
- *
- * <p>It can return arrays of Metadata, Trust, or AAP providers, but
- * it also exposes convenience methods that shop the lookup(),
- * validate(), and trust() calls to each object in the collection
- * until success or failure is determined.</p>
- *
- * <p>For all other parameters, such as Session parameters, you
- * can fetch the XMLBean by calling getApplicationConf() and
- * query their value directly.
- */
- public class ApplicationInfo
- implements Metadata, Trust {
-
- private Application applicationConfig;
-
- public Sessions getSessionsConfig() {
- Sessions sessions = applicationConfig.getSessions();
- if (sessions==null) {
- sessions = defaultApplicationInfo.applicationConfig.getSessions();
- }
- return sessions;
- }
-
-
- public Errors getErrorsConfig() {
- Errors errors = applicationConfig.getErrors();
- if (errors==null) {
- errors = defaultApplicationInfo.applicationConfig.getErrors();
- }
- return errors;
- }
-
- public String[] getAudienceArray() {
- return applicationConfig.getAudienceArray();
- }
-
-
- /**
- * Construct this object from the XML Bean.
- * @param application XMLBean for Application element
- */
- ApplicationInfo(Application application) {
- this.applicationConfig=application;
- }
-
-
- /*
- * Following the general rule, this object may not keep
- * direct references to the plugin interface implementors,
- * but must look them up on every call through their URI keys.
- * So we keep collections of URI strings instead.
- */
- private ArrayList groupUris = new ArrayList();
- private ArrayList trustUris = new ArrayList();
- private ArrayList aapUris = new ArrayList();
-
- void addGroupUri(String uri) {
- groupUris.add(uri);
- }
- void addTrustUri(String uri) {
- trustUris.add(uri);
- }
- void addAapUri(String uri) {
- aapUris.add(uri);
- }
-
- long getMaxSessionLife() {
- Sessions sessions = getSessionsConfig();
- if (sessions!=null)
- return sessions.getLifetime();
- return 7200;
- }
- long getUnusedSessionTimeout() {
- Sessions sessions = getSessionsConfig();
- if (sessions!=null)
- return sessions.getTimeout();
- return 3600;
- }
-
- /**
- * Given the EntityDescriptor of an IdP, find the RelyingParty
- * element of the CredentialsUse section that matches the
- * Entity name or one of its parent group names and return
- * the signing credential that should be used with it. If
- * no specific match occurs, return the default siging
- * credential.
- *
- * @param entity
- * @return
- */
- String getCredentialIdForEntity(EntityDescriptor entity) {
-
- // Get the ID URI of the Entity and all its parent groups
- EntitiesDescriptor entitiesDescriptor = entity.getEntitiesDescriptor();
- ArrayList idlist = new ArrayList();
- idlist.add(entity.getId());
- // An EntityDescriptor must have a name, while groups may have names
- while (entitiesDescriptor!=null) {
- String edname = entitiesDescriptor.getName();
- if (edname!=null)
- idlist.add(edname);
- // Chain up to parent Element, until none left
- entitiesDescriptor=entitiesDescriptor.getEntitiesDescriptor();
- }
-
- // Get the default signing Credential ID and the RelyingParty overrides
- CredentialUse credentialUse = applicationConfig.getCredentialUse();
- if (credentialUse==null) {
- // An <Application> may not have one, so look to the enclosing <Applications>
- credentialUse = defaultApplicationInfo.applicationConfig.getCredentialUse();
- }
- if (credentialUse == null)
- return null; // If there is no CredentialsUse there is no signing
- String defaultCredentialId = credentialUse.getSigning();
- // If no signing= attribute (null), then don't sign
- RelyingParty[] relyingPartyArray = credentialUse.getRelyingPartyArray();
-
- // Search for a match of Entity/Group ID against an overriding RelyingParty
- Iterator iterator = idlist.iterator();
- while (iterator.hasNext()) {
- String id = (String) iterator.next();
- for (int i =0;i<relyingPartyArray.length;i++) {
- if (relyingPartyArray[i].getName().equals(id)) {
- // We have matched a RelyingParty override
- String signingCredName = relyingPartyArray[i].getSigning();
- // If no signing= attribute (null), then don't sign
- return signingCredName;
- }
- }
- }
- // No RelyingParty match, so use the default
- return defaultCredentialId;
- }
-
- /**
- * Return the current array of objects that implement the
- * ...metadata.Metadata interface
- *
- * @return Metadata[]
- */
- Metadata[] getMetadataProviders() {
- Iterator iuris = (
- groupUris.size()!=0?
- groupUris.iterator():
- defaultApplicationInfo.groupUris.iterator());
- int count = groupUris.size();
- Metadata[] metadatas = new Metadata[count];
- for (int i=0;i<count;i++) {
- String uri =(String) iuris.next();
- metadatas[i]=getMetadataImplementor(uri);
- }
- return metadatas;
- }
-
- /**
- * A convenience function based on the Metadata interface.
- *
- * <p>Look for an entity ID through each implementor until the
- * first one finds locates a describing object.</p>
- *
- * <p>Unfortunately, Metadata.lookup() was originally specified to
- * return a "Provider". In current SAML 2.0 terms, the object
- * returned should be an EntityDescriptor. So this is the new
- * function in the new interface that will use the new term, but
- * it does the same thing.</p>
- *
- * @param id ID of the IdP entity
- * @return EntityDescriptor metadata object for that site.
- */
- public EntityDescriptor lookup(String id, boolean strict) {
- Iterator iuris = (
- groupUris.size()!=0?
- groupUris.iterator():
- defaultApplicationInfo.groupUris.iterator());
- while (iuris.hasNext()) {
- String uri =(String) iuris.next();
- Metadata locator=getMetadataImplementor(uri);
- EntityDescriptor entity = locator.lookup(id, strict);
- if (entity!=null) {
- reqlog.debug("Metadata.lookup resolved Entity "+ id);
- return entity;
- }
- }
- reqlog.warn("Metadata.lookup failed to resolve Entity "+ id);
- return null;
- }
-
- public EntityDescriptor lookup(Artifact artifact, boolean strict) {
- Iterator iuris = (
- groupUris.size()!=0?
- groupUris.iterator():
- defaultApplicationInfo.groupUris.iterator());
- while (iuris.hasNext()) {
- String uri =(String) iuris.next();
- Metadata locator=getMetadataImplementor(uri);
- EntityDescriptor entity = locator.lookup(artifact, strict);
- if (entity!=null) {
- reqlog.debug("Metadata.lookup resolved Artifact "+ artifact);
- return entity;
- }
- }
- reqlog.warn("Metadata.lookup failed to resolve Artifact "+ artifact);
- return null;
- }
-
- public EntityDescriptor lookup(String id) {
- return lookup(id,true);
- }
-
- public EntityDescriptor lookup(Artifact artifact) {
- return lookup(artifact,true);
- }
-
- public EntityDescriptor getRootEntity() {
- return null;
- }
-
- public EntitiesDescriptor getRootEntities() {
- return null;
- }
-
- /**
- * Return the current array of objects that implement the Trust interface
- *
- * @return Trust[]
- */
- public Trust[] getTrustProviders() {
- Iterator iuris = (
- trustUris.size()!=0?
- trustUris.iterator():
- defaultApplicationInfo.trustUris.iterator());
- int count = trustUris.size();
- if (count==0)
- return defaultTrust;
- Trust[] trusts = new Trust[count];
- for (int i=0;i<count;i++) {
- String uri =(String) iuris.next();
- trusts[i]=getTrustImplementor(uri);
- }
- return trusts;
- }
-
- /**
- * Return the current array of objects that implement the AAP interface
- *
- * @return AAP[]
- */
- public AAP[] getAAPProviders() {
- Iterator iuris = (
- aapUris.size()!=0?
- aapUris.iterator():
- defaultApplicationInfo.aapUris.iterator());
- int count = aapUris.size();
- AAP[] aaps = new AAP[count];
- for (int i=0;i<count;i++) {
- String uri =(String) iuris.next();
- aaps[i]=getAAPImplementor(uri);
- }
- return aaps;
- }
-
- /**
- * Convenience function to apply AAP by calling the apply()
- * method of each AAP implementor.
- *
- * <p>Any AAP implementor can delete an assertion or value.
- * Empty SAML elements get removed from the assertion.
- * This can yield an AttributeAssertion with no attributes.
- *
- * @param assertion SAML Attribute Assertion
- * @param role Role that issued the assertion
- * @throws SAMLException Raised if assertion is mangled beyond repair
- */
- void applyAAP(SAMLAssertion assertion, RoleDescriptor role) throws SAMLException {
-
- // Foreach AAP in the collection
- AAP[] providers = getAAPProviders();
- if (providers.length == 0) {
- reqlog.info("no filters specified, accepting entire assertion");
- return;
- }
- for (int i=0;i<providers.length;i++) {
- AAP aap = providers[i];
- if (aap.anyAttribute()) {
- reqlog.info("any attribute enabled, accepting entire assertion");
- continue;
- }
- }
-
- // Foreach Statement in the Assertion
- Iterator statements = assertion.getStatements();
-
- // Statements can be deleted out of the assertion
- // which renders the interator invalid unless it is
- // based on a derived collection.
- ArrayList statementList = new ArrayList();
- while (statements.hasNext()) {
- statementList.add(statements.next());
- }
- statements=statementList.iterator();
- 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();
-
- // Same trick for attributes
- ArrayList attributeList = new ArrayList();
- while (attributes.hasNext()) {
- attributeList.add(attributes.next());
- }
- attributes = attributeList.iterator();
-
- 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) {
- reqlog.info("no values remain, removing attribute");
- attributeStatement.removeAttribute(iattribute--);
- break;
- }
- }
- }
- if (!ruleFound) {
- reqlog.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.
- reqlog.info("no attributes remain, removing statement");
- assertion.removeStatement(istatement);
- }
- }
- }
-
- // Now see if we trashed it irrevocably.
- assertion.checkValidity();
- }
-
-
- /**
- * Returns a collection of attribute names to request from the AA.
- *
- * @return Collection of attribute Name values
- */
- public Collection getAttributeDesignators() {
- // TODO Not sure where this should come from
- return new ArrayList();
- }
-
-
- /**
- * Convenience method implementing Trust.validate() across
- * the collection of implementing objects. Returns true if
- * any Trust implementor approves the signatures in the object.
- *
- * <p>In the interface, validate() is passed several arguments
- * that come from this object. In this function, those
- * arguments are ignored "this" is used.
- */
- public boolean
- validate(
- SAMLSignedObject token,
- RoleDescriptor role
- ) {
-
-
- Trust[] trustProviders = getTrustProviders();
- for (int i=0;i<trustProviders.length;i++) {
- Trust trust = trustProviders[i];
- if (trust.validate(token,role))
- return true;
- }
- reqlog.warn("SAML object failed Trust validation.");
- return false;
- }
-
-
- /**
- * A method of Trust that we must declare to claim that
- * ApplicationInfo implements Trust. However, no code in the
- * ServiceProvider calls this (probably an IdP thing).
- *
- * @param revocations
- * @param role
- * @return This dummy always returns false.
- */
- public boolean attach(Iterator revocations, RoleDescriptor role) {
- // Unused
- return false;
- }
-
- public boolean validate(X509Certificate certificateEE, X509Certificate[] certificateChain, RoleDescriptor descriptor) {
- Trust[] trustProviders = getTrustProviders();
- for (int i=0;i<trustProviders.length;i++) {
- Trust trust = trustProviders[i];
- if (trust.validate(certificateEE,certificateChain,descriptor))
- return true;
- }
- reqlog.warn("X.509 Certificate failed Trust validate");
- return false;
- }
-
- public boolean validate(X509Certificate certificateEE, X509Certificate[] certificateChain, RoleDescriptor descriptor, boolean checkName) {
- Trust[] trustProviders = getTrustProviders();
- for (int i=0;i<trustProviders.length;i++) {
- Trust trust = trustProviders[i];
- if (trust.validate(certificateEE,certificateChain,descriptor,checkName))
- return true;
- }
- reqlog.warn("X.509 Certificate failed Trust validate");
- return false;
- }
-
- public String getProviderId() {
- String entityId = this.applicationConfig.getProviderId();
- if (entityId==null && this!=defaultApplicationInfo) {
- entityId = defaultApplicationInfo.getProviderId();
- }
- return entityId;
- }
- }
-
-
-
- private static class InternalConfigurationException extends Exception {
- InternalConfigurationException() {
- super();
- }
- }
-
-
-
- public Credentials getCredentials() {
- return credentials;
- }
-
-}
+++ /dev/null
-/*
- * 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.
- */
-
-/*
- * ServiceProviderContext.java
- *
- * There is one ServiceProviderContext per Service Provider.
- * Other objects and collections of objects are referenced through it.
- *
- * An object of type ServiceProviderContext must be created and
- * shared among the Shibboleth classes in the same Service Provider.
- * The default implimentation is for the object to be created during
- * the static initialization of the class and accessed through the
- * static getInstance() factory method.
- *
- * Any change to this strategy can be propagated to all other classes
- * just by changing the getInstance() method implementation to use
- * a different factory or lookup service.
- */
-package edu.internet2.middleware.shibboleth.serviceprovider;
-
-import org.opensaml.NoSuchProviderException;
-import org.opensaml.ReplayCache;
-import org.opensaml.ReplayCacheFactory;
-
-/**
- * Unique object through which all Service Provider objects and collections
- * are found. Obtain a reference to this object by calling the static
- * getInstance() method.
- *
- * @author Howard Gilbert
- *
- */
-public class ServiceProviderContext {
-
- /*
- * This static object provides the default implimentation of the
- * ServiceProviderContext singleton object. However, the getInstance
- * Factory actually determines the particular instance used.
- *
- * Warning:
- *
- * Some of the following fields may have an initialization
- * expression as in "Foo x = new Foo()".
- * The "Foo" class in turn may have a constructor or its own
- * static and non-static initialization statements. If anywhere
- * in this cascade of initialization triggered directly or
- * indirectly by creating this first new object of type
- * ServiceProviderContext() there is some code that calls
- * back to getServiceProviderContext() then it will get back
- * a null from that call. This is because the SPContext
- * variable is not filled in with a reference to the object
- * until it is constructed, and we are still in the middle of
- * constructing it.
- */
- private static ServiceProviderContext targetContext = new ServiceProviderContext();
-
- /*
- * The fatalErrors flag provides a global reference where Service Provider
- * components can know that we are totally hosed and cannot proceed. When
- * set, this tells all servlets right up front to generate error messages
- * and apologize.
- */
- private boolean fatalErrors = false;
-
-
-
- /**
- * <p>Static Factory method to return the ServiceProviderContext.
- * </p><p>
- * The default implmementation is to use a static field.
- * However, in other environments you may wish to replace this
- * with an object managed by J2EE or by Spring. If so, create
- * the object someplace else and change this factory to locate
- * it with LDAP, an external context, Spring, or whatever.
- * </p>
- * @return Returns the ServiceProviderContext object.
- */
- public static ServiceProviderContext getInstance() {
- return targetContext;
- }
-
- /**
- * The ServiceProviderConfig object holds all information from
- * the configuration file and the other sources of information
- * and metadata to which it refers.
- */
- private ServiceProviderConfig serviceProviderConfig = null;
-
-
-
- /*
- * <p>Manager for the collection (and Cache) of Session Objects
- * </p><p>
- * All access to and creation/deletion of Sessions occurs through
- * this object. This could be a wiring point later if someone
- * wanted to load and configure the Session Manager in Spring.
- */
- private SessionManager sessionManager = null;
-
- private ReplayCache replayCache = null;
-
- private ThreadLocal requestContext = new ThreadLocal();
- public void setRequestContext(RequestTracker trk) {
- requestContext.set(trk);
- }
- public RequestTracker getRequestContext() {
- return (RequestTracker) requestContext.get();
- }
-
- /**
- * Constructor currently made private to force use of getInstance()
- */
- private ServiceProviderContext() {
- }
-
- public void initialize() {
- // Post-construction initialization of elements that require
- // a reference back to the context.
- sessionManager = new SessionManager();
- }
-
-
-
- // property accessor methods
-
- public SessionManager getSessionManager() {
- return sessionManager;
- }
-
- // TODO: Make this pluggable / configurable
- public synchronized ReplayCache getReplayCache() {
- if (replayCache == null) {
- try {
- replayCache = ReplayCacheFactory.getInstance();
- }
- catch (NoSuchProviderException e) {
- }
- }
- return replayCache;
- }
-
- public ServiceProviderConfig getServiceProviderConfig() {
- return serviceProviderConfig;
- }
- public void setServiceProviderConfig(
- ServiceProviderConfig serviceProviderConfig) {
- this.serviceProviderConfig = serviceProviderConfig;
- }
- public boolean isFatalErrors() {
- return fatalErrors;
- }
- public void setFatalErrors(boolean fatalErrors) {
- this.fatalErrors = fatalErrors;
- }
-
-}
+++ /dev/null
-/*
- * 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.
- */
-
-/*
- * ServletContextInitializer.java
- *
- * Each application in a Servlet Container (a Java Web server like Tomcat)
- * occupies its own subdirectory, has its own ClassLoader, and owns a
- * collection of objects and classes that are collectively its "Context".
- *
- * It is not entirely predictable what initialization method will be
- * called first (maybe a Filter, maybe a Servlet, it depends on the
- * way web.xml is coded and processed). Some objects may be marked to
- * preload, and some may be loaded when first called.
- *
- * However, the ServiceProviderContext must be initialzed just once,
- * and it must be initialized before any other ServiceProvider methods
- * are called. So this static class does the job. It can be called from
- * any init() type method in any filter or servlet, and it can be called
- * from the static initialization method of any other class loaded by the
- * container configuration.
- *
- * The gotcha is that the file location of the configuration file may be
- * a parameter specified in the web.xml file. Code provided here will
- * handle the normal cases where the Servlet or Filter intializes it and
- * the web.xml parameter is found through the ServletContext object. If
- * you want to use ServiceProvider methods earlier than that, and do not
- * have access to a ServletContext, then you have to modify this class
- * to find the parameter someplace else (say in the server.xml file).
- * Of course, if you initialize the Service Provider classes from
- * the server's environment instead of the /shibboleth context environment,
- * then the shibboleth JAR files have to be in the server's parent classpath
- * (example: {Tomcat}/common/lib) rather than just in the /shibboleth/WEB-INF/lib.
- *
- * As with Servlet and Filter classes, this class knows about javax.servlet.*
- * objects that other shibboleth classes are not allowed to reference.
- */
-package edu.internet2.middleware.shibboleth.serviceprovider;
-
-import javax.servlet.ServletContext;
-import javax.servlet.UnavailableException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
-import org.apache.log4j.Logger;
-
-import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
-
-
-/**
- * @author Howard Gilbert
- */
-public class ServletContextInitializer {
-
- private static Logger log = Logger.getLogger(ContextListener.SHIBBOLETH_INIT+".Initializer");
- private static ServiceProviderContext context = ServiceProviderContext.getInstance();
-
- public static boolean initialized = false;
-
- public static synchronized void initServiceProvider(ServletContext scontext)
- throws UnavailableException{
-
- if (initialized)
- return;
-
- try {
- log.info("Initializing Service Provider.");
- context.initialize();
- ServiceProviderConfig config = new ServiceProviderConfig();
- context.setServiceProviderConfig(config);
-
- // could config.addOrReplaceXXXImplementor()
-
- String configFileName = getServiceProviderConfigFile(scontext);
- config.loadConfigObjects(configFileName);
-
- // could config.addOrReplaceXXXImplementor()
-
- log.info("Service Provider initialization complete.");
-
- } catch (ShibbolethConfigurationException ex) {
- context.setFatalErrors(true);
- log.fatal("Service Provider runtime configuration error. Please fix and re-initialize. Cause: " + ex);
- throw new UnavailableException("Assertion Consumer Service failed to initialize.");
- }
- initialized = true;
- }
-
- /**
- * Return name of target's XML configuration file from
- * ServiceProviderConfigFile parameter of WEB-INF/web.xml, or
- * default string
- *
- * @param ServletContext or null
- * @return String filename
- * @throws ShibbolethConfigurationException
- */
- private static String getServiceProviderConfigFile(ServletContext scontext)
- throws ShibbolethConfigurationException {
-
- if (scontext!=null) {
- String servletparm = scontext.getInitParameter("ServiceProviderConfigFile");
- if (servletparm != null) {
- return servletparm;
- }
- }
- log.error("ServiceProviderConfigFile parameter missing in WEB-INF/web.xml");
- throw new ShibbolethConfigurationException("ServiceProviderConfigFile parameter missing");
-
- }
-
- /**
- * Initialization specific to processing a request
- * @param request
- * @param response
- */
- public static void beginService(
- HttpServletRequest request,
- HttpServletResponse response) {
-
- String ipaddr = request.getRemoteAddr();
- RequestTracker requestTracker = new RequestTracker();
- requestTracker.setIpaddr(ipaddr);
- context.setRequestContext(requestTracker);
-
- }
-
- /**
- * Cleanup specific to a processing a request
- * @param request
- * @param response
- */
- public static void finishService(
- HttpServletRequest request,
- HttpServletResponse response) {
- RequestTracker requestContext = context.getRequestContext();
- context.setRequestContext(null);
- String ipaddr = requestContext.getIpaddr();
- HttpSession session = request.getSession();
- }
-
-}
+++ /dev/null
-/*
- * 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.
- */
-
-/*
- * Session.java
- *
- * Session object holds Principal ID [handle] and Attributes.
- * A random ID is used as the object key in the Cache and
- * is returned to the Browser as a Cookie value.
- *
- * Recovery Context: No exceptions expected or generated.
- */
-package edu.internet2.middleware.shibboleth.serviceprovider;
-
-import java.io.Serializable;
-import org.opensaml.SAMLAssertion;
-import org.opensaml.SAMLAuthenticationStatement;
-import org.opensaml.SAMLResponse;
-
-/**
- * Session object holds Authentication and Attribute Assertions for one
- * remote Browser/User for one ApplicationId.<br>
- * The collection of Session objects may be checkpointed to disk using
- * any attractive persistence framework, Object Relational mapping,
- * or, hell, just serialize the objects to a flat file if you like.
- *
- * @author Howard Gilbert
- */
-public class Session implements Serializable {
- private long maxSessionLife;
- private long unusedSessionTimeout;
- private long defaultAttributeLifetime;
-
- /**
- * Create a Session object. Only used by the Session Manager, so it has package scope.
- *
- * @param key Random generated sessionId string
- * @param maxSessionLife Maximum time this Session can remain valid
- * @param unusedSessionTimeout Discard an unused Session
- * @param defaultAttributeLifetime Default attribute validity time
- */
- Session(String key,
- long maxSessionLife,
- long unusedSessionTimeout,
- long defaultAttributeLifetime) {
- if (key==null)
- throw new IllegalArgumentException();
- this.sessionId=key;
- this.lastused = System.currentTimeMillis();
- this.created = this.lastused;
- this.maxSessionLife=maxSessionLife*1000;
- this.unusedSessionTimeout=unusedSessionTimeout*1000;
- this.defaultAttributeLifetime=defaultAttributeLifetime*1000;
- }
-
- // Properties
-
- /*
- * The large random SessionId string generated for this Session.
- * It is used as the key of the SessionManager cache, so this
- * field is only actually needed if serialized/persisted Sessions
- * need to be reloaded after a crash.
- */
- private String sessionId;
- public String getSessionId() {
- return sessionId;
- }
-
- /*
- * The ApplicationId associated with this Session. A remote User
- * may have different Sessions with different ApplicationIds that
- * associate to different IdPs or Attributre Release policies.
- */
- private String applicationId = null;
- public String getApplicationId() {
- return applicationId;
- }
- public void setApplicationId(String applicationId) {
- this.applicationId = applicationId;
- }
-
- /*
- * Remote IP address of Browser. Might be used as extra validity check.
- */
- private String ipaddr = null;
- public String getIpaddr() {
- return ipaddr;
- }
- public void setIpaddr(String ipaddr) {
- this.ipaddr = ipaddr;
- }
-
- /*
- * IdP entity
- */
- private String entityId = null;
- public String getEntityId() {
- return entityId;
- }
- public void setEntityId(String entityId) {
- this.entityId = entityId;
- }
-
- private long lastused = 0;
- private long created = 0;
-
- /**
- * Determines if the Session has timed out.
- * @return true if timed out
- */
- public boolean isExpired() {
- long now = System.currentTimeMillis();
- if (maxSessionLife>0 &&
- created+maxSessionLife<now)
- return true;
- if (unusedSessionTimeout>0 &&
- lastused+unusedSessionTimeout<now)
- return true;
- return false;
- }
-
- /**
- * Is this an empty Session object reserved by an RM that has not yet
- * received Assertions.
- * @return true or false
- */
- public boolean isInitialized() {
- return (null!=getAuthenticationStatement());
- }
-
-
- // Stuff saved from the POST
-
- /*
- * The SAML Authentication Assertion from the POST or Artifact
- */
- private SAMLAssertion authenticationAssertion = null;
- public SAMLAssertion getAuthenticationAssertion() {
- return authenticationAssertion;
- }
- public void setAuthenticationAssertion(SAMLAssertion authentication) {
- this.authenticationAssertion = authentication;
- }
-
- /*
- * The saved Authentication Statement containing the Assertion
- * referenced above. There are extra fields at this level that
- * are useful to build the Attribute Query.
- */
- private SAMLAuthenticationStatement authenticationStatement=null;
- public SAMLAuthenticationStatement getAuthenticationStatement() {
- return authenticationStatement;
- }
- public void setAuthenticationStatement(
- SAMLAuthenticationStatement authenticationStatement) {
- this.authenticationStatement = authenticationStatement;
- }
-
- /*
- * The SAMLResponse containing the Attribute Assertions. Note that
- * in Attribute Push or Artifact situations, this Response will
- * also contain the Authentication elements separately referenced
- * above. Otherwise, this Response will have been returned from
- * a Query.
- */
- private SAMLResponse attributeResponse = null;
- public SAMLResponse getAttributeResponse() {
- return attributeResponse;
- }
- public void setAttributeResponse(SAMLResponse attributeResponse) {
- this.attributeResponse = attributeResponse;
- }
-
- /**
- * Called by Session Manager when the Session is used. Reset the
- * unused timer.
- */
- void renew(){
- lastused = System.currentTimeMillis();
- }
-
- /**
- * Return the default lifetime of an Attribute Assertion if the
- * Assertion itself doesn't specify the limit.
- */
- public long getDefaultAttributeLifetime() {
- return defaultAttributeLifetime;
- }
-
- public void setDefaultAttributeLifetime(long defaultAttributeLifetime) {
- this.defaultAttributeLifetime = defaultAttributeLifetime*1000;
- }
-
- public long getMaxSessionLife() {
- return maxSessionLife;
- }
-
- public void setMaxSessionLife(long maxSessionLife) {
- this.maxSessionLife = maxSessionLife*1000;
- }
-
- public long getUnusedSessionTimeout() {
- return unusedSessionTimeout;
- }
-
- public void setUnusedSessionTimeout(long unusedSessionTimeout) {
- this.unusedSessionTimeout = unusedSessionTimeout*1000;
- }
-
-
- /*
- * The SavedTarget URL is meaningful only in an uninitialized but
- * preallocate Session object. It holds the original Resource
- * URL to which the Browser will be redirected after the
- * Session is actually established. This frees the TARGET=
- * sent to the WAYF to be the key of this object rather than
- * a real URL.
- */
- private String savedTargetURL;
- public String getSavedTargetURL() {
- return savedTargetURL;
- }
- public void setSavedTargetURL(String savedResourceURL) {
- this.savedTargetURL = savedResourceURL;
- }
-
-
-}
+++ /dev/null
-/*
- * 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.
- */
-
-/*
- * SessionCache.java
- *
- * A Session Cache implementation saves the content of all current
- * Session objects to some form of disk storage. This has two
- * advantages:
- *
- * It allows the Sessions (and their saved Assertions) to be
- * restored after the host computer, Web server, or /shibboleth
- * context are recycled.
- *
- * It allows the cookies, handles, and assertions to be shared
- * (provided the cache is shared) between multiple hosts in a
- * load balancing configuration.
- *
- * Exactly where you cache Sessions is up to you. A few obvious
- * possible implementations are:
- *
- * Write the Session fields (Strings and XML) to columns of a
- * database table using JDBC. The primary key of the table is
- * the sessionId.
- *
- * Serialize the Session object to a file in a cache directory.
- * The name of the file would be {sessionId}.xml
- *
- * Use a persistance framework or Object Relational mapping
- * system (Hibernate is popular) to persist the objects.
- *
- * Note: The Assertions in the Session extend DOM objects, so
- * they can be serialized to character strings and parsed on
- * the way back if your store doesn't support XML columns natively.
- *
- * Design point: There are two ways to handle a reboot.
- * 1) The Cache could return an iterator and the SessionManager could
- * run through all its entries storing them in the collection.
- * 2) The MemoryMananager can pass the collection to the Cache to
- * fill in from persistent storage.
- * This interface adopts the second approach, but that is just a
- * value judgement.
- */
-package edu.internet2.middleware.shibboleth.serviceprovider;
-
-import java.util.Map;
-
-/**
- * <p>An interface to be implemented by any Plug-In cache Session Cache.
- * </p><p>
- * To create a cache, write an implementation class for this interface
- * and call SessionMananger.setSessionCache(...) passing the cache
- * implementation object. While the cache can be loaded as a Shibboleth
- * Service Provider plugin, it can also be loaded, configured, and attached
- * to the class using J2EE (web.xml) or other Framework (Spring, ...) services.
- * </p>
- *
- * <p>Restriction: There can be only one.</p>
- *
- * @author Howard Gilbert
- */
-/**
- * @author Howard Gilbert
- */
-public interface SessionCache {
-
- /**
- * <p>Find a Session in the cache
- * </p><p>
- * This entry point is only meaningful if the cache is being
- * used for load balancing. Then it finds Sessions created
- * by another host in the cluster. In a single-host cache
- * you can always return null because all Sessions will be
- * in memory, and an id not found in memory will never be
- * in the cache.</p>
- *
- * @param sessionId Key string, typically the Cookie value
- * @return Session object from cache
- */
- public Session find(String sessionId);
-
- public void add(Session s);
-
- public void update(Session s);
-
- public void remove(Session s);
-
- /**
- * Scan all Sessions in the cache and store them in
- * the in memory collection. Typically called after
- * a reboot to restore prior sessions.
- *
- * @param sessions The in memory map to be loaded.
- */
- public void reload(Map sessions);
-
- public void close();
-
-}
+++ /dev/null
-/*
- * 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.
- */
-
-/*
- * SessionManager creates, maintains, and caches Session objects.
- *
- * The SessionManager is a singleton object.
- * A reference to the unique SessionManger object can always be obtained
- * from the ServiceProviderContext.getSessionManager() method.
- *
- * Sessions should only be created, modified, and deleted through methods
- * of this class so that the in-memory collection and any disk Cache can
- * also be changed. Disk cache implementations are referenced through the
- * SessionCache interface.
- */
-package edu.internet2.middleware.shibboleth.serviceprovider;
-
-import java.security.SecureRandom;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.TreeMap;
-
-import org.apache.log4j.Logger;
-import org.opensaml.SAMLAssertion;
-import org.opensaml.SAMLAttribute;
-import org.opensaml.SAMLAttributeStatement;
-import org.opensaml.SAMLAuthenticationStatement;
-import org.opensaml.SAMLResponse;
-import org.opensaml.SAMLStatement;
-
-import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderConfig.ApplicationInfo;
-
-/**
- * <p>SessionManager manages the memory and disk Cache of Session objects.</p>
- *
- * <p>setSessionCache(SessionCache s) is an "IOC" wiring point. Pass it
- * an implementation of the SessionCache interface.</p>
- *
- * @author Howard Gilbert
- */
-public class SessionManager {
-
- /*
- * Sessions can be saved using any Persistance Framework. If a Cache
- * is created, the following pointer is filled in and we start to
- * use it.
- */
- private static Logger log = Logger.getLogger(SessionManager.class.getName());
-
- private SessionCache cache = null; // By default, use memory cache only
-
- private TreeMap sessions = new TreeMap(); // The memory cache of Sessions
-
- private static ServiceProviderContext context = ServiceProviderContext.getInstance();
-
-
-
- /**
- * Generate a 16 byte random ASCII string using
- * cryptgraphically strong Java random generator.
- *
- * @return generated string
- */
- public String generateKey() {
- byte[] trash = new byte[16];
- char[] ctrash = new char[16];
- String key;
- do {
- rand.nextBytes(trash);
- for (int i=0;i<16;i++) {
- trash[i]&=0x3f;
- ctrash[i]=(char)table.charAt(trash[i]);
- }
- key=new String(ctrash);
- } while (null!=sessions.get(key));
- return key;
- }
- private static SecureRandom rand = new SecureRandom();
- private static final String table = "0123456789" +
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"+
- "abcdefgjikjlmnopqrstuvwxyz"+
- "$@";
-
-
- /**
- * Find a Session object given its sessionID key.
- *
- * <p>Will not match uninitialized (reserved) Sessions.</p>
- *
- * @param sessionId ID and key of session
- * @param applicationId Sanity check, must match session contents
- * @return null if not found, else Session
- */
- public synchronized Session findSession(String sessionId, String applicationId ) {
- if (sessionId==null || applicationId==null)
- throw new IllegalArgumentException();
- Session s = (Session) sessions.get(sessionId);
- if (s==null) {
- log.warn("Session not found with ID "+sessionId);
- return null;
- }
- if (!applicationId.equals(s.getApplicationId())) {
- log.error("Session ID "+sessionId+" doesn't match application "+applicationId);
- }
- if (s.isExpired()) {
- log.error("Session ID "+sessionId+" has expired.");
- return null;
- }
- s.renew();
- return s;
- }
-
- /**
- * Locate an empty Session block reserved by a call from the RM.
- * This is a test on the validity of a claimed reserved SessionID.
- *
- * @param sessionId
- * @return Session block (uninitialized).
- */
- synchronized Session findEmptySession(String sessionId) {
- if (sessionId==null)
- throw new IllegalArgumentException();
- Session s = (Session) sessions.get(sessionId);
- if (s==null) {
- log.warn("Session not found with ID "+sessionId);
- return null;
- }
- if (s.isInitialized()){
- log.error("Active Session found when looking for reserved ID:"+sessionId);
- return null;
- }
- s.renew();
- return s;
- }
-
-
- /**
- * Called internally to add a Session block to the cache.
- * @param s Session
- */
- protected synchronized void add(Session s) {
- if (s==null)
- throw new IllegalArgumentException();
- log.debug("Session added: "+s.getSessionId());
- sessions.put(s.getSessionId(), s);
- if (cache!=null)
- cache.add(s);
- }
-
- /**
- * Called internally to replace a Session block in the cache,
- * or more commonly to replace a block with itself and then just
- * notify the cache that it has been refreshed.
- *
- * @param s Session
- */
- protected synchronized void update(Session s) {
- if (s==null)
- throw new IllegalArgumentException();
- s.renew();
- log.debug("Session updated: "+s.getSessionId());
- sessions.put(s.getSessionId(), s);
- if (cache!=null)
- cache.update(s);
- }
-
- /**
- * Called internally to remove a Session from the cache. Since
- * there is no logout, this is called when a Session expires.
- *
- * @param s Session
- */
- protected synchronized void remove(Session s) {
- if (s==null)
- throw new IllegalArgumentException();
- log.debug("Session removed: "+s.getSessionId());
- sessions.remove(s.getSessionId());
- if (cache!=null)
- cache.remove(s);
- }
-
- /**
- * Called by a timer driven process to check for expired
- * Sessions.
- *
- */
- protected synchronized void expireSessions() {
- Iterator iterator = sessions.entrySet().iterator();
- while (iterator.hasNext()) {
- Map.Entry entry = (Map.Entry) iterator.next();
- Session session = (Session) entry.getValue();
- if (session.isExpired()) {
- log.info("Session " + session.getSessionId() + " has expired.");
- iterator.remove();
- }
- }
- }
-
-
-
- /**
- * Store Principal information identified by generated UUID.<br>
- * Called from Authentication Assertion Consumer [SHIRE]
- *
- * @param applicationId The application for this session
- * @param ipaddr The client's remote IP address from HTTP
- * @param entityId The Entity of the AA issuing the authentication
- * @param assertion Assertion in case one needs more data
- * @param authentication subset of assertion with handle
- * @return String (UUID) to go in the browser cookie
- */
- public
- String
- newSession(
- String applicationId, // not null
- String ipaddr, // may be null
- String entityId, // not null
- SAMLAssertion assertion, //not null
- SAMLAuthenticationStatement authenticationStatement, // may be null
- String emptySessionId // may be null
- ){
-
- if (applicationId==null)
- throw new IllegalArgumentException("applicationId null");
- if (entityId==null)
- throw new IllegalArgumentException("entityId null");
- if (assertion==null)
- throw new IllegalArgumentException("assertion null");
-
- ServiceProviderConfig config = context.getServiceProviderConfig();
- ApplicationInfo appinfo = config.getApplication(applicationId);
- String sessionId = null;
- boolean isUpdate = false; // Assume new object
-
- /*
- * If the Id of a reserved, empty session is provided, then find
- * that object and fill it in. Otherwise, create a new object.
- */
- Session session = null;
- if (emptySessionId!=null) {
- session = findEmptySession(emptySessionId);
- }
- if (session==null) {
- session = new Session(generateKey(),
- appinfo.getMaxSessionLife(),
- appinfo.getUnusedSessionTimeout(),
- config.getDefaultAttributeLifetime());
- } else {
- isUpdate=true; // mark so object is updated, not added
- }
- session.setApplicationId(applicationId);
- session.setIpaddr(ipaddr); // may be null
- session.setEntityId(entityId);
-
- session.setAuthenticationAssertion(assertion);
- session.setAuthenticationStatement(authenticationStatement); // may be null
-
- sessionId = session.getSessionId();
-
- if (isUpdate)
- update(session);
- else
- add(session);
-
- log.debug("New Session created "+sessionId);
-
- return sessionId;
- }
-
- /**
- * Create an empty Session object. Reserves a SessionId for the RM
- * that can later be filled in with data from the SSO Assertion.
- *
- * @param applicationId The <Application> associated with the Session.
- * @return
- */
- public
- String
-reserveSession(
- String applicationId,
- String url
- ){
- if (applicationId==null)
- throw new IllegalArgumentException("applicationId null");
-
- ServiceProviderConfig config = context.getServiceProviderConfig();
- ApplicationInfo appinfo = config.getApplication(applicationId);
- String sessionId = null;
- Session session= new Session(generateKey(),
- appinfo.getMaxSessionLife(),
- appinfo.getUnusedSessionTimeout(),
- config.getDefaultAttributeLifetime());
- session.setApplicationId(applicationId);
- session.setSavedTargetURL(url);
-
- sessionId = session.getSessionId();
-
- add(session);
-
- log.debug("SessionId reserved "+sessionId);
-
- return sessionId;
-}
- /**
- * <p>IOC wiring point to plug in an external SessionCache implementation.
- * </p>
- *
- * @param cache Plugin object implementing the SessionCache interface
- */
- public synchronized void
- setCache(
- SessionCache cache) {
-
- if (cache==null)
- throw new IllegalArgumentException("Session cache is null");
- log.info("Enabling Session Cache");
- /*
- * The following code supports dynamic switching from
- * one cache to another if, for example, you decide
- * to change databases without restarting Shibboleth.
- * Whether this is useful or not is a matter of dispute.
- */
- if (this.cache!=null) { // replacing an old cache
- this.cache.close(); // close it and leave it for GC
- return;
- }
-
- this.cache = cache;
-
- /*
- * Make sure the Cache knows about in memory sessions
- *
- * Note: The cache should probably be wired prior to letting
- * the Web server process requests, so in almost all cases this
- * block will not be neeed. However, we may allow the configuration
- * to change dynamically from uncached to cached in the middle
- * of a Shibboleth run, and this allows for that possiblity.
- */
- if (sessions.size()!=0) {
- for (Iterator i=sessions.values().iterator();i.hasNext();) {
- Session s = (Session) i.next();
- cache.add(s);
- }
- }
-
- /*
- * Now load any Sessions in the cache that are not in memory
- * (typically after a reboot).
- */
- cache.reload(sessions);
- }
-
- /**
- * Diagnostic routine not used during normal processing.
- *
- * @param session
- * @return
- */
- public static StringBuffer dumpAttributes(Session session) {
- StringBuffer sb = new StringBuffer();
- SAMLResponse attributeResponse = session.getAttributeResponse();
- Iterator assertions = attributeResponse.getAssertions();
- while (assertions.hasNext()) {
- SAMLAssertion assertion = (SAMLAssertion) assertions.next();
- Iterator statements = assertion.getStatements();
- while (statements.hasNext()) {
- SAMLStatement statement = (SAMLStatement) statements.next();
- if (statement instanceof SAMLAttributeStatement) {
- SAMLAttributeStatement attributeStatement =
- (SAMLAttributeStatement) statement;
-
- // Foreach Attribute in the AttributeStatement
- Iterator attributes = attributeStatement.getAttributes();
- while (attributes.hasNext()) {
- SAMLAttribute attribute =
- (SAMLAttribute) attributes.next();
- String name = attribute.getName();
- String namespace = attribute.getNamespace();
- Iterator values = attribute.getValues();
- while (values.hasNext()){
- String val = (String) values.next();
- sb.append(name+" - "+" "+val+"\n");
- }
- }
- }
- }
- }
-
- return sb;
- }
-
- /**
- * Extract all attributes from the Session in a simpler format than
- * the complete SAML structure.
- *
- * @param session
- * @return
- */
- public static Map /*<String,String>*/
- mapAttributes(Session session) {
- Map /*<String,String>*/attributeMap = new HashMap/*<String,String>*/();
- SAMLResponse attributeResponse = session.getAttributeResponse();
- if (attributeResponse==null)
- return attributeMap;
- Iterator assertions = attributeResponse.getAssertions();
- while (assertions.hasNext()) {
- SAMLAssertion assertion = (SAMLAssertion) assertions.next();
- Iterator statements = assertion.getStatements();
- while (statements.hasNext()) {
- SAMLStatement statement = (SAMLStatement) statements.next();
- if (statement instanceof SAMLAttributeStatement) {
- SAMLAttributeStatement attributeStatement =
- (SAMLAttributeStatement) statement;
-
- // Foreach Attribute in the AttributeStatement
- Iterator attributes = attributeStatement.getAttributes();
- while (attributes.hasNext()) {
- SAMLAttribute attribute =
- (SAMLAttribute) attributes.next();
- String name = attribute.getName();
- ArrayList list = new ArrayList();
- Iterator values = attribute.getValues();
- String val="";
- while (values.hasNext()){
- val = (String) values.next();
- list.add(val);
- }
- if (list.size()==1)
- attributeMap.put(name,val);
- else if (list.size()>1)
- attributeMap.put(name,list);
- }
- }
- }
- }
-
- return attributeMap;
- }
-
-}
+++ /dev/null
-/*
- * 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.
- */
-
-/*
- * ShibBinding.java
- *
- * Corresponds to ShibBinding.cpp
- *
- * A Shibboleth wrapper around the services of SAMLSOAPBinding,
- * this class adds processing from the Shibboleth configuration
- * to the process of sending a SAMLRequest and getting a SAMLResponse.
- * In particular, the caller of a ShibBinding provides arguments
- * that identify the target of the request from the Metadata, and
- * the caller passes an implementation of Trust so that signatures
- * can be validated.
- */
-package edu.internet2.middleware.shibboleth.serviceprovider;
-
-import java.util.Iterator;
-
-import org.apache.log4j.Logger;
-import org.opensaml.NoSuchProviderException;
-import org.opensaml.SAMLAssertion;
-import org.opensaml.SAMLAuthorityBinding;
-import org.opensaml.SAMLBinding;
-import org.opensaml.SAMLBindingFactory;
-import org.opensaml.SAMLCondition;
-import org.opensaml.SAMLException;
-import org.opensaml.SAMLRequest;
-import org.opensaml.SAMLResponse;
-import org.opensaml.SAMLSOAPHTTPBinding;
-import org.opensaml.TrustException;
-import edu.internet2.middleware.shibboleth.common.Trust;
-import edu.internet2.middleware.shibboleth.metadata.AttributeAuthorityDescriptor;
-import edu.internet2.middleware.shibboleth.metadata.Endpoint;
-import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderConfig.ApplicationInfo;
-
-/**
- * Wrapper for a SAMLBinding send/receive operation.
- *
- * <p>A ServiceProvider creates a ShibBinding object and then calls
- * its send() method. The logic is certainly capable of generating any
- * SAML Request/Response sequence. However, the variables have been
- * declared to have more specific types than the general logic, so this
- * version can only be used by a Service Provider to make an attribute query
- * to the AA.</p>
- *
- * <p>The ShibBinding doesn't hold any important resources. The
- * identity of the AA isn't passed until the send() method and could change
- * across calls, so there aren't any persistent network resources. Nothing
- * prevents a ShibBinding object from being reused, but normally it is
- * just a transient object as in resp=(new ShibBinding(appid)).send(req,...)</p>
- *
- * @author Howard Gilbert
- */
-public class ShibBinding {
-
- private static Logger log = Logger.getLogger(ShibBinding.class);
-
- private static ServiceProviderContext context = ServiceProviderContext.getInstance();
-
- private String applicationId = null;
-
- /**
- * While the C++ constructor takes iterators over the Trust and
- * Metadata, here we provide the key of an ApplicationInfo object
- * that contains them.
- *
- * @param applicationId
- * @throws NoSuchProviderException
- */
- public
- ShibBinding(
- String applicationId) {
- this.applicationId=applicationId;
- }
-
- /**
- * Send a SAMLRequest and get back a SAMLResponse.
- *
- * <p>Although this logic could be generalized, this version
- * declares the arguments to be of specific types (an AA role)
- * so it can only be used to send the Attribute Query and get back
- * the Attribute Assertions.
- *
- * @param req SAMLRequest to send
- * @param role AttributeAuthorityRole representing destination
- * @param audiences Audience strings to check SAML conditions
- * @param bindings Stupid idea. Don't use this parameter
- * @return The SAMLResponse
- * @throws SAMLException
- */
- public
- SAMLResponse
- send (
- SAMLRequest req,
- AttributeAuthorityDescriptor role,
- String[] audiences,
- SAMLAuthorityBinding[] bindings,
- Trust trust)
- throws SAMLException {
-
- // For the duration of the request, get local references to
- // configuration objects that might change between requests
- ServiceProviderConfig config = context.getServiceProviderConfig();
- ApplicationInfo appinfo = config.getApplication(applicationId);
-
- SAMLBinding sbinding = null;
- SAMLResponse resp = null;
- String prevBinding = null;
-
- /*
- * Try any inline bindings provided by 1.0/1.1 IdPs.
- */
- if (bindings!=null) {
- for (int ibinding=0;ibinding<bindings.length;ibinding++) {
- try {
- SAMLAuthorityBinding binding = bindings[ibinding];
- if (!binding.getBinding().equals(prevBinding)) {
- prevBinding = binding.getBinding();
- sbinding = SAMLBindingFactory.getInstance(binding.getBinding());
- }
- resp=sbinding.send(binding.getLocation(),req);
- validateResponseSignatures(role, appinfo, resp);
- return resp;
- } catch (TrustException e) {
- log.error("Unable to validate signatures on attribute response: " + e);
- continue;
- } catch (SAMLException e) {
- log.error("Unable to query attributes: " + e);
- continue;
- }
- }
- }
-
- /*
- * Try each metadata endpoint...
- */
- Iterator ends = role.getAttributeServiceManager().getEndpoints();
- while (ends.hasNext()) {
- Endpoint endpoint = (Endpoint)ends.next();
- try {
- if (!endpoint.getBinding().equals(prevBinding)) {
- prevBinding = endpoint.getBinding();
- sbinding = SAMLBindingFactory.getInstance(endpoint.getBinding());
- }
- if (sbinding instanceof SAMLSOAPHTTPBinding) {
- SAMLSOAPHTTPBinding httpbind = (SAMLSOAPHTTPBinding)sbinding;
- httpbind.addHook(new ShibHttpHook(role,trust));
- }
- resp=sbinding.send(endpoint.getLocation(),req);
- validateResponseSignatures(role, appinfo, resp);
- return resp;
- } catch (TrustException e) {
- log.error("Unable to validate signatures on attribute response: " + e);
- continue;
- } catch (SAMLException e) {
- log.error("Unable to query attributes: " + e);
- continue;
- }
- }
- return null;
- }
-
- /**
- * Given a SAMLResponse, check the Response itself and every Assertion it
- * contains for a digital signature. If signed, call Trust to verify the
- * signature against the configured Certificates for this Role in the Metadata.
- *
- * @param role OriginSite
- * @param appinfo Application data
- * @param resp SAML response
- * @throws TrustException on failure
- */
- public static void
- validateResponseSignatures(
- AttributeAuthorityDescriptor role,
- ApplicationInfo appinfo,
- SAMLResponse resp)
- throws TrustException {
-
- // If the entire Response is signed, check it
- if (resp.isSigned()&&
- !appinfo.validate(resp,role)) {
- throw new TrustException("Unable to validate signature of response");
- }
-
- // Now check each Assertion in the Response for a signature
- Iterator assertions = resp.getAssertions();
- while (assertions.hasNext()) {
- SAMLAssertion assertion = (SAMLAssertion) assertions.next();
-
- Iterator conditions = assertion.getConditions();
- while (conditions.hasNext()) {
- SAMLCondition condition = (SAMLCondition) conditions.next();
- // TODO C++ only seems to validate that the audience string is present
- }
-
- if (assertion.isSigned() &&
- !appinfo.validate(assertion,role)) {
- throw new TrustException("Unable to validate signature of assertion in response");
- }
- }
- }
-}
+++ /dev/null
-/*
- * 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.
- */
-
-/*
- * ShibHttpHook - Receive callbacks from OpenSAML HTTP Session processing.
- */
-package edu.internet2.middleware.shibboleth.serviceprovider;
-
-import java.net.HttpURLConnection;
-import java.net.Socket;
-import java.security.KeyManagementException;
-import java.security.NoSuchAlgorithmException;
-import java.security.Principal;
-import java.security.PrivateKey;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509KeyManager;
-import javax.net.ssl.X509TrustManager;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.log4j.Logger;
-import org.opensaml.SAMLException;
-import org.opensaml.SAMLSOAPHTTPBinding.HTTPHook;
-
-import edu.internet2.middleware.shibboleth.common.Constants;
-import edu.internet2.middleware.shibboleth.common.Credential;
-import edu.internet2.middleware.shibboleth.common.Credentials;
-import edu.internet2.middleware.shibboleth.common.Trust;
-import edu.internet2.middleware.shibboleth.metadata.RoleDescriptor;
-
-/**
- * During Attribute Query, SAML creates the HTTP(S) session with
- * the AA. Objects of this class provide a callback for special
- * processing of the Session that SAML has established before data
- * is exchanged. This allows Shib to add its own Metadata and Trust
- * processing to validate the AA identity.
-
- * @author Howard Gilbert
- *
- */
-public class ShibHttpHook implements HTTPHook {
-
- private static Logger log = Logger.getLogger(HTTPHook.class);
-
- ServiceProviderContext context = ServiceProviderContext.getInstance();
- ServiceProviderConfig config = context.getServiceProviderConfig();
-
- // If we present a ClientCert, it will be this one.
- Credentials credentials = config.getCredentials();
-
- // SAML Doesn't know the Shibboleth objects, so they have to be saved
- // by the constructor so they can be used in callbacks without being
- // passed as arguments
- RoleDescriptor role; // The AA object from the Metadata
- Trust trust; // A ShibbolethTrust object
-
- /**
- * @param role
- */
- public ShibHttpHook(RoleDescriptor role, Trust trust) {
- super();
- this.role = role; // Save the AA Role for the callback
- this.trust = trust; // Save the ShibTrust for the callback
- }
-
- public boolean incoming(HttpServletRequest r, Object globalCtx,
- Object callCtx) throws SAMLException {
- log.error("ShibHttpHook method incoming-1 should not have been called.");
- return true;
- }
-
- public boolean outgoing(HttpServletResponse r, Object globalCtx,
- Object callCtx) throws SAMLException {
- log.error("ShibHttpHook method outgoing-1 should not have been called.");
- return true;
- }
-
- public boolean incoming(HttpURLConnection conn, Object globalCtx,
- Object callCtx) throws SAMLException {
- // Called with the AA response, but I have nothing to add here
- return true;
- }
-
- /**
- * After the URLConnection has been initialized and before
- * the connect() method is called, this exit has a chance to
- * do additional processing.
- *
- * <p>If this is an HTTPS session, configure the SocketFactory
- * to use a custom TrustManager for Certificate processing.</p>
- */
- public boolean outgoing(HttpURLConnection conn, Object globalCtx,
- Object callCtx) throws SAMLException {
-
- conn.setRequestProperty("Shibboleth", Constants.SHIB_VERSION);
-
- if (!(conn instanceof HttpsURLConnection)) {
- return true; // HTTP (non-SSL) sessions need no additional processing
- }
- // Cast to subclass with extra info
- HttpsURLConnection sslconn = (HttpsURLConnection) conn;
-
- // To get your own Certificate Processing exits, you have
- // to create a custom SSLContext, configure it, and then
- // obtain a SocketFactory
- SSLContext sslContext = null;
- try {
- sslContext = SSLContext.getInstance("SSL");
- } catch (NoSuchAlgorithmException e) {
- // Cannot happen in code that is already doing SSL
- log.error("Cannot find required SSL support");
- return true;
- }
-
- // Arrays with one element (for init)
- TrustManager[] tms = new TrustManager[] {new ShibTrustManager()};
- KeyManager[] kms = new KeyManager[] {new ShibKeyManager()};
-
- try {
- // Attach the KeyManager and TrustManager to the Context
- sslContext.init(kms,tms,new java.security.SecureRandom());
- } catch (KeyManagementException e) {
- return false;
- }
-
- // Now we can get our own custom SocketFactory and replace
- // the default factory in the caller's URLConnection
- SSLSocketFactory socketFactory = sslContext.getSocketFactory();
- sslconn.setSSLSocketFactory(socketFactory);
-
- // The KeyManager and TrustManager get callbacks from JSSE during
- // the URLConnection.connect() call
- return true;
- }
-
- /**
- * Called to select the Client Certificate the SP will present to
- * the AA.
- *
- * <p>Normally a user KeyManager extends some class backed by a
- * KeyStore. It just chooses an alias, and lets the parent class
- * do the dirty work of extracting the Certificate chain from the
- * backing file. However, in Shibboleth the SP Credentials come
- * from the configuration file and are in memory. There is no
- * meaningful alias, so we make one up.
- */
- class ShibKeyManager implements X509KeyManager {
-
- public String fred ="Fred";
- public String[] freds = {fred};
-
- public String[] getClientAliases(String arg0, Principal[] arg1) {
- return freds;
- }
-
- public String chooseClientAlias(String[] arg0, Principal[] arg1, Socket arg2) {
- return fred;
- }
-
- public String[] getServerAliases(String arg0, Principal[] arg1) {
- return freds;
- }
-
- public String chooseServerAlias(String arg0, Principal[] arg1, Socket arg2) {
- return fred;
- }
-
- public X509Certificate[] getCertificateChain(String arg0) {
- // Obtain the Client Cert from the Credentials object
- // in the configuration file. Ignore argument "fred".
- Credential credential = credentials.getCredential();
- X509Certificate[] certificateChain = credential.getX509CertificateChain();
- return certificateChain;
- }
-
- public PrivateKey getPrivateKey(String arg0) {
- // Obtain the Private Key from the Credentials object.
- Credential credential = credentials.getCredential();
- PrivateKey privateKey = credential.getPrivateKey();
- return privateKey;
- }
-
- }
-
- /**
- * Called to approve or reject an SSL Server Certificate.
- * In practice this is the Certificate of the AA.
- *
- * <p>A TrustManager handles Certificate approval at either end
- * of an SSL connection, but this code is in the SP and is only
- * inserted into the Attribute Query to the AA. When the AA is
- * configured to use HTTPS and presents an SSL Server Certficate,
- * call the commmon code to validate that this Certificate is in
- * the Metadata.</p>
- */
- class ShibTrustManager implements X509TrustManager {
-
- public X509Certificate[] getAcceptedIssuers() {
- log.error("ShibHttpHook method getAcceptedIssuers should not have been called.");
- return new X509Certificate[0];
- }
-
- public void checkClientTrusted(X509Certificate[] arg0, String arg1)
- throws CertificateException {
- log.error("ShibHttpHook method checkClientTrusted should not have been called.");
- }
-
- public void checkServerTrusted(X509Certificate[] certs, String arg1)
- throws CertificateException {
- if (trust.validate(certs[0],certs,role,false)) {
- log.debug("ShibHttpHook accepted AA Server Certificate.");
- return;
- }
- log.info("ShibHttpHook rejected AA Server Certificate.");
- throw new CertificateException("Cannot validate AA Server Certificate in Metadata");
-
- }
-
- }
-
-}
+++ /dev/null
-package edu.internet2.middleware.shibboleth.wayf;
-
-import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
-
-import java.io.IOException;
-import java.net.URLEncoder;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.TreeSet;
-
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.log4j.Logger;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-
-
-public class DiscoveryServiceHandler {
-
- private final static Logger log = Logger.getLogger(DiscoveryServiceHandler.class.getName());
-
- private final static String DEFAULT_JSP_FILE = "/wayf.jsp";
- private final static String DEFAULT_ERROR_JSP_FILE = "/wayferror.jsp";
-
- private final String location;
- private final boolean isDefault;
- private final HandlerConfig config;
- //
- // hacked enum
- //
-
- private final List /*<IdPSiteSet>*/ siteSets = new ArrayList /*<IdPSiteSet>*/ ();
-
-
- protected DiscoveryServiceHandler(Element config,
- Hashtable /*<String, IdPSiteSet>*/ federations,
- HandlerConfig defaultConfig) throws ShibbolethConfigurationException
- {
- this.config = new HandlerConfig(config, defaultConfig);
-
- location = config.getAttribute("location");
-
- if (location == null || location.equals("")) {
-
- log.error("DiscoveryService must have a location specified");
- throw new ShibbolethConfigurationException("DiscoveryService must have a location specified");
-
- }
-
- String attribute = ((Element) config).getAttribute("default");
- if (attribute != null && !attribute.equals("")) {
- isDefault = Boolean.valueOf(attribute).booleanValue();
- } else {
- isDefault = true;
- }
-
- NodeList list = config.getElementsByTagName("Federation");
-
- for (int i = 0; i < list.getLength(); i++ ) {
-
- attribute = ((Element) list.item(i)).getAttribute("identifier");
-
- IdPSiteSet siteset = (IdPSiteSet) federations.get(attribute);
-
- if (siteset == null) {
- log.error("Handler " + location + ": could not find metadata for identifier " + attribute);
- throw new ShibbolethConfigurationException("Handler " + location + ": could not find metadata for identifier " + attribute);
- }
-
- siteSets.add(siteset);
- }
-
- if (siteSets.size() == 0) {
- //
- // No Federations explicitly named
- //
- siteSets.addAll(federations.values());
- }
- }
-
-
- //
- // Standard Beany Methods
- //
- /**
- * Returns the 'Name' of the service - the path used to identify the ServiceHandler
- */
-
- public String getLocation() {
- return location;
- }
-
- public boolean isDefault() {
- return isDefault;
- }
-
- public void doGet(HttpServletRequest req, HttpServletResponse res) {
- // Decide how to route the request based on query string
- String requestType = req.getParameter("action");
- if (requestType == null) {
- requestType = "lookup";
- }
- try {
-
- SamlIdPCookie cookie;
-
- if (config.getHandleCookie() == HandlerConfig.CLEAR_COOKIE) {
-
- //
- // Mark the cookie for deletion (unless we reset it later)
-
- SamlIdPCookie.deleteCookie(req, res);
-
- //
- // And create an empty cookie
- //
- cookie = new SamlIdPCookie(req, res, config.getCacheDomain());
-
- } else {
-
- cookie = SamlIdPCookie.getIdPCookie(req, res, config.getCacheDomain());
- }
-
-
- String searchSP = null;
-
- if (config.getLookupSp()) {
- searchSP = getProviderId(req);
- }
-
- List /*<IdPSite>*/ cookieList = cookie.getIdPList(siteSets, searchSP);
-
- //
- // Put if we have been told to
- //
- if (((config.getHandleCookie() == HandlerConfig.ALWAYS_FOLLOW_COOKIE) && (cookieList.size() > 0)) ||
- ((config.getHandleCookie() == HandlerConfig.FOLLOW_SINGLE_COOKIE) && (cookieList.size() == 1))) {
-
- IdPSite site = (IdPSite) cookieList.get(0);
-
- //
- // Move name to front of cookie, and write back specifying a time of
- // zero (which will leave the time untouched)
- //
- cookie.addIdPName(site.getName(), config.getCacheExpiration());
-
- forwardToIdP(req, res, site);
- } else if (requestType.equals("search")) {
-
- handleSearch(req, res, cookieList);
-
- } else if (requestType.equals("selection")) {
-
- String origin = req.getParameter("origin");
- log.debug("Processing handle selection: " + origin);
-
- IdPSite site = IdPSiteSet.IdPforSP(siteSets, origin, searchSP);
-
- if (site == null) {
- handleLookup(req, res, cookieList);
- } else {
-
- //
- // Write back cache - if we were asked to
- //
-
- if ((req.getParameter("cache") != null)) {
- if (req.getParameter("cache").equalsIgnoreCase("session")) {
- cookie.addIdPName(origin, -1);
- } else if (req.getParameter("cache").equalsIgnoreCase("perm")) {
- cookie.addIdPName(origin, config.getCacheExpiration());
- }
- }
- forwardToIdP(req, res, site);
- }
- } else {
- handleLookup(req, res, cookieList);
- }
- } catch (WayfException we) {
- handleError(req, res, we);
- }
-
- }
-
- /**
- * Displays a WAYF selection page.
- *
- */
- private void handleLookup(HttpServletRequest req, HttpServletResponse res, List/*<IdPSite>*/ cookieList) throws WayfException {
-
- try {
- if ((getSHIRE(req) == null) || (getTarget(req) == null)) { throw new WayfException(
- "Invalid or missing data from SHIRE");
- }
-
- if (cookieList.size() > 0) {
- req.setAttribute("cookieList", cookieList);
- }
- req.setAttribute("shire", getSHIRE(req));
- req.setAttribute("target", getTarget(req));
- String providerId = getProviderId(req);
- if (providerId != null) {
- req.setAttribute("providerId", providerId);
- }
-
- Collection /*<IdPSiteSetEntry>*/ siteLists = null;
- if (config.getProvideListOfLists()) {
- siteLists = new ArrayList /*<IdPSiteSetEntry>*/(siteSets.size());
- }
-
- Collection /*<IdPSite>*/ sites = null;
- if (config.getProvideList()) {
- sites = new TreeSet/*<IdPSite>*/();
- }
-
- String searchSP = null;
-
- if (config.getLookupSp()) {
- searchSP = providerId;
- }
-
- IdPSiteSet.getSiteLists(siteSets, searchSP, siteLists, sites);
-
- req.setAttribute("sites", sites);
- req.setAttribute("siteLists", siteLists);
-
- if (siteLists != null && siteLists.size() == 1) {
- req.setAttribute("singleSiteList", new Object());
- }
-
- req.setAttribute("time", new Long(new Date().getTime() / 1000).toString()); // Unix Time
- req.setAttribute("requestURL", req.getRequestURI().toString());
-
- log.debug("Displaying WAYF selection page.");
- RequestDispatcher rd = req.getRequestDispatcher(config.getJspFile());
-
- rd.forward(req, res);
- } catch (IOException ioe) {
- throw new WayfException("Problem displaying WAYF UI.\n" + ioe.getMessage());
- } catch (ServletException se) {
- throw new WayfException("Problem displaying WAYF UI.\n" + se.getMessage());
- }
- }
-
- /**
- * Looks for origin sites that match search terms supplied by the user
- *
- */
- private void handleSearch(HttpServletRequest req, HttpServletResponse res, List /*<IdPSite>*/ cookieList) throws WayfException {
-
- String parameter = req.getParameter("string");
- if (parameter != null) {
- Collection/*<IdPSite>*/ sites = IdPSiteSet.seachForMatchingOrigins(siteSets, getProviderId(req), parameter, config);
- if (sites.size() != 0) {
- req.setAttribute("searchresults", sites);
- } else {
- req.setAttribute("searchResultsEmpty", "true");
- }
- }
- handleLookup(req, res, cookieList);
- }
-
- /**
- * Uses an HTTP Status 307 redirect to forward the user the HS.
- *
- * @param site - The Idp.
- */
- private void forwardToIdP(HttpServletRequest req, HttpServletResponse res, IdPSite site)
- throws WayfException {
-
- String handleService = site.getAddressFor();
-
- if (handleService != null ) {
-
- log.info("Redirecting to selected Handle Service: " + handleService);
- try {
- StringBuffer buffer = new StringBuffer(handleService + "?target="
- + URLEncoder.encode(getTarget(req), "UTF-8") + "&shire="
- + URLEncoder.encode(getSHIRE(req), "UTF-8"));
- String providerId = getProviderId(req);
- log.debug("WALTER: (" + providerId + ").");
- if (providerId != null) {
- buffer.append("&providerId=" + URLEncoder.encode(getProviderId(req), "UTF-8"));
- }
- buffer.append("&time=" + new Long(new Date().getTime() / 1000).toString()); // Unix Time
- res.sendRedirect(buffer.toString());
- } catch (IOException ioe) {
- //
- // That failed. Purge the cache or we will go around again...
- //
- SamlIdPCookie.deleteCookie(req, res);
- throw new WayfException("Error forwarding to HS: \n" + ioe.getMessage());
- }
- } else {
- log.error("Error finding to IdP: " + site.getDisplayName());
- handleLookup(req, res, null);
- }
- }
-
- /**
- * Handles all "recoverable" errors in WAYF processing by logging the error and forwarding the user to an
- * appropriate error page.
- *
- * @param we
- * The WayfException respective to the error being handled
- */
- private void handleError(HttpServletRequest req, HttpServletResponse res, WayfException we) {
-
- log.error("WAYF Failure: " + we.toString());
- log.debug("Displaying WAYF error page.");
- req.setAttribute("errorText", we.toString());
- req.setAttribute("requestURL", req.getRequestURI().toString());
- RequestDispatcher rd = req.getRequestDispatcher(config.getErrorJspFile());
-
- try {
- rd.forward(req, res);
- } catch (IOException ioe) {
- log.error("Problem trying to display WAYF error page: " + ioe.toString());
- } catch (ServletException se) {
- log.error("Problem trying to display WAYF error page: " + se.toString());
- }
- }
-
- /**
- * Retrieves the SHIRE from the request.
- *
- * @throws WayfException
- * If the request does not contain a shire parameter.
- */
- private String getSHIRE(HttpServletRequest req) throws WayfException {
-
- String shire = (String) req.getAttribute("shire");
- if (req.getParameter("shire") != null) {
- shire = req.getParameter("shire");
- }
- if (shire == null) { throw new WayfException("Invalid data from SHIRE: No acceptance URL received."); }
- return shire;
- }
-
- /**
- * Retrieves the user's target URL from the request.
- *
- * @throws WayfException
- * If the request does not contain a target parameter
- */
- private String getTarget(HttpServletRequest req) throws WayfException {
-
- String target = (String) req.getAttribute("target");
- if (req.getParameter("target") != null) {
- target = req.getParameter("target");
- }
- if (target == null) { throw new WayfException("Invalid data from SHIRE: No target URL received."); }
- return target;
- }
-
- private String getProviderId(HttpServletRequest req) {
-
- String param = req.getParameter("providerId");
- if (param != null && !(param.length() == 0)) {
- return req.getParameter("providerId");
-
- } else {
- String attr = (String) req.getAttribute("providerId");
- if (attr == null || attr.length() == 0) { return null; }
- return attr;
- }
- }
-}
-
+++ /dev/null
-/*
- * 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.wayf;
-
-import java.util.HashSet;
-
-import org.apache.log4j.Logger;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-
-import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
-
-/**
- * Class used by the DiscoveryServiceHandler to handle run time behaviour
- *
- * @author Walter Hoehn wassa@columbia.edu
- */
-
-public class HandlerConfig {
-
- private static final Logger log = Logger.getLogger(HandlerConfig.class.getName());
- public final static String configNameSpace = "urn:mace:shibboleth:wayf:config:1.0";
-
- private final HashSet ignoredForMatch;
- private final int cacheExpiration;
- private final String cacheDomain;
- private final String jspFile;
- private final String errorJspFile;
- private final boolean provideListOfLists; // defaults false below
- private final boolean provideList; // defaults true below
- private final boolean lookupSp; // defaults true below
- private final int handleCookie;
- //
- // hacked enum
- //
- public final static int ALWAYS_FOLLOW_COOKIE = 9;
- public final static int FOLLOW_SINGLE_COOKIE = 10;
- public final static int NEVER_FOLLOW_COOKIE = 11;
- public final static int CLEAR_COOKIE = 12;
-
- public HandlerConfig() {
- //
- // 'Sensible' default values
- //
- cacheExpiration = 604800;
- cacheDomain = "";
- jspFile = "/wayf.jsp";
- errorJspFile = "/wayfError.jsp";
- provideList = true;
- provideListOfLists = false;
- lookupSp = true;
- handleCookie = NEVER_FOLLOW_COOKIE;
- ignoredForMatch = new HashSet();
- }
-
-
- private String getValue(Element element, String what) throws ShibbolethConfigurationException
- {
- NodeList list = element.getElementsByTagName(what);
-
- if (list.getLength() > 0) {
- if (list.getLength() > 1) {
- throw new ShibbolethConfigurationException("More than one <" + what + "/> element");
- }
-
- return list.item(0).getTextContent();
- }
- return null;
- }
-
- /**
- *
- * Parse the Supplied XML element into a new WayfConfig Object
- *
- */
-
- public HandlerConfig(Element config, HandlerConfig defaultValue) throws ShibbolethConfigurationException {
-
- log.debug("Loading global configuration properties.");
-
- String attribute = config.getAttribute("cacheDomain");
- if ((attribute != null) && (attribute != "")) {
- cacheDomain = attribute;
- } else {
- cacheDomain = defaultValue.cacheDomain;
- }
-
- attribute = config.getAttribute("cacheExpiration");
- if ((attribute != null) && (attribute != "")) {
-
- try {
-
- cacheExpiration = Integer.parseInt(attribute);
- } catch (NumberFormatException ex) {
-
- log.error("Invalid CacheExpiration value - " + attribute);
- throw new ShibbolethConfigurationException("Invalid CacheExpiration value - " + attribute, ex);
-
- }
- } else {
- cacheExpiration = defaultValue.cacheExpiration;
- }
-
- NodeList list = config.getElementsByTagName("SearchIgnore");
-
- if (list.getLength() == 0) {
-
- ignoredForMatch = defaultValue.ignoredForMatch;
-
- } else {
-
- ignoredForMatch = new HashSet();
-
- for (int i = 0; i < list.getLength(); i++ ) {
-
- NodeList inner = ((Element) list.item(i)).getElementsByTagName("IgnoreText");
-
- for(int j = 0; j < inner.getLength(); j++) {
-
- addIgnoredForMatch(inner.item(j).getTextContent());
- }
- }
- }
-
- attribute = config.getAttribute("jspFile");
- if (attribute != null && !attribute.equals("")) {
- jspFile = attribute;
- } else {
- jspFile = defaultValue.jspFile;
- }
-
- attribute = config.getAttribute("errorJspFile");
- if (attribute != null && !attribute.equals("")) {
- errorJspFile = attribute;
- } else {
- errorJspFile = defaultValue.errorJspFile;
- }
-
- attribute = ((Element) config).getAttribute("provideList");
- if (attribute != null && !attribute.equals("")) {
- provideList = Boolean.valueOf(attribute).booleanValue();
- } else {
- provideList = defaultValue.provideList;
- }
-
- attribute = ((Element) config).getAttribute("provideListOfList");
- if (attribute != null && !attribute.equals("")) {
- provideListOfLists = Boolean.valueOf(attribute).booleanValue();
- } else {
- provideListOfLists = defaultValue.provideListOfLists;
- }
-
- attribute = ((Element) config).getAttribute("showUnusableIdPs");
- if (attribute != null && !attribute.equals("")) {
- lookupSp = !Boolean.valueOf(attribute).booleanValue();
- } else {
- lookupSp = defaultValue.lookupSp;
- }
-
- attribute = ((Element) config).getAttribute("handleCookie");
- if (attribute == null || attribute.equals("")) {
- handleCookie = defaultValue.handleCookie;
- } else if (attribute.equalsIgnoreCase("alwaysfollow")) {
- handleCookie = ALWAYS_FOLLOW_COOKIE;
- } else if (attribute.equalsIgnoreCase("followsingle")) {
- handleCookie = FOLLOW_SINGLE_COOKIE;
- } else if (attribute.equalsIgnoreCase("neverfollow")) {
- handleCookie = NEVER_FOLLOW_COOKIE;
- } else if (attribute.equalsIgnoreCase("clearcookie")) {
- handleCookie = CLEAR_COOKIE;
- } else {
-
- log.error("Invalid value " + attribute + " to HandleCookie");
- throw new ShibbolethConfigurationException("Invalid value " + attribute + " to HandleCookie");
- }
- }
-
-
- /**
- * Determines if a particular string token should be used for matching when a user searches for origins.
- *
- * @param str
- * The string to lookup
- */
- public boolean isIgnoredForMatch(String str) {
-
- if (ignoredForMatch.contains(str.toLowerCase())) {
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Sets the tokens that should be ignored when a user searches for an origin site.
- *
- * @param s
- * The ignored tokens are passed as a single string, each separated by whitespace
- */
- private void addIgnoredForMatch(String s) {
-
- ignoredForMatch.add(s.toLowerCase());
- }
-
- /**
- * Returns the cacheDomain.
- *
- * @return String
- */
- public String getCacheDomain() {
-
- return cacheDomain;
- }
-
- /**
- * Returns the cacheExpiration.
- *
- * @return int
- */
- public int getCacheExpiration() {
-
- return cacheExpiration;
- }
-
- public String getJspFile() {
- return jspFile;
- }
-
- public String getErrorJspFile() {
- return errorJspFile;
- }
-
- public boolean getProvideListOfLists() {
- return provideListOfLists;
- }
-
- public boolean getProvideList() {
- return provideList;
- }
-
- public boolean getLookupSp() {
- return lookupSp;
- }
-
- public int getHandleCookie() {
- return handleCookie;
- }
-}
+++ /dev/null
-/*
- * 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.wayf;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import java.util.StringTokenizer;
-import java.util.TreeSet;
-
-import edu.internet2.middleware.shibboleth.metadata.EntitiesDescriptor;
-import edu.internet2.middleware.shibboleth.metadata.EntityDescriptor;
-import edu.internet2.middleware.shibboleth.metadata.Metadata;
-
-import edu.internet2.middleware.shibboleth.metadata.Organization;
-
-public class IdPSite implements Comparable {
-
- private final EntityDescriptor entity;
-
- public IdPSite(EntityDescriptor entity)
- {
- this.entity = entity;
- }
-
- public String getName()
- {
- return entity.getId();
- }
-
- public String getDisplayName()
- {
- Organization org = entity.getOrganization();
-
- if (org == null) {
- return entity.getId();
- }
- else {
- return org.getDisplayName();
- }
- }
-
- public boolean equals(Object obj)
- {
- return ((obj instanceof IdPSite) && (((IdPSite)obj).getName().equals(getName())));
- }
-
- /**
- * Based on 1.2 Origin.isMatch. There must have been a reason for it...
- * [Kindas of] support for the search function in the wayf. This return many false positives
- * but given the aim is to provide input for a pull down list...
- *
- * @param str What to match
- * @param config Provides list of tokens to not lookup
- * @return Whether this item matches
- */
-
- public int compareTo(Object o) {
-
- if (equals(o)) return 0;
-
- int result = getDisplayName().toLowerCase().compareTo(((IdPSite) o).getDisplayName().toLowerCase());
- if (result == 0) {
- result = getDisplayName().compareTo(((IdPSite) o).getDisplayName());
- }
- return result;
- }
-
- static private boolean isMatch(EntityDescriptor entity, String str, HandlerConfig config) {
-
- Enumeration input = new StringTokenizer(str);
- while (input.hasMoreElements()) {
- String currentToken = (String) input.nextElement();
-
- if (config.isIgnoredForMatch(currentToken)) {
- continue;
- }
-
- currentToken = currentToken.toLowerCase();
-
- if (entity.getId().indexOf(currentToken) > -1) {
- return true;
- }
-
- Organization org = entity.getOrganization();
-
- if (org != null) {
-
- if (org.getName().toLowerCase().indexOf(currentToken) > -1) {
- return true;
- }
-
- if (org.getDisplayName().toLowerCase().indexOf(currentToken) > -1) {
- return true;
- }
-
- }
- }
- return false;
- }
-
- static public Collection /*<IdPSite>*/ seachForMatchingOrigins(Metadata metadata,
- String searchString,
- HandlerConfig config)
- {
- TreeSet /*<IdPSite>*/ result = new TreeSet /*<IdPSite>*/ ();
- Iterator /*<EntityDescriptor>*/ entities = Entities(metadata);
-
- while (entities.hasNext()) {
-
- EntityDescriptor entity = (EntityDescriptor) entities.next();
-
- if ((entity.isValid() &&
- entity.getIDPSSODescriptor(edu.internet2.middleware.shibboleth.common.XML.SHIB_NS) != null) &&
- isMatch(entity, searchString, config)) {
-
- result.add(new IdPSite(entity));
- }
- } // check entities
- return result;
- }
-
- static public Collection /*<IdPSite>*/ getIdPSites(Metadata metadata)
- {
- TreeSet /*<IdPSite>*/ result = new TreeSet /*<IdPSite>*/ ();
- Iterator /*<EntityDescriptor>*/ entities = Entities(metadata);
-
- while (entities.hasNext()) {
- EntityDescriptor entity = (EntityDescriptor) entities.next();
-
- if (entity.isValid() &&
- entity.getIDPSSODescriptor(edu.internet2.middleware.shibboleth.common.XML.SHIB_NS) != null) {
-
- result.add(new IdPSite(entity));
- }
- } // iterate over all entities
- return result;
- }
-
- /**
- * Lookup
- */
- public String getAddressFor() {
- return entity.getIDPSSODescriptor(edu.internet2.middleware.shibboleth.common.XML.SHIB_NS).getSingleSignOnServiceManager().getDefaultEndpoint().getLocation();
- }
- /**
- * entitiesIterator:
- *
- * Given a metadata object return an iterator which will enumerate all the
- * entities inside it. There are two options for what is at the root of metadata
- * (either a single entity or a single entities list) so we just create the right
- * sort of iterator
- *
- * @param metadata: What to traverse
- * @return an iterator
- */
-
- private static Iterator /*<EntityDescriptor>*/ Entities(Metadata metadata) {
-
- EntitiesDescriptor entities = metadata.getRootEntities();
- EntityDescriptor entity = metadata.getRootEntity();
-
- if (entities != null) {
- return new EntityIterator(entities);
- }
-
- return Collections.singleton(entity).iterator();
- }
-
- private static class EntityIterator implements Iterator /*<EntityDescriptor>*/ {
-
- private Iterator /*<EntitiesDescriptor>*/ entitiesIterator;
- private Iterator /*<EntityDescriptor>*/ entityIterator;
-
- /**
- * An invariant of this class is that the inner iterator (entityIterator) should always be valid.
- * This means that when the current one is at the end we step the outer iterator (entitiesIterator)
- * along and get the next innter iterator.
- *
- * However because the returned inner iterator may already be empty we need to
- * loop until we either get to the end of the outer iterator or the inner iterator has a value
- * to return. Think of it as priming a pump.
- *
- * This method does the work. It is called at the start (in the constructor) and also whenever
- * any innter iterator reaches the end.
- */
-
- private void getNextNonEmptyIterator() {
- while (!entityIterator.hasNext() && entitiesIterator.hasNext()) {
- entityIterator = new EntityIterator((EntitiesDescriptor) entitiesIterator.next());
- }
- }
-
- private EntityIterator(EntitiesDescriptor entities)
- {
- entitiesIterator = entities.getEntitiesDescriptors();
- entityIterator = entities.getEntityDescriptors();
-
- if (entitiesIterator == null) {
- entitiesIterator = new NullIterator /*<EntitiesDescriptor>*/();
- }
-
- if (entityIterator == null) {
- entityIterator = new NullIterator /*<EntityDescriptor>*/();
- }
-
- // prime the pump to get entityIterator valid.
- getNextNonEmptyIterator();
- }
-
-
- public boolean hasNext() {
- return entityIterator.hasNext();
- }
-
- public Object /*EntityDescriptor*/ next() {
- Object /*EntityDescriptor*/ ret = entityIterator.next();
-
- //
- // make entityIterator valid
- ///
- getNextNonEmptyIterator();
- return ret;
- }
-
- public void remove() {
- entityIterator.remove();
- }
-
- //
- // Implementation note - should be removed in Java 5 and replaced by
- // the iterator from an empty collection.
- //
- private static class NullIterator /*<E>*/ implements Iterator/*<E>*/ {
-
- public boolean hasNext() {
- return false;
- }
-
- public /*E*/ Object next() {
- throw new NoSuchElementException();
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
- } //NullIterator
- } // Class EntitiesIterator
-}
-
+++ /dev/null
-/*
- * 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.wayf;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-
-import org.apache.log4j.Logger;
-import org.opensaml.XML;
-import org.w3c.dom.Element;
-
-import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
-import edu.internet2.middleware.shibboleth.metadata.EntityDescriptor;
-import edu.internet2.middleware.shibboleth.metadata.Metadata;
-import edu.internet2.middleware.shibboleth.metadata.MetadataException;
-import edu.internet2.middleware.shibboleth.metadata.MetadataProviderFactory;
-
-
-/**
- *
- * @author Rod Widdowson
- *
- * Represents a collection of related sites - usually a federation. When the WAYF
- * looks to see which IdP sites to show, it trims the list so as to not show IdP's
- * which do not trust the SP.
- *
- * This class is opaque outside this file. The three static methods getSitesLists,
- * searchForMatchingOrigins and lookupIdP provide mechansims for accessing
- * collections of IdPSiteSets.
- *
- */
-
-public class IdPSiteSet {
-
- private static Logger log = Logger.getLogger(IdPSiteSet.class.getName());
-
- private final Metadata metadata;
- private final String identifier;
- private final String displayName;
-
- public IdPSiteSet(Element el) throws ShibbolethConfigurationException {
-
- identifier = el.getAttribute("identifier");
- displayName = el.getAttribute("displayName");
-
- log.info("Loading Metadata for " + displayName);
-
- try {
- metadata = MetadataProviderFactory.loadProvider(el);
- } catch (MetadataException ex) {
- log.error("Could not parse " + displayName, ex);
- throw new ShibbolethConfigurationException("Could not parse " + displayName, ex);
- }
- }
-
- /**
- * The metadata representing this Set
- */
-
- private Metadata getMetadata()
- {
- return metadata;
- }
-
- protected String getIdentifier() {
- return identifier;
- }
-
- private String getDisplayName() {
- return displayName;
- }
-
- /**
- * We do not need to look at set if it doesn't know about the given SP. However if
- * no SP is given (as per 1.1) then we do need to look
- */
-
- private boolean containsSP(String SPName) {
-
- //
- // Deal with the case where we do *not* want to search by
- // SP (also handles the 1.1 case)
- //
-
- if ((SPName == null) || (SPName.length() == 0)) {
- return true;
- }
-
- EntityDescriptor e = metadata.lookup(SPName);
-
- if (e == null) {
- return false;
- }
-
- return (e.getSPSSODescriptor(XML.SAML11_PROTOCOL_ENUM) != null);
- }
-
- private EntityDescriptor IdPforName(String IdPName) {
-
- if ((IdPName == null) || (IdPName.length() == 0)) {
- return null;
- }
-
- return metadata.lookup(IdPName);
-
- }
-
- /**
- * Iterate over all the sitesets and if they know about the SP add them to the
- * list and the list of lists.
- *
- * @param siteSets All the site sets we know about
- *
- * @param SPName The SP we are looking for (null or empty matches all sitesets)
- *
- * @param siteLists If not null this is is populated with a set of sets of sites
- *
- * @param sites. If not Null this is populated with a set of sites.
- */
- public static void getSiteLists(Collection /*<IdPSiteSet>*/ siteSets,
- String SPName,
- Collection /*<IdPSiteSetEntry>*/ siteLists,
- Collection /*<IdPSite>*/ sites) {
- //
- // By having siteLists and sites as parameters we only iterate over
- // the metadata arrays once.
- //
-
- Iterator /*<IdPSiteSet>*/ it = siteSets.iterator();
-
- while (it.hasNext()) {
- IdPSiteSet set = (IdPSiteSet) it.next();
-
- if (set.containsSP(SPName)) {
- Collection c = IdPSite.getIdPSites(set.getMetadata());
-
- if (siteLists != null) {
- siteLists.add(new IdPSiteSetEntry(set.getDisplayName(),c));
- }
-
- if (sites != null) {
- sites.addAll(c);
- }
- }
- }
-
- }
-
-
-
- /**
- * Give the set of siteSets, an SP name and a searchString, look for the name in all
- * the appropriate siteSets.
- *
- */
-
- public static Collection /*<IdPSite>*/ seachForMatchingOrigins(Collection/*<IdPSiteSet>*/ siteSets, String SPName, String parameter, HandlerConfig config) {
-
- Collection/*<IdPSite>*/ result = null;
- Iterator/*<IdPSiteSet>*/ it = siteSets.iterator();
-
- while (it.hasNext()) {
- IdPSiteSet set = (IdPSiteSet) it.next();
-
- if (set.containsSP(SPName)) {
- Collection/*<IdPSite>*/ c = IdPSite.seachForMatchingOrigins(set.getMetadata(),parameter, config);
-
- if (result == null) {
- result = c;
- } else {
- result.addAll(c);
- }
- }
- }
-
- return result;
- }
-
- public static IdPSite IdPforSP(List /*<IdPSiteSet>*/ siteSets, String IdPName, String SPName) {
-
- Iterator /*<IdPSiteSet>*/ it = siteSets.iterator();
-
- while (it.hasNext()) {
- IdPSiteSet set = (IdPSiteSet) it.next();
-
- if (set.containsSP(SPName)) {
- EntityDescriptor e = set.IdPforName(IdPName);
-
- if (e != null) {
- return new IdPSite(e);
- }
- }
- }
-
- return null;
- }
-}
-
+++ /dev/null
-/*
- * 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.wayf;
-
-import java.util.Collection;
-/**
- * @author Rod Widdowson
- *
- * This is just a container class for tieing together a set of IdPs to a name - this being what
- * is sent to the JSP for display purposes.
- */
-public class IdPSiteSetEntry {
-
- private final String name;
- private final Collection/*<IdPSite>*/ sites;
-
- public IdPSiteSetEntry(String name, Collection/*<IdPSite>*/ sites) {
- this.name = name;
- this.sites = sites;
- }
-
- public String getName() {
- return name;
- }
-
- public Collection/*<IdPSite>*/ getSites() {
- return sites;
- }
-
-}
+++ /dev/null
-/*
- * 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.wayf;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.net.URLEncoder;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Iterator;
-
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.log4j.Logger;
-import org.bouncycastle.util.encoders.Base64;
-
-/**
- * Implementation of the <code>_saml_idp </code> cookie.
- *
- * Note that any SamlIdPCookie is only valid for as long as the reqest/response
- * parameters provided to getIdPCookie remain valid.
- *
- * @author Rod Widdowson
- *
- */
-public class SamlIdPCookie {
-
- private static final String COOKIE_NAME = "_saml_idp";
- private static final Logger log = Logger.getLogger(SamlIdPCookie.class.getName());
-
- private final HttpServletRequest req;
- private final HttpServletResponse res;
- private final String domain;
- private final List /*<String>*/ idPList = new ArrayList/*<String>*/();
-
- /**
- * Constructs a <code>SamlIdPCookie</code> from the provided string (which is the raw data
- *
- * @param codedData
- * the information read from the cookie
- * @param domain - if non null the domain for any *created* cookie.
- */
- private SamlIdPCookie(String codedData, HttpServletRequest req, HttpServletResponse res, String domain) {
-
- this.req = req;
- this.res = res;
- this.domain = domain;
-
- int start;
- int end;
-
- if (codedData == null || codedData.equals(""))
- {
- log.info("Empty cookie");
- return;
- }
- //
- // An earlier version saved the cookie without URL encoding it, hence there may be
- // speaces which in turn means we maybe quoted. Strip any quotes.
- //
- if (codedData.charAt(0) == '"' && codedData.charAt(codedData.length()-1) == '"') {
- codedData= codedData.substring(1,codedData.length()-1);
- }
-
- try {
- codedData = URLDecoder.decode(codedData, "UTF-8");
- } catch (UnsupportedEncodingException e) {
- log.error("could not decode cookie");
- return;
- }
-
- start = 0;
- end = codedData.indexOf(' ', start);
- while (end > 0) {
- String value = codedData.substring(start, end);
- start = end + 1;
- end = codedData.indexOf(' ', start);
- if (!value.equals("")) {
- idPList.add(new String(Base64.decode(value)));
- }
- }
- if (start < codedData.length()) {
- String value = codedData.substring(start);
- if (!value.equals("")) {
- idPList.add(new String(Base64.decode(value)));
- }
- }
- }
- /**
- * Create a SamlCookie with no data inside.
- * @param domain - if non null, the domain of the new cookie
- *
- */
- public SamlIdPCookie(HttpServletRequest req, HttpServletResponse res, String domain) {
- this.req = req;
- this.res = res;
- this.domain = domain;
- }
-
- /**
- * Add the specified Shibboleth IdP Name to the cookie list or move to
- * the front and then write it back.
- *
- * We always add to the front (and remove from wherever it was)
- *
- * @param idPName - The name to be added
- * @param expiration - The expiration of the cookie or zero if it is to be unchanged
- */
- public void addIdPName(String idPName, int expiration) {
-
- idPList.remove(idPName);
- idPList.add(0, idPName);
-
- writeCookie(expiration);
- }
-
- /**
- * Delete the <b>entire<\b> cookie contents
- */
-
- public static void deleteCookie(HttpServletRequest req, HttpServletResponse res) {
- Cookie cookie = getCookie(req);
-
- if (cookie == null) {
- return;
- }
-
- cookie.setPath("/");
- cookie.setMaxAge(0);
- res.addCookie(cookie);
- }
-
- /**
- * Load up the cookie and convert it into a SamlIdPCookie. If there is no
- * underlying cookie return a null one.
- * @param domain - if this is set then any <b>created</b> cookies are set to this domain
- */
-
- public static SamlIdPCookie getIdPCookie(HttpServletRequest req, HttpServletResponse res, String domain) {
- Cookie cookie = getCookie(req);
-
- if (cookie == null) {
- return new SamlIdPCookie(req, res, domain);
- } else {
- return new SamlIdPCookie(cookie.getValue(), req, res, domain);
- }
- }
-
- /**
- * Remove origin from the cachedata and write it back.
- * @param origin
- */
-
- public void deleteIdPName(String origin, int expiration) {
- idPList.remove(origin);
- writeCookie(expiration);
- }
-
- private void writeCookie(int expiration)
- {
- Cookie cookie = getCookie(req);
-
- if (idPList.size() == 0) {
- //
- // Nothing to write, so delete the cookie
- //
- cookie.setPath("/");
- cookie.setMaxAge(0);
- res.addCookie(cookie);
- return;
- }
-
- //
- // Otherwise encode up the cookie
- //
-
- StringBuffer buffer = new StringBuffer();
- Iterator /*<String>*/ it = idPList.iterator();
-
- while (it.hasNext()) {
- String next = (String) it.next();
- String what = new String(Base64.encode(next.getBytes()));
- buffer.append(what).append(' ');
- }
-
- String value;
- try {
- value = URLEncoder.encode(buffer.toString(), "UTF-8");
- } catch (UnsupportedEncodingException e) {
- log.error("Could not encode cookie");
- return;
- }
-
- if (cookie == null) {
- cookie = new Cookie(COOKIE_NAME, value);
- } else {
- cookie.setValue(value);
- }
- cookie.setComment("Used to cache selection of a user's Shibboleth IdP");
- cookie.setPath("/");
-
-
- cookie.setMaxAge(expiration);
-
- if (domain != null && domain != "") {
- cookie.setDomain(domain);
- }
- res.addCookie(cookie);
-
- }
-
- /**
- * Lookup to see whether there is an IdP for the given SP
- */
-
- public List /*<IdPSite>*/ getIdPList(List /*<IdPSiteSet>*/ siteSets, String SPName)
- {
-
- Iterator /*<String>*/ it = idPList.iterator();
- List /*<IdPSite>*/ result = new ArrayList /*<IdPSite>*/(idPList.size());
-
- while (it.hasNext()) {
- String idPName = (String) it.next();
- IdPSite site = IdPSiteSet.IdPforSP(siteSets, idPName, SPName);
- if (site != null){
- result.add(site);
- }
- }
- return result;
- }
-
-
- private static Cookie getCookie(HttpServletRequest req) {
-
- Cookie[] cookies = req.getCookies();
- if (cookies != null) {
- for (int i = 0; i < cookies.length; i++) {
- if (cookies[i].getName().equals(COOKIE_NAME)) {
- return cookies[i];
- }
- }
- }
- return null;
- }
-}
+++ /dev/null
-/*
- * 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.wayf;
-
-/**
- * Signals that an error has occurred while processing a Shibboleth WAYF request.
- *
- * @author Walter Hoehn wassa@columbia.edu
- */
-
-public class WayfException extends Exception {
-
- public WayfException(String message) {
-
- super(message);
- }
-
-}
\ No newline at end of file
+++ /dev/null
-/*
- * 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.wayf;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.List;
-import javax.servlet.GenericServlet;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.log4j.Logger;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
-import edu.internet2.middleware.shibboleth.xml.Parser;
-
-/**
- * A servlet implementation of the Shibboleth WAYF service. Allows a browser
- * user to select from among a group of origin sites. User selection is
- * optionally cached and the user is forwarded to the HandleService appropriate
- * to his selection.
- *
- * @author Walter Hoehn wassa@columbia.edu
- */
-public class WayfService extends HttpServlet {
-
- private String wayfConfigFileLocation;
- private static final Logger log = Logger.getLogger(WayfService.class.getName());
-
- private List /*<DiscoveryServiceHandler>*/ discoveryServices = new ArrayList /*<DiscoveryServiceHandler>*/();
-
- /**
- * @see GenericServlet#init()
- */
- public void init() throws ServletException {
-
- super.init();
-
- wayfConfigFileLocation = getServletContext().getInitParameter("WAYFConfigFileLocation");
- if (wayfConfigFileLocation == null) {
- wayfConfigFileLocation = getServletConfig().getInitParameter("WAYFConfigFileLocation");
- }
- if (wayfConfigFileLocation == null) {
- wayfConfigFileLocation = "/conf/wayfconfig.xml";
- }
-
- try {
-
- Document doc = Parser.loadDom(wayfConfigFileLocation, true);
-
- NodeList itemElements = doc.getDocumentElement().getElementsByTagNameNS(HandlerConfig.configNameSpace, "Default");
-
- HandlerConfig defaultHandlerConfig;
-
- if (itemElements.getLength() == 1) {
-
- Element element = (Element) itemElements.item(0);
- String attribute = element.getAttribute("location");
-
- if (attribute != null && !attribute.equals("")) {
-
- log.error("<Default> element cannot