You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2012/10/04 20:54:19 UTC
git commit: TAP5-2008: Implement HMAC signatures on object streams
stored on the client
Updated Branches:
refs/heads/5.3 acfdee71c -> 5ad5257fd
TAP5-2008: Implement HMAC signatures on object streams stored on the client
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/5ad5257f
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/5ad5257f
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/5ad5257f
Branch: refs/heads/5.3
Commit: 5ad5257fdfacbad2c7c480fdf2afa15d9a37e6b0
Parents: acfdee7
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Thu Oct 4 11:30:20 2012 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Thu Oct 4 11:40:04 2012 -0700
----------------------------------------------------------------------
.../java/org/apache/tapestry5/SymbolConstants.java | 11 ++
.../internal/services/ClientDataEncoderImpl.java | 78 +++++++++--
.../internal/services/ClientDataSinkImpl.java | 19 ++-
.../tapestry5/internal/util/MacOutputStream.java | 86 ++++++++++++
.../tapestry5/internal/util/TeeOutputStream.java | 73 ++++++++++
.../tapestry5/services/ClientDataEncoder.java | 17 ++-
.../apache/tapestry5/services/TapestryModule.java | 4 +
.../services/ClientDataEncoderImplTest.groovy | 108 +++++++++++++++
.../integration/app1/services/AppModule.java | 2 +
9 files changed, 378 insertions(+), 20 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/5ad5257f/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java b/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java
index 9a63b6e..d90ee41 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java
@@ -365,4 +365,15 @@ public class SymbolConstants
* Prefix to be used for all asset paths
*/
public static final String ASSET_PATH_PREFIX = "tapestry.asset-path-prefix";
+
+ /**
+ * A passphrase used as the basis of hash-based message authentication (HMAC) for any object stream data stored on
+ * the client. The default phrase is the empty string, which will result in a logged runtime <em>error</em>.
+ * You should configure this to a reasonable value (longer is better) and ensure that all servers in your cluster
+ * share the same value (configuring this in code, rather than the command line, is preferred).
+ *
+ * @see org.apache.tapestry5.services.ClientDataEncoder
+ * @since 5.3.6
+ */
+ public static final String HMAC_PASSPHRASE = "tapestry.hmac-passphrase";
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/5ad5257f/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientDataEncoderImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientDataEncoderImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientDataEncoderImpl.java
index 243e39b..3bf26cc 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientDataEncoderImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientDataEncoderImpl.java
@@ -1,4 +1,4 @@
-// Copyright 2009 The Apache Software Foundation
+// Copyright 2009, 2012 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,32 +14,54 @@
package org.apache.tapestry5.internal.services;
+import org.apache.tapestry5.SymbolConstants;
+import org.apache.tapestry5.internal.TapestryInternalUtils;
import org.apache.tapestry5.internal.util.Base64InputStream;
+import org.apache.tapestry5.internal.util.MacOutputStream;
+import org.apache.tapestry5.ioc.annotations.Symbol;
import org.apache.tapestry5.services.ClientDataEncoder;
import org.apache.tapestry5.services.ClientDataSink;
import org.apache.tapestry5.services.URLEncoder;
+import org.slf4j.Logger;
+import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
+import java.io.UnsupportedEncodingException;
+import java.security.Key;
import java.util.zip.GZIPInputStream;
public class ClientDataEncoderImpl implements ClientDataEncoder
{
private final URLEncoder urlEncoder;
- public ClientDataEncoderImpl(URLEncoder urlEncoder)
+ private final Key hmacKey;
+
+ public ClientDataEncoderImpl(URLEncoder urlEncoder, @Symbol(SymbolConstants.HMAC_PASSPHRASE) String passphrase, Logger logger) throws UnsupportedEncodingException
{
this.urlEncoder = urlEncoder;
+
+ if (passphrase.equals(""))
+ {
+ logger.error(String.format("The symbol '%s' has not been configured. " +
+ "This is used to configure hash-based message authentication of Tapestry data stored in forms, or in the URL. " +
+ "You application is less secure, and more vulnerable to denial-of-service attacks, when this symbol is left unconfigured.",
+ SymbolConstants.HMAC_PASSPHRASE));
+
+ // Errors at lower levels if the passphrase is empty, so override the parameter to set a default value.
+ passphrase = "DEFAULT";
+ }
+
+ hmacKey = new SecretKeySpec(passphrase.getBytes("UTF8"), "HmacSHA1");
}
public ClientDataSink createSink()
{
try
{
- return new ClientDataSinkImpl(urlEncoder);
- }
- catch (IOException ex)
+ return new ClientDataSinkImpl(urlEncoder, hmacKey);
+ } catch (IOException ex)
{
throw new RuntimeException(ex);
}
@@ -48,21 +70,57 @@ public class ClientDataEncoderImpl implements ClientDataEncoder
public ObjectInputStream decodeClientData(String clientData)
{
// The clientData is Base64 that's been gzip'ed (i.e., this matches
- // what ClientDataSinkImpl does.
+ // what ClientDataSinkImpl does).
+
+ int colonx = clientData.indexOf(':');
+
+ if (colonx < 0)
+ {
+ throw new IllegalArgumentException("Client data must be prefixed with its HMAC code.");
+ }
+
+ // Extract the string presumably encoded by the server using the secret key.
+
+ String storedHmacResult = clientData.substring(0, colonx);
+
+ String clientStream = clientData.substring(colonx + 1);
try
{
- BufferedInputStream buffered = new BufferedInputStream(
- new GZIPInputStream(new Base64InputStream(clientData)));
+ Base64InputStream b64in = new Base64InputStream(clientStream);
+
+ validateHMAC(storedHmacResult, b64in);
+
+ // After reading it once to validate, reset it for the actual read (which includes the GZip decompression).
+
+ b64in.reset();
+
+ BufferedInputStream buffered = new BufferedInputStream(new GZIPInputStream(b64in));
return new ObjectInputStream(buffered);
- }
- catch (IOException ex)
+ } catch (IOException ex)
{
throw new RuntimeException(ex);
}
}
+ private void validateHMAC(String storedHmacResult, Base64InputStream b64in) throws IOException
+ {
+ MacOutputStream macOs = MacOutputStream.streamFor(hmacKey);
+
+ TapestryInternalUtils.copy(b64in, macOs);
+
+ macOs.close();
+
+ String actual = macOs.getResult();
+
+ if (!storedHmacResult.equals(actual))
+ {
+ throw new IOException("Client data associated with the current request appears to have been tampered with " +
+ "(the HMAC signature does not match).");
+ }
+ }
+
public ObjectInputStream decodeEncodedClientData(String clientData) throws IOException
{
return decodeClientData(urlEncoder.decode(clientData));
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/5ad5257f/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientDataSinkImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientDataSinkImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientDataSinkImpl.java
index 5ac3012..aebecac 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientDataSinkImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientDataSinkImpl.java
@@ -1,4 +1,4 @@
-// Copyright 2009 The Apache Software Foundation
+// Copyright 2009, 2012 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
package org.apache.tapestry5.internal.services;
import org.apache.tapestry5.internal.util.Base64OutputStream;
+import org.apache.tapestry5.internal.util.MacOutputStream;
+import org.apache.tapestry5.internal.util.TeeOutputStream;
import org.apache.tapestry5.services.ClientDataSink;
import org.apache.tapestry5.services.URLEncoder;
@@ -22,6 +24,7 @@ import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
+import java.security.Key;
import java.util.zip.GZIPOutputStream;
public class ClientDataSinkImpl implements ClientDataSink
@@ -34,12 +37,17 @@ public class ClientDataSinkImpl implements ClientDataSink
private boolean closed;
- public ClientDataSinkImpl(URLEncoder urlEncoder) throws IOException
+ private final MacOutputStream macOutputStream;
+
+ public ClientDataSinkImpl(URLEncoder urlEncoder, Key hmacKey) throws IOException
{
this.urlEncoder = urlEncoder;
+
base64OutputStream = new Base64OutputStream();
+ macOutputStream = MacOutputStream.streamFor(hmacKey);
- final BufferedOutputStream pipeline = new BufferedOutputStream(new GZIPOutputStream(base64OutputStream));
+ final BufferedOutputStream pipeline = new BufferedOutputStream(new GZIPOutputStream(
+ new TeeOutputStream(macOutputStream, base64OutputStream)));
OutputStream guard = new OutputStream()
{
@@ -92,14 +100,13 @@ public class ClientDataSinkImpl implements ClientDataSink
try
{
objectOutputStream.close();
- }
- catch (IOException ex)
+ } catch (IOException ex)
{
// Ignore.
}
}
- return base64OutputStream.toBase64();
+ return macOutputStream.getResult() + ":" + base64OutputStream.toBase64();
}
public String getEncodedClientData()
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/5ad5257f/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MacOutputStream.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MacOutputStream.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MacOutputStream.java
new file mode 100644
index 0000000..2b21278
--- /dev/null
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MacOutputStream.java
@@ -0,0 +1,86 @@
+// Copyright 2012 The Apache Software Foundation
+//
+// Licensed 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.tapestry5.internal.util;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+
+import javax.crypto.Mac;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.Key;
+
+/**
+ * An output stream that wraps around a {@link Mac} (message authentication code algorithm). This is currently
+ * used for symmetric (private) keys, but in theory could be used with assymetric (public/private) keys.
+ *
+ * @since 5.3.6
+ */
+public class MacOutputStream extends OutputStream
+{
+ private final Mac mac;
+
+ public static MacOutputStream streamFor(Key key) throws IOException
+ {
+ try
+ {
+ Mac mac = Mac.getInstance(key.getAlgorithm());
+ mac.init(key);
+
+ return new MacOutputStream(mac);
+ } catch (Exception ex)
+ {
+ throw new IOException("Unable to create MacOutputStream: " + InternalUtils.toMessage(ex), ex);
+ }
+ }
+
+ public MacOutputStream(Mac mac)
+ {
+ assert mac != null;
+
+ this.mac = mac;
+ }
+
+ /**
+ * Should only be invoked once, immediately after this stream is closed; it generates the final MAC result, and
+ * returns it as a Base64 encoded string.
+ *
+ * @return Base64 encoded MAC result
+ */
+ public String getResult()
+ {
+ byte[] result = mac.doFinal();
+
+ return new String(Base64.encodeBase64(result));
+ }
+
+ @Override
+ public void write(int b) throws IOException
+ {
+ mac.update((byte) b);
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException
+ {
+ mac.update(b);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException
+ {
+ mac.update(b, off, len);
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/5ad5257f/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/TeeOutputStream.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/TeeOutputStream.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/TeeOutputStream.java
new file mode 100644
index 0000000..f12ebd0
--- /dev/null
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/TeeOutputStream.java
@@ -0,0 +1,73 @@
+// Copyright 2012 The Apache Software Foundation
+//
+// Licensed 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.tapestry5.internal.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * An output stream that acts like a "tee", copying all provided bytes to two output streams. This is used, for example,
+ * to accumulate a hash of content even as it is being written.
+ *
+ * @since 5.3.5
+ */
+public class TeeOutputStream extends OutputStream
+{
+ private final OutputStream left, right;
+
+ public TeeOutputStream(OutputStream left, OutputStream right)
+ {
+ assert left != null;
+ assert right != null;
+
+ this.left = left;
+ this.right = right;
+ }
+
+ @Override
+ public void write(int b) throws IOException
+ {
+ left.write(b);
+ right.write(b);
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException
+ {
+ left.write(b);
+ right.write(b);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException
+ {
+ left.write(b, off, len);
+ right.write(b, off, len);
+ }
+
+ @Override
+ public void flush() throws IOException
+ {
+ left.flush();
+ right.flush();
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ left.close();
+ right.close();
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/5ad5257f/tapestry-core/src/main/java/org/apache/tapestry5/services/ClientDataEncoder.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/ClientDataEncoder.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/ClientDataEncoder.java
index e959e97..89ac933 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/ClientDataEncoder.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/ClientDataEncoder.java
@@ -1,4 +1,4 @@
-// Copyright 2009 The Apache Software Foundation
+// Copyright 2009, 2012 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -21,6 +21,10 @@ import java.io.ObjectInputStream;
* A service used when a component or service needs to encode some amount of data on the client as a string. The string
* may be a query parameter, hidden form field, or a portion of a URL. The default implementation converts the object
* output stream into a Base64 string.
+ * <p/>
+ * Starting in release 5.3.6, the encoded data incorporates an HMAC (hash based message authentication code) signature,
+ * as a prefix. HMAC requires a secret key, configured using the
+ * {@link org.apache.tapestry5.SymbolConstants#HMAC_PASSPHRASE} symbol.
*
* @since 5.1.0.1
*/
@@ -37,17 +41,22 @@ public interface ClientDataEncoder
/**
* Decodes data previously obtained from {@link ClientDataSink#getClientData()}.
*
- * @param clientData encoded client data
+ * @param clientData
+ * encoded client data
* @return stream of decoded data
+ * @throws IOException
+ * if the client data has been corrupted (verified via the HMAC)
*/
ObjectInputStream decodeClientData(String clientData) throws IOException;
/**
- * Decoes client data obtained via {@link ClientDataSink#getEncodedClientData()}.
+ * Decodes client data obtained via {@link ClientDataSink#getEncodedClientData()}.
*
- * @param clientData URLEncoded client data
+ * @param clientData
+ * URLEncoded client data
* @return stream of objects
* @throws IOException
+ * if the client data has been corrupted (verified via the HMAC)
* @since 5.1.0.4
*/
ObjectInputStream decodeEncodedClientData(String clientData) throws IOException;
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/5ad5257f/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
index 3159e76..28126fa 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
@@ -2394,6 +2394,10 @@ public final class TapestryModule
// By default, no page is on the whitelist unless it has the @WhitelistAccessOnly annotation
configuration.add(MetaDataConstants.WHITELIST_ONLY_PAGE, false);
+
+ // Leaving this as the default results in a runtime error logged to the console (and a default password is used);
+ // you are expected to override this symbol.
+ configuration.add(SymbolConstants.HMAC_PASSPHRASE, "");
}
/**
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/5ad5257f/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ClientDataEncoderImplTest.groovy
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ClientDataEncoderImplTest.groovy b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ClientDataEncoderImplTest.groovy
new file mode 100644
index 0000000..07399f4
--- /dev/null
+++ b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ClientDataEncoderImplTest.groovy
@@ -0,0 +1,108 @@
+package org.apache.tapestry5.internal.services
+
+import org.apache.tapestry5.ioc.test.TestBase
+import org.apache.tapestry5.services.ClientDataEncoder
+import org.easymock.EasyMock
+import org.slf4j.Logger
+import org.testng.annotations.Test
+
+class ClientDataEncoderImplTest extends TestBase {
+
+ def tryEncodeAndDecode(ClientDataEncoder cde) {
+ def now = new Date()
+ def input = "The current time is $now"
+
+
+ String clientData = convertToClientData cde, input
+
+ def stream = cde.decodeClientData clientData
+
+ def output = stream.readObject()
+
+ assert !input.is(output)
+ assert input == output
+ }
+
+ def String convertToClientData(ClientDataEncoder cde, input) {
+ def sink = cde.createSink()
+
+ sink.getObjectOutputStream().with { stream ->
+ stream << input
+ stream.close()
+ }
+
+ sink.clientData
+ }
+
+ def extractData(String encoded) {
+ def colonx = encoded.indexOf(':')
+
+ encoded.substring(colonx + 1)
+ }
+
+ @Test
+ void blank_passphrase_works_but_logs_error() {
+ Logger logger = newMock Logger
+
+ logger.error(EasyMock.isA(String))
+
+ replay()
+
+ ClientDataEncoder cde = new ClientDataEncoderImpl(null, "", logger)
+
+ tryEncodeAndDecode cde
+
+ verify()
+ }
+
+ @Test
+ void no_logged_error_with_non_blank_passphrase() {
+ ClientDataEncoder cde = new ClientDataEncoderImpl(null, "Testing, Testing, 1.., 2.., 3...", null)
+
+ tryEncodeAndDecode cde
+ }
+
+ @Test
+ void passphrase_affects_encoded_output() {
+ ClientDataEncoder first = new ClientDataEncoderImpl(null, "first passphrase", null)
+ ClientDataEncoder second = new ClientDataEncoderImpl(null, " different passphrase ", null)
+
+ def input = "current time millis is ${System.currentTimeMillis()} ms"
+
+ def output1 = convertToClientData first, input
+ def output2 = convertToClientData second, input
+
+ assert output1 != output2
+
+ assert extractData(output1) == extractData(output2)
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException)
+ void decode_with_missing_hmac_prefix_is_a_failure() {
+ ClientDataEncoder cde = new ClientDataEncoderImpl(null, "a passphrase", null)
+
+ cde.decodeClientData("so completely invalid")
+ }
+
+ @Test
+ void incorrect_hmac_is_detected() {
+
+ // Simulate tampering by encoding with one passphrase and attempting to decode with a different
+ // passphrase.
+ ClientDataEncoder first = new ClientDataEncoderImpl(null, "first passphrase", null)
+ ClientDataEncoder second = new ClientDataEncoderImpl(null, " different passphrase ", null)
+
+ def input = "current time millis is ${System.currentTimeMillis()} ms"
+
+ def output = convertToClientData first, input
+
+ try {
+ second.decodeClientData(output)
+ unreachable()
+ }
+ catch (Exception e) {
+ assert e.message.contains("HMAC signature does not match")
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/5ad5257f/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java
index a698826..8812352 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java
@@ -157,6 +157,8 @@ public class AppModule
configuration.add(SymbolConstants.SECURE_ENABLED, "true");
configuration.add("app.injected-symbol", "Symbol contributed to ApplicationDefaults");
+
+ configuration.add(SymbolConstants.HMAC_PASSPHRASE, "testing, testing, 1... 2... 3...");
}
public static void contributeIgnoredPathsFilter(Configuration<String> configuration)