View Javadoc

1   /*
2    * Copyright (c) 2004 UNINETT FAS
3    *
4    * This program is free software; you can redistribute it and/or modify it
5    * under the terms of the GNU General Public License as published by the Free
6    * Software Foundation; either version 2 of the License, or (at your option)
7    * any later version.
8    *
9    * This program is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11   * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12   * more details.
13   *
14   * You should have received a copy of the GNU General Public License along with
15   * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16   * Place - Suite 330, Boston, MA 02111-1307, USA.
17   *
18   * $Id: AuthenticationImpl.java,v 1.4 2006/02/14 15:16:01 catoolsen Exp $
19   */
20  
21  package no.feide.moria.webservices.v2_3;
22  
23  import java.util.ArrayList;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Properties;
28  import java.util.Set;
29  
30  import no.feide.moria.controller.AuthenticationException;
31  import no.feide.moria.controller.AuthorizationException;
32  import no.feide.moria.controller.DirectoryUnavailableException;
33  import no.feide.moria.controller.InoperableStateException;
34  import no.feide.moria.controller.MoriaController;
35  import no.feide.moria.log.MessageLogger;
36  import no.feide.moria.servlet.RequestUtil;
37  import no.feide.moria.servlet.soap.AuthenticationFailedException;
38  import no.feide.moria.servlet.soap.AuthenticationUnavailableException;
39  import no.feide.moria.servlet.soap.AuthorizationFailedException;
40  import no.feide.moria.servlet.soap.IllegalInputException;
41  import no.feide.moria.servlet.soap.InternalException;
42  import no.feide.moria.servlet.soap.UnknownTicketException;
43  
44  import org.apache.axis.MessageContext;
45  import org.apache.axis.session.Session;
46  import org.apache.axis.transport.http.AxisHttpSession;
47  import org.apache.log4j.Level;
48  
49  /***
50   * 
51   */
52  public final class AuthenticationImpl
53  implements Authentication {
54  
55      /*** Class wide logger. */
56      private MessageLogger messageLogger;
57  
58      /*** Log message for AuthorizationExceptions. */
59      private static final String AUTHZ_EX_MESSAGE = "Authorization failed. Throwing RemoteException to service: ";
60  
61      /*** Log message for AuthenticationExceptions. */
62      private static final String AUTHN_EX_MSG = "Authentication failed. Throwing RemoteException to service: ";
63  
64      /*** Log message for DirectoryUnavailableExceptions. */
65      private static final String DIR_UNAV_EX_MSG = "Directory unavailable. Throwing RemoteException to service: ";
66  
67      /*** Log message for MoriaControllerExceptions. */
68      private static final String MORIACTRL_EX_MESSAGE = "Exception from MoriaController. Throwing RemoteException to service: ";
69  
70      /*** Log message for InoperableStateExceptions. */
71      private static final String INOP_STATE_EX_MSG = "Controller in inoperable state. Throwing RemoteException to service: ";
72  
73      /*** Log message for UnknownTicketExceptions. */
74      private static final String UNKNOWN_TICKET_EX_MSG = "Ticket is unknown. Throwing RemoteException to service: ";
75  
76  
77      /***
78       * Default constructor. Initializes the message logger.
79       */
80      public AuthenticationImpl() {
81  
82          messageLogger = new MessageLogger(AuthenticationImpl.class);
83      }
84  
85  
86      /***
87       * @see no.feide.moria.webservices.v2_1.Authentication#initiateAuthentication(java.lang.String[],
88       *      java.lang.String, java.lang.String, boolean)
89       */
90      public String initiateAuthentication(final String[] attributes, final String returnURLPrefix, final String returnURLPostfix, final boolean forceInteractiveAuthentication)
91      throws AuthorizationFailedException, IllegalInputException,
92      InternalException {
93  
94          /* Axis message context containg request data. */
95          MessageContext messageContext = MessageContext.getCurrentContext();
96          String servicePrincipal = messageContext.getUsername();
97  
98          String urlPrefix = null;
99          Session genericSession = messageContext.getSession();
100 
101         if (genericSession instanceof AxisHttpSession) {
102             AxisHttpSession axisHttpSession = (AxisHttpSession) genericSession;
103             Properties properties = (Properties) axisHttpSession.getRep().getServletContext().getAttribute("no.feide.moria.web.config");
104             urlPrefix = (properties.getProperty(RequestUtil.PROP_LOGIN_URL_PREFIX) + "?" + properties.getProperty(RequestUtil.PROP_LOGIN_TICKET_PARAM) + "=");
105         }
106 
107         try {
108 
109             return urlPrefix + MoriaController.initiateAuthentication(attributes, returnURLPrefix, returnURLPostfix, forceInteractiveAuthentication, servicePrincipal);
110 
111         } catch (AuthorizationException e) {
112 
113             // Client service did something it was not authorized to do.
114             messageLogger.logWarn(AUTHZ_EX_MESSAGE + servicePrincipal, e);
115             throw new AuthorizationFailedException(e.getMessage());
116 
117         } catch (no.feide.moria.controller.IllegalInputException e) {
118 
119             // Illegal input from client service.
120             messageLogger.logWarn(MORIACTRL_EX_MESSAGE + servicePrincipal, e);
121             throw new IllegalInputException(e.getMessage());
122 
123         } catch (InoperableStateException e) {
124 
125             // Moria is in an inoperable state.
126             messageLogger.logCritical(INOP_STATE_EX_MSG + servicePrincipal, e);
127             throw new InternalException(e.getMessage());
128 
129         }
130     }
131 
132 
133     /***
134      * @see no.feide.moria.webservices.v2_1.Authentication#directNonInteractiveAuthentication(java.lang.String[],
135      *      java.lang.String, java.lang.String)
136      */
137     public Attribute[] directNonInteractiveAuthentication(final String[] attributes, final String username, final String password)
138     throws AuthorizationFailedException, AuthenticationFailedException,
139     AuthenticationUnavailableException, IllegalInputException,
140     InternalException {
141 
142         /* Axis message context containg request data. */
143         MessageContext messageContext = MessageContext.getCurrentContext();
144         String servicePrincipal = messageContext.getUsername();
145 
146         try {
147             Map returnAttributes = MoriaController.directNonInteractiveAuthentication(attributes, username, password, servicePrincipal);
148             return mapToAttributeArray(returnAttributes, null);
149         } catch (AuthorizationException e) {
150 
151             // Client service did something it was not authorized to do.
152             messageLogger.logWarn(AUTHZ_EX_MESSAGE + servicePrincipal, e);
153             throw new AuthorizationFailedException(e.getMessage());
154 
155         } catch (AuthenticationException e) {
156 
157             // User failed authentication.
158             messageLogger.logWarn(AUTHN_EX_MSG + servicePrincipal, e);
159             throw new AuthenticationFailedException(e.getMessage());
160 
161         } catch (DirectoryUnavailableException e) {
162 
163             // Authentication server was unavailable.
164             messageLogger.logWarn(DIR_UNAV_EX_MSG + servicePrincipal, e);
165             throw new AuthenticationUnavailableException(e.getMessage());
166 
167         } catch (no.feide.moria.controller.IllegalInputException e) {
168 
169             // Illegal input from client service.
170             messageLogger.logWarn(MORIACTRL_EX_MESSAGE + servicePrincipal, e);
171             throw new IllegalInputException(e.getMessage());
172 
173         } catch (InoperableStateException e) {
174 
175             // Moria is in an inoperable state.
176             messageLogger.logCritical(INOP_STATE_EX_MSG + servicePrincipal, e);
177             throw new InternalException(e.getMessage());
178 
179         }
180     }
181 
182 
183     /***
184      * @see no.feide.moria.webservices.v2_1.Authentication#proxyAuthentication(java.lang.String[],
185      *      java.lang.String)
186      */
187     public Attribute[] proxyAuthentication(final String[] attributes, final String proxyTicket)
188     throws AuthorizationFailedException, IllegalInputException,
189     InternalException, UnknownTicketException {
190 
191         /* Axis message context containg request data. */
192         MessageContext messageContext = MessageContext.getCurrentContext();
193         String servicePrincipal = messageContext.getUsername();
194 
195         try {
196 
197             Map returnAttributes = MoriaController.proxyAuthentication(attributes, proxyTicket, servicePrincipal);
198             return mapToAttributeArray(returnAttributes, proxyTicket);
199 
200         } catch (AuthorizationException e) {
201 
202             // Client service did something it was not authorized to do.
203             messageLogger.logWarn(AUTHZ_EX_MESSAGE + servicePrincipal, e);
204             throw new AuthorizationFailedException(e.getMessage());
205 
206         } catch (no.feide.moria.controller.IllegalInputException e) {
207 
208             // Illegal input from client service.
209             messageLogger.logWarn(MORIACTRL_EX_MESSAGE + servicePrincipal, e);
210             throw new IllegalInputException(e.getMessage());
211 
212         } catch (InoperableStateException e) {
213 
214             // Moria is in an inoperable state.
215             messageLogger.logCritical(INOP_STATE_EX_MSG + servicePrincipal, e);
216             throw new InternalException(e.getMessage());
217 
218         } catch (no.feide.moria.controller.UnknownTicketException e) {
219 
220             // An unknown ticket was used by the client service.
221             messageLogger.logWarn(UNKNOWN_TICKET_EX_MSG + servicePrincipal, e);
222             throw new UnknownTicketException(e.getMessage());
223 
224         }
225     }
226 
227 
228     /***
229      * @see no.feide.moria.webservices.v2_1.Authentication#getProxyTicket(java.lang.String,
230      *      java.lang.String)
231      */
232     public String getProxyTicket(final String ticketGrantingTicket, final String proxyServicePrincipal)
233     throws AuthorizationFailedException, IllegalInputException,
234     InternalException, UnknownTicketException {
235 
236         /* Axis message context containg request data. */
237         MessageContext messageContext = MessageContext.getCurrentContext();
238         String servicePrincipal = messageContext.getUsername();
239 
240         try {
241 
242             return MoriaController.getProxyTicket(ticketGrantingTicket, proxyServicePrincipal, servicePrincipal);
243 
244         } catch (AuthorizationException e) {
245 
246             // Client service did something it was not supposed to do.
247             messageLogger.logWarn(AUTHZ_EX_MESSAGE + servicePrincipal, e);
248             throw new AuthorizationFailedException(e.getMessage());
249 
250         } catch (no.feide.moria.controller.IllegalInputException e) {
251 
252             // Illegal input from client service.
253             messageLogger.logWarn(MORIACTRL_EX_MESSAGE + servicePrincipal, e);
254             throw new IllegalInputException(e.getMessage());
255 
256         } catch (InoperableStateException e) {
257 
258             // Moria is in an inoperable state.
259             messageLogger.logCritical(INOP_STATE_EX_MSG + servicePrincipal, e);
260             throw new InternalException(e.getMessage());
261 
262         } catch (no.feide.moria.controller.UnknownTicketException e) {
263 
264             // Client service used an unknown ticket.
265             messageLogger.logWarn(UNKNOWN_TICKET_EX_MSG + servicePrincipal, e);
266             throw new UnknownTicketException(e.getMessage());
267 
268         }
269     }
270 
271 
272     /***
273      * @see no.feide.moria.webservices.v2_1.Authentication#getUserAttributes(java.lang.String)
274      */
275     public Attribute[] getUserAttributes(final String serviceTicket)
276     throws AuthorizationFailedException, IllegalInputException,
277     InternalException, UnknownTicketException {
278 
279         /* Axis message context containg request data. */
280         MessageContext messageContext = MessageContext.getCurrentContext();
281         String servicePrincipal = messageContext.getUsername();
282 
283         try {
284             Map returnAttributes = MoriaController.getUserAttributes(serviceTicket, servicePrincipal);
285             
286             // Prepare debug output.
287             if (messageLogger.isEnabledFor(Level.DEBUG)) {
288                 String attributeNames = "";
289                 Set keySet = returnAttributes.keySet();
290                 if (keySet != null) {
291                     Iterator i = keySet.iterator();
292                     while (i.hasNext())
293                         attributeNames = attributeNames + i.next() + ", ";
294                     if (attributeNames.length() > 0)
295                         attributeNames = attributeNames.substring(0, attributeNames.length() - 2);
296                 }
297                 messageLogger.logDebug("Returned attributes [" + attributeNames + "] to service '" + servicePrincipal + "'", serviceTicket);
298             }
299             
300             return mapToAttributeArray(returnAttributes, serviceTicket);
301         } catch (no.feide.moria.controller.IllegalInputException e) {
302 
303             // Illegal input used by service.
304             messageLogger.logWarn(MORIACTRL_EX_MESSAGE + servicePrincipal, e);
305             throw new IllegalInputException(e.getMessage());
306 
307         } catch (InoperableStateException e) {
308 
309             // Moria is in an inoperable state!
310             messageLogger.logCritical(INOP_STATE_EX_MSG + servicePrincipal, e);
311             throw new InternalException(e.getMessage());
312 
313         } catch (no.feide.moria.controller.UnknownTicketException e) {
314 
315             // An unknown ticket was used.
316             messageLogger.logWarn(UNKNOWN_TICKET_EX_MSG + servicePrincipal, e);
317             throw new UnknownTicketException(e.getMessage());
318 
319         } catch (AuthorizationException e) {
320 
321             // Service was not authorized for this operation.
322             messageLogger.logWarn("Service not allowed for organization. Throwing RemoteException to service: ", e);
323             throw new AuthorizationFailedException(e.getMessage());
324         }
325 
326     }
327 
328 
329     /***
330      * @see no.feide.moria.webservices.v2_1.Authentication#verifyUserExistence(java.lang.String)
331      */
332     public boolean verifyUserExistence(final String username)
333     throws AuthorizationFailedException, AuthenticationUnavailableException,
334     IllegalInputException, InternalException {
335 
336         /* Axis message context containg request data. */
337         MessageContext messageContext = MessageContext.getCurrentContext();
338         String servicePrincipal = messageContext.getUsername();
339 
340         try {
341 
342             return MoriaController.verifyUserExistence(username, servicePrincipal);
343 
344         } catch (AuthorizationException e) {
345 
346             // Client service did something it was not supposed to do.
347             messageLogger.logWarn(AUTHZ_EX_MESSAGE + servicePrincipal, e);
348             throw new AuthorizationFailedException(e.getMessage());
349 
350         } catch (DirectoryUnavailableException e) {
351 
352             // Authentication server is unavailable.
353             messageLogger.logWarn(DIR_UNAV_EX_MSG + servicePrincipal, e);
354             throw new AuthenticationUnavailableException(e.getMessage());
355 
356         } catch (no.feide.moria.controller.IllegalInputException e) {
357 
358             // Illegal input from client service.
359             messageLogger.logWarn(MORIACTRL_EX_MESSAGE + servicePrincipal, e);
360             throw new IllegalInputException(e.getMessage());
361 
362         } catch (InoperableStateException e) {
363 
364             // Moria is in an inoperable state.
365             messageLogger.logCritical(INOP_STATE_EX_MSG + servicePrincipal, e);
366             throw new InternalException(e.getMessage());
367 
368         }
369     }
370 
371 
372     /***
373      * Utility method to convert a <code>Map</code> to an array of
374      * <code>Attribute</code>s.
375      * @param map
376      *            The <code>Map</code> to be converted.
377      * @param activeTicketId
378      *            Optional variable for logging purposes.
379      * @return Array of <code>Attribute</code> objects.
380      */
381     private Attribute[] mapToAttributeArray(final Map map, final String activeTicketId) {
382 
383         /* Get iterator for map keys. */
384         Iterator iterator = map.keySet().iterator();
385 
386         /* List to hold finished Attributes while processing map. */
387         List attributeList = new ArrayList();
388 
389         /* Iterate over keys in map. */
390         while (iterator.hasNext()) {
391             Object key = iterator.next();
392             Object value = map.get(key);
393 
394             Attribute attribute = new Attribute();
395 
396             /* Check that key is a String, if not will ignore the whole entry. */
397             if (key instanceof String) {
398                 /* Add the key as name of attribute. */
399                 attribute.setName((String) key);
400 
401                 /*
402                  * Check type of value. If not String or String[] we don't add
403                  * it to the attribute list resulting in the whole entry beeing
404                  * ignored.
405                  */
406                 if (value instanceof String) {
407                     /* Create one-element String[] of value before setting. */
408                     attribute.setValues(new String[] {(String) value});
409                     attributeList.add(attribute);
410                 } else if (value instanceof String[]) {
411                     attribute.setValues((String[]) value);
412                     attributeList.add(attribute);
413                 } else if (value != null) {
414                     messageLogger.logInfo("Attribute value not String or String[]. Entry not added to Attribute[]. ", activeTicketId);
415                 }
416             } else if (value != null) {
417                 messageLogger.logInfo("Attribute key not String. Entry not added to Attribute[]", activeTicketId);
418             }
419         }
420         return (Attribute[]) attributeList.toArray(new Attribute[] {});
421     }
422 }