This is an automated email from the ASF dual-hosted git repository.

jleroux pushed a commit to branch release22.01
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git


The following commit(s) were added to refs/heads/release22.01 by this push:
     new 55b603e69d Fixed: JWT Authentication Error (OFBIZ-12724)
55b603e69d is described below

commit 55b603e69d9fb88f319d879493a5eecdcd90c3c6
Author: Jacques Le Roux <jacques.le.r...@les7arts.com>
AuthorDate: Thu Dec 15 09:28:16 2022 +0100

    Fixed: JWT Authentication Error (OFBIZ-12724)
    
    Ensures the length of the secret is at least 512 bit long
    https://www.rfc-editor.org/rfc/rfc7518#page-7
    
https://javadoc.io/doc/com.auth0/java-jwt/latest/com/auth0/jwt/algorithms/Algorithm.html#HMAC512
    We should follow the rule and give a 512 bit key by default and provide
    validation based on the same rule.
    
    jleroux:
    based on recommendation by Les Hazlewood (JJWT founder, Apache Shiro 
founder):
    
https://github.com/jhipster/generator-jhipster/issues/8165#issuecomment-416246549
    I used a 512 bits key I created using https://www.allkeysgenerator.com
    (Encryption key mode).
    But I got this error:
    EntitySaxReader               |E| Fatal Error reading XML on line 23, 
column 155
    org.xml.sax.SAXParseException: The reference to entity "F" must end with 
the ';'
    delimiter. It was due to SSOJWTDemoData content. So I removed 
security.token.key
    from this file and used only the property in security.properties.
    
    Thanks: Ayan Farooqui for report and suggestion
---
 framework/security/config/security.properties                 | 11 +++++++----
 framework/security/data/SSOJWTDemoData.xml                    |  1 -
 .../src/docs/asciidoc/_include/sy-password-and-JWT.adoc       |  7 +++----
 .../main/java/org/apache/ofbiz/webapp/control/JWTManager.java |  8 ++++++--
 4 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/framework/security/config/security.properties 
b/framework/security/config/security.properties
index 1aa8c7ff9b..1e79caa265 100644
--- a/framework/security/config/security.properties
+++ b/framework/security/config/security.properties
@@ -141,17 +141,20 @@ security.login.externalLoginKey.enabled=true
 
 # -- Security key used to encrypt and decrypt the autogenerated password in 
forgot password functionality.
 #    Read Passwords and JWT (JSON Web Tokens) usage documentation to choose 
the way you want to store this key
-login.secret_key_string=login.secret_key_string
+#    The key must be 512 bits (ie 64 chars) as we use HMAC512 to create the 
token, cf. OFBIZ-12724
+login.secret_key_string=p2s5u8x/A?D(G+KbPeShVmYq3t6w9z$B&E)H@McQfTjWnZr4u7x!A%D*F-JaNdRg
 
 # -- Time To Live of the token send to the external server in seconds
 security.jwt.token.expireTime=1800
 
 # -- Enables the internal Single Sign On feature which allows a token based 
login between OFBiz instances
-# -- To make this work you also have to configure a secret key with 
security.token.key
+#    To make this work you also have to configure a secret key with 
security.token.key
 security.internal.sso.enabled=false
 
-# -- The secret key for the JWT token signature. Read Passwords and JWT (JSON 
Web Tokens) usage documentation to choose the way you want to store this key
-security.token.key=security.token.key
+# -- The secret key for the JWT token signature.
+#    Read Passwords and JWT (JSON Web Tokens) usage documentation to choose 
the way you want to store this key
+#    The key must be 512 bits (ie 64 chars) as we use HMAC512 to create the 
token, cf. OFBIZ-12724
+security.token.key=%D*G-JaNdRgUkXp2s5v8y/B?E(H+MbPeShVmYq3t6w9z$C&F)J@NcRfTjWnZr4u7
 
 # -- List of domains or IP addresses to be checked to prevent Host Header 
Injection,
 # -- no spaces after commas,no wildcard, can be extended of course...
diff --git a/framework/security/data/SSOJWTDemoData.xml 
b/framework/security/data/SSOJWTDemoData.xml
index 5e0e8823bb..27eb0f1eab 100644
--- a/framework/security/data/SSOJWTDemoData.xml
+++ b/framework/security/data/SSOJWTDemoData.xml
@@ -20,6 +20,5 @@ under the License.
 
 <entity-engine-xml>
     <SystemProperty systemResourceId="security" 
systemPropertyId="security.internal.sso.enabled" systemPropertyValue="false"/>
-    <SystemProperty systemResourceId="security" 
systemPropertyId="security.token.key" systemPropertyValue="security.token.key"/>
     <SystemProperty systemResourceId="security" 
systemPropertyId="SameSiteCookieAttribute" systemPropertyValue="strict"/>
 </entity-engine-xml>
