1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package no.feide.mellon.demo;
22
23 import javax.servlet.ServletException;
24 import javax.servlet.http.HttpServlet;
25 import javax.servlet.http.HttpServletRequest;
26 import javax.servlet.http.HttpServletResponse;
27
28 import no.feide.mellon.Moria;
29 import no.feide.mellon.MoriaException;
30
31 import java.io.File;
32 import java.io.FileInputStream;
33 import java.io.IOException;
34 import java.io.PrintWriter;
35 import java.net.MalformedURLException;
36 import java.util.ArrayList;
37 import java.util.HashMap;
38 import java.util.Iterator;
39 import java.util.Properties;
40 import java.util.StringTokenizer;
41
42 /***
43 * This is a simple demonstration servlet, primarily intended as a code example
44 * of how to access the Moria SOAP interface. <br>
45 * <br>
46 * This implementation uses the Mellon2 API. <br>
47 * <br>
48 * The servlet works as follows: <br>
49 * <ol>
50 * <li>If the HTTP request does not contain a service ticket (found by checking
51 * URL parameter <code>PARAM_TICKET</code>) the user is redirected to a Moria
52 * instance (given by <code>SERVICE_ENDPOINT</code>) for authentication. <br>
53 * This is done using the <code>initiateAuthentication(...)</code> method to
54 * receive a correct redirect URL to the Moria instance.
55 * <li>Once the user has gone through a successful authentication, he or she is
56 * redirected back to this servlet, now with the previously missing service
57 * ticket.
58 * <li>The servlet then attempts to read the attributes requested by the
59 * earlier use of <code>initiateAuthentication(...)</code>, by using
60 * <code>getUserAttributes(...)</code> with the given service ticket.
61 * <li>If successful, the attributes and their values are then displayed.
62 * </ol>
63 * A few other points to note:
64 * <ul>
65 * <li>The attributes requested are given by <code>ATTRIBUTE_REQUEST</code>.
66 * <li>This servlet, as a Moria client service, authenticates itself to Moria
67 * using the username/password combination given by <code>CLIENT_USERNAME</code>
68 * and <code>CLIENT_PASSWORD</code>.
69 * <li>The Moria service instance used is given by
70 * <code>SERVICE_ENDPOINT</code>.
71 * </ul>
72 * @see no.feide.moria.webservices.v2_1.AuthenticationSoapBindingStub#initiateAuthentication(String[],
73 * String, String, boolean)
74 * @see no.feide.moria.webservices.v2_1.AuthenticationSoapBindingStub#getUserAttributes(String)
75 */
76 public class Moria1DemoServlet
77 extends HttpServlet {
78
79 /***
80 * Serial version UID.
81 */
82 private static final long serialVersionUID = 855155044401873910L;
83
84 /***
85 * The system property giving the configuration file name for the Demo
86 * servlet. <br>
87 * <br>
88 * Current value is <code>"no.feide.mellon.demo.config"</code>.
89 */
90 private static final String CONFIG_FILENAME = "no.feide.mellon.demo.config";
91
92 /***
93 * The service endpoint. <br>
94 * <br>
95 * Current value is <code>"no.feide.mellon.demo.serviceEndpoint"</code>.
96 */
97 private static final String CONFIG_SERVICE_ENDPOINT = "no.feide.mellon.demo.serviceEndpoint";
98
99 /***
100 * A comma-separated list of attributes requested by the main service. <br>
101 * <br>
102 * Current value is
103 * <code>"no.feide.mellon.demo.master.attributeRequest"</code>.
104 */
105 private static final String CONFIG_MASTER_ATTRIBUTE_REQUEST = "no.feide.mellon.demo.master.attributeRequest";
106
107 /***
108 * The username used by DemoServlet to access Moria2 as a main service. <br>
109 * <br>
110 * Current value is <code>"no.feide.mellon.demo.master.username"</code>.
111 */
112 private static final String CONFIG_MASTER_USERNAME = "no.feide.mellon.demo.master.username";
113
114 /***
115 * The password used by DemoServlet to access Moria2 as a main service. <br>
116 * <br>
117 * Current value is <code>"no.feide.mellon.demo.master.password"</code>.
118 */
119 private static final String CONFIG_MASTER_PASSWORD = "no.feide.mellon.demo.master.password";
120
121 /***
122 * The URL that the user should be redirected to in order to complete
123 * logout. <br>
124 * <br>
125 * Current value is <code>"no.feide.mellon.demo.logout.url"</code>.
126 */
127 private static final String CONFIG_LOGOUT_URL = "no.feide.mellon.demo.logout.url";
128
129 /***
130 * The truststore filename used when accepting Moria's certificate. If not
131 * set, no custom truststore will be used. <br>
132 * <br>
133 * Current value is <code>"no.feide.mellon.demo.trustStore"</code>.
134 */
135 private static final String CONFIG_TRUSTSTORE = "no.feide.mellon.demo.trustStore";
136
137 /***
138 * The truststore password used in conjunction with
139 * <code>CONFIG_TRUSTSTORE</code>.<br>
140 * <br>
141 * Current value is <code>"no.feide.mellon.demo.trustStorePassword"</code>.
142 */
143 private static final String CONFIG_TRUSTSTORE_PASSWORD = "no.feide.mellon.demo.trustStorePassword";
144
145 /***
146 * Required parameters.
147 */
148 private static final String[] REQUIRED_PARAMETERS = {
149 CONFIG_SERVICE_ENDPOINT,
150 CONFIG_MASTER_USERNAME,
151 CONFIG_MASTER_PASSWORD,
152 CONFIG_LOGOUT_URL};
153
154 /***
155 * Name of the URL parameter used to retrieve the Moria service ticket. <br>
156 * <br>
157 * Current value is <code>"ticket"</code>.
158 */
159 private static final String PARAM_TICKET = "ticket";
160
161
162 /***
163 * Initialization. Will set the truststore used by the servlet when trusting
164 * the Moria instance's certificate, if it is not covered by the default
165 * truststore.
166 * @throws ServletException
167 * Never.
168 */
169 public final void init() throws ServletException {
170
171
172 final Properties config = getConfig();
173 System.setProperty("javax.net.ssl.trustStore", config.getProperty(CONFIG_TRUSTSTORE));
174 System.setProperty("javax.net.ssl.trustStorePassword", config.getProperty(CONFIG_TRUSTSTORE_PASSWORD));
175
176 }
177
178
179 /***
180 * Handles the GET requests.
181 * @param request
182 * The HTTP request object. If it contains a request parameter
183 * <i>moriaID </i>, the request's attribute <i>attributes </i>
184 * will be filled with the attributes contained in the session
185 * given by <i>moriaID </i>.
186 * @param response
187 * The HTTP response object.
188 * @throws java.io.IOException
189 * If an input or output error is detected when the servlet
190 * handles the GET request.
191 * @throws javax.servlet.ServletException
192 * If the request for the GET could not be handled.
193 * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest,
194 * javax.servlet.http.HttpServletResponse)
195 */
196 public final void doGet(final HttpServletRequest request,
197 final HttpServletResponse response) throws IOException,
198 ServletException {
199
200
201 try {
202
203
204 final Properties config = getConfig();
205
206
207 if (request.getParameter("logout") != null) {
208
209
210 response.sendRedirect(config.getProperty(CONFIG_LOGOUT_URL));
211 }
212
213
214 System.setProperty(Moria.SERVICE_ENDPOINT_PROPERTY, config.getProperty(CONFIG_SERVICE_ENDPOINT));
215 System.setProperty(Moria.CLIENT_USERNAME, config.getProperty(CONFIG_MASTER_USERNAME));
216 System.setProperty(Moria.CLIENT_PASSWORD, config.getProperty(CONFIG_MASTER_PASSWORD));
217 Moria service = Moria.getInstance();
218
219
220 final String ticket = request.getParameter(PARAM_TICKET);
221 if (ticket == null) {
222
223
224 String redirectURL = service.requestSession(convert(config.getProperty(CONFIG_MASTER_ATTRIBUTE_REQUEST)), request.getRequestURL().toString() + "?" + PARAM_TICKET + "=", "", false);
225 response.sendRedirect(redirectURL);
226
227 } else {
228
229
230 response.setContentType("text/html");
231 PrintWriter out = response.getWriter();
232 out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01" + "Transitional//EN\">\n");
233 out.println("<html><head><title>Moria Demo Service</title></head><body>");
234 out.println("<h1 align=\"center\">Authentication successful</h1>");
235 out.println("<p align=\"center\"><a href=\"" + config.getProperty(CONFIG_LOGOUT_URL) + "\">Logout</a></p>");
236 out.println("<i>System '" + config.getProperty(CONFIG_MASTER_USERNAME) + "':</i>");
237
238
239
240 HashMap attributes = service.getAttributes(ticket);
241 out.println("<table align=\"center\"><tr><td><b>Attribute Name</b></td><td><b>Attribute Value(s)</b></td></tr>");
242 Iterator i = attributes.keySet().iterator();
243 String name = null;
244 while (i.hasNext()) {
245
246
247 name = (String) i.next();
248 out.println("<tr><td>" + name + "</td>");
249 String[] values = (String[]) attributes.get(name);
250 for (int j = 0; j < values.length; j++) {
251 if (j > 0)
252 out.println("<tr><td></td>");
253 out.println("<td>" + values[j] + "</td></tr>");
254 }
255
256 }
257 out.println("</table>");
258
259
260 out.println("</html></body>");
261
262 }
263
264 } catch (MoriaException e) {
265 System.err.println("MoriaException caugth: " + e);
266 throw new ServletException(e);
267 } catch (MalformedURLException e) {
268 System.err.println("MalformedURLException caught: " + e);
269 throw new ServletException(e);
270 }
271
272 }
273
274
275 /***
276 * Read configuration from the file given by <code>CONFIG_FILENAME</code>
277 * and check that all required properties are given.
278 * @throws IllegalStateException
279 * If the required property <code>CONFIG_FILENAME</code> is
280 * not set, or if the file given by this property could not be
281 * read.
282 * @return Configuration properties from file.
283 * @see #REQUIRED_PARAMETERS
284 */
285 private Properties getConfig() throws IllegalStateException {
286
287
288 final String configFile = System.getProperty(CONFIG_FILENAME);
289 if (configFile == null) { throw new IllegalStateException("Required base property '" + CONFIG_FILENAME + "' not set"); }
290 Properties config = new Properties();
291 try {
292 config.load(new FileInputStream(new File(configFile)));
293 } catch (IOException e) {
294 throw new IllegalStateException("Unable to read configuration from " + configFile);
295 }
296
297
298 for (int i = 0; i < REQUIRED_PARAMETERS.length; i++) {
299 String parvalue = config.getProperty(REQUIRED_PARAMETERS[i]);
300 if ((parvalue == null) || (parvalue.equals(""))) { throw new IllegalStateException("Required parameter '" + REQUIRED_PARAMETERS[i] + "' not set in '" + configFile + "'"); }
301 }
302 return config;
303
304 }
305
306
307 /***
308 * Convert a comma-separated list into an array.
309 * @param commaSeparatedList
310 * A comma-separated list of elements. May be <code>null</code>
311 * or an empty string.
312 * @return <code>commaSeparatedList</code> as a string array. Will always
313 * return an empty array if <code>commaSeparatedList</code> is
314 * <code>null</code> or an empty string.
315 */
316 private String[] convert(final String commaSeparatedList) {
317
318
319 if ((commaSeparatedList == null) || (commaSeparatedList.length() == 0))
320 return new String[] {};
321
322
323 ArrayList buffer = new ArrayList();
324 StringTokenizer tokenizer = new StringTokenizer(commaSeparatedList, ",");
325 while (tokenizer.hasMoreTokens())
326 buffer.add(tokenizer.nextToken());
327 return (String[]) buffer.toArray(new String[] {});
328
329 }
330
331 }