GlassFish SHA-256 digest authentication
I have been storing my passwords in plain-text for development purposes but want to start storing the hashes instead, but have so far not yet succeeded in having GlassFish properly authen开发者_运维知识库ticate against a hashed password due to the following SecurityException:
SEVERE: jdbcrealm.invaliduserreason
WARNING: WEB9102: Web Login Failed: com.sun.enterprise.security.auth.login.common.LoginException: Login failed: Security Exception
First off, I am running GlassFish 3.1 and have setup the digest for my JDBC realm to SHA-256.
My User
class has the following annotated password field:
@Basic(fetch = FetchType.LAZY)
@Column(length = 45, nullable = false)
private String password;
The following helper method is responsible for hashing the password:
private byte[] digest(String input) {
byte[] output = null;
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
output = md.digest(input.getBytes("UTF-8"));
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(RegistrationController.class.getName()).log(Level.SEVERE, null, ex);
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(RegistrationController.class.getName()).log(Level.SEVERE, null, ex);
}
return output;
}
I then set the password on the user as follows:
u.setPassword(Base64.encode(digest(password)).toString());
I wouldn't have Base64 encoded the because this seems to be undocumented but this question: Glassfish Security - jdbcRealm: How to configure login with SHA-256 digest suggests you do need to do so.
So I guess what I would like to know is, does GlassFish expect a String (VARCHAR) or a byte[] (BLOB) as the password field in the database, am I correctly hashing the password, and is it correct to additionally Base64 encode the password hash?
Thanks!
Does GlassFish expect a String (VARCHAR) or a byte[] (BLOB) as the password field in the database?
It expects a column that maps to the Java Type java.lang.String
in JDBC, and those would typically be CHAR, VARCHAR etc. LOBs would not work as the JDBC realm implementation issues a ResultSet.getString
method call invocation to obtain the password hash.
Am I correctly hashing the password, and is it correct to additionally Base64 encode the password hash?
Base64 encoding is not the only supported option. You can perform Hex encoding as well. But you must perform either of these, and configure the JDBC Realm to perform the same at runtime. In the absence of an encoding parameter, Glassfish will convert the byte sequence associated with the digest, to a sequence of characters in the charset
configured for the realm.
I suspect the problem has something to do with the mention of UTF-8 encoding in the expression input.getBytes("UTF-8")
. It would be worth verifying if the Base64 encoding of the result provided by your digest
method actually matches the password hashes stored in the database.
Also, considering the reason provided for the failure being jdbcrealm.invaliduserreason
, I would also suspect that one of the following conditions might be true:
- The encoding parameter is not specified for the JDBC Realm; it should preferably be one of
base64
orhex
(the case does not matter, going by the source code of the JDBC realm), otherwise you would end up in the scenario where the digest byte array is converted to a character array (which in my opinion is a bit flaky unless you can guarantee that the password provided by users are always in a particular encoding). - No password hash exists for the user in the database. See my previous answer on the SQL query executed; you might want to run the query yourself. You can log the statements issued by Derby (if you are using it as the database), by placing a file named
derby.properties
in the location of your Derby database with the propertyderby.language.logStatementText=true
in it. On shutting down the database, the derby.log file will be populated with all the queries issued by the application server. - The SQL statement prepared by Glassfish is incorrect.
- A connection to the database could not be established.
精彩评论