Statistics
| Branch: | Tag: | Revision:

root / src / gr / ebs / gss / server / Login.java @ d0d4d0f5

History | View | Annotate | Download (13.2 kB)

1 14ad7326 pastith
/*
2 14ad7326 pastith
 * Copyright 2008, 2009 Electronic Business Systems Ltd.
3 14ad7326 pastith
 *
4 14ad7326 pastith
 * This file is part of GSS.
5 14ad7326 pastith
 *
6 14ad7326 pastith
 * GSS is free software: you can redistribute it and/or modify
7 14ad7326 pastith
 * it under the terms of the GNU General Public License as published by
8 14ad7326 pastith
 * the Free Software Foundation, either version 3 of the License, or
9 14ad7326 pastith
 * (at your option) any later version.
10 14ad7326 pastith
 *
11 14ad7326 pastith
 * GSS is distributed in the hope that it will be useful,
12 14ad7326 pastith
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 14ad7326 pastith
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 14ad7326 pastith
 * GNU General Public License for more details.
15 14ad7326 pastith
 *
16 14ad7326 pastith
 * You should have received a copy of the GNU General Public License
17 14ad7326 pastith
 * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
18 14ad7326 pastith
 */
19 14ad7326 pastith
package gr.ebs.gss.server;
20 14ad7326 pastith
21 bde4eafb pastith
import static gr.ebs.gss.server.configuration.GSSConfigurationFactory.getConfiguration;
22 14ad7326 pastith
import gr.ebs.gss.client.exceptions.DuplicateNameException;
23 14ad7326 pastith
import gr.ebs.gss.client.exceptions.ObjectNotFoundException;
24 14ad7326 pastith
import gr.ebs.gss.client.exceptions.RpcException;
25 14ad7326 pastith
import gr.ebs.gss.server.domain.Nonce;
26 14ad7326 pastith
import gr.ebs.gss.server.domain.User;
27 14ad7326 pastith
import gr.ebs.gss.server.ejb.ExternalAPI;
28 14ad7326 pastith
29 14ad7326 pastith
import java.io.IOException;
30 14ad7326 pastith
import java.io.PrintWriter;
31 4b7228e1 pastith
import java.io.UnsupportedEncodingException;
32 144fe6ce Panagiotis Astithas
import java.net.URI;
33 144fe6ce Panagiotis Astithas
import java.net.URISyntaxException;
34 14ad7326 pastith
import java.net.URLEncoder;
35 cbe69def pastith
import java.util.Formatter;
36 14ad7326 pastith
37 14ad7326 pastith
import javax.naming.Context;
38 14ad7326 pastith
import javax.naming.InitialContext;
39 14ad7326 pastith
import javax.naming.NamingException;
40 14ad7326 pastith
import javax.rmi.PortableRemoteObject;
41 14ad7326 pastith
import javax.servlet.http.Cookie;
42 14ad7326 pastith
import javax.servlet.http.HttpServlet;
43 14ad7326 pastith
import javax.servlet.http.HttpServletRequest;
44 14ad7326 pastith
import javax.servlet.http.HttpServletResponse;
45 14ad7326 pastith
46 14ad7326 pastith
import org.apache.commons.codec.binary.Base64;
47 14ad7326 pastith
import org.apache.commons.logging.Log;
48 14ad7326 pastith
import org.apache.commons.logging.LogFactory;
49 14ad7326 pastith
50 14ad7326 pastith
/**
51 14ad7326 pastith
 * The servlet that handles user logins.
52 14ad7326 pastith
 *
53 14ad7326 pastith
 * @author past
54 14ad7326 pastith
 */
