1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package no.feide.moria.servlet;
22
23 import java.io.IOException;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.Map;
27 import java.util.Properties;
28 import java.util.ResourceBundle;
29 import java.util.Arrays;
30 import javax.servlet.RequestDispatcher;
31 import javax.servlet.ServletException;
32 import javax.servlet.http.HttpServlet;
33 import javax.servlet.http.HttpServletRequest;
34 import javax.servlet.http.HttpServletResponse;
35 import java.io.File;
36 import javax.xml.parsers.SAXParserFactory;
37 import javax.xml.parsers.SAXParser;
38 import no.feide.moria.controller.AuthorizationException;
39 import no.feide.moria.controller.IllegalInputException;
40 import no.feide.moria.controller.InoperableStateException;
41 import no.feide.moria.controller.MoriaController;
42 import no.feide.moria.controller.UnknownTicketException;
43 import no.feide.moria.log.MessageLogger;
44 import java.util.Vector;
45
46
47 /***
48 * This servlet is responsible for retrieving information about a user, and
49 * sending it to information.jsp for display.
50 *
51 * @author Eva Indal
52 * @version $Revision: 1.33 $
53 */
54 public class InformationServlet extends MoriaServlet {
55
56 /***
57 * A hash map containing all possible attributes for a user.
58 * Each item in the hashmap maps from an attribute name to an
59 * AttribsData class instance
60 */
61 private HashMap feideattribsStored = null;
62
63 /***
64 * Monitor for the attribute description file.
65 */
66 private FileMonitor feideattribsMonitor = null;
67
68 /*** Principal name of the service.
69 * Current value is "info"
70 */
71 private static final String PRINCIPAL = "info";
72
73 /*** Used for logging. */
74 private final MessageLogger log = new MessageLogger(InformationServlet.class);
75
76 /***
77 * List of parameters required by <code>InformationServlet</code>.
78 * <br>
79 * <br>
80 * Current required parameters are:
81 * <ul>
82 * <li><code>RequestUtil.PROP_COOKIE_LANG</code>
83 * <li><code>RequestUtil.PROP_COOKIE_LANG_TTL</code>
84 * <li><code>RequestUtil.PROP_COOKIE_DENYSSO</code>
85 * <li><code>RequestUtil.PROP_LOGIN_TICKET_PARAM</code>
86 * <li><code>RequestUtil.PROP_INFORMATION_URL_PREFIX</code>
87 * <li><code>RequestUtil.PROP_INFORMATION_DESCRIPTIONS</code>
88 * <li><code>RequestUtil.PIC_LINK</code>
89 * </ul>
90 * @see RequestUtil#PROP_COOKIE_LANG
91 * @see RequestUtil#PROP_COOKIE_LANG_TTL
92 * @see RequestUtil#PROP_COOKIE_DENYSSO
93 * @see RequestUtil#PROP_LOGIN_TICKET_PARAM
94 * @see RequestUtil#PROP_INFORMATION_URL_PREFIX
95 * @see RequestUtil#PROP_INFORMATION_DESCRIPTIONS
96 * @see RequestUtil#PIC_LINK
97 */
98 private static final String[] REQUIRED_PARAMETERS = {
99 RequestUtil.PROP_COOKIE_LANG,
100 RequestUtil.PROP_COOKIE_LANG_TTL,
101 RequestUtil.PROP_COOKIE_DENYSSO,
102 RequestUtil.PROP_LOGIN_TICKET_PARAM,
103 RequestUtil.PROP_INFORMATION_URL_PREFIX,
104 RequestUtil.PROP_INFORMATION_DESCRIPTIONS,
105 RequestUtil.PIC_LINK
106 };
107
108 /***
109 *
110 * @return the required parameters for this servlet.
111 */
112 public static String[] getRequiredParameters() {
113 return REQUIRED_PARAMETERS;
114 }
115 /***
116 * Constructor.
117 */
118 public InformationServlet() {
119 }
120
121 /***
122 * Implements a simple xml parser that parses the attribute description file
123 * into a HashMap with AttribsData instances.
124 *
125 * @see AttribsHandler
126 * AttribsData
127 */
128 public final synchronized HashMap getAttribs() {
129 if (feideattribsMonitor == null || feideattribsMonitor.hasChanged()) {
130 Properties config;
131 try {
132 config = getServletConfig(getRequiredParameters(), log);
133 } catch (IllegalStateException e) {
134 config = null;
135 }
136 if (config != null) {
137 AttribsHandler handler = new AttribsHandler();
138 SAXParserFactory factory = SAXParserFactory.newInstance();
139 String filename = (String) config.get(RequestUtil.PROP_INFORMATION_DESCRIPTIONS);
140 try {
141 if ((filename == null) || (filename.equals(""))) {
142 log.logCritical("Required configuration property PROP_INFORMATION_DESCRIPTIONS is not set");
143 throw new IllegalStateException();
144 }
145 SAXParser saxParser = factory.newSAXParser();
146 saxParser.parse(new File(filename), handler);
147 feideattribsMonitor = new FileMonitor(filename);
148 } catch (Throwable t) {
149 log.logCritical("Error parsing attribute description file '" + filename + "'");
150 throw new IllegalStateException();
151 } finally {
152 feideattribsStored = handler.getAttribs();
153 }
154 }
155 }
156 return feideattribsStored;
157 }
158
159 /***
160 * Generates table for a user. The vector consists of rows of data. Each row
161 * has four columns. The first column is the URL link for the user attribute. The
162 * second column is the attribute description as presented to the user. The
163 * third column is the actual data stored for the attribute, and the fourth
164 * columns is either fd_mandatory or fd_optional, as a key for a mandatory
165 * or optional attribute.
166 *
167 * @param userData The user data.
168 * @param bundle Resource bundle for language.
169 * @return Vector with table data.
170 */
171 private Vector printTableToVector(final Map userData, final ResourceBundle bundle) {
172
173
174 Vector temp = new Vector();
175 HashMap feideattribs = getAttribs();
176 for (Iterator iterator = feideattribs.keySet().iterator(); iterator.hasNext();) {
177 String key = (String) iterator.next();
178 AttribsData attribsData = (AttribsData) feideattribs.get(key);
179 temp.add(attribsData);
180 }
181
182 Object[] attribsArray = temp.toArray();
183 Arrays.sort(attribsArray, new AttribsData(0));
184
185 Vector out = new Vector();
186
187
188 int n = temp.size();
189 for (int i = 0; i < n; i++) {
190 AttribsData adata = (AttribsData) attribsArray[i];
191 String key2 = (String) adata.getData("key");
192 boolean hasuserdata = userData.containsKey(key2);
193 String[] userdata = (String[]) userData.get(key2);
194
195 String description = adata.getData("description");
196 String bundleid = adata.getData("resourcebundle");
197 String bundlename = (String) bundle.getString(bundleid);
198
199 if (bundlename != null)
200 description = bundlename;
201 String link = adata.getData("link");
202 String relevance = adata.getData("relevance");
203 String o_relevance =adata.getData("o-relevance");
204
205 String userstring = "";
206
207
208
209 if (userdata != null) {
210 for (int j = 0; j < userdata.length; j++) {
211 userstring += userdata[j];
212 userstring += "<BR>";
213 }
214 }
215
216
217 if (key2.equals("jpegPhoto")) {
218 if (userdata != null) {
219 userstring = "p_yes";
220 }
221 }
222 out.add(link);
223 out.add(description);
224 out.add(userstring);
225 out.add(relevance);
226 out.add(o_relevance);
227 out.add(key2);
228 }
229 return out;
230 }
231
232 /***
233 * Implements the HttpServlet.doGet method.
234 *
235 * @param request The HTTP request.
236 * @param response The HTTP response.
237 * @throws IOException
238 * If getAttribs returns null.
239 * @throws ServletException
240 * If the Moria controller throws an exception.
241 * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
242 */
243 public final void doGet(final HttpServletRequest request, final HttpServletResponse response)
244 throws ServletException, IOException {
245 if (getAttribs() == null) throw new IOException("Attribute description file not parsed");
246
247 String ticketId = request.getParameter("moriaID");
248
249 if (request.getParameter("logout") != null) {
250 log.logDebug("Logout received");
251 final RequestDispatcher rd = getServletContext().getNamedDispatcher("Logout");
252 rd.forward(request, response);
253 return;
254 }
255
256
257
258
259
260 Properties config;
261
262 try {
263 config = getServletConfig(getRequiredParameters(), log);
264 } catch (IllegalStateException e) {
265 config = null;
266 }
267
268
269 String langFromCookie = null;
270 if (config != null && request.getCookies() != null) {
271 langFromCookie = RequestUtil.getCookieValue((String) config.get(RequestUtil.PROP_COOKIE_LANG), request.getCookies());
272 }
273
274
275 final ResourceBundle bundle = RequestUtil.getBundle(
276 RequestUtil.BUNDLE_INFORMATIONSERVLET,
277 request.getParameter(RequestUtil.PARAM_LANG), langFromCookie, null,
278 request.getHeader("Accept-Language"), (String) config.get(RequestUtil.PROP_LOGIN_DEFAULT_LANGUAGE));
279
280 request.setAttribute("bundle", bundle);
281 String urlPrefix = (String)config.get(RequestUtil.PROP_INFORMATION_URL_PREFIX);
282 if ((urlPrefix == null) || (urlPrefix.equals(""))) {
283 log.logCritical("Required configuration property PROP_INFORMATION_DESCRIPTIONS is not set");
284 throw new IllegalStateException();
285 } else {
286 request.setAttribute("urlPrefix", urlPrefix);
287 }
288
289
290 boolean changelanguage = false;
291 if (request.getParameter(RequestUtil.PARAM_LANG) != null) {
292 response.addCookie(RequestUtil.createCookie(
293 (String) config.get(RequestUtil.PROP_COOKIE_LANG),
294 request.getParameter(RequestUtil.PARAM_LANG),
295 new Integer((String) config.get(RequestUtil.PROP_COOKIE_LANG_TTL)).intValue()));
296 changelanguage = true;
297 }
298 Map userData = null;
299
300 if (ticketId != null && !changelanguage) {
301 try {
302 userData = MoriaController.getUserAttributes(ticketId, PRINCIPAL);
303 } catch (AuthorizationException e) {
304 log.logCritical("AuthorizationException");
305 throw new ServletException(e);
306 } catch (IllegalInputException e) {
307 log.logCritical("IllegalInputException");
308 throw new ServletException(e);
309 } catch (UnknownTicketException e) {
310 log.logCritical("UnknownTicketException");
311 throw new ServletException(e);
312 } catch (InoperableStateException e) {
313 log.logCritical("InoperableStateException");
314 throw new ServletException(e);
315 }
316 }
317 if (userData != null) {
318
319
320 String [] userorgarray = (String[]) userData.get("o");
321 String userorg = bundle.getString("unknown_userorg");
322 if (userorgarray != null && userorgarray.length > 0) {
323 userorg = userorgarray[0];
324 }
325 request.setAttribute("userorg", userorg);
326
327 String[] usernamearray = (String[]) userData.get("eduPersonPrincipalName");
328 String username = null;
329 if (usernamearray != null && usernamearray.length > 0) {
330 username = usernamearray[0];
331 }
332 request.setAttribute("username", username);
333
334 String[] picarr = (String[]) userData.get(new String("jpegPhoto"));
335 if (picarr != null && picarr.length > 0) {
336 request.setAttribute(PictureServlet.PICTURE_ATTRIBUTE, picarr);
337 }
338
339 Vector tabledata = printTableToVector(userData, bundle);
340 request.setAttribute("tabledata", tabledata);
341
342
343 request.setAttribute(RequestUtil.ATTR_ORGANIZATIONS,
344 RequestUtil.parseConfig(config, RequestUtil.PROP_ORG, bundle.getLocale().getLanguage()));
345 request.setAttribute(RequestUtil.ATTR_LANGUAGES,
346 RequestUtil.parseConfig(config, RequestUtil.PROP_LANGUAGE, RequestUtil.PROP_COMMON));
347 request.setAttribute(RequestUtil.ATTR_BASE_URL,
348 config.getProperty(RequestUtil.PROP_INFORMATION_URL_PREFIX) + "?"
349 + config.getProperty(RequestUtil.PROP_LOGIN_TICKET_PARAM) + "=" + ticketId);
350 request.setAttribute(RequestUtil.ATTR_SELECTED_LANG, bundle.getLocale());
351 request.setAttribute(RequestUtil.PIC_LINK, config.getProperty(RequestUtil.PIC_LINK));
352
353
354 final String denySSOChoice = RequestUtil.getCookieValue(config.getProperty(RequestUtil.PROP_COOKIE_DENYSSO), request.getCookies());
355 final boolean denySSO;
356 if (denySSOChoice == null || denySSOChoice.equals("false") || denySSOChoice.equals("")) {
357
358 request.setAttribute(RequestUtil.ATTR_SELECTED_DENYSSO, new Boolean(false));
359 denySSO = false;
360
361 } else {
362
363 request.setAttribute(RequestUtil.ATTR_SELECTED_DENYSSO, new Boolean(true));
364 denySSO = true;
365 }
366
367 final RequestDispatcher rd = getServletContext().getNamedDispatcher("Information.JSP");
368 rd.forward(request, response);
369 } else {
370
371 doPost(request, response);
372 }
373 }
374
375 /***
376 * Implements the HttpServlet.doPost method.
377 *
378 * @param request The HTTP request.
379 * @param response The HTTP response.
380 * @throws IOException Required by interface.
381 * @throws ServletException
382 * If the Moria controller throws an exception.
383 * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
384 */
385 public final void doPost(final HttpServletRequest request, final HttpServletResponse response)
386 throws ServletException, IOException {
387
388 String jspLocation = getServletContext().getInitParameter("jsp.location");
389 log.logDebug("jsp.location is '" + jspLocation + "'");
390 String moriaID = null;
391 boolean error = false;
392
393 String attributes = getAllAttributes();
394 String urlPrefix = (String) request.getAttribute("urlPrefix") + "?moriaID=";
395 String urlPostfix = "";
396 String principal = PRINCIPAL;
397
398 try {
399 MoriaController.initController(getServletContext());
400 log.logDebug("Requested attributes: " + attributes);
401 log.logDebug("URL prefix: " + urlPrefix);
402 log.logDebug("URL postfix: " + urlPostfix);
403 log.logDebug("Principal: " + principal);
404 moriaID = MoriaController.initiateAuthentication(attributes.split(","),
405 urlPrefix, urlPostfix, true, principal);
406 log.logDebug("Moria ID is now " + moriaID);
407
408 } catch (IllegalInputException e) {
409 log.logCritical("IllegalInputException");
410 throw new ServletException(e);
411 } catch (AuthorizationException e) {
412 log.logCritical("AuthorizationException");
413 throw new ServletException(e);
414 } catch (InoperableStateException e) {
415 log.logCritical("InoperableStateException");
416 throw new ServletException(e);
417 }
418
419 if (!error) {
420 Properties config = (Properties) getServletContext().getAttribute(RequestUtil.PROP_CONFIG);
421 log.logDebug("Configuration: " + config.toString());
422 String redirectURL = config.getProperty(RequestUtil.PROP_LOGIN_URL_PREFIX)
423 + "?" + config.getProperty(RequestUtil.PROP_LOGIN_TICKET_PARAM) + "=" + moriaID;
424 log.logDebug("Redirect URL: " + redirectURL);
425 response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
426 response.setHeader("Location", redirectURL);
427 } else {
428
429 throw new ServletException("Unknown error in InformationServlet");
430 }
431 }
432
433 /***
434 * Builds a list of all possible user attributes.
435 *
436 * @return Comma separated list of attributes.
437 */
438 private String getAllAttributes() {
439 String acc = "";
440 HashMap feideattribs = getAttribs();
441 for (Iterator iterator = feideattribs.keySet().iterator(); iterator.hasNext();) {
442 String key = (String) iterator.next();
443 acc += key;
444 if (iterator.hasNext()) acc += ",";
445 }
446 return acc;
447 }
448 }
449