Skip to content

Commit

Permalink
Fixed: JWT Authentication Error (OFBIZ-12724)
Browse files Browse the repository at this point in the history
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):
jhipster/generator-jhipster#8165 (comment)
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
  • Loading branch information
JacquesLeRoux committed Dec 15, 2022
1 parent 310ca13 commit 2ec3d24
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 11 deletions.
11 changes: 7 additions & 4 deletions framework/security/config/security.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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...
Expand Down
1 change: 0 additions & 1 deletion framework/security/data/SSOJWTDemoData.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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"/>
----

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -257,7 +261,7 @@ public static Map<String, Object> 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
Expand Down

0 comments on commit 2ec3d24

Please sign in to comment.