Author: mgrigorov
Date: Mon May 30 16:06:28 2011
New Revision: 1129236
URL: http://svn.apache.org/viewvc?rev=1129236&view=rev
Log:
WICKET-3514 SimpleTree example not working with CryptoMapper
Encode the crypted URL as url segments and add some artificial segments to fix
the problem with broken urls for images in .css files.
Added:
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/mapper/CryptoMapperTest.java
Modified:
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/mapper/CryptoMapper.java
wicket/trunk/wicket-request/src/main/java/org/apache/wicket/request/mapper/parameter/PageParameters.java
Modified:
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/mapper/CryptoMapper.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/mapper/CryptoMapper.java?rev=1129236&r1=1129235&r2=1129236&view=diff
==============================================================================
---
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/mapper/CryptoMapper.java
(original)
+++
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/mapper/CryptoMapper.java
Mon May 30 16:06:28 2011
@@ -16,6 +16,8 @@
*/
package org.apache.wicket.request.mapper;
+import java.util.List;
+
import org.apache.wicket.Application;
import org.apache.wicket.request.IRequestHandler;
import org.apache.wicket.request.IRequestMapper;
@@ -24,6 +26,8 @@ import org.apache.wicket.request.Url;
import org.apache.wicket.util.IProvider;
import org.apache.wicket.util.crypt.ICrypt;
import org.apache.wicket.util.string.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Request mapper that encrypts urls generated by another mapper.
@@ -32,6 +36,8 @@ import org.apache.wicket.util.string.Str
*/
public class CryptoMapper implements IRequestMapper
{
+ private static final Logger log =
LoggerFactory.getLogger(CryptoMapper.class);
+
private final IRequestMapper wrappedMapper;
private final IProvider<ICrypt> cryptProvider;
private final Application application;
@@ -104,9 +110,39 @@ public class CryptoMapper implements IRe
private Url encryptUrl(Url url)
{
- Url encrypted = new Url();
+ if (url.getSegments().isEmpty() &&
url.getQueryParameters().isEmpty())
+ {
+ return url;
+ }
String encryptedUrlString =
getCrypt().encryptUrlSafe(url.toString());
- encrypted.addQueryParameter(getCryptParameterName(),
encryptedUrlString);
+
+ Url encrypted = new Url(url.getCharset());
+ encrypted.getSegments().add(encryptedUrlString);
+ encrypted.getQueryParameters().addAll(url.getQueryParameters());
+
+ int numberOfSegments = url.getSegments().size();
+ if (numberOfSegments == 0 &&
!url.getQueryParameters().isEmpty())
+ {
+ numberOfSegments = 1;
+ }
+ char[] encryptedChars = encryptedUrlString.toCharArray();
+ int hash = 0;
+ for (int segNo = 0; segNo < numberOfSegments; segNo++)
+ {
+ char a = encryptedChars[Math.abs(hash %
encryptedChars.length)];
+ hash++;
+ char b = encryptedChars[Math.abs(hash %
encryptedChars.length)];
+ hash++;
+ char c = encryptedChars[Math.abs(hash %
encryptedChars.length)];
+
+ String segment = "" + a + b + c;
+ hash = hashString(segment);
+
+ segment += String.format("%02x", Math.abs(hash % 256));
+ encrypted.getSegments().add(segment);
+ hash = hashString(segment);
+ }
+
return encrypted;
}
@@ -117,33 +153,89 @@ public class CryptoMapper implements IRe
return encryptedUrl;
}
- String encryptedUrlString =
encryptedUrl.getQueryParameterValue(getCryptParameterName())
- .toString();
- if (Strings.isEmpty(encryptedUrlString))
+ List<String> segments = encryptedUrl.getSegments();
+ if (segments.size() < 2)
{
return null;
}
- Url url = null;
+ Url url = new Url(request.getCharset());
try
{
- String urlString =
getCrypt().decryptUrlSafe(encryptedUrlString);
- url = Url.parse(urlString, request.getCharset());
+ String encryptedUrlString = segments.get(0);
+ if (Strings.isEmpty(encryptedUrlString))
+ {
+ return null;
+ }
+
+ String decryptedUrl =
getCrypt().decryptUrlSafe(encryptedUrlString);
+ Url originalUrl = Url.parse(decryptedUrl,
request.getCharset());
+
+ int originalNumberOfSegments =
originalUrl.getSegments().size();
+ int numberOfSegments =
encryptedUrl.getSegments().size();
+
+ char[] encryptedChars =
encryptedUrlString.toCharArray();
+ int hash = 0;
+
+ int segNo;
+ for (segNo = 1; segNo < numberOfSegments && segNo <
originalNumberOfSegments + 1; segNo++)
+ {
+ char a = encryptedChars[Math.abs(hash %
encryptedChars.length)];
+ hash++;
+ char b = encryptedChars[Math.abs(hash %
encryptedChars.length)];
+ hash++;
+ char c = encryptedChars[Math.abs(hash %
encryptedChars.length)];
+
+ String segment = "" + a + b + c;
+ hash = hashString(segment);
+
+ segment += String.format("%02x", Math.abs(hash
% 256));
+ hash = hashString(segment);
+
+ if
(segment.equals(encryptedUrl.getSegments().get(segNo)))
+ {
+
url.getSegments().add(originalUrl.getSegments().get(segNo - 1));
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (segNo < numberOfSegments)
+ {
+
url.getQueryParameters().addAll(encryptedUrl.getQueryParameters());
+
+ for (; segNo < numberOfSegments; segNo++)
+ {
+
url.getSegments().add(encryptedUrl.getSegments().get(segNo));
+ }
+ }
+ else
+ {
+
url.getQueryParameters().addAll(originalUrl.getQueryParameters());
+ }
}
catch (Exception e)
{
+ log.error("Error decrypting URL", e);
url = null;
}
return url;
}
- /**
- * @return the name of the parameter that brings the encrypted url
- */
- protected String getCryptParameterName()
+ private int hashString(final String str)
{
- return application.getMapperContext().getNamespace();
+ int hash = 97;
+
+ for (char c : str.toCharArray())
+ {
+ int i = c;
+ hash = 47 * hash + i;
+ }
+
+ return hash;
}
private static class ApplicationCryptProvider implements
IProvider<ICrypt>
Added:
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/mapper/CryptoMapperTest.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/mapper/CryptoMapperTest.java?rev=1129236&view=auto
==============================================================================
---
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/mapper/CryptoMapperTest.java
(added)
+++
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/mapper/CryptoMapperTest.java
Mon May 30 16:06:28 2011
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.request.mapper;
+
+import org.apache.wicket.protocol.http.WebApplication;
+import org.apache.wicket.request.IRequestHandler;
+import org.apache.wicket.request.Request;
+import org.apache.wicket.request.Url;
+import org.apache.wicket.request.handler.PageProvider;
+import org.apache.wicket.request.handler.RenderPageRequestHandler;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.util.tester.DummyHomePage;
+import org.apache.wicket.util.tester.WicketTester;
+
+/**
+ * Tests for {@link CryptoMapper}
+ */
+public class CryptoMapperTest extends AbstractMapperTest
+{
+ /**
+ * the encrypted version of {@link #EXPECTED_URL}
+ */
+ private static final String ENCRYPTED_URL =
"SnPh82L4Kl4/SnPe4/4Sn8e/nPh75/h8211";
+
+ /**
+ * The url to encrypt
+ */
+ private static final Url EXPECTED_URL = Url.parse("a/b/c/d");
+
+ private CryptoMapper mapper;
+
+ private WicketTester tester;
+
+ /**
+ * Creates the {@link CryptoMapper}
+ *
+ * @throws Exception
+ */
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ tester = new WicketTester();
+ WebApplication webApplication = tester.getApplication();
+ webApplication.mountPage(EXPECTED_URL.toString(),
DummyHomePage.class);
+ mapper = new
CryptoMapper(webApplication.getRootRequestMapper(), webApplication);
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ tester.destroy();
+
+ super.tearDown();
+ }
+
+ /**
+ * Tests that {@link CryptoMapper} wraps the original request mapper
and encrypts the url
+ * produced by it
+ */
+ public void testEncrypt()
+ {
+ Url url = mapper.mapHandler(new RenderPageRequestHandler(new
PageProvider(
+ DummyHomePage.class, new PageParameters())));
+ assertEquals(ENCRYPTED_URL, url.toString());
+ }
+
+ /**
+ * Tests that {@link CryptoMapper} decrypts the passed url and pass it
to the original request
+ * mapper which resolves the page from the application mounts
+ */
+ public void testDecrypt()
+ {
+ Request request = getRequest(Url.parse(ENCRYPTED_URL));
+ IRequestHandler requestHandler = mapper.mapRequest(request);
+ assertTrue(requestHandler instanceof RenderPageRequestHandler);
+
+ RenderPageRequestHandler handler =
(RenderPageRequestHandler)requestHandler;
+ assertEquals(DummyHomePage.class, handler.getPageClass());
+ }
+
+ /**
+ * Tests that named and indexed parameters are properly (en|de)crypted
+ */
+ public void testPageParameters()
+ {
+ String expectedEncrypted =
"ywKWg-Qpk7YQBiYCmj9MaAJSIV1gtssNinjiALijtet62VMQc2-sMK_RchttkidUpYM_cplXKeZSfGxBkvWzH_E_zWv4Ii7MNSm5nXKno7o/ywK6c/MK_c0/nji3c/Qpk1b/XKnba/c2-cd?namedKey1=namedValue1&namedKey2=namedValue2";
+
+ PageParameters expectedParameters = new PageParameters();
+ expectedParameters.add("namedKey1", "namedValue1");
+ expectedParameters.add("namedKey2", "namedValue2");
+ expectedParameters.set(0, "indexedValue1");
+ expectedParameters.set(1, "indexedValue2");
+ RenderPageRequestHandler renderPageRequestHandler = new
RenderPageRequestHandler(
+ new PageProvider(DummyHomePage.class,
expectedParameters));
+ Url url = mapper.mapHandler(renderPageRequestHandler);
+// System.err.println(url.toString());
+ assertEquals(expectedEncrypted, url.toString());
+
+ Request request = getRequest(url);
+ IRequestHandler requestHandler = mapper.mapRequest(request);
+ assertTrue(requestHandler instanceof RenderPageRequestHandler);
+
+ RenderPageRequestHandler handler =
(RenderPageRequestHandler)requestHandler;
+ assertEquals(DummyHomePage.class, handler.getPageClass());
+ PageParameters actualParameters = handler.getPageParameters();
+ assertEquals(expectedParameters, actualParameters);
+ }
+}
Modified:
wicket/trunk/wicket-request/src/main/java/org/apache/wicket/request/mapper/parameter/PageParameters.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/wicket-request/src/main/java/org/apache/wicket/request/mapper/parameter/PageParameters.java?rev=1129236&r1=1129235&r2=1129236&view=diff
==============================================================================
---
wicket/trunk/wicket-request/src/main/java/org/apache/wicket/request/mapper/parameter/PageParameters.java
(original)
+++
wicket/trunk/wicket-request/src/main/java/org/apache/wicket/request/mapper/parameter/PageParameters.java
Mon May 30 16:06:28 2011
@@ -56,6 +56,43 @@ public class PageParameters implements S
private String key;
private String value;
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((key == null) ? 0 :
key.hashCode());
+ result = prime * result + ((value == null) ? 0 :
value.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Entry other = (Entry)obj;
+ if (key == null)
+ {
+ if (other.key != null)
+ return false;
+ }
+ else if (!key.equals(other.key))
+ return false;
+ if (value == null)
+ {
+ if (other.value != null)
+ return false;
+ }
+ else if (!value.equals(other.value))
+ return false;
+ return true;
+ }
}
private static final long serialVersionUID = 1L;