1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package no.feide.moria.webservices.v2_2;
20
21 import java.util.ArrayList;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Properties;
26 import java.util.Random;
27 import java.util.Set;
28
29 import no.feide.moria.controller.AuthenticationException;
30 import no.feide.moria.controller.AuthorizationException;
31 import no.feide.moria.controller.DirectoryUnavailableException;
32 import no.feide.moria.controller.InoperableStateException;
33 import no.feide.moria.controller.MoriaController;
34 import no.feide.moria.log.MessageLogger;
35 import no.feide.moria.servlet.RequestUtil;
36 import no.feide.moria.servlet.soap.AuthenticationFailedException;
37 import no.feide.moria.servlet.soap.AuthenticationUnavailableException;
38 import no.feide.moria.servlet.soap.AuthorizationFailedException;
39 import no.feide.moria.servlet.soap.IllegalInputException;
40 import no.feide.moria.servlet.soap.InternalException;
41 import no.feide.moria.servlet.soap.UnknownTicketException;
42
43 import org.apache.axis.MessageContext;
44 import org.apache.axis.session.Session;
45 import org.apache.axis.transport.http.AxisHttpSession;
46 import org.apache.log4j.Level;
47
48 /***
49 * Implements the Moria2 v2.1 SOAP interface.
50 * @see no.feide.moria.webservices.v2_2.Authentication
51 */
52 public final class AuthenticationImpl
53 implements Authentication {
54
55 /***
56 * The message logger.
57 */
58 private MessageLogger messageLogger;
59
60 /***
61 * Log message for <code>AuthorizationException</code>s.
62 */
63 private static final String AUTHZ_EX_MESSAGE = "Authorization failed. Throwing RemoteException to service: ";
64
65 /***
66 * Log message for <code>AuthenticationException</code>s.
67 */
68 private static final String AUTHN_EX_MSG = "Authentication failed. Throwing RemoteException to service: ";
69
70 /***
71 * Log message for <code>DirectoryUnavailableException</code>s.
72 */
73 private static final String DIR_UNAV_EX_MSG = "Directory unavailable. Throwing RemoteException to service: ";
74
75 /***
76 * Log message for <code>MoriaControllerException</code>s.
77 */
78 private static final String MORIACTRL_EX_MESSAGE = "Exception from MoriaController. Throwing RemoteException to service: ";
79
80 /***
81 * Log message for <code>InoperableStateException</code>s.
82 */
83 private static final String INOP_STATE_EX_MSG = "Controller in inoperable state. Throwing RemoteException to service: ";
84
85 /***
86 * Log message for <code>UnknownTicketException</code>s.
87 */
88 private static final String UNKNOWN_TICKET_EX_MSG = "Ticket is unknown. Throwing RemoteException to service: ";
89
90
91 /***
92 * Default constructor. Initializes the logger.
93 */
94 public AuthenticationImpl() {
95
96 messageLogger = new MessageLogger(AuthenticationImpl.class);
97 }
98
99
100 /***
101 * @see no.feide.moria.webservices.v2_2.Authentication#initiateAuthentication(java.lang.String[],
102 * java.lang.String, java.lang.String, boolean)
103 */
104 public String initiateAuthentication(final String[] attributes, final String returnURLPrefix, final String returnURLPostfix, final boolean forceInteractiveAuthentication)
105 throws AuthorizationFailedException, IllegalInputException,
106 InternalException {
107
108
109 MessageContext messageContext = MessageContext.getCurrentContext();
110 String servicePrincipal = messageContext.getUsername();
111
112 String urlPrefix = null;
113 Session genericSession = messageContext.getSession();
114
115 if (genericSession instanceof AxisHttpSession) {
116 AxisHttpSession axisHttpSession = (AxisHttpSession) genericSession;
117 Properties properties = (Properties) axisHttpSession.getRep().getServletContext().getAttribute("no.feide.moria.web.config");
118 urlPrefix = (properties.getProperty(RequestUtil.PROP_LOGIN_URL_PREFIX) + "?" + properties.getProperty(RequestUtil.PROP_LOGIN_TICKET_PARAM) + "=");
119 }
120
121 try {
122
123 return urlPrefix + MoriaController.initiateAuthentication(attributes, returnURLPrefix, returnURLPostfix, forceInteractiveAuthentication, servicePrincipal);
124
125 } catch (AuthorizationException e) {
126
127
128 messageLogger.logWarn(AUTHZ_EX_MESSAGE + servicePrincipal, e);
129 throw new AuthorizationFailedException(e.getMessage());
130
131 } catch (no.feide.moria.controller.IllegalInputException e) {
132
133
134 messageLogger.logWarn(MORIACTRL_EX_MESSAGE + servicePrincipal, e);
135 throw new IllegalInputException(e.getMessage());
136
137 } catch (InoperableStateException e) {
138
139
140 messageLogger.logCritical(INOP_STATE_EX_MSG + servicePrincipal, e);
141 throw new InternalException(e.getMessage());
142
143 }
144 }
145
146
147 /***
148 * @see no.feide.moria.webservices.v2_2.Authentication#directNonInteractiveAuthentication(java.lang.String[],
149 * java.lang.String, java.lang.String)
150 */
151 public Attribute[] directNonInteractiveAuthentication(final String[] attributes, final String username, final String password)
152 throws AuthorizationFailedException, AuthenticationFailedException,
153 AuthenticationUnavailableException, IllegalInputException,
154 InternalException {
155
156
157 MessageContext messageContext = MessageContext.getCurrentContext();
158 String servicePrincipal = messageContext.getUsername();
159
160 try {
161 Map returnAttributes = MoriaController.directNonInteractiveAuthentication(attributes, username, password, servicePrincipal);
162 return mapToAttributeArray(returnAttributes, null);
163 } catch (AuthorizationException e) {
164
165
166 messageLogger.logWarn(AUTHZ_EX_MESSAGE + servicePrincipal, e);
167 throw new AuthorizationFailedException(e.getMessage());
168
169 } catch (AuthenticationException e) {
170
171
172 messageLogger.logWarn(AUTHN_EX_MSG + servicePrincipal, e);
173 throw new AuthenticationFailedException(e.getMessage());
174
175 } catch (DirectoryUnavailableException e) {
176
177
178 messageLogger.logWarn(DIR_UNAV_EX_MSG + servicePrincipal, e);
179 throw new AuthenticationUnavailableException(e.getMessage());
180
181 } catch (no.feide.moria.controller.IllegalInputException e) {
182
183
184 messageLogger.logWarn(MORIACTRL_EX_MESSAGE + servicePrincipal, e);
185 throw new IllegalInputException(e.getMessage());
186
187 } catch (InoperableStateException e) {
188
189
190 messageLogger.logCritical(INOP_STATE_EX_MSG + servicePrincipal, e);
191 throw new InternalException(e.getMessage());
192
193 }
194 }
195
196
197 /***
198 * @see no.feide.moria.webservices.v2_2.Authentication#proxyAuthentication(java.lang.String[],
199 * java.lang.String)
200 */
201 public Attribute[] proxyAuthentication(final String[] attributes, final String proxyTicket)
202 throws AuthorizationFailedException, IllegalInputException,
203 InternalException, UnknownTicketException {
204
205
206 MessageContext messageContext = MessageContext.getCurrentContext();
207 String servicePrincipal = messageContext.getUsername();
208
209 try {
210
211 Map returnAttributes = MoriaController.proxyAuthentication(attributes, proxyTicket, servicePrincipal);
212 return mapToAttributeArray(returnAttributes, proxyTicket);
213
214 } catch (AuthorizationException e) {
215
216
217 messageLogger.logWarn(AUTHZ_EX_MESSAGE + servicePrincipal, e);
218 throw new AuthorizationFailedException(e.getMessage());
219
220 } catch (no.feide.moria.controller.IllegalInputException e) {
221
222
223 messageLogger.logWarn(MORIACTRL_EX_MESSAGE + servicePrincipal, e);
224 throw new IllegalInputException(e.getMessage());
225
226 } catch (InoperableStateException e) {
227
228
229 messageLogger.logCritical(INOP_STATE_EX_MSG + servicePrincipal, e);
230 throw new InternalException(e.getMessage());
231
232 } catch (no.feide.moria.controller.UnknownTicketException e) {
233
234
235 messageLogger.logWarn(UNKNOWN_TICKET_EX_MSG + servicePrincipal, e);
236 throw new UnknownTicketException(e.getMessage());
237
238 }
239 }
240
241
242 /***
243 * @see no.feide.moria.webservices.v2_2.Authentication#getProxyTicket(java.lang.String,
244 * java.lang.String)
245 */
246 public String getProxyTicket(final String ticketGrantingTicket, final String proxyServicePrincipal)
247 throws AuthorizationFailedException, IllegalInputException,
248 InternalException, UnknownTicketException {
249
250
251 MessageContext messageContext = MessageContext.getCurrentContext();
252 String servicePrincipal = messageContext.getUsername();
253
254 try {
255
256 return MoriaController.getProxyTicket(ticketGrantingTicket, proxyServicePrincipal, servicePrincipal);
257
258 } catch (AuthorizationException e) {
259
260
261 messageLogger.logWarn(AUTHZ_EX_MESSAGE + servicePrincipal, e);
262 throw new AuthorizationFailedException(e.getMessage());
263
264 } catch (no.feide.moria.controller.IllegalInputException e) {
265
266
267 messageLogger.logWarn(MORIACTRL_EX_MESSAGE + servicePrincipal, e);
268 throw new IllegalInputException(e.getMessage());
269
270 } catch (InoperableStateException e) {
271
272
273 messageLogger.logCritical(INOP_STATE_EX_MSG + servicePrincipal, e);
274 throw new InternalException(e.getMessage());
275
276 } catch (no.feide.moria.controller.UnknownTicketException e) {
277
278
279 messageLogger.logWarn(UNKNOWN_TICKET_EX_MSG + servicePrincipal, e);
280 throw new UnknownTicketException(e.getMessage());
281
282 }
283 }
284
285
286 /***
287 * @see no.feide.moria.webservices.v2_2.Authentication#getUserAttributes(java.lang.String)
288 */
289 public Attribute[] getUserAttributes(final String serviceTicket)
290 throws AuthorizationFailedException, IllegalInputException,
291 InternalException, UnknownTicketException {
292
293
294 MessageContext messageContext = MessageContext.getCurrentContext();
295 String servicePrincipal = messageContext.getUsername();
296
297 try {
298 Map returnAttributes = MoriaController.getUserAttributes(serviceTicket, servicePrincipal);
299
300
301 if (messageLogger.isEnabledFor(Level.DEBUG)) {
302 String attributeNames = "";
303 Set keySet = returnAttributes.keySet();
304 if (keySet != null) {
305 Iterator i = keySet.iterator();
306 while (i.hasNext())
307 attributeNames = attributeNames + i.next() + ", ";
308 if (attributeNames.length() > 0)
309 attributeNames = attributeNames.substring(0, attributeNames.length() - 2);
310 }
311 messageLogger.logDebug("Returned attributes [" + attributeNames + "] to service '" + servicePrincipal + "'", serviceTicket);
312 }
313
314 return mapToAttributeArray(returnAttributes, serviceTicket);
315 } catch (no.feide.moria.controller.IllegalInputException e) {
316
317
318 messageLogger.logWarn(MORIACTRL_EX_MESSAGE + servicePrincipal, e);
319 throw new IllegalInputException(e.getMessage());
320
321 } catch (InoperableStateException e) {
322
323
324 messageLogger.logCritical(INOP_STATE_EX_MSG + servicePrincipal, e);
325 throw new InternalException(e.getMessage());
326
327 } catch (no.feide.moria.controller.UnknownTicketException e) {
328
329
330 messageLogger.logWarn(UNKNOWN_TICKET_EX_MSG + servicePrincipal, e);
331 throw new UnknownTicketException(e.getMessage());
332
333 } catch (AuthorizationException e) {
334
335
336 messageLogger.logWarn("Service not allowed for organization. Throwing RemoteException to service: ", e);
337 throw new AuthorizationFailedException(e.getMessage());
338 }
339
340 }
341
342
343 /***
344 * @see no.feide.moria.webservices.v2_2.Authentication#verifyUserExistence(java.lang.String)
345 */
346 public boolean verifyUserExistence(final String username)
347 throws AuthorizationFailedException, AuthenticationUnavailableException,
348 IllegalInputException, InternalException {
349
350
351 MessageContext messageContext = MessageContext.getCurrentContext();
352 String servicePrincipal = messageContext.getUsername();
353
354 try {
355
356 return MoriaController.verifyUserExistence(username, servicePrincipal);
357
358 } catch (AuthorizationException e) {
359
360
361 messageLogger.logWarn(AUTHZ_EX_MESSAGE + servicePrincipal, e);
362 throw new AuthorizationFailedException(e.getMessage());
363
364 } catch (DirectoryUnavailableException e) {
365
366
367 messageLogger.logWarn(DIR_UNAV_EX_MSG + servicePrincipal, e);
368 throw new AuthenticationUnavailableException(e.getMessage());
369
370 } catch (no.feide.moria.controller.IllegalInputException e) {
371
372
373 messageLogger.logWarn(MORIACTRL_EX_MESSAGE + servicePrincipal, e);
374 throw new IllegalInputException(e.getMessage());
375
376 } catch (InoperableStateException e) {
377
378
379 messageLogger.logCritical(INOP_STATE_EX_MSG + servicePrincipal, e);
380 throw new InternalException(e.getMessage());
381
382 }
383 }
384
385
386 /***
387 * Utility method to convert a <code>Map</code> to an array of
388 * <code>Attribute</code>s.
389 * @param map
390 * The <code>Map</code> to be converted.
391 * @param activeTicketId
392 * Optional variable for logging purposes.
393 * @return Array of <code>Attribute</code> objects.
394 */
395 private Attribute[] mapToAttributeArray(final Map map, final String activeTicketId) {
396
397
398 Iterator iterator = map.keySet().iterator();
399
400
401 List attributeList = new ArrayList();
402
403
404 while (iterator.hasNext()) {
405 Object key = iterator.next();
406 Object value = map.get(key);
407
408
409 Attribute attribute = new Attribute();
410 Random randomGenerator = new Random();
411 String separator = "_";
412 for (int i=0; i<4; i++)
413 separator = separator + (char) (97+randomGenerator.nextInt(25));
414 separator = separator + "_";
415 attribute.setSeparator(separator);
416
417
418 if (key instanceof String) {
419
420 attribute.setName((String) key);
421
422
423
424
425
426
427 if (value instanceof String) {
428
429
430 attribute.setValues((String) value);
431 attributeList.add(attribute);
432
433 } else if (value instanceof String[]) {
434
435
436 attribute.setValues(encodeValues(separator, (String[]) value));
437 attributeList.add(attribute);
438
439 } else if (value != null) {
440 messageLogger.logInfo("Attribute value not String or String[]. Entry not added to Attribute[]. ", activeTicketId);
441 }
442 } else if (value != null) {
443 messageLogger.logInfo("Attribute key not String. Entry not added to Attribute[]", activeTicketId);
444 }
445 }
446 return (Attribute[]) attributeList.toArray(new Attribute[] {});
447 }
448
449
450 /***
451 * Encode a <code>String</code> array into a single string, using the
452 * <code>separator</code> between attribute values. All occurrences of
453 * <code>separator</code> in the original attribute values are replaced by
454 * two <code>separator</code>s.
455 * @param separator
456 * The separator to be used.
457 * @param values
458 * The values to be encoded using <code>separator</code>.
459 * @return The encoded values.
460 */
461 private static String encodeValues(final String separator, final String[] values) {
462
463 String encoded = new String();
464 for (int i = 0; i < values.length; i++)
465 encoded = encoded + values[i].replaceAll(separator, separator + separator) + separator;
466 encoded = encoded.substring(0, encoded.length() - separator.length());
467 return new String(encoded);
468
469 }
470
471 }