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