root / gss / src / gr / ebs / gss / server / Login.java @ 11af52e2
History | View | Annotate | Download (11 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.client.exceptions.DuplicateNameException; |
23 |
import gr.ebs.gss.client.exceptions.ObjectNotFoundException; |
24 |
import gr.ebs.gss.client.exceptions.RpcException; |
25 |
import gr.ebs.gss.server.domain.Nonce; |
26 |
import gr.ebs.gss.server.domain.User; |
27 |
import gr.ebs.gss.server.ejb.ExternalAPI; |
28 |
|
29 |
import java.io.IOException; |
30 |
import java.io.PrintWriter; |
31 |
import java.net.URL; |
32 |
import java.net.URLEncoder; |
33 |
|
34 |
import javax.naming.Context; |
35 |
import javax.naming.InitialContext; |
36 |
import javax.naming.NamingException; |
37 |
import javax.rmi.PortableRemoteObject; |
38 |
import javax.servlet.http.Cookie; |
39 |
import javax.servlet.http.HttpServlet; |
40 |
import javax.servlet.http.HttpServletRequest; |
41 |
import javax.servlet.http.HttpServletResponse; |
42 |
|
43 |
import org.apache.commons.codec.binary.Base64; |
44 |
import org.apache.commons.logging.Log; |
45 |
import org.apache.commons.logging.LogFactory; |
46 |
|
47 |
/**
|
48 |
* The servlet that handles user logins.
|
49 |
*
|
50 |
* @author past
|
51 |
*/
|
52 |
public class Login extends HttpServlet { |
53 |
/**
|
54 |
* The request parameter name for the nonce.
|
55 |
*/
|
56 |
private static final String NONCE_PARAM = "nonce"; |
57 |
|
58 |
/**
|
59 |
* The request parameter name for the URL to redirect
|
60 |
* to after authentication.
|
61 |
*/
|
62 |
private static final String NEXT_URL_PARAM = "next"; |
63 |
|
64 |
/**
|
65 |
* The serial version UID of the class.
|
66 |
*/
|
67 |
private static final long serialVersionUID = 1L; |
68 |
|
69 |
/**
|
70 |
* The name of the authentication cookie.
|
71 |
*/
|
72 |
private static final String AUTH_COOKIE = "_gss_a"; |
73 |
|
74 |
/**
|
75 |
* The separator character for the authentication cookie.
|
76 |
*/
|
77 |
private static final char COOKIE_SEPARATOR = '|'; |
78 |
|
79 |
/**
|
80 |
* The logger.
|
81 |
*/
|
82 |
private static Log logger = LogFactory.getLog(Login.class); |
83 |
|
84 |
/**
|
85 |
* A helper method that retrieves a reference to the ExternalAPI bean and
|
86 |
* stores it for future use.
|
87 |
*
|
88 |
* @return an ExternalAPI instance
|
89 |
* @throws RpcException in case an error occurs
|
90 |
*/
|
91 |
private ExternalAPI getService() throws RpcException { |
92 |
try {
|
93 |
final Context ctx = new InitialContext(); |
94 |
final Object ref = ctx.lookup(getConfiguration().getString("externalApiPath")); |
95 |
return (ExternalAPI) PortableRemoteObject.narrow(ref, ExternalAPI.class); |
96 |
} catch (final NamingException e) { |
97 |
logger.error("Unable to retrieve the ExternalAPI EJB", e);
|
98 |
throw new RpcException("An error occurred while contacting the naming service"); |
99 |
} |
100 |
} |
101 |
|
102 |
/**
|
103 |
* Return the name of the service.
|
104 |
*/
|
105 |
private String getServiceName() { |
106 |
return getConfiguration().getString("serviceName", "GSS"); |
107 |
} |
108 |
|
109 |
@Override
|
110 |
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { |
111 |
// Fetch the next URL to display, if any.
|
112 |
String nextUrl = request.getParameter(NEXT_URL_PARAM);
|
113 |
// Fetch the supplied nonce, if any.
|
114 |
String nonce = request.getParameter(NONCE_PARAM);
|
115 |
String[] attrs = new String[] {"REMOTE_USER", "HTTP_SHIB_INETORGPERSON_DISPLAYNAME", |
116 |
"HTTP_SHIB_INETORGPERSON_GIVENNAME", "HTTP_SHIB_PERSON_COMMONNAME", |
117 |
"HTTP_SHIB_PERSON_SURNAME", "HTTP_SHIB_INETORGPERSON_MAIL", |
118 |
"HTTP_SHIB_EP_UNSCOPEDAFFILIATION"};
|
119 |
StringBuilder buf = new StringBuilder("Shibboleth Attributes\n"); |
120 |
for (String attr: attrs) |
121 |
buf.append(attr+": ").append(request.getAttribute(attr)).append('\n'); |
122 |
logger.info(buf); |
123 |
User user = null;
|
124 |
response.setContentType("text/html");
|
125 |
Object usernameAttr = request.getAttribute("REMOTE_USER"); |
126 |
Object nameAttr = request.getAttribute("HTTP_SHIB_INETORGPERSON_DISPLAYNAME"); |
127 |
Object givennameAttr = request.getAttribute("HTTP_SHIB_INETORGPERSON_GIVENNAME"); // Multi-valued |
128 |
Object cnAttr = request.getAttribute("HTTP_SHIB_PERSON_COMMONNAME"); // Multi-valued |
129 |
Object snAttr = request.getAttribute("HTTP_SHIB_PERSON_SURNAME"); // Multi-valued |
130 |
Object mailAttr = request.getAttribute("HTTP_SHIB_INETORGPERSON_MAIL"); // Multi-valued |
131 |
Object userclassAttr = request.getAttribute("HTTP_SHIB_EP_UNSCOPEDAFFILIATION"); // Multi-valued |
132 |
if (usernameAttr == null) { |
133 |
String authErrorUrl = "authenticationError.jsp"; |
134 |
authErrorUrl += "?name=" + (nameAttr==null? "-": nameAttr.toString()); |
135 |
authErrorUrl += "&givenname=" + (givennameAttr==null? "-": givennameAttr.toString()); |
136 |
authErrorUrl += "&sn=" + (snAttr==null? "-": snAttr.toString()); |
137 |
authErrorUrl += "&cn=" + (cnAttr==null? "-": cnAttr.toString()); |
138 |
authErrorUrl += "&mail=" + (mailAttr==null? "-": mailAttr.toString()); |
139 |
authErrorUrl += "&userclass=" + (userclassAttr==null? "-": userclassAttr.toString()); |
140 |
response.sendRedirect(authErrorUrl); |
141 |
return;
|
142 |
} |
143 |
String username = usernameAttr.toString();
|
144 |
String name;
|
145 |
if (nameAttr != null && !nameAttr.toString().isEmpty()) |
146 |
name = nameAttr.toString(); |
147 |
else if (cnAttr != null && !cnAttr.toString().isEmpty()) { |
148 |
name = cnAttr.toString(); |
149 |
if (name.indexOf(';') != -1) |
150 |
name = name.substring(0, name.indexOf(';')); |
151 |
} else if (givennameAttr != null && snAttr != null && !givennameAttr.toString().isEmpty() && !snAttr.toString().isEmpty()) { |
152 |
String givenname = givennameAttr.toString();
|
153 |
if (givenname.indexOf(';') != -1) |
154 |
givenname = givenname.substring(0, givenname.indexOf(';')); |
155 |
String sn = snAttr.toString();
|
156 |
if (sn.indexOf(';') != -1) |
157 |
sn = sn.substring(0, sn.indexOf(';')); |
158 |
name = givenname + ' ' + sn;
|
159 |
} else if (givennameAttr == null && snAttr != null && !snAttr.toString().isEmpty()) { |
160 |
name = snAttr.toString(); |
161 |
if (name.indexOf(';') != -1) |
162 |
name = name.substring(0, name.indexOf(';')); |
163 |
} else
|
164 |
name = username; |
165 |
String mail = mailAttr != null ? mailAttr.toString() : username; |
166 |
if (mail.indexOf(';') != -1) |
167 |
mail = mail.substring(0, mail.indexOf(';')); |
168 |
// XXX we are not using the user class currently
|
169 |
String userclass = userclassAttr != null ? userclassAttr.toString() : ""; |
170 |
if (userclass.indexOf(';') != -1) |
171 |
userclass = userclass.substring(0, userclass.indexOf(';')); |
172 |
try {
|
173 |
user = getService().findUser(username); |
174 |
if (user == null) |
175 |
user = getService().createUser(username, name, mail); |
176 |
if (!user.hasAcceptedPolicy()) {
|
177 |
String policyUrl = "policy.jsp"; |
178 |
if (request.getQueryString() != null) |
179 |
policyUrl += "?user=" + username + "&" + request.getQueryString(); |
180 |
response.sendRedirect(policyUrl); |
181 |
return;
|
182 |
} |
183 |
// Update the user name and e-mail if modified.
|
184 |
if (!user.getName().equals(name) || !user.getEmail().equals(mail))
|
185 |
user = getService().updateUser(username, name, mail); |
186 |
if (user.getAuthToken() == null) |
187 |
user = getService().updateUserToken(user.getId()); |
188 |
} catch (RpcException e) {
|
189 |
String error = "An error occurred while communicating with the service"; |
190 |
logger.error(error, e); |
191 |
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error); |
192 |
return;
|
193 |
} catch (DuplicateNameException e) {
|
194 |
String error = "User with username " + username + " already exists"; |
195 |
logger.error(error, e); |
196 |
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error); |
197 |
return;
|
198 |
} catch (ObjectNotFoundException e) {
|
199 |
String error = "No username was provided"; |
200 |
logger.error(error, e); |
201 |
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error); |
202 |
return;
|
203 |
} |
204 |
String tokenEncoded = new String(Base64.encodeBase64(user.getAuthToken()), "US-ASCII"); |
205 |
String userEncoded = URLEncoder.encode(user.getUsername(), "US-ASCII"); |
206 |
if (logger.isDebugEnabled())
|
207 |
logger.debug("user: "+userEncoded+" token: "+tokenEncoded); |
208 |
if (nextUrl != null) { |
209 |
URL next = new URL(nextUrl); |
210 |
String domain = next.getHost();
|
211 |
String path = next.getPath();
|
212 |
Cookie cookie = new Cookie(AUTH_COOKIE, userEncoded + COOKIE_SEPARATOR +
|
213 |
tokenEncoded); |
214 |
cookie.setMaxAge(-1);
|
215 |
cookie.setDomain(domain); |
216 |
cookie.setPath(path); |
217 |
response.addCookie(cookie); |
218 |
response.sendRedirect(nextUrl); |
219 |
} else if (nonce != null) { |
220 |
nonce = URLEncoder.encode(nonce, "US-ASCII"); |
221 |
Nonce n = null;
|
222 |
try {
|
223 |
if (logger.isDebugEnabled())
|
224 |
logger.debug("user: "+user.getId()+" nonce: "+nonce); |
225 |
n = getService().getNonce(nonce, user.getId()); |
226 |
} catch (ObjectNotFoundException e) {
|
227 |
PrintWriter out = response.getWriter();
|
228 |
out.println("<HTML>");
|
229 |
out.println("<HEAD><TITLE>" + getServiceName() + " Authentication</TITLE>" + |
230 |
"<LINK TYPE='text/css' REL='stylesheet' HREF='gss.css'></HEAD>");
|
231 |
out.println("<BODY><CENTER><P>");
|
232 |
out.println("The supplied nonce could not be found!");
|
233 |
out.println("</CENTER></BODY></HTML>");
|
234 |
return;
|
235 |
} catch (RpcException e) {
|
236 |
String error = "An error occurred while communicating with the service"; |
237 |
logger.error(error, e); |
238 |
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error); |
239 |
return;
|
240 |
} |
241 |
try {
|
242 |
getService().activateUserNonce(user.getId(), nonce, n.getNonceExpiryDate()); |
243 |
} catch (ObjectNotFoundException e) {
|
244 |
String error = "Unable to find user"; |
245 |
logger.error(error, e); |
246 |
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error); |
247 |
return;
|
248 |
} catch (RpcException e) {
|
249 |
String error = "An error occurred while communicating with the service"; |
250 |
logger.error(error, e); |
251 |
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error); |
252 |
return;
|
253 |
} |
254 |
try {
|
255 |
getService().removeNonce(n.getId()); |
256 |
} catch (ObjectNotFoundException e) {
|
257 |
logger.info("Nonce already removed!", e);
|
258 |
} catch (RpcException e) {
|
259 |
logger.warn("Could not remove nonce from data store", e);
|
260 |
} |
261 |
PrintWriter out = response.getWriter();
|
262 |
out.println("<HTML>");
|
263 |
out.println("<HEAD><TITLE>" + getServiceName() + " Authentication</TITLE>" + |
264 |
"<LINK TYPE='text/css' REL='stylesheet' HREF='gss.css'></HEAD>");
|
265 |
out.println("<BODY><CENTER><P>");
|
266 |
out.println("You can now close this browser window and return to your application.");
|
267 |
out.println("</CENTER></BODY></HTML>");
|
268 |
} else {
|
269 |
PrintWriter out = response.getWriter();
|
270 |
out.println("<HTML>");
|
271 |
out.println("<HEAD><TITLE>" + getServiceName() + " Authentication</TITLE>" + |
272 |
"<LINK TYPE='text/css' REL='stylesheet' HREF='gss.css'></HEAD>");
|
273 |
out.println("<BODY><CENTER><P>");
|
274 |
out.println("Name: " + user.getName() + "<BR>"); |
275 |
out.println("E-mail: " + user.getEmail() + "<BR><P>"); |
276 |
out.println("Username: " + user.getUsername() + "<BR>"); |
277 |
out.println("Athentication token: " + tokenEncoded + "<BR>"); |
278 |
out.println("</CENTER></BODY></HTML>");
|
279 |
} |
280 |
} |
281 |
} |