Commit bd4d07bc authored by Dave Cridland's avatar Dave Cridland Committed by GitHub

Merge pull request #671 from surevine/of-1104

OF-1104 Ensure SCRAM uses AuthProvider API
parents 2249ae78 121db7f2
...@@ -293,4 +293,17 @@ public class AuthFactory { ...@@ -293,4 +293,17 @@ public class AuthFactory {
// TODO Auto-generated method stub // TODO Auto-generated method stub
return authProvider.isScramSupported(); return authProvider.isScramSupported();
} }
public static String getSalt(String username) throws UnsupportedOperationException, UserNotFoundException {
return authProvider.getSalt(username);
}
public static int getIterations(String username) throws UnsupportedOperationException, UserNotFoundException {
return authProvider.getIterations(username);
}
public static String getServerKey(String username) throws UnsupportedOperationException, UserNotFoundException {
return authProvider.getServerKey(username);
}
public static String getStoredKey(String username) throws UnsupportedOperationException, UserNotFoundException {
return authProvider.getStoredKey(username);
}
} }
\ No newline at end of file
...@@ -90,4 +90,8 @@ public interface AuthProvider { ...@@ -90,4 +90,8 @@ public interface AuthProvider {
public boolean supportsPasswordRetrieval(); public boolean supportsPasswordRetrieval();
boolean isScramSupported(); boolean isScramSupported();
String getSalt(String username) throws UnsupportedOperationException, UserNotFoundException;
int getIterations(String username) throws UnsupportedOperationException, UserNotFoundException;
String getServerKey(String username) throws UnsupportedOperationException, UserNotFoundException;
String getStoredKey(String username) throws UnsupportedOperationException, UserNotFoundException;
} }
\ No newline at end of file
...@@ -55,7 +55,7 @@ public class DefaultAuthProvider implements AuthProvider { ...@@ -55,7 +55,7 @@ public class DefaultAuthProvider implements AuthProvider {
private static final String LOAD_PASSWORD = private static final String LOAD_PASSWORD =
"SELECT plainPassword,encryptedPassword FROM ofUser WHERE username=?"; "SELECT plainPassword,encryptedPassword FROM ofUser WHERE username=?";
private static final String TEST_PASSWORD = private static final String TEST_PASSWORD =
"SELECT plainPassword,encryptedPassword,iterations,salt,storedKey FROM ofUser WHERE username=?"; "SELECT plainPassword,encryptedPassword,iterations,salt,storedKey,serverKey FROM ofUser WHERE username=?";
private static final String UPDATE_PASSWORD = private static final String UPDATE_PASSWORD =
"UPDATE ofUser SET plainPassword=?, encryptedPassword=?, storedKey=?, serverKey=?, salt=?, iterations=? WHERE username=?"; "UPDATE ofUser SET plainPassword=?, encryptedPassword=?, storedKey=?, serverKey=?, salt=?, iterations=? WHERE username=?";
...@@ -68,6 +68,89 @@ public class DefaultAuthProvider implements AuthProvider { ...@@ -68,6 +68,89 @@ public class DefaultAuthProvider implements AuthProvider {
} }
private class UserInfo {
String plainText;
String encrypted;
int iterations;
String salt;
String storedKey;
String serverKey;
}
private UserInfo getUserInfo(String username) throws UnsupportedOperationException, UserNotFoundException {
if (!isScramSupported()) {
// Reject the operation since the provider does not support SCRAM
throw new UnsupportedOperationException();
}
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(TEST_PASSWORD);
pstmt.setString(1, username);
rs = pstmt.executeQuery();
if (!rs.next()) {
throw new UserNotFoundException(username);
}
UserInfo userInfo = new UserInfo();
userInfo.plainText = rs.getString(1);
userInfo.encrypted = rs.getString(2);
userInfo.iterations = rs.getInt(3);
userInfo.salt = rs.getString(4);
userInfo.storedKey = rs.getString(5);
userInfo.serverKey = rs.getString(6);
if (userInfo.encrypted != null) {
try {
userInfo.plainText = AuthFactory.decryptPassword(userInfo.encrypted);
}
catch (UnsupportedOperationException uoe) {
// Ignore and return plain password instead.
}
}
if (userInfo.plainText != null) {
boolean scramOnly = JiveGlobals.getBooleanProperty("user.scramHashedPasswordOnly");
if (scramOnly) {
// If we have a password here, but we're meant to be scramOnly, we should reset it.
setPassword(username, userInfo.plainText);
}
if (userInfo.salt == null) {
// RECURSE
return getUserInfo(username);
}
}
// Good to go.
return userInfo;
}
catch (SQLException sqle) {
Log.error("User SQL failure:", sqle);
throw new UserNotFoundException(sqle);
}
finally {
DbConnectionManager.closeConnection(rs, pstmt, con);
}
}
@Override
public String getSalt(String username) throws UserNotFoundException {
return getUserInfo(username).salt;
}
@Override
public int getIterations(String username) throws UserNotFoundException {
return getUserInfo(username).iterations;
}
@Override
public String getStoredKey(String username) throws UserNotFoundException {
return getUserInfo(username).storedKey;
}
@Override
public String getServerKey(String username) throws UserNotFoundException {
return getUserInfo(username).serverKey;
}
@Override @Override
public void authenticate(String username, String password) throws UnauthorizedException { public void authenticate(String username, String password) throws UnauthorizedException {
if (username == null || password == null) { if (username == null || password == null) {
......
...@@ -232,4 +232,24 @@ public class HybridAuthProvider implements AuthProvider { ...@@ -232,4 +232,24 @@ public class HybridAuthProvider implements AuthProvider {
// TODO Auto-generated method stub // TODO Auto-generated method stub
return false; return false;
} }
@Override
public String getSalt(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
@Override
public int getIterations(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
@Override
public String getServerKey(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
@Override
public String getStoredKey(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
} }
\ No newline at end of file
...@@ -448,7 +448,27 @@ public class JDBCAuthProvider implements AuthProvider, PropertyEventListener { ...@@ -448,7 +448,27 @@ public class JDBCAuthProvider implements AuthProvider, PropertyEventListener {
// TODO Auto-generated method stub // TODO Auto-generated method stub
return false; return false;
} }
@Override
public String getSalt(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
@Override
public int getIterations(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
@Override
public String getServerKey(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
@Override
public String getStoredKey(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
/** /**
* Support a subset of JDBCAuthProvider properties when updated via REST, * Support a subset of JDBCAuthProvider properties when updated via REST,
* web GUI, or other sources. Provider strings (and related settings) must * web GUI, or other sources. Provider strings (and related settings) must
......
...@@ -139,4 +139,48 @@ public class MappedAuthProvider implements AuthProvider ...@@ -139,4 +139,48 @@ public class MappedAuthProvider implements AuthProvider
return false; return false;
} }
@Override
public String getSalt(String username) throws UserNotFoundException
{
final AuthProvider provider = mapper.getAuthProvider( username );
if ( provider == null )
{
throw new UserNotFoundException();
}
return provider.getSalt( username );
}
@Override
public int getIterations(String username) throws UserNotFoundException
{
final AuthProvider provider = mapper.getAuthProvider( username );
if ( provider == null )
{
throw new UserNotFoundException();
}
return provider.getIterations( username );
}
@Override
public String getServerKey(String username) throws UserNotFoundException
{
final AuthProvider provider = mapper.getAuthProvider( username );
if ( provider == null )
{
throw new UserNotFoundException();
}
return provider.getServerKey( username );
}
@Override
public String getStoredKey(String username) throws UserNotFoundException
{
final AuthProvider provider = mapper.getAuthProvider( username );
if ( provider == null )
{
throw new UserNotFoundException();
}
return provider.getStoredKey( username );
}
} }
...@@ -204,4 +204,24 @@ public class NativeAuthProvider implements AuthProvider { ...@@ -204,4 +204,24 @@ public class NativeAuthProvider implements AuthProvider {
// TODO Auto-generated method stub // TODO Auto-generated method stub
return false; return false;
} }
@Override
public String getSalt(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
@Override
public int getIterations(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
@Override
public String getServerKey(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
@Override
public String getStoredKey(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
} }
...@@ -240,4 +240,24 @@ public class POP3AuthProvider implements AuthProvider { ...@@ -240,4 +240,24 @@ public class POP3AuthProvider implements AuthProvider {
public boolean isScramSupported() { public boolean isScramSupported() {
return false; return false;
} }
@Override
public String getSalt(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
@Override
public int getIterations(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
@Override
public String getServerKey(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
@Override
public String getStoredKey(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
} }
\ No newline at end of file
...@@ -107,4 +107,24 @@ public class CrowdAuthProvider implements AuthProvider { ...@@ -107,4 +107,24 @@ public class CrowdAuthProvider implements AuthProvider {
return false; return false;
} }
@Override
public String getSalt(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
@Override
public int getIterations(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
@Override
public String getServerKey(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
@Override
public String getStoredKey(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
} }
...@@ -157,4 +157,24 @@ public class LdapAuthProvider implements AuthProvider { ...@@ -157,4 +157,24 @@ public class LdapAuthProvider implements AuthProvider {
public boolean isScramSupported() { public boolean isScramSupported() {
return false; return false;
} }
@Override
public String getSalt(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
@Override
public int getIterations(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
@Override
public String getServerKey(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
@Override
public String getStoredKey(String username) throws UnsupportedOperationException, UserNotFoundException {
throw new UnsupportedOperationException();
}
} }
\ No newline at end of file
...@@ -38,7 +38,6 @@ import org.jivesoftware.openfire.auth.AuthFactory; ...@@ -38,7 +38,6 @@ import org.jivesoftware.openfire.auth.AuthFactory;
import org.jivesoftware.openfire.auth.ConnectionException; import org.jivesoftware.openfire.auth.ConnectionException;
import org.jivesoftware.openfire.auth.InternalUnauthenticatedException; import org.jivesoftware.openfire.auth.InternalUnauthenticatedException;
import org.jivesoftware.openfire.auth.ScramUtils; import org.jivesoftware.openfire.auth.ScramUtils;
import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.openfire.user.UserNotFoundException; import org.jivesoftware.openfire.user.UserNotFoundException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -315,13 +314,13 @@ public class ScramSha1SaslServer implements SaslServer { ...@@ -315,13 +314,13 @@ public class ScramSha1SaslServer implements SaslServer {
*/ */
private byte[] getSalt(final String username) { private byte[] getSalt(final String username) {
try { try {
String saltshaker = UserManager.getUserProvider().loadUser(username).getSalt(); String saltshaker = AuthFactory.getSalt(username);
byte[] salt; byte[] salt;
if (saltshaker == null) { if (saltshaker == null) {
Log.debug("No salt found, so resetting password."); Log.debug("No salt found, so resetting password.");
String password = AuthFactory.getPassword(username); String password = AuthFactory.getPassword(username);
AuthFactory.setPassword(username, password); AuthFactory.setPassword(username, password);
salt = DatatypeConverter.parseBase64Binary(UserManager.getUserProvider().loadUser(username).getSalt()); salt = DatatypeConverter.parseBase64Binary(AuthFactory.getSalt(username));
} else { } else {
salt = DatatypeConverter.parseBase64Binary(saltshaker); salt = DatatypeConverter.parseBase64Binary(saltshaker);
} }
...@@ -338,14 +337,14 @@ public class ScramSha1SaslServer implements SaslServer { ...@@ -338,14 +337,14 @@ public class ScramSha1SaslServer implements SaslServer {
* Retrieve the iteration count from the database for a given username. * Retrieve the iteration count from the database for a given username.
*/ */
private int getIterations(final String username) throws UserNotFoundException { private int getIterations(final String username) throws UserNotFoundException {
return UserManager.getUserProvider().loadUser(username).getIterations(); return AuthFactory.getIterations(username);
} }
/** /**
* Retrieve the server key from the database for a given username. * Retrieve the server key from the database for a given username.
*/ */
private byte[] getServerKey(final String username) throws UserNotFoundException { private byte[] getServerKey(final String username) throws UserNotFoundException {
final String serverKey = UserManager.getUserProvider().loadUser( username ).getServerKey(); final String serverKey = AuthFactory.getServerKey(username);
if (serverKey == null) { if (serverKey == null) {
return null; return null;
} else { } else {
...@@ -357,7 +356,7 @@ public class ScramSha1SaslServer implements SaslServer { ...@@ -357,7 +356,7 @@ public class ScramSha1SaslServer implements SaslServer {
* Retrieve the stored key from the database for a given username. * Retrieve the stored key from the database for a given username.
*/ */
private byte[] getStoredKey(final String username) throws UserNotFoundException { private byte[] getStoredKey(final String username) throws UserNotFoundException {
final String storedKey = UserManager.getUserProvider().loadUser( username ).getStoredKey(); final String storedKey = AuthFactory.getStoredKey(username);
if (storedKey == null) { if (storedKey == null) {
return null; return null;
} else { } else {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment