You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2022/03/22 08:15:08 UTC
[isis] 02/02: ISIS-2981: adds crypto roundtrip tests
This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git
commit 13d3689afa31eda419125d7fa7f12da454b2ae3f
Author: Andi Huber <ah...@apache.org>
AuthorDate: Tue Mar 22 09:14:57 2022 +0100
ISIS-2981: adds crypto roundtrip tests
---
viewers/wicket/viewer/pom.xml | 7 ++
.../viewer/wicketapp/IsisWicketApplication.java | 9 +-
.../wicket/viewer/wicketapp/_CryptFactory.java | 65 ++++++++++++
.../wicket/viewer/wicketapp/CryptFactoryTest.java | 117 +++++++++++++++++++++
4 files changed, 194 insertions(+), 4 deletions(-)
diff --git a/viewers/wicket/viewer/pom.xml b/viewers/wicket/viewer/pom.xml
index 0a3b49f..9373a71 100644
--- a/viewers/wicket/viewer/pom.xml
+++ b/viewers/wicket/viewer/pom.xml
@@ -184,6 +184,13 @@
<scope>test</scope>
</dependency>
+ <!-- so we can test Cookies -->
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <scope>test</scope>
+ </dependency>
+
<dependency>
<groupId>org.jmock</groupId>
<artifactId>jmock-junit4</artifactId>
diff --git a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/wicketapp/IsisWicketApplication.java b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/wicketapp/IsisWicketApplication.java
index fb4f5b1..e744f4e 100644
--- a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/wicketapp/IsisWicketApplication.java
+++ b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/wicketapp/IsisWicketApplication.java
@@ -336,13 +336,14 @@ implements
val rememberMe = configuration.getViewer().getWicket().getRememberMe();
val cookieKey = rememberMe.getCookieKey();
val encryptionKey = rememberMe.getEncryptionKey().orElse(defaultEncryptionKey());
- return new DefaultAuthenticationStrategy(cookieKey, encryptionKey);
+ return new DefaultAuthenticationStrategy(cookieKey, _CryptFactory.sunJceCrypt(encryptionKey));
}
/**
- * As called by {@link #newAuthenticationStrategy(IsisConfiguration)}; if an encryption key for the 'rememberMe'
- * cookie hasn't been configured, then use a different encryption key for the 'rememberMe' cookie each time the
- * app is restarted.
+ * As called by {@link #newAuthenticationStrategy(IsisConfiguration)}.
+ * If an encryption key for the 'rememberMe' cookie hasn't been configured,
+ * then use a different encryption key for the 'rememberMe'
+ * cookie each time the app is restarted.
*/
String defaultEncryptionKey() {
return systemEnvironment.isPrototyping()
diff --git a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/wicketapp/_CryptFactory.java b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/wicketapp/_CryptFactory.java
new file mode 100644
index 0000000..cbd27a5
--- /dev/null
+++ b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/wicketapp/_CryptFactory.java
@@ -0,0 +1,65 @@
+/*
+ * 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.isis.viewer.wicket.viewer.wicketapp;
+
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.wicket.core.random.DefaultSecureRandomSupplier;
+import org.apache.wicket.core.random.ISecureRandomSupplier;
+import org.apache.wicket.core.util.crypt.AESCrypt;
+import org.apache.wicket.util.crypt.ICrypt;
+import org.apache.wicket.util.crypt.SunJceCrypt;
+
+import lombok.SneakyThrows;
+import lombok.val;
+import lombok.experimental.UtilityClass;
+
+@UtilityClass
+class _CryptFactory {
+
+ ICrypt sunJceCrypt(final String encryptionKey) {
+ final byte[] salt = SunJceCrypt.randomSalt();
+ val crypt = new SunJceCrypt(salt, 1000);
+ crypt.setKey(encryptionKey);
+ return crypt;
+ }
+
+ @SneakyThrows
+ ICrypt aesCrypt(final String encryptionKey) {
+
+ final byte[] salt = SunJceCrypt.randomSalt();
+
+ SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
+ KeySpec spec = new PBEKeySpec(encryptionKey.toCharArray(), salt, 65536, 256);
+ SecretKey tmp = factory.generateSecret(spec);
+ SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
+
+ ISecureRandomSupplier rGen = new DefaultSecureRandomSupplier();
+
+ return new AESCrypt(secret, rGen);
+ }
+
+ //XXX BCryptPasswordEncoder (Spring);
+
+}
diff --git a/viewers/wicket/viewer/src/test/java/org/apache/isis/viewer/wicket/viewer/wicketapp/CryptFactoryTest.java b/viewers/wicket/viewer/src/test/java/org/apache/isis/viewer/wicket/viewer/wicketapp/CryptFactoryTest.java
new file mode 100644
index 0000000..08fe26c
--- /dev/null
+++ b/viewers/wicket/viewer/src/test/java/org/apache/isis/viewer/wicket/viewer/wicketapp/CryptFactoryTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.isis.viewer.wicket.viewer.wicketapp;
+
+import java.util.stream.Stream;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.wicket.ThreadContext;
+import org.apache.wicket.authentication.strategy.DefaultAuthenticationStrategy;
+import org.apache.wicket.mock.MockWebResponse;
+import org.apache.wicket.protocol.http.servlet.ServletWebRequest;
+import org.apache.wicket.request.IExceptionMapper;
+import org.apache.wicket.request.IRequestMapper;
+import org.apache.wicket.request.Url;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.cycle.RequestCycleContext;
+import org.apache.wicket.util.crypt.ICrypt;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.Mockito.mock;
+
+import lombok.val;
+
+/**
+ * Requires
+ * <pre>{@code
+ * <dependency>
+ * <groupId>javax.servlet</groupId>
+ * <artifactId>javax.servlet-api</artifactId>
+ * <scope>test</scope>
+ * </dependency>}
+ * </pre>
+ */
+class CryptFactoryTest {
+
+ private ServletWebRequest servletWebRequest;
+ private MockWebResponse mockWebResponse;
+ private HttpServletRequest mockHttpServletRequest;
+
+ @BeforeEach
+ void setUp() throws Exception {
+
+ // quite a bit of ceremony to allow Cookie testing ...
+
+ mockHttpServletRequest = new org.springframework.mock.web.MockHttpServletRequest() {
+ @Override
+ public Cookie[] getCookies() {
+ return mockWebResponse.getCookies().toArray(new Cookie[] {});
+ }
+ };
+
+ servletWebRequest = new ServletWebRequest(mockHttpServletRequest, "", Url.parse("/"));
+ mockWebResponse = new MockWebResponse();
+
+ ThreadContext.setRequestCycle(new RequestCycle(new RequestCycleContext(
+ servletWebRequest,
+ mockWebResponse,
+ mock(IRequestMapper.class),
+ mock(IExceptionMapper.class))));
+
+ }
+
+ @ParameterizedTest(name = "{index} {0}")
+ @MethodSource("provideCryptoCandidates")
+ void authenticationStrategyRoundtrip(
+ final String displayName,
+ final ICrypt crypto) {
+
+ val strategy =
+ new DefaultAuthenticationStrategy("cookieKey", crypto);
+
+ strategy.save("hello", "world");
+ val data = strategy.load();
+
+ assertNotNull(data);
+ assertEquals(2, data.length);
+ assertEquals("hello", data[0]);
+ assertEquals("world", data[1]);
+ }
+
+ private static Stream<Arguments> provideCryptoCandidates() {
+
+ return Stream.of(
+ Arguments.of(
+ "sunJceCrypt",
+ _CryptFactory.sunJceCrypt("encryptionKey")),
+ Arguments.of(
+ "aesCrypt",
+ _CryptFactory.aesCrypt("encryptionKey"))
+ );
+ }
+
+
+}