Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (12.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 366f3f31 Natasa Kapravelou
import gr.ebs.gss.server.domain.UserLogin;
28 14ad7326 pastith
29 14ad7326 pastith
import java.io.IOException;
30 14ad7326 pastith
import java.io.PrintWriter;
31 144fe6ce Panagiotis Astithas
import java.net.URI;
32 144fe6ce Panagiotis Astithas
import java.net.URISyntaxException;
33 14ad7326 pastith
import java.net.URLEncoder;
34 125c5690 Panagiotis Astithas
import java.util.Date;
35 14ad7326 pastith
36 14ad7326 pastith
import javax.servlet.http.Cookie;
37 14ad7326 pastith
import javax.servlet.http.HttpServletRequest;
38 14ad7326 pastith
import javax.servlet.http.HttpServletResponse;
39 14ad7326 pastith
40 14ad7326 pastith
import org.apache.commons.codec.binary.Base64;
41 14ad7326 pastith
import org.apache.commons.logging.Log;
42 14ad7326 pastith
import org.apache.commons.logging.LogFactory;
43 14ad7326 pastith
44 14ad7326 pastith
/**
45 14ad7326 pastith
 * The servlet that handles user logins.
46 14ad7326 pastith
 *
47 14ad7326 pastith
 * @author past
48 14ad7326 pastith
 */
49 978061e3 Panagiotis Astithas
public class Login extends BaseServlet {
50 14ad7326 pastith
        /**
51 14ad7326 pastith
         * The request parameter name for the nonce.
52 14ad7326 pastith
         */
53 14ad7326 pastith
        private static final String NONCE_PARAM = "nonce";
54 14ad7326 pastith
55 14ad7326 pastith
        /**
56 14ad7326 pastith
         * The request parameter name for the URL to redirect
57 14ad7326 pastith
         * to after authentication.
58 14ad7326 pastith
         */
59 14ad7326 pastith
        private static final String NEXT_URL_PARAM = "next";
60 14ad7326 pastith
61 14ad7326 pastith
        /**
62 14ad7326 pastith
         * The serial version UID of the class.
63 14ad7326 pastith
         */
64 14ad7326 pastith
        private static final long serialVersionUID = 1L;
65 14ad7326 pastith
66 14ad7326 pastith
        /**
67 14ad7326 pastith
         * The name of the authentication cookie.
68 14ad7326 pastith
         */
69 a91ef7e8 Panagiotis Astithas
        public static final String AUTH_COOKIE = "_gss_a";
70 14ad7326 pastith
71 14ad7326 pastith
        /**
72 14ad7326 pastith
         * The separator character for the authentication cookie.
73 14ad7326 pastith
         */
74 a91ef7e8 Panagiotis Astithas
        public static final char COOKIE_SEPARATOR = '|';
75 14ad7326 pastith
76 14ad7326 pastith
        /**
77 3ef7b691 Dimitris Routsis
         * The name of the the webdav cookie.
78 3ef7b691 Dimitris Routsis
         */
79 3ef7b691 Dimitris Routsis
        public static final String WEBDAV_COOKIE = "_gss_wd";
80 3ef7b691 Dimitris Routsis
81 3ef7b691 Dimitris Routsis
        /**
82 14ad7326 pastith
         * The logger.
83 14ad7326 pastith
         */
84 14ad7326 pastith
        private static Log logger = LogFactory.getLog(Login.class);
85 14ad7326 pastith
86 14ad7326 pastith
        @Override
87 14ad7326 pastith
        public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
88 14ad7326 pastith
                // Fetch the next URL to display, if any.
89 14ad7326 pastith
                String nextUrl = request.getParameter(NEXT_URL_PARAM);
90 14ad7326 pastith
                // Fetch the supplied nonce, if any.
91 14ad7326 pastith
                String nonce = request.getParameter(NONCE_PARAM);
92 91fb506c pastith
                String[] attrs = new String[] {"REMOTE_USER", "HTTP_SHIB_INETORGPERSON_DISPLAYNAME",
93 91fb506c pastith
                                        "HTTP_SHIB_INETORGPERSON_GIVENNAME", "HTTP_SHIB_PERSON_COMMONNAME",
94 91fb506c pastith
                                        "HTTP_SHIB_PERSON_SURNAME", "HTTP_SHIB_INETORGPERSON_MAIL",
95 27f2be2f Panagiotis Astithas
                                        "HTTP_SHIB_EP_UNSCOPEDAFFILIATION", "HTTP_PERSISTENT_ID"};
96 91fb506c pastith
                StringBuilder buf = new StringBuilder("Shibboleth Attributes\n");
97 91fb506c pastith
                for (String attr: attrs)
98 91fb506c pastith
                        buf.append(attr+": ").append(request.getAttribute(attr)).append('\n');
99 91fb506c pastith
                logger.info(buf);
100 5005b2b6 pastith
                if (logger.isDebugEnabled()) {
101 5005b2b6 pastith
                        buf = new StringBuilder("Shibboleth Attributes as bytes\n");
102 5005b2b6 pastith
                        for (String attr: attrs)
103 5005b2b6 pastith
                                if (request.getAttribute(attr) != null)
104 cbe69def pastith
                                        buf.append(attr+": ").append(getHexString(request.getAttribute(attr).toString().getBytes("UTF-8"))).append('\n');
105 5005b2b6 pastith
                        logger.debug(buf);
106 5005b2b6 pastith
                }
107 14ad7326 pastith
                User user = null;
108 14ad7326 pastith
                response.setContentType("text/html");
109 14ad7326 pastith
                Object usernameAttr = request.getAttribute("REMOTE_USER");
110 40347b0e pastith
                Object nameAttr = request.getAttribute("HTTP_SHIB_INETORGPERSON_DISPLAYNAME");
111 91fb506c pastith
                Object givennameAttr = request.getAttribute("HTTP_SHIB_INETORGPERSON_GIVENNAME"); // Multi-valued
112 8be15957 pastith
                Object cnAttr = request.getAttribute("HTTP_SHIB_PERSON_COMMONNAME"); // Multi-valued
113 8be15957 pastith
                Object snAttr = request.getAttribute("HTTP_SHIB_PERSON_SURNAME"); // Multi-valued
114 8be15957 pastith
                Object mailAttr = request.getAttribute("HTTP_SHIB_INETORGPERSON_MAIL"); // Multi-valued
115 533ade50 Panagiotis Astithas
                Object persistentIdAttr = request.getAttribute("HTTP_PERSISTENT_ID");
116 c917374b Panagiotis Astithas
                // Use a configured test username if found, as a shortcut for development deployments.
117 51264241 Panagiotis Astithas
                String gwtServer = null;
118 51264241 Panagiotis Astithas
                if (getConfiguration().getString("testUsername") != null) {
119 c917374b Panagiotis Astithas
                        usernameAttr = getConfiguration().getString("testUsername");
120 51264241 Panagiotis Astithas
                        // Fetch the GWT code server URL, if any.
121 51264241 Panagiotis Astithas
                        gwtServer = request.getParameter(GWT_SERVER_PARAM);
122 51264241 Panagiotis Astithas
                }
123 14ad7326 pastith
                if (usernameAttr == null) {
124 11af52e2 pastith
                        String authErrorUrl = "authenticationError.jsp";
125 11af52e2 pastith
                        authErrorUrl += "?name=" + (nameAttr==null? "-": nameAttr.toString());
126 11af52e2 pastith
                        authErrorUrl += "&givenname=" + (givennameAttr==null? "-": givennameAttr.toString());
127 11af52e2 pastith
                        authErrorUrl += "&sn=" + (snAttr==null? "-": snAttr.toString());
128 11af52e2 pastith
                        authErrorUrl += "&cn=" + (cnAttr==null? "-": cnAttr.toString());
129 11af52e2 pastith
                        authErrorUrl += "&mail=" + (mailAttr==null? "-": mailAttr.toString());
130 11af52e2 pastith
                        response.sendRedirect(authErrorUrl);
131 14ad7326 pastith
                        return;
132 14ad7326 pastith
                }
133 4b7228e1 pastith
                String username = decodeAttribute(usernameAttr);
134 1bd363d7 pastith
                String name;
135 21daa3af pastith
                if (nameAttr != null && !nameAttr.toString().isEmpty())
136 4b7228e1 pastith
                        name = decodeAttribute(nameAttr);
137 91fb506c pastith
                else if (cnAttr != null && !cnAttr.toString().isEmpty()) {
138 4b7228e1 pastith
                        name = decodeAttribute(cnAttr);
139 91fb506c pastith
                        if (name.indexOf(';') != -1)
140 91fb506c pastith
                                name = name.substring(0, name.indexOf(';'));
141 91fb506c pastith
                } else if (givennameAttr != null && snAttr != null && !givennameAttr.toString().isEmpty() && !snAttr.toString().isEmpty()) {
142 4b7228e1 pastith
                        String givenname = decodeAttribute(givennameAttr);
143 91fb506c pastith
                        if (givenname.indexOf(';') != -1)
144 91fb506c pastith
                                givenname = givenname.substring(0, givenname.indexOf(';'));
145 4b7228e1 pastith
                        String sn = decodeAttribute(snAttr);
146 91fb506c pastith
                        if (sn.indexOf(';') != -1)
147 91fb506c pastith
                                sn = sn.substring(0, sn.indexOf(';'));
148 91fb506c pastith
                        name = givenname + ' ' + sn;
149 91fb506c pastith
                } else if (givennameAttr == null && snAttr != null && !snAttr.toString().isEmpty()) {
150 4b7228e1 pastith
                        name = decodeAttribute(snAttr);
151 91fb506c pastith
                        if (name.indexOf(';') != -1)
152 91fb506c pastith
                                name = name.substring(0, name.indexOf(';'));
153 91fb506c pastith
                } else
154 1bd363d7 pastith
                        name = username;
155 14ad7326 pastith
                String mail = mailAttr != null ? mailAttr.toString() : username;
156 91fb506c pastith
                if (mail.indexOf(';') != -1)
157 91fb506c pastith
                        mail = mail.substring(0, mail.indexOf(';'));
158 533ade50 Panagiotis Astithas
                String persistentId = persistentIdAttr != null ? persistentIdAttr.toString() : "";
159 c35f359f Panagiotis Astithas
                String idp = "";
160 c35f359f Panagiotis Astithas
                String idpid = "";
161 c35f359f Panagiotis Astithas
                if (!persistentId.isEmpty()) {
162 c35f359f Panagiotis Astithas
                        int bang = persistentId.indexOf('!');
163 c35f359f Panagiotis Astithas
                        if (bang > -1) {
164 c35f359f Panagiotis Astithas
                                idp = persistentId.substring(0, bang);
165 c35f359f Panagiotis Astithas
                                idpid = persistentId.substring(bang + 1);
166 c35f359f Panagiotis Astithas
                        }
167 c35f359f Panagiotis Astithas
                }
168 14ad7326 pastith
                try {
169 14ad7326 pastith
                        user = getService().findUser(username);
170 14ad7326 pastith
                        if (user == null)
171 c35f359f Panagiotis Astithas
                                user = getService().createUser(username, name, mail, idp, idpid);
172 ed7db29f Panagiotis Astithas
                        if (!user.isActive()) {
173 ed7db29f Panagiotis Astithas
                                logger.info("Disabled user " + username + " tried to login.");
174 ed7db29f Panagiotis Astithas
                                response.sendError(HttpServletResponse.SC_FORBIDDEN, "This account is disabled");
175 ed7db29f Panagiotis Astithas
                                return;
176 ed7db29f Panagiotis Astithas
                        }
177 0a4b8f82 pastith
                        if (!user.hasAcceptedPolicy()) {
178 0a4b8f82 pastith
                                String policyUrl = "policy.jsp";
179 0a4b8f82 pastith
                                if (request.getQueryString() != null)
180 0a4b8f82 pastith
                                        policyUrl += "?user=" + username + "&" + request.getQueryString();
181 0a4b8f82 pastith
                                response.sendRedirect(policyUrl);
182 0a4b8f82 pastith
                                return;
183 0a4b8f82 pastith
                        }
184 125c5690 Panagiotis Astithas
                        user.setName(name);
185 125c5690 Panagiotis Astithas
                        user.setEmail(mail);
186 c35f359f Panagiotis Astithas
                        user.setIdentityProvider(idp);
187 c35f359f Panagiotis Astithas
                        user.setIdentityProviderId(idpid);
188 366f3f31 Natasa Kapravelou
                        
189 366f3f31 Natasa Kapravelou
                        UserLogin userLogin = new UserLogin();
190 366f3f31 Natasa Kapravelou
                        userLogin.setLoginDate(new Date());
191 a3d193a5 Natasa Kapravelou
                        userLogin.setUser(user);
192 14ad7326 pastith
                        if (user.getAuthToken() == null)
193 14ad7326 pastith
                                user = getService().updateUserToken(user.getId());
194 503040ef Dimitris Routsis
                        // Set WebDAV password to token if it's never been set.
195 125c5690 Panagiotis Astithas
                        if (user.getWebDAVPassword() == null || user.getWebDAVPassword().length() == 0) {
196 503040ef Dimitris Routsis
                                String tokenEncoded = new String(Base64.encodeBase64(user.getAuthToken()), "US-ASCII");
197 503040ef Dimitris Routsis
                                user.setWebDAVPassword(tokenEncoded);
198 533ade50 Panagiotis Astithas
                        }
199 01a30cd0 Panagiotis Astithas
                        // Set the default user class if none was set.
200 01a30cd0 Panagiotis Astithas
                        if (user.getUserClass() == null)
201 a3d193a5 Natasa Kapravelou
                                user.setUserClass(getService().getUserClasses().get(0));                        
202 125c5690 Panagiotis Astithas
                        getService().updateUser(user);
203 a3d193a5 Natasa Kapravelou
                        getService().addUserLogin(userLogin);                
204 14ad7326 pastith
                } catch (RpcException e) {
205 14ad7326 pastith
                        String error = "An error occurred while communicating with the service";
206 14ad7326 pastith
                        logger.error(error, e);
207 14ad7326 pastith
                        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error);
208 14ad7326 pastith
                        return;
209 14ad7326 pastith
                } catch (DuplicateNameException e) {
210 14ad7326 pastith
                        String error = "User with username " + username + " already exists";
211 14ad7326 pastith
                        logger.error(error, e);
212 14ad7326 pastith
                        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error);
213 14ad7326 pastith
                        return;
214 14ad7326 pastith
                } catch (ObjectNotFoundException e) {
215 14ad7326 pastith
                        String error = "No username was provided";
216 14ad7326 pastith
                        logger.error(error, e);
217 14ad7326 pastith
                        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error);
