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.webservices.v2_0;
22
23 import java.rmi.RemoteException;
24 import java.util.ArrayList;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Properties;
29 import java.util.Set;
30
31 import no.feide.moria.controller.AuthenticationException;
32 import no.feide.moria.controller.AuthorizationException;
33 import no.feide.moria.controller.DirectoryUnavailableException;
34 import no.feide.moria.controller.IllegalInputException;
35 import no.feide.moria.controller.InoperableStateException;
36 import no.feide.moria.controller.MoriaController;
37 import no.feide.moria.controller.UnknownTicketException;
38 import no.feide.moria.log.MessageLogger;
39 import no.feide.moria.servlet.RequestUtil;
40
41 import org.apache.axis.MessageContext;
42 import org.apache.axis.session.Session;
43 import org.apache.axis.transport.http.AxisHttpSession;
44 import org.apache.log4j.Level;
45
46 /***
47 * @author Bjørn Ola Smievoll <b.o@smievoll.no>
48 * @version $Revision: 1.6 $
49 */
50 public final class AuthenticationImpl implements Authentication {
51
52 /*** Class wide logger. */
53 private MessageLogger messageLogger;
54
55 /*** Log message for AuthorizationExceptions. */
56 private static final String AUTHZ_EX_MSG = "Authorization failed. Throwing RemoteException to service: ";
57
58 /*** Log message for AuthenticationExceptions. */
59 private static final String AUTHN_EX_MSG = "AuthenticationImpl failed. Throwing RemoteException to service: ";
60
61 /*** Log message for DirectoryUnavailableExceptions. */
62 private static final String DIR_UNAV_EX_MSG = "Directory unavailable. Throwing RemoteException to service: ";
63
64 /*** Log message for IllegalInputExceptions. */
65 private static final String ILLEGAL_INPUT_EX_MSG = "Illegal input. Throwing RemoteException to service: ";
66
67 /*** Log message for InoperableStateExceptions. */
68 private static final String INOP_STATE_EX_MSG = "Controller in inoperable state. Throwing RemoteException to service: ";
69
70 /*** Log message for UnknownTicketExceptions. */
71 private static final String UNKNOWN_TICKET_EX_MSG = "Ticket is unknown. Throwing RemoteException to service: ";
72
73 /***
74 * Default constructor.
75 * Initializes the logger.
76 */
77 public AuthenticationImpl() {
78 messageLogger = new MessageLogger(AuthenticationImpl.class);
79 }
80
81 /***
82 * Initiates authentication.
83 *
84 * The initial call done by a service to start a login attempt.
85 *
86 * @param attributes
87 * The attributes the service wants returned on login
88 * @param returnURLPrefix
89 * The prefix of the url the user is to be returned to
90 * @param returnURLPostfix
91 * The optional postfix of the return url
92 * @param forceInteractiveAuthentication
93 * Whether or not cookie based authentication (SSO Light)
94 * should be allowed.
95 * @return The Moria url the client is to be redirected to.
96 * @throws RemoteException
97 * If anything fails during the call.
98 * @see no.feide.moria.webservices.v2_0.Authentication#initiateAuthentication(java.lang.String[],
99 * java.lang.String, java.lang.String, boolean)
100 */
101 public String initiateAuthentication(final String[] attributes, final String returnURLPrefix, final String returnURLPostfix,
102 final boolean forceInteractiveAuthentication) throws RemoteException {
103
104
105 MessageContext messageContext = MessageContext.getCurrentContext();
106 String servicePrincipal = messageContext.getUsername();
107
108 String urlPrefix = null;
109 Session genericSession = messageContext.getSession();
110
111 if (genericSession instanceof AxisHttpSession) {
112 AxisHttpSession axisHttpSession = (AxisHttpSession) genericSession;
113 Properties properties = (Properties) axisHttpSession.getRep().getServletContext().getAttribute(
114 "no.feide.moria.web.config");
115 urlPrefix = (properties.getProperty(RequestUtil.PROP_LOGIN_URL_PREFIX) + "?"
116 + properties.getProperty(RequestUtil.PROP_LOGIN_TICKET_PARAM) + "=");
117 }
118
119 try {
120 return urlPrefix
121 + MoriaController.initiateAuthentication(attributes, returnURLPrefix, returnURLPostfix,
122 forceInteractiveAuthentication, servicePrincipal);
123 } catch (AuthorizationException ae) {
124 messageLogger.logWarn(AUTHZ_EX_MSG + servicePrincipal, ae);
125 throw new RemoteException(ae.getMessage());
126 } catch (IllegalInputException iie) {
127 messageLogger.logWarn(ILLEGAL_INPUT_EX_MSG + servicePrincipal, iie);
128 throw new RemoteException(iie.getMessage());
129 } catch (InoperableStateException ise) {
130 messageLogger.logCritical(INOP_STATE_EX_MSG + servicePrincipal, ise);
131 throw new RemoteException(ise.getMessage());
132 }
133 }
134
135 /***
136 * Performs direct non-interactive authentication.
137 *
138 * A redirect- and html-less login method. Only to be used in
139 * special cases where the client for some reason does not
140 * support the standard login procedure. Inherently insecure as
141 * the service will have knowledge of the plaintext password.
142 *
143 * @param attributes
144 * The attributes the service wants returned on login.
145 * @param username
146 * The user name of the user to be authenticated.
147 * @param password
148 * The password of the user to be authenticated.
149 * @return Array of attributes as requested.
150 * @throws RemoteException
151 * If anything fails during the call.
152 * @see no.feide.moria.webservices.v2_0.Authentication#directNonInteractiveAuthentication(java.lang.String[],
153 * java.lang.String, java.lang.String)
154 */
155 public Attribute[] directNonInteractiveAuthentication(final String[] attributes, final String username, final String password)
156 throws RemoteException {
157
158
159 MessageContext messageContext = MessageContext.getCurrentContext();
160 String servicePrincipal = messageContext.getUsername();
161
162 try {
163 Map returnAttributes = MoriaController.directNonInteractiveAuthentication(attributes, username, password,
164 servicePrincipal);
165 return mapToAttributeArray(returnAttributes, null);
166 } catch (AuthenticationException ae) {
167 messageLogger.logWarn(AUTHN_EX_MSG + servicePrincipal, ae);
168 throw new RemoteException(ae.getMessage());
169 } catch (AuthorizationException ae) {
170 messageLogger.logWarn(AUTHZ_EX_MSG + servicePrincipal, ae);
171 throw new RemoteException(ae.getMessage());
172 } catch (DirectoryUnavailableException due) {
173 messageLogger.logWarn(DIR_UNAV_EX_MSG + servicePrincipal, due);
174 throw new RemoteException(due.getMessage());
175 } catch (IllegalInputException iie) {
176 messageLogger.logWarn(ILLEGAL_INPUT_EX_MSG + servicePrincipal, iie);
177 throw new RemoteException(iie.getMessage());
178 } catch (InoperableStateException ise) {
179 messageLogger.logCritical(INOP_STATE_EX_MSG + servicePrincipal, ise);
180 throw new RemoteException(ise.getMessage());
181 }
182 }
183
184 /***
185 * Gets user attributes.
186 *
187 * Called by the service when the user returns after a successful
188 * login.
189 *
190 * @param serviceTicket
191 * The ticket included in the return request issued by the client.
192 * @return Array of attributes as requested in initiateAuthentication.
193 * @throws RemoteException
194 * If anything fails during the call.
195 * @see no.feide.moria.webservices.v2_0.Authentication#getUserAttributes(java.lang.String)
196 */
197 public Attribute[] getUserAttributes(final String serviceTicket) throws RemoteException {
198
199
200 MessageContext messageContext = MessageContext.getCurrentContext();
201 String servicePrincipal = messageContext.getUsername();
202
203 try {
204 Map returnAttributes = MoriaController.getUserAttributes(serviceTicket, servicePrincipal);
205
206
207 if (messageLogger.isEnabledFor(Level.DEBUG)) {
208 String attributeNames = "";
209 Set keySet = returnAttributes.keySet();
210 if (keySet != null) {
211 Iterator i = keySet.iterator();
212 while (i.hasNext())
213 attributeNames = attributeNames + i.next() + ", ";
214 if (attributeNames.length() > 0)
215 attributeNames = attributeNames.substring(0, attributeNames.length() - 2);
216 }
217 messageLogger.logDebug("Returned attributes [" + attributeNames + "] to service '" + servicePrincipal + "'", serviceTicket);
218 }
219
220 return mapToAttributeArray(returnAttributes, serviceTicket);
221 } catch (IllegalInputException iie) {
222 messageLogger.logWarn(ILLEGAL_INPUT_EX_MSG + servicePrincipal, iie);
223 throw new RemoteException(iie.getMessage());
224 } catch (InoperableStateException ise) {
225 messageLogger.logCritical(INOP_STATE_EX_MSG + servicePrincipal, ise);
226 throw new RemoteException(ise.getMessage());
227 } catch (UnknownTicketException ute) {
228 messageLogger.logWarn(UNKNOWN_TICKET_EX_MSG + servicePrincipal, ute);
229 throw new RemoteException(ute.getMessage());
230 } catch (AuthorizationException e) {
231 messageLogger.logWarn("Service not allowed for organization. Throwing RemoteException to service: ", e);
232 throw new RemoteException(e.getMessage());
233 }
234 }
235
236 /***
237 * Verifies the existence of a given user in the underlying directories.
238 *
239 * @param username
240 * The username to be validated.
241 * @return true if the user is found.
242 * @throws RemoteException
243 * If anything fails during the call.
244 * @see no.feide.moria.webservices.v2_0.Authentication#verifyUserExistence(java.lang.String)
245 */
246 public boolean verifyUserExistence(final String username) throws RemoteException {
247
248
249 MessageContext messageContext = MessageContext.getCurrentContext();
250 String servicePrincipal = messageContext.getUsername();
251
252 try {
253 return MoriaController.verifyUserExistence(username, servicePrincipal);
254 } catch (AuthorizationException ae) {
255 messageLogger.logWarn(AUTHZ_EX_MSG + servicePrincipal, ae);
256 throw new RemoteException(ae.getMessage());
257 } catch (DirectoryUnavailableException due) {
258 messageLogger.logWarn(DIR_UNAV_EX_MSG + servicePrincipal, due);
259 throw new RemoteException(due.getMessage());
260 } catch (IllegalInputException iie) {
261 messageLogger.logWarn(ILLEGAL_INPUT_EX_MSG + servicePrincipal, iie);
262 throw new RemoteException(iie.getMessage());
263 } catch (InoperableStateException ise) {
264 messageLogger.logCritical(INOP_STATE_EX_MSG + servicePrincipal, ise);
265 throw new RemoteException(ise.getMessage());
266 }
267 }
268
269 /***
270 * Converts a Map to an array of Attributes.
271 * Utility method.
272 *
273 * @param map
274 * The Map to be converted.
275 * @param activeTicketId
276 * Optional variable for logging purposes.
277 * @return Array of attribute objects.
278 */
279 private Attribute[] mapToAttributeArray(final Map map, final String activeTicketId) {
280
281
282 Iterator iterator = map.keySet().iterator();
283
284
285 List attributeList = new ArrayList();
286
287
288 while (iterator.hasNext()) {
289 Object key = iterator.next();
290 Object value = map.get(key);
291
292 Attribute attribute = new Attribute();
293
294
295 if (key instanceof String) {
296
297 attribute.setName((String) key);
298
299
300
301
302
303 if (value instanceof String) {
304
305 attribute.setValues(new String[] {(String) value});
306 attributeList.add(attribute);
307 } else if (value instanceof String[]) {
308 attribute.setValues((String[]) value);
309 attributeList.add(attribute);
310 } else if (value != null) {
311 messageLogger.logInfo("Attribute value not String or String[]. Entry not added to Attribute[]. ",
312 activeTicketId);
313 }
314 } else if (value != null) {
315 messageLogger.logInfo("Attribute key not String. Entry not added to Attribute[]", activeTicketId);
316 }
317 }
318 return (Attribute[]) attributeList.toArray(new Attribute[] {});
319 }
320 }