55 14ad7326 pastith
public class Login extends HttpServlet {
56 14ad7326 pastith
        /**
57 14ad7326 pastith
         * The request parameter name for the nonce.
58 14ad7326 pastith
         */
59 14ad7326 pastith
        private static final String NONCE_PARAM = "nonce";
60 14ad7326 pastith
61 14ad7326 pastith
        /**
62 14ad7326 pastith
         * The request parameter name for the URL to redirect
63 14ad7326 pastith
         * to after authentication.
64 14ad7326 pastith
         */
65 14ad7326 pastith
        private static final String NEXT_URL_PARAM = "next";
66 14ad7326 pastith
67 14ad7326 pastith
        /**
68 14ad7326 pastith
         * The serial version UID of the class.
69 14ad7326 pastith
         */
70 14ad7326 pastith
        private static final long serialVersionUID = 1L;
71 14ad7326 pastith
72 14ad7326 pastith
        /**
73 14ad7326 pastith
         * The name of the authentication cookie.
74 14ad7326 pastith
         */
75 14ad7326 pastith
        private static final String AUTH_COOKIE = "_gss_a";
76 14ad7326 pastith
77 14ad7326 pastith
        /**
78 14ad7326 pastith
         * The separator character for the authentication cookie.
79 14ad7326 pastith
         */
80 14ad7326 pastith
        private static final char COOKIE_SEPARATOR = '|';
81 14ad7326 pastith
82 14ad7326 pastith
        /**
83 3ef7b691 Dimitris Routsis
         * The name of the the webdav cookie.
84 3ef7b691 Dimitris Routsis
         */
85 3ef7b691 Dimitris Routsis
        public static final String WEBDAV_COOKIE = "_gss_wd";
86 3ef7b691 Dimitris Routsis
87 3ef7b691 Dimitris Routsis
        /**
88 14ad7326 pastith
         * The logger.
89 14ad7326 pastith
         */
90 14ad7326 pastith
        private static Log logger = LogFactory.getLog(Login.class);
91 14ad7326 pastith
92 14ad7326 pastith
        /**
93 14ad7326 pastith
         * A helper method that retrieves a reference to the ExternalAPI bean and
94 14ad7326 pastith
         * stores it for future use.
95 14ad7326 pastith
         *
96 14ad7326 pastith
         * @return an ExternalAPI instance
97 14ad7326 pastith
         * @throws RpcException in case an error occurs
98 14ad7326 pastith
         */
99 14ad7326 pastith
        private ExternalAPI getService() throws RpcException {
100 14ad7326 pastith
                try {
101 14ad7326 pastith
                        final Context ctx = new InitialContext();
102 bde4eafb pastith
                        final Object ref = ctx.lookup(getConfiguration().getString("externalApiPath"));
103 14ad7326 pastith
                        return (ExternalAPI) PortableRemoteObject.narrow(ref, ExternalAPI.class);
104 14ad7326 pastith
                } catch (final NamingException e) {
105 14ad7326 pastith
                        logger.error("Unable to retrieve the ExternalAPI EJB", e);
106 14ad7326 pastith
                        throw new RpcException("An error occurred while contacting the naming service");
107 14ad7326 pastith
                }
108 14ad7326 pastith
        }
109 14ad7326 pastith
110 8270b533 pastith
        /**
111 8270b533 pastith
         * Return the name of the service.
112 8270b533 pastith
         */
113 8270b533 pastith
        private String getServiceName() {
114 bde4eafb pastith
                return getConfiguration().getString("serviceName", "GSS");
115 8270b533 pastith
        }
116 8270b533 pastith
117 14ad7326 pastith
        @Override
118 14ad7326 pastith
        public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
119 14ad7326 pastith
                // Fetch the next URL to display, if any.
120 14ad7326 pastith
                String nextUrl = request.getParameter(NEXT_URL_PARAM);
121 14ad7326 pastith
                // Fetch the supplied nonce, if any.
122 14ad7326 pastith
                String nonce = request.getParameter(NONCE_PARAM);
123 91fb506c pastith
                String[] attrs = new String[] {"REMOTE_USER", "HTTP_SHIB_INETORGPERSON_DISPLAYNAME",
124 91fb506c pastith
                                        "HTTP_SHIB_INETORGPERSON_GIVENNAME", "HTTP_SHIB_PERSON_COMMONNAME",
125 91fb506c pastith
                                        "HTTP_SHIB_PERSON_SURNAME", "HTTP_SHIB_INETORGPERSON_MAIL",
126 91fb506c pastith
                                        "HTTP_SHIB_EP_UNSCOPEDAFFILIATION"};
127 91fb506c pastith
                StringBuilder buf = new StringBuilder("Shibboleth Attributes\n");
128 91fb506c pastith
                for (String attr: attrs)
129 91fb506c pastith
                        buf.append(attr+": ").append(request.getAttribute(attr)).append('\n');
130 91fb506c pastith
                logger.info(buf);
131 5005b2b6 pastith
                if (logger.isDebugEnabled()) {
132 5005b2b6 pastith
                        buf = new StringBuilder("Shibboleth Attributes as bytes\n");
133 5005b2b6 pastith
                        for (String attr: attrs)
134 5005b2b6 pastith
                                if (request.getAttribute(attr) != null)
135 cbe69def pastith
                                        buf.append(attr+": ").append(getHexString(request.getAttribute(attr).toString().getBytes("UTF-8"))).append('\n');
136 5005b2b6 pastith
                        logger.debug(buf);
137 5005b2b6 pastith
                }
138 14ad7326 pastith
                User user = null;
139 14ad7326 pastith
                response.setContentType("text/html");
140 14ad7326 pastith
                Object usernameAttr = request.getAttribute("REMOTE_USER");
141 40347b0e pastith
                Object nameAttr = request.getAttribute("HTTP_SHIB_INETORGPERSON_DISPLAYNAME");
142 91fb506c pastith
                Object givennameAttr = request.getAttribute("HTTP_SHIB_INETORGPERSON_GIVENNAME"); // Multi-valued
143 8be15957 pastith
                Object cnAttr = request.getAttribute("HTTP_SHIB_PERSON_COMMONNAME"); // Multi-valued
144 8be15957 pastith
                Object snAttr = request.getAttribute("HTTP_SHIB_PERSON_SURNAME"); // Multi-valued
145 8be15957 pastith
                Object mailAttr = request.getAttribute("HTTP_SHIB_INETORGPERSON_MAIL"); // Multi-valued
146 8be15957 pastith
                Object userclassAttr = request.getAttribute("HTTP_SHIB_EP_UNSCOPEDAFFILIATION"); // Multi-valued
147 c917374b Panagiotis Astithas
                // Use a configured test username if found, as a shortcut for development deployments.
148 c917374b Panagiotis Astithas
                if (getConfiguration().getString("testUsername") != null)
149 c917374b Panagiotis Astithas
                        usernameAttr = getConfiguration().getString("testUsername");
150 14ad7326 pastith
                if (usernameAttr == null) {
151 11af52e2 pastith
                        String authErrorUrl = "authenticationError.jsp";
152 11af52e2 pastith
                        authErrorUrl += "?name=" + (nameAttr==null? "-": nameAttr.toString());
153 11af52e2 pastith
                        authErrorUrl += "&givenname=" + (givennameAttr==null? "-": givennameAttr.toString());
154 11af52e2 pastith
                        authErrorUrl += "&sn=" + (snAttr==null? "-": snAttr.toString());
155 11af52e2 pastith
                        authErrorUrl += "&cn=" + (cnAttr==null? "-": cnAttr.toString());
156 11af52e2 pastith
                        authErrorUrl += "&mail=" + (mailAttr==null? "-": mailAttr.toString());
157 11af52e2 pastith
                        authErrorUrl += "&userclass=" + (userclassAttr==null? "-": userclassAttr.toString());
158 11af52e2 pastith
                        response.sendRedirect(authErrorUrl);
159 14ad7326 pastith
                        return;
160 14ad7326 pastith
                }
161 4b7228e1 pastith
                String username = decodeAttribute(usernameAttr);
162 1bd363d7 pastith
                String name;
163 21daa3af pastith
                if (nameAttr != null && !nameAttr.toString().isEmpty())
164 4b7228e1 pastith
                        name = decodeAttribute(nameAttr);
165 91fb506c pastith
                else if (cnAttr != null && !cnAttr.toString().isEmpty()) {
166 4b7228e1 pastith
                        name = decodeAttribute(cnAttr);
167 91fb506c pastith
                        if (name.indexOf(';') != -1)
168 91fb506c pastith
                                name = name.substring(0, name.indexOf(';'));
169 91fb506c pastith
                } else if (givennameAttr != null && snAttr != null && !givennameAttr.toString().isEmpty() && !snAttr.toString().isEmpty()) {
170 4b7228e1 pastith
                        String givenname = decodeAttribute(givennameAttr);
171 91fb506c pastith
                        if (givenname.indexOf(';') != -1)
172 91fb506c pastith
                                givenname = givenname.substring(0, givenname.indexOf(';'));
173 4b7228e1 pastith
                        String sn = decodeAttribute(snAttr);
174 91fb506c pastith
                        if (sn.indexOf(';') != -1)
175 91fb506c pastith
                                sn = sn.substring(0, sn.indexOf(';'));
176 91fb506c pastith
                        name = givenname + ' ' + sn;
177 91fb506c pastith
                } else if (givennameAttr == null && snAttr != null && !snAttr.toString().isEmpty()) {
178 4b7228e1 pastith
                        name = decodeAttribute(snAttr);
179 91fb506c pastith
                        if (name.indexOf(';') != -1)
180 91fb506c pastith
                                name = name.substring(0, name.indexOf(';'));
181 91fb506c pastith
                } else
182 1bd363d7 pastith
                        name = username;
183 14ad7326 pastith
                String mail = mailAttr != null ? mailAttr.toString() : username;
184 91fb506c pastith
                if (mail.indexOf(';') != -1)
185 91fb506c pastith
                        mail = mail.substring(0, mail.indexOf(';'));
186 14ad7326 pastith
                // XXX we are not using the user class currently
187 14ad7326 pastith
                String userclass = userclassAttr != null ? userclassAttr.toString() : "";
188 91fb506c pastith
                if (userclass.indexOf(';') != -1)
189 91fb506c pastith
                        userclass = userclass.substring(0, userclass.indexOf(';'));
190 14ad7326 pastith
                try {
191 14ad7326 pastith
                        user = getService().findUser(username);
192 14ad7326 pastith
                        if (user == null)
193 14ad7326 pastith
                                user = getService().createUser(username, name, mail);
194 0a4b8f82 pastith
                        if (!user.hasAcceptedPolicy()) {
195 0a4b8f82 pastith
                                String policyUrl = "policy.jsp";
196 0a4b8f82 pastith
                                if (request.getQueryString() != null)
197 0a4b8f82 pastith
                                        policyUrl += "?user=" + username + "&" + request.getQueryString();
198 0a4b8f82 pastith
                                response.sendRedirect(policyUrl);
199 0a4b8f82 pastith
                                return;
200 0a4b8f82 pastith
                        }
201 14ad7326 pastith
                        // Update the user name and e-mail if modified.
202 503040ef Dimitris Routsis
                        boolean update = false;
203 503040ef Dimitris Routsis
                        if (!user.getName().equals(name)) {
204 503040ef Dimitris Routsis
                                user.setName(name);
205 503040ef Dimitris Routsis
                                update = true;
206 503040ef Dimitris Routsis
                        }
207 503040ef Dimitris Routsis
                        if (!user.getEmail().equals(mail)) {
208 503040ef Dimitris Routsis
                                user.setEmail(mail);
209 503040ef Dimitris Routsis
                                update = true;
210 503040ef Dimitris Routsis
                        }
211 14ad7326 pastith
                        if (user.getAuthToken() == null)
212 14ad7326 pastith
                                user = getService().updateUserToken(user.getId());
213 503040ef Dimitris Routsis
                        // Set WebDAV password to token if it's never been set.
214 503040ef Dimitris Routsis
                        if (user.getWebDAVPassword()==null || user.getWebDAVPassword().length()==0) {
215 503040ef Dimitris Routsis
                                String tokenEncoded = new String(Base64.encodeBase64(user.getAuthToken()), "US-ASCII");
216 503040ef Dimitris Routsis
                                user.setWebDAVPassword(tokenEncoded);
217 503040ef Dimitris Routsis
                                update = true;
218 503040ef Dimitris Routsis
                        }
219 503040ef Dimitris Routsis
                        if (update)
220 503040ef Dimitris Routsis
                                getService().updateUser(user);
221 14ad7326 pastith
                } catch (RpcException e) {
222 14ad7326 pastith
                        String error = "An error occurred while communicating with the service";
223 14ad7326 pastith
                        logger.error(error, e);
224 14ad7326 pastith
                        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error);
225 14ad7326 pastith
                        return;
226 14ad7326 pastith
                } catch (DuplicateNameException e) {
227 14ad7326 pastith
                        String error = "User with username " + username + " already exists";
228 14ad7326 pastith
                        logger.error(error, e);
229 14ad7326 pastith
                        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error);
230 14ad7326 pastith
                        return;
231 14ad7326 pastith
                } catch (ObjectNotFoundException e) {
232 14ad7326 pastith
                        String error = "No username was provided";
233 14ad7326 pastith
                        logger.error(error, e);
234 14ad7326 pastith
                        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error);
235 14ad7326 pastith
                        return;
236 14ad7326 pastith
                }
237 14ad7326 pastith
                String tokenEncoded = new String(Base64.encodeBase64(user.getAuthToken()), "US-ASCII");
238 14ad7326 pastith
                String userEncoded = URLEncoder.encode(user.getUsername(), "US-ASCII");
239 14ad7326 pastith
                if (logger.isDebugEnabled())
240 14ad7326 pastith
                        logger.debug("user: "+userEncoded+" token: "+tokenEncoded);
241 739f501e Panagiotis Astithas
                if (nextUrl != null && !nextUrl.isEmpty()) {
242 144fe6ce Panagiotis Astithas
                        URI next;
243 144fe6ce Panagiotis Astithas
                        try {
244 144fe6ce Panagiotis Astithas
                                next = new URI(nextUrl);
245 144fe6ce Panagiotis Astithas
                        } catch (URISyntaxException e) {
246 144fe6ce Panagiotis Astithas
                                response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
247 144fe6ce Panagiotis Astithas
                                return;
248 144fe6ce Panagiotis Astithas
                        }
249 14ad7326 pastith
                        String domain = next.getHost();
250 14ad7326 pastith
                        String path = next.getPath();
251 14ad7326 pastith
                        Cookie cookie = new Cookie(AUTH_COOKIE, userEncoded + COOKIE_SEPARATOR +
252 14ad7326 pastith
                                                tokenEncoded);
253 14ad7326 pastith
                        cookie.setMaxAge(-1);
254 14ad7326 pastith
                        cookie.setDomain(domain);
255 14ad7326 pastith
                        cookie.setPath(path);
256 14ad7326 pastith
                    response.addCookie(cookie);
257 3ef7b691 Dimitris Routsis
                    cookie = new Cookie(WEBDAV_COOKIE, user.getWebDAVPassword());
258 3ef7b691 Dimitris Routsis
                        cookie.setMaxAge(-1);
259 3ef7b691 Dimitris Routsis
                        cookie.setDomain(domain);
260 3ef7b691 Dimitris Routsis
                        cookie.setPath(path);
261 3ef7b691 Dimitris Routsis
                    response.addCookie(cookie);
262 14ad7326 pastith
                    response.sendRedirect(nextUrl);
263 14ad7326 pastith
                } else if (nonce != null) {
264 d08fa1c0 pastith
                        nonce = URLEncoder.encode(nonce, "US-ASCII");
265 14ad7326 pastith
                        Nonce n = null;
266 14ad7326 pastith
                        try {
267 14ad7326 pastith
                                if (logger.isDebugEnabled())
268 14ad7326 pastith
                                        logger.debug("user: "+user.getId()+" nonce: "+nonce);
269 14ad7326 pastith
                                n = getService().getNonce(nonce, user.getId());
270 14ad7326 pastith
                        } catch (ObjectNotFoundException e) {
271 14ad7326 pastith
                            PrintWriter out = response.getWriter();
272 14ad7326 pastith
                            out.println("<HTML>");
273 8270b533 pastith
                            out.println("<HEAD><TITLE>" + getServiceName() + " Authentication</TITLE>" +
274 14ad7326 pastith
                                            "<LINK TYPE='text/css' REL='stylesheet' HREF='gss.css'></HEAD>");
275 14ad7326 pastith
                            out.println("<BODY><CENTER><P>");
276 14ad7326 pastith
                            out.println("The supplied nonce could not be found!");
277 14ad7326 pastith
                            out.println("</CENTER></BODY></HTML>");
278 14ad7326 pastith
                            return;
279 14ad7326 pastith
                        } catch (RpcException e) {
280 14ad7326 pastith
                                String error = "An error occurred while communicating with the service";
281 14ad7326 pastith
                                logger.error(error, e);
282 14ad7326 pastith
                                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error);
283 14ad7326 pastith
                                return;
284 14ad7326 pastith
                        }