218 14ad7326 pastith
                        return;
219 14ad7326 pastith
                }
220 14ad7326 pastith
                String tokenEncoded = new String(Base64.encodeBase64(user.getAuthToken()), "US-ASCII");
221 14ad7326 pastith
                String userEncoded = URLEncoder.encode(user.getUsername(), "US-ASCII");
222 14ad7326 pastith
                if (logger.isDebugEnabled())
223 14ad7326 pastith
                        logger.debug("user: "+userEncoded+" token: "+tokenEncoded);
224 739f501e Panagiotis Astithas
                if (nextUrl != null && !nextUrl.isEmpty()) {
225 144fe6ce Panagiotis Astithas
                        URI next;
226 51264241 Panagiotis Astithas
                        if (gwtServer != null)
227 51264241 Panagiotis Astithas
                                nextUrl += '?' + GWT_SERVER_PARAM + '=' + gwtServer;
228 144fe6ce Panagiotis Astithas
                        try {
229 144fe6ce Panagiotis Astithas
                                next = new URI(nextUrl);
230 144fe6ce Panagiotis Astithas
                        } catch (URISyntaxException e) {
231 144fe6ce Panagiotis Astithas
                                response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
232 144fe6ce Panagiotis Astithas
                                return;
233 144fe6ce Panagiotis Astithas
                        }
234 a1aa74a8 Panagiotis Astithas
                        if ("x-gr-ebs-igss".equalsIgnoreCase(next.getScheme()))
235 a1aa74a8 Panagiotis Astithas
                                nextUrl += "?u=" + userEncoded + "&t=" + tokenEncoded;
236 a1aa74a8 Panagiotis Astithas
                        else {
237 a1aa74a8 Panagiotis Astithas
                                String domain = next.getHost();
238 6567092b Panagiotis Astithas
                                String path = getServletContext().getContextPath() + '/';
239 a1aa74a8 Panagiotis Astithas
                                Cookie cookie = new Cookie(AUTH_COOKIE, userEncoded + COOKIE_SEPARATOR +
240 a1aa74a8 Panagiotis Astithas
                                                        tokenEncoded);
241 a1aa74a8 Panagiotis Astithas
                                cookie.setMaxAge(-1);
242 a1aa74a8 Panagiotis Astithas
                                cookie.setDomain(domain);
243 a1aa74a8 Panagiotis Astithas
                                cookie.setPath(path);
244 a1aa74a8 Panagiotis Astithas
                            response.addCookie(cookie);
245 a1aa74a8 Panagiotis Astithas
                            cookie = new Cookie(WEBDAV_COOKIE, user.getWebDAVPassword());
246 a1aa74a8 Panagiotis Astithas
                                cookie.setMaxAge(-1);
247 a1aa74a8 Panagiotis Astithas
                                cookie.setDomain(domain);
248 a1aa74a8 Panagiotis Astithas
                                cookie.setPath(path);
249 a1aa74a8 Panagiotis Astithas
                                response.addCookie(cookie);
250 a1aa74a8 Panagiotis Astithas
                        }
251 14ad7326 pastith
                    response.sendRedirect(nextUrl);
252 14ad7326 pastith
                } else if (nonce != null) {
253 d08fa1c0 pastith
                        nonce = URLEncoder.encode(nonce, "US-ASCII");
254 14ad7326 pastith
                        Nonce n = null;
255 14ad7326 pastith
                        try {
256 14ad7326 pastith
                                if (logger.isDebugEnabled())
257 14ad7326 pastith
                                        logger.debug("user: "+user.getId()+" nonce: "+nonce);
258 14ad7326 pastith
                                n = getService().getNonce(nonce, user.getId());
259 14ad7326 pastith
                        } catch (ObjectNotFoundException e) {
260 14ad7326 pastith
                            PrintWriter out = response.getWriter();
261 14ad7326 pastith
                            out.println("<HTML>");
262 8270b533 pastith
                            out.println("<HEAD><TITLE>" + getServiceName() + " Authentication</TITLE>" +
263 14ad7326 pastith
                                            "<LINK TYPE='text/css' REL='stylesheet' HREF='gss.css'></HEAD>");
264 14ad7326 pastith
                            out.println("<BODY><CENTER><P>");
265 14ad7326 pastith
                            out.println("The supplied nonce could not be found!");
266 14ad7326 pastith
                            out.println("</CENTER></BODY></HTML>");
267 14ad7326 pastith
                            return;
268 14ad7326 pastith
                        } catch (RpcException e) {
269 14ad7326 pastith
                                String error = "An error occurred while communicating with the service";
270 14ad7326 pastith
                                logger.error(error, e);
271 14ad7326 pastith
                                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error);
272 14ad7326 pastith
                                return;
273 14ad7326 pastith
                        }
