diff --git a/framework/security/config/security.properties b/framework/security/config/security.properties index b7acb533467..2222fc22d8a 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 5e0e8823bbb..27eb0f1eab6 100644 --- a/framework/security/data/SSOJWTDemoData.xml +++ b/framework/security/data/SSOJWTDemoData.xml @@ -20,6 +20,5 @@ under the License. - 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 2bd20d774f0..c63a708ecc1 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] ---- - ---- 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 6b9f17e2ab4..758ec1e571f 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.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 static String getJWTKey(Delegator delegator) { */ 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 static Map validateToken(String jwtToken, String key) { /** * 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