285 14ad7326 pastith
                        try {
286 14ad7326 pastith
                                getService().activateUserNonce(user.getId(), nonce, n.getNonceExpiryDate());
287 14ad7326 pastith
                        } catch (ObjectNotFoundException e) {
288 14ad7326 pastith
                                String error = "Unable to find user";
289 14ad7326 pastith
                                logger.error(error, e);
290 14ad7326 pastith
                                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error);
291 14ad7326 pastith
                                return;
292 14ad7326 pastith
                        } catch (RpcException e) {
293 14ad7326 pastith
                                String error = "An error occurred while communicating with the service";
294 14ad7326 pastith
                                logger.error(error, e);
295 14ad7326 pastith
                                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error);
296 14ad7326 pastith
                                return;
297 14ad7326 pastith
                        }
298 14ad7326 pastith
                        try {
299 14ad7326 pastith
                                getService().removeNonce(n.getId());
300 14ad7326 pastith
                        } catch (ObjectNotFoundException e) {
301 14ad7326 pastith
                                logger.info("Nonce already removed!", e);
302 14ad7326 pastith
                        } catch (RpcException e) {
303 14ad7326 pastith
                                logger.warn("Could not remove nonce from data store", e);
304 14ad7326 pastith
                        }
305 14ad7326 pastith
                    PrintWriter out = response.getWriter();
306 14ad7326 pastith
                    out.println("<HTML>");
307 8270b533 pastith
                    out.println("<HEAD><TITLE>" + getServiceName() + " Authentication</TITLE>" +
308 14ad7326 pastith
                                    "<LINK TYPE='text/css' REL='stylesheet' HREF='gss.css'></HEAD>");
309 14ad7326 pastith
                    out.println("<BODY><CENTER><P>");
310 14ad7326 pastith
                    out.println("You can now close this browser window and return to your application.");
311 14ad7326 pastith
                    out.println("</CENTER></BODY></HTML>");
312 14ad7326 pastith
                } else {
313 14ad7326 pastith
                    PrintWriter out = response.getWriter();
314 14ad7326 pastith
                    out.println("<HTML>");
315 8270b533 pastith
                    out.println("<HEAD><TITLE>" + getServiceName() + " Authentication</TITLE>" +
316 14ad7326 pastith
                                    "<LINK TYPE='text/css' REL='stylesheet' HREF='gss.css'></HEAD>");
317 14ad7326 pastith
                    out.println("<BODY><CENTER><P>");
318 14ad7326 pastith
                    out.println("Name: " + user.getName() + "<BR>");
319 14ad7326 pastith
                    out.println("E-mail: " + user.getEmail() + "<BR><P>");
320 14ad7326 pastith
                    out.println("Username: " + user.getUsername() + "<BR>");
321 14ad7326 pastith
                    out.println("Athentication token: " + tokenEncoded + "<BR>");
322 14ad7326 pastith
                    out.println("</CENTER></BODY></HTML>");
323 14ad7326 pastith
                }