274 14ad7326 pastith
                        try {
275 14ad7326 pastith
                                getService().activateUserNonce(user.getId(), nonce, n.getNonceExpiryDate());
276 14ad7326 pastith
                        } catch (ObjectNotFoundException e) {
277 14ad7326 pastith
                                String error = "Unable to find user";
278 14ad7326 pastith
                                logger.error(error, e);
279 14ad7326 pastith
                                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error);
280 14ad7326 pastith
                                return;
281 14ad7326 pastith
                        } catch (RpcException e) {
282 14ad7326 pastith
                                String error = "An error occurred while communicating with the service";
283 14ad7326 pastith
                                logger.error(error, e);
284 14ad7326 pastith
                                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error);
285 14ad7326 pastith
                                return;
286 14ad7326 pastith
                        }
287 14ad7326 pastith
                        try {
288 14ad7326 pastith
                                getService().removeNonce(n.getId());
289 14ad7326 pastith
                        } catch (ObjectNotFoundException e) {
290 14ad7326 pastith
                                logger.info("Nonce already removed!", e);
291 14ad7326 pastith
                        } catch (RpcException e) {
292 14ad7326 pastith
                                logger.warn("Could not remove nonce from data store", e);
293 14ad7326 pastith
                        }
294 14ad7326 pastith
                    PrintWriter out = response.getWriter();
