Add setting to throw PageExpiredException when encrypted URL is no longer decryptable
Project: http://git-wip-us.apache.org/repos/asf/wicket/repo Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/88ef25b6 Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/88ef25b6 Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/88ef25b6 Branch: refs/heads/wicket-6.x Commit: 88ef25b6ab7f94c7e9e4bfe2e5787072f2f7cf89 Parents: 6af2d59 Author: Jesse Long <[email protected]> Authored: Thu Oct 9 17:32:22 2014 +0200 Committer: Jesse Long <[email protected]> Committed: Tue Oct 14 22:32:01 2014 +0200 ---------------------------------------------------------------------- .../core/request/mapper/CryptoMapper.java | 71 +++++++++++++++++++- .../core/request/mapper/CryptoMapperTest.java | 28 ++++++++ 2 files changed, 97 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/wicket/blob/88ef25b6/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/CryptoMapper.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/CryptoMapper.java b/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/CryptoMapper.java index 8dde7b1..e626705 100755 --- a/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/CryptoMapper.java +++ b/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/CryptoMapper.java @@ -21,6 +21,7 @@ import java.util.List; import org.apache.wicket.Application; import org.apache.wicket.core.request.handler.RequestSettingRequestHandler; +import org.apache.wicket.protocol.http.PageExpiredException; import org.apache.wicket.request.IRequestHandler; import org.apache.wicket.request.IRequestMapper; import org.apache.wicket.request.Request; @@ -70,6 +71,12 @@ import org.slf4j.LoggerFactory; * When encrypting mounted URLs, we look for the {@link PageComponentInfo} parameter, and encrypt only that parameter. * </p> * + * <p> + * {@link CryptoMapper} can be configured to mark encrypted URLs as encrypted, and throw a {@link PageExpiredException} + * exception if a encrypted URL cannot be decrypted. This can occur when using {@code KeyInSessionSubJceCryptFactory}, and + * the session has expired. + * </p> + * * @author igor.vaynberg * @author Jesse Long * @author svenmeier @@ -83,10 +90,17 @@ public class CryptoMapper implements IRequestMapperDelegate */ private static final String ENCRYPTED_PAGE_COMPONENT_INFO_PARAMETER = "wicket"; + private static final String ENCRYPTED_URL_MARKER_PREFIX = "crypt."; + private final IRequestMapper wrappedMapper; private final IProvider<ICrypt> cryptProvider; /** + * Whether or not to mark encrypted URLs as encrypted. + */ + private boolean markEncryptedUrls = false; + + /** * Encrypt with {@link ISecuritySettings#getCryptFactory()}. * <p> * Note: Encryption is done with {@link ISecuritySettings#DEFAULT_ENCRYPTION_KEY} if you haven't @@ -118,6 +132,32 @@ public class CryptoMapper implements IRequestMapperDelegate } /** + * Whether or not to mark encrypted URLs as encrypted. If set, a {@link PageExpiredException} is thrown when + * a encrypted URL can no longer be decrypted. + * + * @return whether or not to mark encrypted URLs as encrypted. + */ + public boolean getMarkEncryptedUrls() + { + return markEncryptedUrls; + } + + /** + * Sets whether or not to mark encrypted URLs as encrypted. If set, a {@link PageExpiredException} is thrown when + * a encrypted URL can no longer be decrypted. + * + * @param markEncryptedUrls + * whether or not to mark encrypted URLs as encrypted. + * + * @return {@code this}, for chaining. + */ + public CryptoMapper setMarkEncryptedUrls(boolean markEncryptedUrls) + { + this.markEncryptedUrls = markEncryptedUrls; + return this; + } + + /** * {@inheritDoc} * <p> * This implementation decrypts the URL and passes the decrypted URL to the wrapped mapper. @@ -253,7 +293,15 @@ public class CryptoMapper implements IRequestMapperDelegate String encryptedUrlString = getCrypt().encryptUrlSafe(url.toString()); Url encryptedUrl = new Url(url.getCharset()); - encryptedUrl.getSegments().add(encryptedUrlString); + + if (getMarkEncryptedUrls()) + { + encryptedUrl.getSegments().add(ENCRYPTED_URL_MARKER_PREFIX + encryptedUrlString); + } + else + { + encryptedUrl.getSegments().add(encryptedUrlString); + } int numberOfSegments = url.getSegments().size() - 1; HashedSegmentGenerator generator = new HashedSegmentGenerator(encryptedUrlString); @@ -373,6 +421,18 @@ public class CryptoMapper implements IRequestMapperDelegate return null; } + if (getMarkEncryptedUrls()) + { + if (encryptedUrlString.startsWith(ENCRYPTED_URL_MARKER_PREFIX)) + { + encryptedUrlString = encryptedUrlString.substring(ENCRYPTED_URL_MARKER_PREFIX.length()); + } + else + { + return null; + } + } + String decryptedUrl; try { @@ -386,7 +446,14 @@ public class CryptoMapper implements IRequestMapperDelegate if (decryptedUrl == null) { - return null; + if (getMarkEncryptedUrls()) + { + throw new PageExpiredException("Encrypted URL is no longer decryptable"); + } + else + { + return null; + } } Url originalUrl = Url.parse(decryptedUrl, request.getCharset()); http://git-wip-us.apache.org/repos/asf/wicket/blob/88ef25b6/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/CryptoMapperTest.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/CryptoMapperTest.java b/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/CryptoMapperTest.java index 8a6181c..b8213e6 100644 --- a/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/CryptoMapperTest.java +++ b/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/CryptoMapperTest.java @@ -27,6 +27,7 @@ import org.apache.wicket.markup.IMarkupFragment; import org.apache.wicket.markup.Markup; import org.apache.wicket.markup.html.WebPage; import org.apache.wicket.markup.html.link.ILinkListener; +import org.apache.wicket.protocol.http.PageExpiredException; import org.apache.wicket.protocol.http.WebApplication; import org.apache.wicket.request.IRequestHandler; import org.apache.wicket.request.IRequestHandlerDelegate; @@ -573,6 +574,33 @@ public class CryptoMapperTest extends AbstractMapperTest .toString()); } + @Test + public void markedEncryptedUrlDecrypt() + { + mapper.setMarkEncryptedUrls(true); + Request request = getRequest(Url.parse("crypt." + ENCRYPTED_BOOKMARKABLE_URL)); + IRequestHandler requestHandler = mapper.mapRequest(request); + + assertNotNull(requestHandler); + requestHandler = unwrapRequestHandlerDelegate(requestHandler); + + assertTrue(requestHandler instanceof RenderPageRequestHandler); + + RenderPageRequestHandler handler = (RenderPageRequestHandler) requestHandler; + assertEquals(Page2.class, handler.getPageClass()); + } + + @Test(expected = PageExpiredException.class) + public void expiredMarkedEncryptedUrlThrowsPageExpiredException() + { + mapper.setMarkEncryptedUrls(true); + Url encryptedUrl = mapper.mapHandler(new RenderPageRequestHandler(new PageProvider(Page2.class))); + assertTrue(encryptedUrl.getSegments().get(0).startsWith("crypt.")); + encryptedUrl.getSegments().remove(0); + encryptedUrl.getSegments().add(0, "crypt.no decryptable"); + mapper.mapRequest(getRequest(encryptedUrl)); + } + private static IRequestHandler unwrapRequestHandlerDelegate(IRequestHandler handler) { while (handler instanceof IRequestHandlerDelegate)
