2 * The Shibboleth License, Version 1. Copyright (c) 2002 University Corporation for Advanced Internet Development, Inc.
3 * All rights reserved Redistribution and use in source and binary forms, with or without modification, are permitted
4 * provided that the following conditions are met: Redistributions of source code must retain the above copyright
5 * notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the
6 * above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other
7 * materials provided with the distribution, if any, must include the following acknowledgment: "This product includes
8 * software developed by the University Corporation for Advanced Internet Development <http://www.ucaid.edu> Internet2
9 * Project. Alternately, this acknowledegement may appear in the software itself, if and wherever such third-party
10 * acknowledgments normally appear. Neither the name of Shibboleth nor the names of its contributors, nor Internet2,
11 * nor the University Corporation for Advanced Internet Development, Inc., nor UCAID may be used to endorse or promote
12 * products derived from this software without specific prior written permission. For written permission, please
13 * contact shibboleth@shibboleth.org Products derived from this software may not be called Shibboleth, Internet2,
14 * UCAID, or the University Corporation for Advanced Internet Development, nor may Shibboleth appear in their name,
15 * without prior written permission of the University Corporation for Advanced Internet Development. THIS SOFTWARE IS
16 * PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES,
17 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
18 * NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS
19 * WITH LICENSEE. IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY CORPORATION FOR ADVANCED
20 * INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
23 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
27 package edu.internet2.middleware.shibboleth.common;
31 import java.util.HashMap;
34 import org.apache.log4j.Logger;
35 import org.w3c.dom.Element;
37 import edu.internet2.middleware.shibboleth.aa.AARelyingParty;
38 import edu.internet2.middleware.shibboleth.hs.HSRelyingParty;
39 import edu.internet2.middleware.shibboleth.metadata.Metadata;
40 import edu.internet2.middleware.shibboleth.metadata.Provider;
43 * Base class for determining the effective relying party from the unique id of the service provider. Checks first for
44 * an exact match on the service provider, then for membership in a federation. Uses the default relying party if
47 * @author Walter Hoehn
49 public abstract class ServiceProviderMapper {
51 private static Logger log = Logger.getLogger(ServiceProviderMapper.class.getName());
52 protected Map relyingParties = new HashMap();
53 private Metadata metaData;
58 public ServiceProviderMapper(Metadata metaData) {
59 this.metaData = metaData;
62 protected abstract ShibbolethOriginConfig getOriginConfig();
64 protected void verifyDefaultParty(ShibbolethOriginConfig configuration) throws ServiceProviderMapperException {
65 //Verify we have a proper default party
66 String defaultParty = configuration.getDefaultRelyingPartyName();
67 if (defaultParty == null || defaultParty.equals("")) {
68 if (relyingParties.size() != 1) {
70 .error("Default Relying Party not specified. Add a (defaultRelyingParty) attribute to <ShibbolethOriginConfig>.");
71 throw new ServiceProviderMapperException("Required configuration not specified.");
73 log.debug("Only one Relying Party loaded. Using this as the default.");
76 log.debug("Default Relying Party set to: (" + defaultParty + ").");
77 if (!relyingParties.containsKey(defaultParty)) {
78 log.error("Default Relying Party refers to a Relying Party that has not been loaded.");
79 throw new ServiceProviderMapperException("Invalid configuration (Default Relying Party).");
83 protected RelyingParty getRelyingPartyImpl(String providerIdFromTarget) {
85 //Null request, send the default
86 if (providerIdFromTarget == null) {
87 RelyingParty relyingParty = getDefaultRelyingParty();
88 log.info("Using default Relying Party: (" + relyingParty.getName() + ").");
89 return new UnknownProviderWrapper(relyingParty, providerIdFromTarget);
92 //Look for a configuration for the specific relying party
93 if (relyingParties.containsKey(providerIdFromTarget)) {
94 log.info("Found Relying Party for (" + providerIdFromTarget + ").");
95 return (RelyingParty) relyingParties.get(providerIdFromTarget);
98 //Next, check to see if the relying party is in any groups
99 RelyingParty groupParty = findRelyingPartyByGroup(providerIdFromTarget);
100 if (groupParty != null) {
101 log.info("Provider is a member of Relying Party (" + groupParty.getName() + ").");
102 return new RelyingPartyGroupWrapper(groupParty, providerIdFromTarget);
105 //OK, we can't find it... just send the default
106 RelyingParty relyingParty = getDefaultRelyingParty();
107 log.info("Could not locate Relying Party configuration for (" + providerIdFromTarget
108 + "). Using default Relying Party: (" + relyingParty.getName() + ").");
109 return new UnknownProviderWrapper(relyingParty, providerIdFromTarget);
112 private RelyingParty findRelyingPartyByGroup(String providerIdFromTarget) {
114 Provider provider = metaData.lookup(providerIdFromTarget);
115 if (provider != null) {
116 String[] groups = provider.getGroups();
117 for (int i = 0; groups.length > i; i++) {
118 //We need to iterate backward because the groups go from least to most specific
119 String group = groups[groups.length - 1 - i];
120 if (relyingParties.containsKey(group)) {
121 log.info("Found matching Relying Party for group (" + group + ").");
122 return (RelyingParty) relyingParties.get(group);
125 .debug("Provider is a member of group (" + group
126 + "), but no matching Relying Party was found.");
133 public RelyingParty getDefaultRelyingParty() {
135 //If there is no explicit default, pick the single configured Relying
137 String defaultParty = getOriginConfig().getDefaultRelyingPartyName();
138 if (defaultParty == null || defaultParty.equals("")) {
139 return (RelyingParty) relyingParties.values().iterator().next();
142 //If we do have a default specified, use it...
143 return (RelyingParty) relyingParties.get(defaultParty);
147 * Base relying party implementation.
149 * @author Walter Hoehn
151 protected abstract class BaseRelyingPartyImpl implements RelyingParty {
153 protected RelyingPartyIdentityProvider identityProvider;
154 protected String name;
155 protected String overridenOriginProviderId;
157 public BaseRelyingPartyImpl(Element partyConfig) throws ServiceProviderMapperException {
160 name = ((Element) partyConfig).getAttribute("name");
161 if (name == null || name.equals("")) {
162 log.error("Relying Party name not set. Add a (name) attribute to <RelyingParty>.");
163 throw new ServiceProviderMapperException("Required configuration not specified.");
165 log.debug("Loading Relying Party: (" + name + ").");
167 //Process overrides for global data
168 String attribute = ((Element) partyConfig).getAttribute("providerId");
169 if (attribute != null && !attribute.equals("")) {
170 log.debug("Overriding providerId for Relying Pary (" + name + ") with (" + attribute + ").");
171 overridenOriginProviderId = attribute;
176 public String getProviderId() {
180 public String getName() {
184 public IdentityProvider getIdentityProvider() {
185 return identityProvider;
189 * Default identity provider implementation.
191 * @author Walter Hoehn
193 protected class RelyingPartyIdentityProvider implements IdentityProvider {
195 private String providerId;
196 private Credential responseSigningCredential;
197 private Credential assertionSigningCredential;
199 public RelyingPartyIdentityProvider(String providerId, Credential responseSigningCred) {
200 this.providerId = providerId;
201 this.responseSigningCredential = responseSigningCred;
204 public RelyingPartyIdentityProvider(String providerId, Credential responseSigningCred,
205 Credential assertionSigningCred) {
206 this.providerId = providerId;
207 this.responseSigningCredential = responseSigningCred;
208 this.assertionSigningCredential = assertionSigningCred;
211 public String getProviderId() {
215 public Credential getResponseSigningCredential() {
216 return responseSigningCredential;
219 public Credential getAssertionSigningCredential() {
220 return assertionSigningCredential;
227 * Relying party implementation wrapper for relying parties that are federations.
229 * @author Walter Hoehn
231 class RelyingPartyGroupWrapper implements RelyingParty, HSRelyingParty, AARelyingParty {
233 private RelyingParty wrapped;
234 private String providerId;
236 RelyingPartyGroupWrapper(RelyingParty wrapped, String providerId) {
237 this.wrapped = wrapped;
238 this.providerId = providerId;
241 public String getName() {
242 return wrapped.getName();
245 public boolean isLegacyProvider() {
249 public IdentityProvider getIdentityProvider() {
250 return wrapped.getIdentityProvider();
253 public String getProviderId() {
257 public String getHSNameFormatId() {
258 if (!(wrapped instanceof HSRelyingParty)) {
261 return ((HSRelyingParty) wrapped).getHSNameFormatId();
264 public URL getAAUrl() {
265 if (!(wrapped instanceof HSRelyingParty)) {
268 return ((HSRelyingParty) wrapped).getAAUrl();
271 public URI getDefaultAuthMethod() {
272 if (!(wrapped instanceof HSRelyingParty)) {
275 return ((HSRelyingParty) wrapped).getDefaultAuthMethod();
278 public boolean passThruErrors() {
279 if (!(wrapped instanceof AARelyingParty)) {
282 return ((AARelyingParty) wrapped).passThruErrors();
287 * Relying party implementation wrapper for anonymous service providers.
289 * @author Walter Hoehn
291 protected class UnknownProviderWrapper implements RelyingParty, HSRelyingParty, AARelyingParty {
293 protected RelyingParty wrapped;
294 protected String providerId;
296 protected UnknownProviderWrapper(RelyingParty wrapped, String providerId) {
297 this.wrapped = wrapped;
298 this.providerId = providerId;
301 public String getName() {
302 return wrapped.getName();
305 public IdentityProvider getIdentityProvider() {
306 return wrapped.getIdentityProvider();
309 public String getProviderId() {
313 public String getHSNameFormatId() {
314 if (!(wrapped instanceof HSRelyingParty)) {
317 return ((HSRelyingParty) wrapped).getHSNameFormatId();
320 public boolean isLegacyProvider() {
321 if (!(wrapped instanceof HSRelyingParty)) {
324 return ((HSRelyingParty) wrapped).isLegacyProvider();
327 public URL getAAUrl() {
328 if (!(wrapped instanceof HSRelyingParty)) {
331 return ((HSRelyingParty) wrapped).getAAUrl();
334 public URI getDefaultAuthMethod() {
335 if (!(wrapped instanceof HSRelyingParty)) {
338 return ((HSRelyingParty) wrapped).getDefaultAuthMethod();
341 public boolean passThruErrors() {
342 if (!(wrapped instanceof AARelyingParty)) {
345 return ((AARelyingParty) wrapped).passThruErrors();