295 14ad7326 pastith
                    out.println("<HTML>");
296 8270b533 pastith
                    out.println("<HEAD><TITLE>" + getServiceName() + " Authentication</TITLE>" +
297 14ad7326 pastith
                                    "<LINK TYPE='text/css' REL='stylesheet' HREF='gss.css'></HEAD>");
298 14ad7326 pastith
                    out.println("<BODY><CENTER><P>");
299 14ad7326 pastith
                    out.println("You can now close this browser window and return to your application.");
300 14ad7326 pastith
                    out.println("</CENTER></BODY></HTML>");
301 14ad7326 pastith
                } else {
302 14ad7326 pastith
                    PrintWriter out = response.getWriter();
303 14ad7326 pastith
                    out.println("<HTML>");
304 8270b533 pastith
                    out.println("<HEAD><TITLE>" + getServiceName() + " Authentication</TITLE>" +
305 14ad7326 pastith
                                    "<LINK TYPE='text/css' REL='stylesheet' HREF='gss.css'></HEAD>");
306 14ad7326 pastith
                    out.println("<BODY><CENTER><P>");
307 14ad7326 pastith
                    out.println("Name: " + user.getName() + "<BR>");
308 14ad7326 pastith
                    out.println("E-mail: " + user.getEmail() + "<BR><P>");
309 14ad7326 pastith
                    out.println("Username: " + user.getUsername() + "<BR>");
310 14ad7326 pastith
                    out.println("Athentication token: " + tokenEncoded + "<BR>");
311 14ad7326 pastith
                    out.println("</CENTER></BODY></HTML>");
312 14ad7326 pastith
                }
313 14ad7326 pastith
        }
314 14ad7326 pastith
}