Fixed a few bugs caused by the conversion away from Properties.
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / common / ServiceProviderMapper.java
1 /*
2  * The Shibboleth License, Version 1. Copyright (c) 2002 University Corporation
3  * for Advanced Internet Development, Inc. All rights reserved
4  * 
5  * 
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  * 
9  * Redistributions of source code must retain the above copyright notice, this
10  * list of conditions and the following disclaimer.
11  * 
12  * Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution, if any, must include
15  * the following acknowledgment: "This product includes software developed by
16  * the University Corporation for Advanced Internet Development
17  * <http://www.ucaid.edu> Internet2 Project. Alternately, this acknowledegement
18  * may appear in the software itself, if and wherever such third-party
19  * acknowledgments normally appear.
20  * 
21  * Neither the name of Shibboleth nor the names of its contributors, nor
22  * Internet2, nor the University Corporation for Advanced Internet Development,
23  * Inc., nor UCAID may be used to endorse or promote products derived from this
24  * software without specific prior written permission. For written permission,
25  * please contact shibboleth@shibboleth.org
26  * 
27  * Products derived from this software may not be called Shibboleth, Internet2,
28  * UCAID, or the University Corporation for Advanced Internet Development, nor
29  * may Shibboleth appear in their name, without prior written permission of the
30  * University Corporation for Advanced Internet Development.
31  * 
32  * 
33  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
34  * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
35  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
36  * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK
37  * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE.
38  * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY
39  * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY
40  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
41  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
45  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46  */
47 package edu.internet2.middleware.shibboleth.common;
48
49 import java.util.HashMap;
50 import java.util.Map;
51
52 import org.apache.log4j.Logger;
53 import org.w3c.dom.Element;
54
55 /**
56  * @author Walter Hoehn
57  *  
58  */
59 public abstract class ServiceProviderMapper {
60
61         private static Logger log = Logger.getLogger(ServiceProviderMapper.class.getName());
62         protected Map relyingParties = new HashMap();
63
64         protected abstract ShibbolethOriginConfig getOriginConfig();
65
66         protected void verifyDefaultParty(ShibbolethOriginConfig configuration) throws ServiceProviderMapperException {
67                 //Verify we have a proper default party
68                 String defaultParty = configuration.getDefaultRelyingPartyName();
69                 if (defaultParty == null || defaultParty.equals("")) {
70                         if (relyingParties.size() != 1) {
71                                 log.error(
72                                         "Default Relying Party not specified.  Add a (defaultRelyingParty) attribute to <ShibbolethOriginConfig>.");
73                                 throw new ServiceProviderMapperException("Required configuration not specified.");
74                         } else {
75                                 log.debug("Only one Relying Party loaded.  Using this as the default.");
76                         }
77                 }
78                 log.debug("Default Relying Party set to: (" + defaultParty + ").");
79                 if (!relyingParties.containsKey(defaultParty)) {
80                         log.error("Default Relying Party refers to a Relying Party that has not been loaded.");
81                         throw new ServiceProviderMapperException("Invalid configuration (Default Relying Party).");
82                 }
83         }
84
85         protected RelyingParty getRelyingPartyImpl(String providerIdFromTarget) {
86
87                 //Look for a configuration for the specific relying party
88                 if (relyingParties.containsKey(providerIdFromTarget)) {
89                         log.info("Found Relying Party for (" + providerIdFromTarget + ").");
90                         return (RelyingParty) relyingParties.get(providerIdFromTarget);
91                 }
92
93                 //Next, check to see if the relying party is in any groups
94                 RelyingParty groupParty = findRelyingPartyByGroup(providerIdFromTarget);
95                 if (groupParty != null) {
96                         log.info("Provider is a member of Relying Party (" + groupParty.getName() + ").");
97                         return new RelyingPartyGroupWrapper(groupParty, providerIdFromTarget);
98                 }
99
100                 //OK, just send the default
101                 log.info(
102                         "Could not locate Relying Party configuration for ("
103                                 + providerIdFromTarget
104                                 + ").  Using default Relying Party.");
105                 return new UnknownProviderWrapper(getDefaultRelyingPatry());
106         }
107
108         private RelyingParty findRelyingPartyByGroup(String providerIdFromTarget) {
109
110                 // TODO This is totally a stub and needs to be based on target metadata
111                 // lookup
112                 if (providerIdFromTarget.startsWith("urn:mace:inqueue:")) {
113                         if (relyingParties.containsKey("urn:mace:inqueue")) {
114                                 return (RelyingParty) relyingParties.get("urn:mace:inqueue");
115                         }
116                 }
117                 return null;
118         }
119
120         protected RelyingParty getDefaultRelyingPatry() {
121
122                 //If there is no explicit default, pick the single configured Relying
123                 // Party
124                 String defaultParty = getOriginConfig().getDefaultRelyingPartyName();
125                 if (defaultParty == null || defaultParty.equals("")) {
126                         return (RelyingParty) relyingParties.values().iterator().next();
127                 }
128
129                 //If we do have a default specified, use it...
130                 return (RelyingParty) relyingParties.get(defaultParty);
131         }
132
133         protected abstract class BaseRelyingPartyImpl implements RelyingParty {
134
135                 protected RelyingPartyIdentityProvider identityProvider;
136                 protected String name;
137                 protected String overridenOriginProviderId;
138
139                 /**
140                  * Shared construction
141                  */
142                 public BaseRelyingPartyImpl(Element partyConfig) throws ServiceProviderMapperException {
143
144                         //Get party name
145                         name = ((Element) partyConfig).getAttribute("name");
146                         if (name == null || name.equals("")) {
147                                 log.error("Relying Party name not set.  Add a (name) attribute to <RelyingParty>.");
148                                 throw new ServiceProviderMapperException("Required configuration not specified.");
149                         }
150                         log.debug("Loading Relying Party: (" + name + ").");
151
152                         //Process overrides for global data
153                         String attribute = ((Element) partyConfig).getAttribute("providerId");
154                         if (attribute != null && !attribute.equals("")) {
155                                 log.debug("Overriding providerId for Relying Pary (" + name + ") with (" + attribute + ").");
156                                 overridenOriginProviderId = attribute;
157                         }
158
159                 }
160
161                 public String getProviderId() {
162                         return name;
163                 }
164
165                 public String getName() {
166                         return name;
167                 }
168
169                 public IdentityProvider getIdentityProvider() {
170                         return identityProvider;
171                 }
172                 
173                 protected class RelyingPartyIdentityProvider implements IdentityProvider {
174
175                         private String providerId;
176                         private Credential responseSigningCredential;
177
178                         public RelyingPartyIdentityProvider(String providerId, Credential responseSigningCred) {
179                                 this.providerId = providerId;
180                                 this.responseSigningCredential = responseSigningCred;
181                         }
182
183                         public String getProviderId() {
184                                 return providerId;
185                         }
186
187                         public Credential getResponseSigningCredential() {
188                                 return responseSigningCredential;
189                         }
190
191                         public Credential getAssertionSigningCredential() {
192                                 return null;
193                         }
194
195                 }
196         }
197
198         //TODO this will break because it doesn't implement both interfaces
199         class RelyingPartyGroupWrapper implements RelyingParty {
200
201                 private RelyingParty wrapped;
202                 private String providerId;
203
204                 RelyingPartyGroupWrapper(RelyingParty wrapped, String providerId) {
205                         this.wrapped = wrapped;
206                         this.providerId = providerId;
207                 }
208
209                 public String getName() {
210                         return wrapped.getName();
211                 }
212
213                 public boolean isLegacyProvider() {
214                         return false;
215                 }
216
217                 public IdentityProvider getIdentityProvider() {
218                         return wrapped.getIdentityProvider();
219                 }
220
221                 public String getProviderId() {
222                         return providerId;
223                 }
224         }
225
226         //TODO this will break because it doesn't implement both interfaces
227         protected class UnknownProviderWrapper implements RelyingParty {
228                 protected RelyingParty wrapped;
229
230                 protected UnknownProviderWrapper(RelyingParty wrapped) {
231                         this.wrapped = wrapped;
232                 }
233
234                 public String getName() {
235                         return wrapped.getName();
236                 }
237
238                 public IdentityProvider getIdentityProvider() {
239                         return wrapped.getIdentityProvider();
240                 }
241
242                 public String getProviderId() {
243                         return null;
244                 }
245         }
246
247 }