Author: sdumitriu
Date: 2007-12-28 15:06:59 +0100 (Fri, 28 Dec 2007)
New Revision: 6503
Modified:
xwiki-platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/user/impl/xwiki/MyPersistentLoginManager.java
Log:
XWIKI-1971: Deleting or putting "false" in the validation cookie bypasses
cookie validation
Fixed.
[cleanup] Fix checkstyle errors, added some javadoc, reorganize duplicated code.
Modified:
xwiki-platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/user/impl/xwiki/MyPersistentLoginManager.java
===================================================================
---
xwiki-platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/user/impl/xwiki/MyPersistentLoginManager.java
2007-12-28 12:08:59 UTC (rev 6502)
+++
xwiki-platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/user/impl/xwiki/MyPersistentLoginManager.java
2007-12-28 14:06:59 UTC (rev 6503)
@@ -21,12 +21,10 @@
package com.xpn.xwiki.user.impl.xwiki;
-import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
-import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -72,6 +70,11 @@
private static final Log LOG =
LogFactory.getLog(MyPersistentLoginManager.class);
/**
+ * Default value to use when getting the authentication cookie values.
+ */
+ private static final String DEFAULT_VALUE = "false";
+
+ /**
* The domain generalization for which the cookies are active. Configured
by the
* xwiki.authentication.cookiedomains parameter. If a request comes from a
host not in this
* list, then the cookie is valid only for the requested domain. If a
request comes from a host
@@ -426,6 +429,13 @@
* Given an array of Cookies, a name, and a default value, this method
tries to find the value
* of the cookie with the given name. If there is no cookie matching the
name in the array, then
* the default value is returned instead.
+ *
+ * @param cookies The list of cookies to search.
+ * @param cookieName The name of the cookie whose value should be returned.
+ * @param defaultValue The default value that should be returned when no
cookie with the given
+ * name was found.
+ * @return The value of the cookie with the given name, or defaultValue if
no such cookie was
+ * found.
*/
private static String getCookieValue(Cookie[] cookies, String cookieName,
String defaultValue)
{
@@ -441,119 +451,110 @@
}
/**
- * Get remembered username
+ * Checks if the cookies are valid.
*
- * @param request the servlet request
- * @param response the servlet response
- * @return the username value or null if not found or a problem with
security of cookie
+ * @param request The servlet request.
+ * @param response The servlet response.
+ * @return True if the validation cookie holds a valid value or is not
present, false otherwise.
+ * @todo Don't ignore it when set to "false", check the validation method.
*/
+ private boolean checkValidation(HttpServletRequest request,
HttpServletResponse response)
+ {
+ if (protection.equals(PROTECTION_ALL) ||
protection.equals(PROTECTION_VALIDATION)) {
+ String username =
+ getCookieValue(request.getCookies(), COOKIE_USERNAME,
DEFAULT_VALUE);
+ String password =
+ getCookieValue(request.getCookies(), COOKIE_PASSWORD,
DEFAULT_VALUE);
+ String cookieHash =
+ getCookieValue(request.getCookies(), COOKIE_VALIDATION,
DEFAULT_VALUE);
+ String calculatedHash = getValidationHash(username, password,
getClientIP(request));
+ if (cookieHash.equals(calculatedHash)) {
+ return true;
+ } else {
+ LOG
+ .warn("Login cookie validation hash mismatch! Cookies have
been tampered with");
+ LOG.info("Login cookie is being deleted!");
+ forgetLogin(request, response);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get the username stored (in a cookie) in the request. Also checks the
validity of the cookie.
+ *
+ * @param request The servlet request.
+ * @param response The servlet response.
+ * @return The username value, or <tt>null</tt> if not found or the cookie
isn't valid.
+ * @todo Also use the URL, in case cookies are disabled [XWIKI-1071].
+ */
public String getRememberedUsername(HttpServletRequest request,
HttpServletResponse response)
- throws IOException, ServletException
{
- String username = getCookieValue(request.getCookies(),
COOKIE_USERNAME, "false");
- String password = getCookieValue(request.getCookies(),
COOKIE_PASSWORD, "false");
+ String username = getCookieValue(request.getCookies(),
COOKIE_USERNAME, DEFAULT_VALUE);
- String validationHash = getCookieValue(request.getCookies(),
COOKIE_VALIDATION, "false");
- if (!username.equals("false")) {
- if (!validationHash.equals("false")) {
- // check hash
- String calculatedHash =
- getValidationHash(username, password,
getClientIP(request));
- if (validationHash.equals(calculatedHash)) {
- if (protection.equals(PROTECTION_ALL)
- || protection.equals(PROTECTION_ENCRYPTION)) {
- username = decryptText(username);
- }
- return username;
- } else {
- System.out.println("!remember-me cookie validation hash
mismatch! ");
- System.out.println("!remember-me cookie has been tampered
with! ");
- System.out.println("!remember-me cookie is being deleted!
");
- removeCookie(request, response, COOKIE_USERNAME);
- removeCookie(request, response, COOKIE_PASSWORD);
- removeCookie(request, response, COOKIE_REMEMBERME);
- removeCookie(request, response, COOKIE_VALIDATION);
- return null;
- }
- } else {
+ if (!username.equals(DEFAULT_VALUE)) {
+ if (checkValidation(request, response)) {
if (protection.equals(PROTECTION_ALL) ||
protection.equals(PROTECTION_ENCRYPTION)) {
username = decryptText(username);
}
return username;
}
- } else {
- return null;
}
+ return null;
}
/**
- * Get remembered password
+ * Get the password stored (in a cookie) in the request. Also checks the
validity of the cookie.
*
- * @param request the servlet request
- * @param response the servlet response
- * @return the password value or null if not found or a problem with
security of cookie
+ * @param request The servlet request.
+ * @param response The servlet response.
+ * @return The password value, or <tt>null</tt> if not found or the cookie
isn't valid.
+ * @todo Also use the URL, in case cookies are disabled [XWIKI-1071].
*/
public String getRememberedPassword(HttpServletRequest request,
HttpServletResponse response)
- throws IOException, ServletException
{
- String username = getCookieValue(request.getCookies(),
COOKIE_USERNAME, "false");
- String password = getCookieValue(request.getCookies(),
COOKIE_PASSWORD, "false");
-
- String validationHash = getCookieValue(request.getCookies(),
COOKIE_VALIDATION, "false");
- if (!password.equals("false")) {
- if (!validationHash.equals("false")) {
- String calculatedHash =
- getValidationHash(username, password,
getClientIP(request));
- if (validationHash.equals(calculatedHash)) {
- if (protection.equals(PROTECTION_ALL)
- || protection.equals(PROTECTION_ENCRYPTION)) {
- password = decryptText(password);
- }
- return password;
- } else {
- System.out.println("!remember-me cookie validation hash
mismatch! ");
- System.out.println("!remember-me cookie has been tampered
with! ");
- System.out.println("!remember-me cookie is being deleted!
");
- removeCookie(request, response, COOKIE_USERNAME);
- removeCookie(request, response, COOKIE_PASSWORD);
- removeCookie(request, response, COOKIE_REMEMBERME);
- removeCookie(request, response, COOKIE_VALIDATION);
- return null;
- }
- } else {
+ String password = getCookieValue(request.getCookies(),
COOKIE_PASSWORD, DEFAULT_VALUE);
+ if (!password.equals(DEFAULT_VALUE)) {
+ if (checkValidation(request, response)) {
if (protection.equals(PROTECTION_ALL) ||
protection.equals(PROTECTION_ENCRYPTION)) {
password = decryptText(password);
}
return password;
}
- } else {
- return null;
}
+ return null;
}
/**
* Decrypt a string.
*
- * @param encryptedText
+ * @param encryptedText The encrypted value.
* @return encryptedText, decrypted
*/
private String decryptText(String encryptedText)
{
sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();
try {
- byte decodedEncryptedText[] = decoder.decodeBuffer(encryptedText);
+ byte[] decodedEncryptedText = decoder.decodeBuffer(encryptedText);
Cipher c1 = Cipher.getInstance(cipherParameters);
c1.init(Cipher.DECRYPT_MODE, secretKey);
byte[] decryptedText = c1.doFinal(decodedEncryptedText);
String decryptedTextString = new String(decryptedText);
return decryptedTextString;
} catch (Exception e) {
- System.out.println("Error: " + e);
- e.printStackTrace();
+ LOG.error(e);
return null;
}
}
+ /**
+ * Returns the original client IP. Needed because request.getRemoteAddr
returns the address of
+ * the last requesting host, which can be either the real client, or a
proxy. The original
+ * method prevents logging in when using a cluster of reverse proxies in
front of XWiki.
+ *
+ * @param request The servlet request.
+ * @return The IP of the actual client.
+ */
protected String getClientIP(HttpServletRequest request)
{
String remoteIP = request.getHeader("X-Forwarded-For");
_______________________________________________
notifications mailing list
[email protected]
http://lists.xwiki.org/mailman/listinfo/notifications