1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package edu.internet2.middleware.shibboleth.wayf;
18
19 import java.io.FileInputStream;
20 import java.io.FileNotFoundException;
21 import java.lang.reflect.Constructor;
22 import java.util.ArrayList;
23 import java.util.Hashtable;
24 import java.util.Iterator;
25 import java.util.List;
26
27 import javax.servlet.GenericServlet;
28 import javax.servlet.ServletException;
29 import javax.servlet.http.HttpServlet;
30 import javax.servlet.http.HttpServletRequest;
31 import javax.servlet.http.HttpServletResponse;
32
33 import org.opensaml.DefaultBootstrap;
34 import org.opensaml.xml.parse.BasicParserPool;
35 import org.opensaml.xml.util.DatatypeHelper;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38 import org.w3c.dom.Document;
39 import org.w3c.dom.Element;
40 import org.w3c.dom.NodeList;
41
42 import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
43 import edu.internet2.middleware.shibboleth.wayf.plugins.Plugin;
44
45
46
47
48
49
50
51 public class WayfService extends HttpServlet {
52
53
54 private static final long serialVersionUID = 5244503011625804940L;
55
56
57 private static final Logger LOG = LoggerFactory.getLogger(WayfService.class.getName());
58
59
60 private String wayfConfigFileLocation;
61
62
63 private LogbackLoggingService logService;
64
65
66 private List <DiscoveryServiceHandler> discoveryServices = new ArrayList <DiscoveryServiceHandler>();
67
68
69
70
71
72
73
74
75 public void init() throws ServletException {
76
77 super.init();
78
79 wayfConfigFileLocation = getServletContext().getInitParameter("WAYFConfigFileLocation");
80 if (wayfConfigFileLocation == null) {
81 wayfConfigFileLocation = getServletConfig().getInitParameter("WAYFConfigFileLocation");
82 }
83 if (wayfConfigFileLocation == null) {
84 wayfConfigFileLocation = "/wayfconfig.xml";
85 }
86
87
88 try {
89
90
91
92 String wayfLogfile = getServletContext().getInitParameter("WAYFLogConfig");
93 if (null == wayfLogfile) {
94 wayfLogfile = getServletConfig().getInitParameter("WAYFLogConfig");
95 }
96 long pollingFrequency = 1000*60*5;
97
98 String wayfLogfilePollFrequency = getServletContext().getInitParameter("WAYFLogConfigPollFrequency");
99 if (null == wayfLogfilePollFrequency) {
100 wayfLogfilePollFrequency = getServletConfig().getInitParameter("WAYFLogConfigPollFrequency");
101 }
102 if(!DatatypeHelper.isEmpty(wayfLogfilePollFrequency)){
103 pollingFrequency = Long.parseLong(wayfLogfilePollFrequency);
104 }
105 if (wayfLogfile != null) {
106 logService = new LogbackLoggingService(wayfLogfile, pollingFrequency);
107 }
108
109 LOG.info("Logging initiated");
110
111
112
113
114 DefaultBootstrap.bootstrap();
115
116 BasicParserPool parser = new BasicParserPool();
117 parser.setNamespaceAware(true);
118 Document doc;
119 try {
120 doc = parser.parse(new FileInputStream(wayfConfigFileLocation));
121 } catch (FileNotFoundException e) {
122 LOG.error("Could not parse " + wayfConfigFileLocation, e);
123 throw new ShibbolethConfigurationException("Could not parse " + wayfConfigFileLocation, e);
124 }
125 NodeList itemElements = doc.getDocumentElement().getElementsByTagNameNS(XMLConstants.CONFIG_NS,
126 "Default");
127
128 HandlerConfig defaultHandlerConfig;
129
130 if (itemElements.getLength() == 1) {
131
132 Element element = (Element) itemElements.item(0);
133 String attribute = element.getAttribute("location");
134
135 if (attribute != null && !attribute.equals("")) {
136
137 LOG.error("<Default> element cannot contain a location attribute");
138 throw new ShibbolethConfigurationException("<Default> element cannot contain a location attribute");
139
140 }
141
142 attribute = element.getAttribute("default");
143
144 if (attribute != null && !attribute.equals("")) {
145
146 LOG.error("<Default> element cannot contain a default attribute");
147 throw new ShibbolethConfigurationException("<Default> element cannot contain a default attribute");
148
149 }
150
151 itemElements = element.getElementsByTagName("Federation");
152
153 if (itemElements.getLength() != 0) {
154
155 LOG.error("<Default> element cannot contain <Federation> elements");
156 throw new ShibbolethConfigurationException("<Default> element cannot contain <Federation> elements");
157
158 }
159
160 defaultHandlerConfig = new HandlerConfig(element, new HandlerConfig());
161
162 } else if (itemElements.getLength() == 0) {
163
164 defaultHandlerConfig = new HandlerConfig();
165
166 } else {
167 LOG.error("Must specify exactly one <Default> element");
168 throw new ShibbolethConfigurationException("Must specify exactly one <Default> element");
169 }
170
171
172
173
174 Hashtable <String, IdPSiteSet> siteSets = new Hashtable <String, IdPSiteSet>();
175
176 itemElements = doc.getDocumentElement().getElementsByTagNameNS(XMLConstants.CONFIG_NS,
177 "MetadataProvider");
178
179 for (int i = 0; i < itemElements.getLength(); i++) {
180
181 Element element = (Element) itemElements.item(i);
182
183 IdPSiteSet siteset = new IdPSiteSet(element, parser, defaultHandlerConfig.getWarnOnBadBinding());
184
185 siteSets.put(siteset.getIdentifier(), siteset);
186 }
187 if (siteSets.size() < 1) {
188 LOG.error("No Metadata Provider metadata loaded.");
189 throw new ShibbolethConfigurationException("Could not load SAML metadata.");
190 }
191
192
193
194
195 Hashtable <String, Plugin> plugins = new Hashtable <String, Plugin>();
196
197 itemElements = doc.getDocumentElement().getElementsByTagNameNS(XMLConstants.CONFIG_NS,
198 "Plugin");
199
200 for (int i = 0; i < itemElements.getLength(); i++) {
201
202 Plugin plugin;
203
204 Element element = (Element) itemElements.item(i);
205
206 String identifier = element.getAttribute("identifier");
207
208 if (null == identifier || identifier.equals("")) {
209 LOG.error("Could not load plugin with no identifier");
210 continue;
211 }
212
213 String className = element.getAttribute("type");
214 if (null == className || className.equals("")) {
215 LOG.error("Plugin " + identifier + " did not have a valid type");
216 }
217
218
219
220 try {
221 Class<Plugin> pluginClass = (Class<Plugin>) Class.forName(className);
222 Class[] classParams = {Element.class};
223 Constructor<Plugin> pluginConstructor = pluginClass.getConstructor(classParams);
224 Object[] constructorParams = {element};
225
226 plugin = pluginConstructor.newInstance(constructorParams);
227
228 } catch (Exception e) {
229 LOG.error("Plugin " + identifier + " could not be loaded ", e);
230 continue;
231 }
232
233 plugins.put(identifier, plugin);
234 }
235
236
237
238
239
240 itemElements = doc.getDocumentElement().getElementsByTagNameNS(XMLConstants.CONFIG_NS,
241 "DiscoveryServiceHandler");
242
243 for (int i = 0; i < itemElements.getLength(); i++) {
244
245 discoveryServices.add(new DiscoveryServiceHandler((Element)itemElements.item(i),
246 siteSets,
247 plugins,
248 defaultHandlerConfig));
249
250 }
251
252 } catch (Exception e) {
253
254
255
256 if (LOG != null) {
257 LOG.error("Error parsing DS configuration file.", e);
258 }
259 throw new ServletException("Error parsing DS configuration file.", e);
260 }
261
262 LOG.info("DS initialization completed.");
263 }
264
265
266
267
268
269
270
271 public void doGet(HttpServletRequest req, HttpServletResponse res) {
272
273 LOG.info("Handling DS request.");
274
275 res.setHeader("Cache-Control", "no-cache");
276 res.setHeader("Pragma", "no-cache");
277 res.setDateHeader("Expires", 0);
278
279 DiscoveryServiceHandler serviceHandler = lookupServiceHandler(req);
280
281 serviceHandler.doGet(req, res);
282
283 }
284
285
286
287
288
289
290 private DiscoveryServiceHandler lookupServiceHandler(HttpServletRequest req) {
291
292 Iterator<DiscoveryServiceHandler> it = discoveryServices.iterator();
293 String requestURL = req.getRequestURL().toString();
294 DiscoveryServiceHandler defaultHandler = null;
295
296 while (it.hasNext()) {
297 DiscoveryServiceHandler handler = it.next();
298
299 if (requestURL.matches(handler.getLocation())) {
300 return handler;
301 }
302 if (defaultHandler == null || handler.isDefault()) {
303 defaultHandler = handler;
304 }
305 }
306 LOG.warn("Could not find Discovery service Handler for " + requestURL);
307 return defaultHandler;
308 }
309 }