Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (12.2 kB)

1
/*
2
 * Copyright 2008, 2009 Electronic Business Systems Ltd.
3
 *
4
 * This file is part of GSS.
5
 *
6
 * GSS is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * GSS is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19
package gr.ebs.gss.server;
20

    
21
import static gr.ebs.gss.server.configuration.GSSConfigurationFactory.getConfiguration;
22
import gr.ebs.gss.common.exceptions.DuplicateNameException;
23
import gr.ebs.gss.common.exceptions.ObjectNotFoundException;
24
import gr.ebs.gss.common.exceptions.RpcException;
25
import gr.ebs.gss.server.domain.Nonce;
26
import gr.ebs.gss.server.domain.User;
27
import gr.ebs.gss.server.domain.UserLogin;
28

    
29
import java.io.IOException;
30
import java.io.PrintWriter;
31
import java.net.URI;
32
import java.net.URISyntaxException;
33
import java.net.URLEncoder;
34
import java.util.Date;
35

    
36
import javax.servlet.http.Cookie;
37
import javax.servlet.http.HttpServletRequest;
38
import javax.servlet.http.HttpServletResponse;
39

    
40
import org.apache.commons.codec.binary.Base64;
41
import org.apache.commons.logging.Log;
42
import org.apache.commons.logging.LogFactory;
43

    
44
/**
45
 * The servlet that handles user logins.
46
 *
47
 * @author past
48
 */
