SEC-3190: Add support for colons in remember-me token values
We have an issue where token strings that contain a colon break the existing decoding strategy, which tokenizes on colons. so this change urlencodes the individual tokens when creating the cookie string; and urldecodes them decoding the cookie and extracting the tokens. This also eliminates the need for existing code to deal with openid tokens which contain urls, and thus colons.
This commit is contained in:
parent
8d717c62af
commit
832f5c39c1
|
@ -15,8 +15,12 @@
|
|||
*/
|
||||
package org.springframework.security.web.authentication.rememberme;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Base64;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -50,7 +54,7 @@ import org.springframework.util.StringUtils;
|
|||
*
|
||||
* @author Luke Taylor
|
||||
* @author Rob Winch
|
||||
* @author Edd<EFBFBD> Mel<EFBFBD>ndez
|
||||
* @author Edd? Mel?ndez
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract class AbstractRememberMeServices implements RememberMeServices,
|
||||
|
@ -229,13 +233,16 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
|
|||
String[] tokens = StringUtils.delimitedListToStringArray(cookieAsPlainText,
|
||||
DELIMITER);
|
||||
|
||||
if ((tokens[0].equalsIgnoreCase("http") || tokens[0].equalsIgnoreCase("https"))
|
||||
&& tokens[1].startsWith("//")) {
|
||||
// Assume we've accidentally split a URL (OpenID identifier)
|
||||
String[] newTokens = new String[tokens.length - 1];
|
||||
newTokens[0] = tokens[0] + ":" + tokens[1];
|
||||
System.arraycopy(tokens, 2, newTokens, 1, newTokens.length - 1);
|
||||
tokens = newTokens;
|
||||
for (int i = 0; i < tokens.length; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
tokens[i] = URLDecoder.decode(tokens[i], StandardCharsets.UTF_8.toString());
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
return tokens;
|
||||
|
@ -250,7 +257,14 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
|
|||
protected String encodeCookie(String[] cookieTokens) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < cookieTokens.length; i++) {
|
||||
sb.append(cookieTokens[i]);
|
||||
try
|
||||
{
|
||||
sb.append(URLEncoder.encode(cookieTokens[i], StandardCharsets.UTF_8.toString()));
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
if (i < cookieTokens.length - 1) {
|
||||
sb.append(DELIMITER);
|
||||
|
|
|
@ -90,7 +90,7 @@ public class AbstractRememberMeServicesTests {
|
|||
|
||||
@Test
|
||||
public void cookieShouldBeCorrectlyEncodedAndDecoded() throws Exception {
|
||||
String[] cookie = new String[] { "name", "cookie", "tokens", "blah" };
|
||||
String[] cookie = new String[] { "name:with:colon", "cookie", "tokens", "blah" };
|
||||
MockRememberMeServices services = new MockRememberMeServices(uds);
|
||||
|
||||
String encoded = services.encodeCookie(cookie);
|
||||
|
@ -98,7 +98,7 @@ public class AbstractRememberMeServicesTests {
|
|||
assertThat(encoded.endsWith("=")).isFalse();
|
||||
String[] decoded = services.decodeCookie(encoded);
|
||||
|
||||
assertThat(decoded).containsExactly("name", "cookie", "tokens", "blah");
|
||||
assertThat(decoded).containsExactly("name:with:colon", "cookie", "tokens", "blah");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue