You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by sv...@apache.org on 2018/10/30 12:59:31 UTC
[52/52] [abbrv] wicket git commit: WICKET-6559 new encrypting page
store
WICKET-6559 new encrypting page store
Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/bf72e279
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/bf72e279
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/bf72e279
Branch: refs/heads/WICKET-6563
Commit: bf72e27980070572b57c8ad0130c83a7d024aa0f
Parents: c43d3a3
Author: Sven Meier <sv...@apache.org>
Authored: Tue Oct 30 09:13:41 2018 +0100
Committer: Sven Meier <sv...@apache.org>
Committed: Tue Oct 30 13:56:24 2018 +0100
----------------------------------------------------------------------
.../wicket/DefaultPageManagerProvider.java | 11 +-
.../wicket/pageStore/CryptingPageStore.java | 146 +++++++++++++++++++
.../wicket/pageStore/crypt/DefaultCrypter.java | 108 ++++++++++++++
.../apache/wicket/pageStore/crypt/ICrypter.java | 28 ++++
.../apache/wicket/settings/StoreSettings.java | 17 ++-
.../wicket/pageStore/CryptingPageStoreTest.java | 87 +++++++++++
6 files changed, 393 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/wicket/blob/bf72e279/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java b/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
index cf4f84a..36c1fac 100644
--- a/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
+++ b/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
@@ -21,6 +21,7 @@ import java.io.File;
import org.apache.wicket.page.IPageManager;
import org.apache.wicket.page.PageManager;
import org.apache.wicket.pageStore.AsynchronousPageStore;
+import org.apache.wicket.pageStore.CryptingPageStore;
import org.apache.wicket.pageStore.DiskPageStore;
import org.apache.wicket.pageStore.FilePageStore;
import org.apache.wicket.pageStore.GroupingPageStore;
@@ -41,8 +42,8 @@ import org.apache.wicket.util.lang.Bytes;
* <ol>
* <li>{@link RequestPageStore} caching pages until end of the request</li>
* <li>{@link InSessionPageStore} keeping the last accessed page in the session</li>
- * <li>{@link AsynchronousPageStore} moving storage of pages to a worker thread (if enabled in
- * {@link StoreSettings#isAsynchronous()})</li>
+ * <li>{@link AsynchronousPageStore} moving storage of pages to a worker thread (if enabled in {@link StoreSettings#isAsynchronous()})</li>
+ * <li>{@link CryptingPageStore} encrypting all pages (if enabled in {@link StoreSettings#isEncrypted()})</li>
* <li>{@link DiskPageStore} keeping all pages, configured according to {@link StoreSettings}</li>
* </ol>
* An alternative chain with all pages held in-memory could be:
@@ -166,6 +167,10 @@ public class DefaultPageManagerProvider implements IPageManagerProvider
Bytes maxSizePerSession = storeSettings.getMaxSizePerSession();
File fileStoreFolder = storeSettings.getFileStoreFolder();
- return new DiskPageStore(application.getName(), fileStoreFolder, maxSizePerSession, getSerializer());
+ if (storeSettings.isEncrypted()) {
+ return new SerializingPageStore(new CryptingPageStore(new DiskPageStore(application.getName(), fileStoreFolder, maxSizePerSession)), getSerializer());
+ } else {
+ return new DiskPageStore(application.getName(), fileStoreFolder, maxSizePerSession, getSerializer());
+ }
}
}
http://git-wip-us.apache.org/repos/asf/wicket/blob/bf72e279/wicket-core/src/main/java/org/apache/wicket/pageStore/CryptingPageStore.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/CryptingPageStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/CryptingPageStore.java
new file mode 100644
index 0000000..2b27e80
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/CryptingPageStore.java
@@ -0,0 +1,146 @@
+/*
+ * 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.pageStore;
+
+import java.io.Serializable;
+
+import org.apache.wicket.MetaDataKey;
+import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.page.IManageablePage;
+import org.apache.wicket.pageStore.crypt.DefaultCrypter;
+import org.apache.wicket.pageStore.crypt.ICrypter;
+import org.apache.wicket.serialize.ISerializer;
+
+/**
+ * A store that encrypts all pages before delegating and vice versa.
+ * <p>
+ * All pages passing through this store are restricted to be {@link SerializedPage}s. You can
+ * achieve this with
+ * <ul>
+ * <li>a {@link SerializingPageStore} delegating to this store and</li>
+ * <li>delegating to a store that does not deserialize its pages, e.g. a {@link DiskPageStore}
+ * without {@link ISerializer}</li>.
+ * </ul>
+ */
+public class CryptingPageStore extends DelegatingPageStore
+{
+ private static final MetaDataKey<SessionData> KEY = new MetaDataKey<SessionData>()
+ {
+ };
+
+ /**
+ * @param delegate
+ * store to delegate to
+ * @param applicationName
+ * name of application
+ */
+ public CryptingPageStore(IPageStore delegate)
+ {
+ super(delegate);
+ }
+
+ /**
+ * Supports asynchronous add if the delegate supports it.
+ */
+ @Override
+ public boolean canBeAsynchronous(IPageContext context)
+ {
+ context.bind();
+
+ getSessionData(context);
+
+ return getDelegate().canBeAsynchronous(context);
+ }
+
+ private SessionData getSessionData(IPageContext context)
+ {
+ SessionData data = context.getSessionData(KEY);
+ if (data == null)
+ {
+ data = context.setSessionData(KEY, new SessionData(newCrypter(context)));
+ }
+ return data;
+ }
+
+ /**
+ * Create a new {@link ICrypter} for the given context.
+ */
+ protected ICrypter newCrypter(IPageContext context) {
+ return new DefaultCrypter();
+ }
+
+ @Override
+ public IManageablePage getPage(IPageContext context, int id)
+ {
+ IManageablePage page = super.getPage(context, id);
+
+ if (page != null)
+ {
+ if (page instanceof SerializedPage == false)
+ {
+ throw new WicketRuntimeException("CryptingPageStore expects serialized pages");
+ }
+ SerializedPage serializedPage = (SerializedPage)page;
+
+ byte[] encrypted = serializedPage.getData();
+ byte[] decrypted = getSessionData(context).decrypt(encrypted);
+
+ page = new SerializedPage(page.getPageId(), serializedPage.getPageType(), decrypted);
+ }
+
+ return page;
+ }
+
+ @Override
+ public void addPage(IPageContext context, IManageablePage page)
+ {
+ if (page instanceof SerializedPage == false)
+ {
+ throw new WicketRuntimeException("CryptingPageStore works with serialized pages only");
+ }
+
+ SerializedPage serializedPage = (SerializedPage)page;
+
+ byte[] decrypted = serializedPage.getData();
+ byte[] encrypted = getSessionData(context).encrypt(decrypted);
+
+ page = new SerializedPage(page.getPageId(), serializedPage.getPageType(), encrypted);
+
+ super.addPage(context, page);
+ }
+
+ private static class SessionData implements Serializable
+ {
+
+ private ICrypter cypter;
+
+ public SessionData(ICrypter crypter)
+ {
+ this.cypter= crypter;
+ }
+
+ public byte[] encrypt(byte[] decrypted)
+ {
+ return cypter.encrypt(decrypted);
+ }
+
+ public byte[] decrypt(byte[] encrypted)
+ {
+ return cypter.decrypt(encrypted);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/wicket/blob/bf72e279/wicket-core/src/main/java/org/apache/wicket/pageStore/crypt/DefaultCrypter.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/crypt/DefaultCrypter.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/crypt/DefaultCrypter.java
new file mode 100644
index 0000000..53c63be
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/crypt/DefaultCrypter.java
@@ -0,0 +1,108 @@
+/*
+ * 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.pageStore.crypt;
+
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Arrays;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+
+import org.apache.wicket.WicketRuntimeException;
+
+/**
+ * Default encryption and decryption implementation.
+ */
+public class DefaultCrypter implements ICrypter
+{
+ private final SecureRandom random;
+
+ private final SecretKey key;
+
+ public DefaultCrypter()
+ {
+ try
+ {
+ random = SecureRandom.getInstance("SHA1PRNG", "SUN");
+
+ KeyGenerator generator = KeyGenerator.getInstance("AES");
+ generator.init(256, random);
+ key = generator.generateKey();
+ }
+ catch (GeneralSecurityException ex)
+ {
+ throw new WicketRuntimeException(ex);
+ }
+ }
+
+ protected Cipher getCipher() throws GeneralSecurityException
+ {
+ return Cipher.getInstance("AES/CBC/PKCS5Padding");
+ }
+
+ @Override
+ public byte[] encrypt(byte[] decrypted)
+ {
+ try
+ {
+ Cipher cipher = getCipher();
+ cipher.init(Cipher.ENCRYPT_MODE, key, random);
+
+ AlgorithmParameters params = cipher.getParameters();
+ byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
+
+ byte[] ciphertext = cipher.doFinal(decrypted);
+
+ byte[] encrypted = Arrays.copyOf(iv, iv.length + ciphertext.length);
+ System.arraycopy(ciphertext, 0, encrypted, iv.length, ciphertext.length);
+
+ return encrypted;
+ }
+ catch (GeneralSecurityException ex)
+ {
+ throw new WicketRuntimeException(ex);
+ }
+ }
+
+ @Override
+ public byte[] decrypt(byte[] encrypted)
+ {
+ try
+ {
+ byte[] iv = new byte[16];
+ byte[] ciphertext = new byte[encrypted.length - 16];
+ System.arraycopy(encrypted, 0, iv, 0, iv.length);
+ System.arraycopy(encrypted, 16, ciphertext, 0, ciphertext.length);
+
+ Cipher cipher = getCipher();
+ cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
+ byte[] decrypted = cipher.doFinal(ciphertext);
+
+ return decrypted;
+ }
+ catch (GeneralSecurityException ex)
+ {
+ throw new WicketRuntimeException(ex);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/wicket/blob/bf72e279/wicket-core/src/main/java/org/apache/wicket/pageStore/crypt/ICrypter.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/crypt/ICrypter.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/crypt/ICrypter.java
new file mode 100644
index 0000000..1cdbeaf
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/crypt/ICrypter.java
@@ -0,0 +1,28 @@
+/*
+ * 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.pageStore.crypt;
+
+import java.io.Serializable;
+
+/**
+ * An encrypter and decrypter of pages.
+ */
+public interface ICrypter extends Serializable {
+ byte[] encrypt(byte[] bytes);
+
+ byte[] decrypt(byte[] bytes);
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/wicket/blob/bf72e279/wicket-core/src/main/java/org/apache/wicket/settings/StoreSettings.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/settings/StoreSettings.java b/wicket-core/src/main/java/org/apache/wicket/settings/StoreSettings.java
index 7c32101..965258c 100644
--- a/wicket-core/src/main/java/org/apache/wicket/settings/StoreSettings.java
+++ b/wicket-core/src/main/java/org/apache/wicket/settings/StoreSettings.java
@@ -49,6 +49,8 @@ public class StoreSettings
private boolean asynchronous = true;
+ private boolean encrypted = false;
+
/**
* Construct.
*
@@ -179,4 +181,17 @@ public class StoreSettings
{
return asynchronous;
}
-}
\ No newline at end of file
+
+ public void setEncrypted(boolean encrypted)
+ {
+ this.encrypted = encrypted;
+ }
+
+ /**
+ * @return {@code true} if the storing of page is encrypted
+ */
+ public boolean isEncrypted()
+ {
+ return encrypted;
+ }
+}
http://git-wip-us.apache.org/repos/asf/wicket/blob/bf72e279/wicket-core/src/test/java/org/apache/wicket/pageStore/CryptingPageStoreTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/pageStore/CryptingPageStoreTest.java b/wicket-core/src/test/java/org/apache/wicket/pageStore/CryptingPageStoreTest.java
new file mode 100644
index 0000000..a4b547e
--- /dev/null
+++ b/wicket-core/src/test/java/org/apache/wicket/pageStore/CryptingPageStoreTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.pageStore;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.security.GeneralSecurityException;
+
+import org.apache.wicket.MockPage;
+import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.mock.MockPageStore;
+import org.apache.wicket.serialize.java.JavaSerializer;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test for {@link CryptingPageStore}.
+ *
+ * @author svenmeier
+ */
+public class CryptingPageStoreTest
+{
+
+ @Test
+ void test()
+ {
+ CryptingPageStore store = new CryptingPageStore(new MockPageStore());
+ JavaSerializer serializer = new JavaSerializer("test");
+
+ IPageContext context = new DummyPageContext();
+
+ for (int p = 0; p < 10; p++)
+ {
+ MockPage add = new MockPage(p);
+ SerializedPage serializedAdd = new SerializedPage(p, "foo", serializer.serialize(add));
+ store.addPage(context, serializedAdd);
+
+ SerializedPage serializedGot = (SerializedPage)store.getPage(context, p);
+ MockPage got = (MockPage)serializer.deserialize(serializedGot.getData());
+ assertEquals(p, got.getPageId());
+ }
+ }
+
+ @Test
+ void testFail()
+ {
+ CryptingPageStore store = new CryptingPageStore(new MockPageStore());
+ JavaSerializer serializer = new JavaSerializer("test");
+
+ DummyPageContext context = new DummyPageContext();
+
+ int p = 42;
+
+ MockPage add = new MockPage(p);
+ SerializedPage serializedAdd = new SerializedPage(p, "foo", serializer.serialize(add));
+ store.addPage(context, serializedAdd);
+
+ // remove key from session
+ context.clearSession();
+
+ try
+ {
+ SerializedPage serializedGot = (SerializedPage)store.getPage(context, p);
+
+ MockPage got = (MockPage)serializer.deserialize(serializedGot.getData());
+ assertEquals(p, got.getPageId());
+ }
+ catch (WicketRuntimeException ex)
+ {
+ assertTrue("unable to decrypt with new key", ex.getCause() instanceof GeneralSecurityException);
+ }
+ }
+}