324 14ad7326 pastith
        }
325 cbe69def pastith
326 cbe69def pastith
        /**
327 4b7228e1 pastith
         * Decode the request attribute provided by the container to a UTF-8
328 4b7228e1 pastith
         * string, since GSS assumes all data to be encoded in UTF-8. The
329 4b7228e1 pastith
         * servlet container's encoding can be specified in gss.properties.
330 4b7228e1 pastith
         */
331 4b7228e1 pastith
        private String decodeAttribute(Object attribute) throws UnsupportedEncodingException {
332 4b7228e1 pastith
                return new String(attribute.toString().getBytes(getConfiguration().getString("requestAttributeEncoding")), "UTF-8");
333 4b7228e1 pastith
        }
334 4b7228e1 pastith
335 4b7228e1 pastith
        /**
336 cbe69def pastith
         * A helper method that converts a byte buffer to a printable list of
337 cbe69def pastith
         * hexadecimal numbers.
338 cbe69def pastith
         */
339 cbe69def pastith
        private String getHexString(byte[] buffer) {
340 cbe69def pastith
                StringBuilder sb = new StringBuilder();
341 cbe69def pastith
                Formatter formatter = new Formatter(sb);
342 cbe69def pastith
                for (int i=0; i<buffer.length; i++)
343 cbe69def pastith
                        formatter.format("0x%x, ", buffer[i]);
344 cbe69def pastith
                return sb.toString();
345 cbe69def pastith
        }
346 cbe69def pastith
347 14ad7326 pastith
}