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 |
} |