[
https://issues.apache.org/jira/browse/SHIRO-552?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16053244#comment-16053244
]
Steinar Bang commented on SHIRO-552:
------------------------------------
I've been trying to convert my existing salt to a form understood by the
JdbcRealm but so far I've failed:
I can't get the same byte[] out of CodecSupport.toBytes(String) that I'm
putting in.
Has anyone successfully used the JdbcRealm with salt?
So far I haven't found any google matches that shows working code examples of
this. The closest I've been getting is [this stackoverflow
answer|https://stackoverflow.com/a/23755827], which has saving the salt as a
TODO
This is what I've done to try to fix the salt in the database:
# Add a liquibase changeset that adds a new column to the users table in the
database
{code:xml}
<changeSet author="sb" id="add-password-salt-column-to-users-table">
<addColumn tableName="users">
<column name="password_salt" type="varchar(255)" />
</addColumn>
</changeSet>
{code}
# Add a liquibase changeset that runs a custom task to convert the old base64
encoded salt values to utf-8 encoded salt values
{code:xml}
<changeSet author="sb" id="convert-salt-from-base64-to-utf8"
runAlways="false" failOnError="true>
<customChange
class="no.priv.bang.ukelonn.bundle.db.liquibase.customchange.ConvertUsersTableSaltEncodingFromBase64ToUtf8"
/>
</changeSet>
{code}
The essential part of the custom task, is:
{code:java}
public class ConvertUsersTableSaltEncodingFromBase64ToUtf8 implements
CustomTaskChange {
@Override
public void execute(Database database) throws CustomChangeException {
JdbcConnection connection = (JdbcConnection)
database.getConnection();
try {
PreparedStatement getsalt = connection.prepareStatement("select
user_id, salt from users");
PreparedStatement updateUtf8EncodedSalt =
connection.prepareStatement("update users set password_salt=? where user_id=?");
ResultSet result = getsalt.executeQuery();
while(result.next()) {
int userId = result.getInt(0);
String base64EncodedSalt = result.getString(1);
byte[] decodedSalt =
Base64.getDecoder().decode(base64EncodedSalt);
char[] utf8EncodedSalt = CodecSupport.toChars(decodedSalt);
//String utf8EncodedSalt = CodecSupport.toString(decodedSalt);
//String utf8EncodedSalt = new String(decodedSalt,
StandardCharsets.UTF_8);
updateUtf8EncodedSalt.setString(0, new
String(utf8EncodedSalt));
updateUtf8EncodedSalt.setInt(1, userId);
updateUtf8EncodedSalt.executeUpdate();
}
} catch (Exception e) {
throw new CustomChangeException("Failed to convert users table salt
values from base64 to utf-8", e);
}
}
}
{code}
The variuous commented out variants all give the same results:
What I put in, is:
{noformat}
[34, -17, 112, -83, -19, -119, -127, 123, -79, -67, 20, -10, 48, 13, 2, 25]
{noformat}
What I get out, is:
{noformat}
[34, -17, -65, -67, 112, -17, -65, -67, -19, -119, -127, 123, -17, -65, -67,
-17, -65, -67, 20, -17, -65, -67, 48, 13, 2, 25]
{noformat}
There is a pattern there: byte three in the original sequence can be found as
byte 5 in the second, the start and end are the same in both sequences
But trying to figure out what the correct way of encoding the salt should be
has so far evaded me...
Base64 would have been much simpler, and I know from my own custom realm: it
works
(and when I think about it: the issues around the salt may be why I ended up
with a custom realm last autumn...? I remember something vaguely about that)
> JdbcRealm in SaltStyle.COLUMN assumes that password column is Base64 but salt
> column is utf8 bytes
> --------------------------------------------------------------------------------------------------
>
> Key: SHIRO-552
> URL: https://issues.apache.org/jira/browse/SHIRO-552
> Project: Shiro
> Issue Type: Bug
> Affects Versions: 1.2.4
> Reporter: Richard Bradley
>
> The {{org.apache.shiro.realm.jdbc.JdbcRealm}} class, when configured with
> SaltStyle.COLUMN, assumes that password column is Base64 but salt column is
> utf8 bytes.
> The password is returned as a {{char[]}} (see JdbcRealm.java:241), which
> {{org.apache.shiro.authc.credential.HashedCredentialsMatcher}} (see
> HashedCredentialsMatcher.java:353):
> {code}
> if (credentials instanceof String || credentials instanceof char[]) {
> //account.credentials were a char[] or String, so
> //we need to do text decoding first:
> if (isStoredCredentialsHexEncoded()) {
> storedBytes = Hex.decode(storedBytes);
> } else {
> storedBytes = Base64.decode(storedBytes);
> }
> }
> {code}
> However, the salt is returned as a {{ByteSource}}, by converting the
> DB-returned String into its UTF-8 bytes. See JdbcRealm.java:224:
> {code}
> if (salt != null) {
> info.setCredentialsSalt(ByteSource.Util.bytes(salt));
> }
> {code}
> This is broken and inconsistent.
> Not all salt byte[]s are valid UTF8 strings, so the default assumption should
> be that the salt column is Base64 encoded.
--
This message was sent by Atlassian JIRA
(v6.4.14#64029)