49
public class Login extends BaseServlet {
50
        /**
51
         * The request parameter name for the nonce.
52
         */
53
        private static final String NONCE_PARAM = "nonce";
54

    
55
        /**
56
         * The request parameter name for the URL to redirect
57
         * to after authentication.
58
         */
59
        private static final String NEXT_URL_PARAM = "next";
60

    
61
        /**
62
         * The serial version UID of the class.
63
         */
64
        private static final long serialVersionUID = 1L;
65

    
66
        /**
67
         * The name of the authentication cookie.
68
         */
69
        public static final String AUTH_COOKIE = "_gss_a";
70

    
71
        /**
72
         * The separator character for the authentication cookie.
73
         */
74
        public static final char COOKIE_SEPARATOR = '|';
75

    
76
        /**
77
         * The name of the the webdav cookie.
78
         */
79
        public static final String WEBDAV_COOKIE = "_gss_wd";
80

    
81
        /**
82
         * The logger.
83
         */
84
        private static Log logger = LogFactory.getLog(Login.class);
85

    
86
        @Override
87
        public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
88
                // Fetch the next URL to display, if any.
89
                String nextUrl = request.getParameter(NEXT_URL_PARAM);
90
                // Fetch the supplied nonce, if any.
91
                String nonce = request.getParameter(NONCE_PARAM);
92
                String[] attrs = new String[] {"REMOTE_USER", "HTTP_SHIB_INETORGPERSON_DISPLAYNAME",
93
                                        "HTTP_SHIB_INETORGPERSON_GIVENNAME", "HTTP_SHIB_PERSON_COMMONNAME",
94
                                        "HTTP_SHIB_PERSON_SURNAME", "HTTP_SHIB_INETORGPERSON_MAIL",
95
                                        "HTTP_SHIB_EP_UNSCOPEDAFFILIATION", "HTTP_PERSISTENT_ID"};
96
                StringBuilder buf = new StringBuilder("Shibboleth Attributes\n");
97
                for (String attr: attrs)
98
                        buf.append(attr+": ").append(request.getAttribute(attr)).append('\n');
99
                logger.info(buf);
100
                if (logger.isDebugEnabled()) {
101
                        buf = new StringBuilder("Shibboleth Attributes as bytes\n");
102
                        for (String attr: attrs)
103
                                if (request.getAttribute(attr) != null)
104
                                        buf.append(attr+": ").append(getHexString(request.getAttribute(attr).toString().getBytes("UTF-8"))).append('\n');
105
                        logger.debug(buf);
106
                }
107
                User user = null;
108
                response.setContentType("text/html");
109
                Object usernameAttr = request.getAttribute("REMOTE_USER");
110
                Object nameAttr = request.getAttribute("HTTP_SHIB_INETORGPERSON_DISPLAYNAME");
111
                Object givennameAttr = request.getAttribute("HTTP_SHIB_INETORGPERSON_GIVENNAME"); // Multi-valued
112
                Object cnAttr = request.getAttribute("HTTP_SHIB_PERSON_COMMONNAME"); // Multi-valued
113
                Object snAttr = request.getAttribute("HTTP_SHIB_PERSON_SURNAME"); // Multi-valued
114
                Object mailAttr = request.getAttribute("HTTP_SHIB_INETORGPERSON_MAIL"); // Multi-valued
115
                Object persistentIdAttr = request.getAttribute("HTTP_PERSISTENT_ID");
116
                // Use a configured test username if found, as a shortcut for development deployments.
117
                String gwtServer = null;
118
                if (getConfiguration().getString("testUsername") != null) {
119
                        usernameAttr = getConfiguration().getString("testUsername");
120
                        // Fetch the GWT code server URL, if any.
121
                        gwtServer = request.getParameter(GWT_SERVER_PARAM);
122
                }
123
                if (usernameAttr == null) {
124
                        String authErrorUrl = "authenticationError.jsp";
125
                        authErrorUrl += "?name=" + (nameAttr==null? "-": nameAttr.toString());
126
                        authErrorUrl += "&givenname=" + (givennameAttr==null? "-": givennameAttr.toString());
127
                        authErrorUrl += "&sn=" + (snAttr==null? "-": snAttr.toString());
128
                        authErrorUrl += "&cn=" + (cnAttr==null? "-": cnAttr.toString());
129
                        authErrorUrl += "&mail=" + (mailAttr==null? "-": mailAttr.toString());
130
                        response.sendRedirect(authErrorUrl);
131
                        return;
132
                }
133
                String username = decodeAttribute(usernameAttr);
134
                String name;
135
                if (nameAttr != null && !nameAttr.toString().isEmpty())
136
                        name = decodeAttribute(nameAttr);
137
                else if (cnAttr != null && !cnAttr.toString().isEmpty()) {
138
                        name = decodeAttribute(cnAttr);
139
                        if (name.indexOf(';') != -1)
140
                                name = name.substring(0, name.indexOf(';'));
141
                } else if (givennameAttr != null && snAttr != null && !givennameAttr.toString().isEmpty() && !snAttr.toString().isEmpty()) {
142
                        String givenname = decodeAttribute(givennameAttr);
143
                        if (givenname.indexOf(';') != -1)
144
                                givenname = givenname.substring(0, givenname.indexOf(';'));
145
                        String sn = decodeAttribute(snAttr);
146
                        if (sn.indexOf(';') != -1)
147
                                sn = sn.substring(0, sn.indexOf(';'));
148
                        name = givenname + ' ' + sn;
149
                } else if (givennameAttr == null && snAttr != null && !snAttr.toString().isEmpty()) {
150
                        name = decodeAttribute(snAttr);
151
                        if (name.indexOf(';') != -1)
152
                                name = name.substring(0, name.indexOf(';'));
153
                } else
154
                        name = username;
155
                String mail = mailAttr != null ? mailAttr.toString() : username;
156
                if (mail.indexOf(';') != -1)
157
                        mail = mail.substring(0, mail.indexOf(';'));
158
                String persistentId = persistentIdAttr != null ? persistentIdAttr.toString() : "";
159
                String idp = "";
160
                String idpid = "";
161
                if (!persistentId.isEmpty()) {
162
                        int bang = persistentId.indexOf('!');
163
                        if (bang > -1) {
164
                                idp = persistentId.substring(0, bang);
165
                                idpid = persistentId.substring(bang + 1);
166
                        }
167
                }
168
                try {
169
                        user = getService().findUser(username);
170
                        if (user == null)
171
                                user = getService().createUser(username, name, mail, idp, idpid);
172
                        if (!user.isActive()) {
173
                                logger.info("Disabled user " + username + " tried to login.");
174
                                response.sendError(HttpServletResponse.SC_FORBIDDEN, "This account is disabled");
175
                                return;
176
                        }
177
                        if (!user.hasAcceptedPolicy()) {
178
                                String policyUrl = "policy.jsp";
179
                                if (request.getQueryString() != null)
180
                                        policyUrl += "?user=" + username + "&" + request.getQueryString();
181
                                response.sendRedirect(policyUrl);
182
                                return;
183
                        }
184
                        user.setName(name);
185
                        user.setEmail(mail);
186
                        user.setIdentityProvider(idp);
187
                        user.setIdentityProviderId(idpid);
188
                        
189
                        UserLogin userLogin = new UserLogin();
190
                        userLogin.setLoginDate(new Date());
191
                        userLogin.setUser(user);
192
                        if (user.getAuthToken() == null)
193
                                user = getService().updateUserToken(user.getId());
194
                        // Set WebDAV password to token if it's never been set.
195
                        if (user.getWebDAVPassword() == null || user.getWebDAVPassword().length() == 0) {
196
                                String tokenEncoded = new String(Base64.encodeBase64(user.getAuthToken()), "US-ASCII");
197
                                user.setWebDAVPassword(tokenEncoded);
198
                        }
199
                        // Set the default user class if none was set.
200
                        if (user.getUserClass() == null)
201
                                user.setUserClass(getService().getUserClasses().get(0));                        
202
                        getService().updateUser(user);
203
                        getService().addUserLogin(userLogin);                
204
                } catch (RpcException e) {
205
                        String error = "An error occurred while communicating with the service";
206
                        logger.error(error, e);
207
                        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error);
208
                        return;
209
                } catch (DuplicateNameException e) {
210
                        String error = "User with username " + username + " already exists";
211
                        logger.error(error, e);
212
                        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error);
213
                        return;