diff --git 
a/framework/security/src/docs/asciidoc/_include/sy-password-and-JWT.adoc 
b/framework/security/src/docs/asciidoc/_include/sy-password-and-JWT.adoc
index 2bd20d774f..c63a708ecc 100644
--- a/framework/security/src/docs/asciidoc/_include/sy-password-and-JWT.adoc
+++ b/framework/security/src/docs/asciidoc/_include/sy-password-and-JWT.adoc
@@ -64,7 +64,7 @@ You might prefer to use pair of public/private keys, for now 
by default OFBiz us
 . We recommend to not use an environment variable as those can be considered 
weak:
 * http://movingfast.io/articles/environment-variables-considered-harmful
 * 
https://security.stackexchange.com/questions/49725/is-it-really-secure-to-store-api-keys-in-environment-variables
-    
+
 . You may want to tie the encryption key to the logged in user. This is used 
by the password recreation feature. The JWT secret key is salted with a 
combination of the current logged in user and her/his password. This is a 
simple and effective safe way.
 . Use a https://tools.ietf.org/html/rfc7519#section-4.1.7[JTI] (JWT ID). A JTI 
prevents a JWT from being replayed. This 
https://auth0.com/blog/blacklist-json-web-token-api-keys/[auth0 blog article 
get deeper in that].  The same is kinda achieved with the password recreation 
feature. When the user log in after the new password creation, the password has 
already been  changed. So the link (in the sent email) containing the JWT for 
the creation of the new password can't be reused.
 . Tie the encryption key to the hardware. You can refer to this 
https://en.wikipedia.org/wiki/Hardware_security_module[Wikipedia page] for more 
information.
@@ -86,7 +86,7 @@ The _security.properties_ file contains five related 
properties:
 
     # -- Security key used to encrypt and decrypt the autogenerated password 
in forgot password functionality.
     #    Read Passwords and JWT (JSON Web Tokens) usage documentation to 
choose the way you want to store this key
-    login.secret_key_string=login.secret_key_string
+    
login.secret_key_string=p2s5u8x/A?D(G+KbPeShVmYq3t6w9z$B&E)H@McQfTjWnZr4u7x!A%D*F-JaNdRg
 
     # -- Time To Live of the token send to the external server in seconds
     security.jwt.token.expireTime=1800
@@ -96,14 +96,13 @@ The _security.properties_ file contains five related 
properties:
     security.internal.sso.enabled=false
 
     # -- The secret key for the JWT token signature. Read Passwords and JWT 
(JSON Web Tokens) usage documentation to choose the way you want to store this 
key
-    security.token.key=security.token.key
+    
security.token.key=D*G-JaNdRgUkXp2s5v8y/B?E(H+MbPeShVmYq3t6w9z$C&F)J@NcRfTjWnZr4u7
 
 
 There are also SSO related SystemProperties in __SSOJWTDemoData.xml__:
 [source,xml]
 ----
     <SystemProperty systemResourceId="security" 
systemPropertyId="security.internal.sso.enabled" systemPropertyValue="false"/>
-    <SystemProperty systemResourceId="security" 
systemPropertyId="security.token.key" systemPropertyValue="security.token.key"/>
     <SystemProperty systemResourceId="security" 
systemPropertyId="SameSiteCookieAttribute" systemPropertyValue="strict"/>
 ----
 
diff --git 
a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/JWTManager.java
 
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/JWTManager.java
index 6b9f17e2ab..758ec1e571 100644
--- 
a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/JWTManager.java
+++ 
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/JWTManager.java
@@ -33,6 +33,7 @@ import org.apache.ofbiz.base.util.StringUtil;
 import org.apache.ofbiz.base.util.UtilDateTime;
 import org.apache.ofbiz.base.util.UtilHttp;
 import org.apache.ofbiz.base.util.UtilMisc;
+import org.apache.ofbiz.base.util.UtilProperties;
 import org.apache.ofbiz.base.util.UtilValidate;
 import org.apache.ofbiz.entity.Delegator;
 import org.apache.ofbiz.entity.DelegatorFactory;
@@ -140,7 +141,10 @@ public class JWTManager {
      */
 
     public static String getJWTKey(Delegator delegator, String salt) {
-        String key = EntityUtilProperties.getPropertyValue("security", 
"security.token.key", delegator);
+        String key = UtilProperties.getPropertyValue("security", 
"security.token.key");
+        if (key.length() < 64) { // The key must be 512 bits (ie 64 chars)  as 
we use HMAC512 to create the token, cf. OFBIZ-12724
+            throw new SecurityException("The JWT secret key is too short. It 
must be at least 512 bites.");
+        }
         if (salt != null) {
             return StringUtil.toHexString(salt.getBytes()) + key;
         }
@@ -257,7 +261,7 @@ public class JWTManager {
 
     /**
      * Validates the provided token using a salt to recreate the key from the 
secret
-     * If the token is valid it will get the conteined claims and return them.
+     * If the token is valid it will get the contained claims and return them.
      * If token validation failed it will return an error.
      * @param delegator
      * @param jwtToken

Reply via email to