214
                } catch (ObjectNotFoundException e) {
215
                        String error = "No username was provided";
216
                        logger.error(error, e);
217
                        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error);
218
                        return;
219
                }
220
                String tokenEncoded = new String(Base64.encodeBase64(user.getAuthToken()), "US-ASCII");
221
                String userEncoded = URLEncoder.encode(user.getUsername(), "US-ASCII");
222
                if (logger.isDebugEnabled())
223
                        logger.debug("user: "+userEncoded+" token: "+tokenEncoded);
224
                if (nextUrl != null && !nextUrl.isEmpty()) {
225
                        URI next;
226
                        if (gwtServer != null)
227
                                nextUrl += '?' + GWT_SERVER_PARAM + '=' + gwtServer;
228
                        try {
229
                                next = new URI(nextUrl);
230
                        } catch (URISyntaxException e) {
231
                                response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
232
                                return;
233
                        }
234
                        if ("x-gr-ebs-igss".equalsIgnoreCase(next.getScheme()))
235
                                nextUrl += "?u=" + userEncoded + "&t=" + tokenEncoded;
236
                        else {
237
                                String domain = next.getHost();
238
                                String path = getServletContext().getContextPath() + '/';
239
                                Cookie cookie = new Cookie(AUTH_COOKIE, userEncoded + COOKIE_SEPARATOR +
240
                                                        tokenEncoded);
241
                                cookie.setMaxAge(-1);
242
                                cookie.setDomain(domain);
243
                                cookie.setPath(path);
244
                            response.addCookie(cookie);
245
                            cookie = new Cookie(WEBDAV_COOKIE, user.getWebDAVPassword());
246
                                cookie.setMaxAge(-1);
247
                                cookie.setDomain(domain);
248
                                cookie.setPath(path);
249
                                response.addCookie(cookie);
250
                        }
251
                    response.sendRedirect(nextUrl);
252
                } else if (nonce != null) {
253
                        nonce = URLEncoder.encode(nonce, "US-ASCII");
254
                        Nonce n = null;
255
                        try {
256
                                if (logger.isDebugEnabled())
257
                                        logger.debug("user: "+user.getId()+" nonce: "+nonce);
258
                                n = getService().getNonce(nonce, user.getId());
259
                        } catch (ObjectNotFoundException e) {
260
                            PrintWriter out = response.getWriter();
261
                            out.println("<HTML>");
262
                            out.println("<HEAD><TITLE>" + getServiceName() + " Authentication</TITLE>" +
263
                                            "<LINK TYPE='text/css' REL='stylesheet' HREF='gss.css'></HEAD>");
264
                            out.println("<BODY><CENTER><P>");
265
                            out.println("The supplied nonce could not be found!");
266
                            out.println("</CENTER></BODY></HTML>");
267
                            return;
268
                        } catch (RpcException e) {
269
                                String error = "An error occurred while communicating with the service";
270
                                logger.error(error, e);
271
                                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error);
272
                                return;
273
                        }
274
                        try {
275
                                getService().activateUserNonce(user.getId(), nonce, n.getNonceExpiryDate());
276
                        } catch (ObjectNotFoundException e) {
277
                                String error = "Unable to find user";
278
                                logger.error(error, e);
279
                                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error);
280
                                return;
281
                        } catch (RpcException e) {
282
                                String error = "An error occurred while communicating with the service";
283
                                logger.error(error, e);
284
                                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error);
285
                                return;
286
                        }
287
                        try {
288
                                getService().removeNonce(n.getId());
289
                        } catch (ObjectNotFoundException e) {
290
                                logger.info("Nonce already removed!", e);
291
                        } catch (RpcException e) {
292
                                logger.warn("Could not remove nonce from data store", e);
293
                        }
294
                    PrintWriter out = response.getWriter();
295
                    out.println("<HTML>");
296
                    out.println("<HEAD><TITLE>" + getServiceName() + " Authentication</TITLE>" +
297
                                    "<LINK TYPE='text/css' REL='stylesheet' HREF='gss.css'></HEAD>");
298
                    out.println("<BODY><CENTER><P>");
299
                    out.println("You can now close this browser window and return to your application.");
300
                    out.println("</CENTER></BODY></HTML>");
301
                } else {
302
                    PrintWriter out = response.getWriter();
303
                    out.println("<HTML>");
304
                    out.println("<HEAD><TITLE>" + getServiceName() + " Authentication</TITLE>" +
305
                                    "<LINK TYPE='text/css' REL='stylesheet' HREF='gss.css'></HEAD>");
306
                    out.println("<BODY><CENTER><P>");
307
                    out.println("Name: " + user.getName() + "<BR>");
308
                    out.println("E-mail: " + user.getEmail() + "<BR><P>");
309
                    out.println("Username: " + user.getUsername() + "<BR>");
310
                    out.println("Athentication token: " + tokenEncoded + "<BR>");
311
                    out.println("</CENTER></BODY></HTML>");
312
                }
313
        }
314
}