mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
CLOUDSTACK-1734: Make SHA1 default password encoding mechanism
Description: Making SHA256SALT the default encoding algorithm to encode passwords when creating/updating users. Introducing a new configurable list to allow admins to separately configure the order of preference for encoding and authentication schemes. Since passwords are now sent by clients as clear text, fixing the Plain text authenticator to check against the password passed in rather than its md5 digest.
This commit is contained in:
parent
58c962ef15
commit
2dbdc46337
@ -63,7 +63,7 @@ public class CreateAccountCmd extends BaseCmd {
|
||||
@Parameter(name=ApiConstants.LASTNAME, type=CommandType.STRING, required=true, description="lastname")
|
||||
private String lastName;
|
||||
|
||||
@Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required=true, description="Hashed password (Default is MD5). If you wish to use any other hashing algorithm, you would need to write a custom authentication adapter See Docs section.")
|
||||
@Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required=true, description="Clear text password (Default hashed to SHA256SALT). If you wish to use any other hashing algorithm, you would need to write a custom authentication adapter See Docs section.")
|
||||
private String password;
|
||||
|
||||
@Parameter(name=ApiConstants.TIMEZONE, type=CommandType.STRING, description="Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.")
|
||||
|
||||
@ -56,7 +56,7 @@ public class CreateUserCmd extends BaseCmd {
|
||||
@Parameter(name=ApiConstants.LASTNAME, type=CommandType.STRING, required=true, description="lastname")
|
||||
private String lastname;
|
||||
|
||||
@Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required=true, description="Hashed password (Default is MD5). If you wish to use any other hashing algorithm, you would need to write a custom authentication adapter See Docs section.")
|
||||
@Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required=true, description="Clear text password (Default hashed to SHA256SALT). If you wish to use any other hashing algorithm, you would need to write a custom authentication adapter See Docs section.")
|
||||
private String password;
|
||||
|
||||
@Parameter(name=ApiConstants.TIMEZONE, type=CommandType.STRING, description="Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.")
|
||||
|
||||
@ -59,7 +59,7 @@ public class UpdateUserCmd extends BaseCmd {
|
||||
@Parameter(name=ApiConstants.LASTNAME, type=CommandType.STRING, description="last name")
|
||||
private String lastname;
|
||||
|
||||
@Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, description="Hashed password (default is MD5). If you wish to use any other hasing algorithm, you would need to write a custom authentication adapter")
|
||||
@Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, description="Clear text password (default hashed to SHA256SALT). If you wish to use any other hasing algorithm, you would need to write a custom authentication adapter")
|
||||
private String password;
|
||||
|
||||
@Parameter(name=ApiConstants.SECRET_KEY, type=CommandType.STRING, description="The secret key for the user. Must be specified with userApiKey")
|
||||
|
||||
@ -379,6 +379,60 @@
|
||||
<bean id="LDAPUserAuthenticator" class="com.cloud.server.auth.LDAPUserAuthenticator">
|
||||
<property name="name" value="LDAP"/>
|
||||
</bean>
|
||||
<bean id="SHA256SaltedUserAuthenticator" class="com.cloud.server.auth.SHA256SaltedUserAuthenticator">
|
||||
<property name="name" value="SHA256SALT"/>
|
||||
</bean>
|
||||
<bean id="PlainTextUserAuthenticator" class="com.cloud.server.auth.PlainTextUserAuthenticator">
|
||||
<property name="name" value="PLAINTEXT"/>
|
||||
</bean>
|
||||
|
||||
<bean id="accountManagerImpl" class="com.cloud.user.AccountManagerImpl" >
|
||||
<property name="UserAuthenticators">
|
||||
<list>
|
||||
<ref bean="SHA256SaltedUserAuthenticator"/>
|
||||
<ref bean="MD5UserAuthenticator"/>
|
||||
<ref bean="LDAPUserAuthenticator"/>
|
||||
<ref bean="PlainTextUserAuthenticator"/>
|
||||
</list>
|
||||
</property>
|
||||
<property name="UserPasswordEncoders">
|
||||
<list>
|
||||
<ref bean="SHA256SaltedUserAuthenticator"/>
|
||||
<ref bean="MD5UserAuthenticator"/>
|
||||
<ref bean="LDAPUserAuthenticator"/>
|
||||
<ref bean="PlainTextUserAuthenticator"/>
|
||||
</list>
|
||||
</property>
|
||||
<property name="SecurityCheckers">
|
||||
<list>
|
||||
<ref bean="domainChecker"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="managementServerImpl" class ="com.cloud.server.ManagementServerImpl">
|
||||
<property name="UserAuthenticators">
|
||||
<list>
|
||||
<ref bean="SHA256SaltedUserAuthenticator"/>
|
||||
<ref bean="MD5UserAuthenticator"/>
|
||||
<ref bean="LDAPUserAuthenticator"/>
|
||||
<ref bean="PlainTextUserAuthenticator"/>
|
||||
</list>
|
||||
</property>
|
||||
<property name="UserPasswordEncoders">
|
||||
<list>
|
||||
<ref bean="SHA256SaltedUserAuthenticator"/>
|
||||
<ref bean="MD5UserAuthenticator"/>
|
||||
<ref bean="LDAPUserAuthenticator"/>
|
||||
<ref bean="PlainTextUserAuthenticator"/>
|
||||
</list>
|
||||
</property>
|
||||
<property name="HostAllocators">
|
||||
<list>
|
||||
<ref bean="FirstFitRouting"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!--
|
||||
Network Elements
|
||||
|
||||
@ -40,34 +40,6 @@
|
||||
<!--
|
||||
Managers & pluggable adapters configuration under OSS deployment
|
||||
-->
|
||||
<bean id="accountManagerImpl" class="com.cloud.user.AccountManagerImpl" >
|
||||
<property name="UserAuthenticators">
|
||||
<list>
|
||||
<ref bean="MD5UserAuthenticator"/>
|
||||
<ref bean="LDAPUserAuthenticator"/>
|
||||
</list>
|
||||
</property>
|
||||
<property name="SecurityCheckers">
|
||||
<list>
|
||||
<ref bean="domainChecker"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="managementServerImpl" class ="com.cloud.server.ManagementServerImpl">
|
||||
<property name="UserAuthenticators">
|
||||
<list>
|
||||
<ref bean="MD5UserAuthenticator"/>
|
||||
<ref bean="LDAPUserAuthenticator"/>
|
||||
</list>
|
||||
</property>
|
||||
<property name="HostAllocators">
|
||||
<list>
|
||||
<ref bean="FirstFitRouting"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="storageManagerImpl" class="com.cloud.storage.StorageManagerImpl">
|
||||
<property name="StoragePoolAllocators">
|
||||
<list>
|
||||
|
||||
@ -131,34 +131,6 @@
|
||||
<!--
|
||||
Managers & pluggable adapters configuration under non-OSS deployment
|
||||
-->
|
||||
<bean id="accountManagerImpl" class="com.cloud.user.AccountManagerImpl" >
|
||||
<property name="UserAuthenticators">
|
||||
<list>
|
||||
<ref bean="MD5UserAuthenticator"/>
|
||||
<ref bean="LDAPUserAuthenticator"/>
|
||||
</list>
|
||||
</property>
|
||||
<property name="SecurityCheckers">
|
||||
<list>
|
||||
<ref bean="domainChecker"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="managementServerImpl" class ="com.cloud.server.ManagementServerImpl">
|
||||
<property name="UserAuthenticators">
|
||||
<list>
|
||||
<ref bean="MD5UserAuthenticator"/>
|
||||
<ref bean="LDAPUserAuthenticator"/>
|
||||
</list>
|
||||
</property>
|
||||
<property name="HostAllocators">
|
||||
<list>
|
||||
<ref bean="FirstFitRouting"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="storageManagerImpl" class="com.cloud.storage.StorageManagerImpl">
|
||||
<property name="StoragePoolAllocators">
|
||||
<list>
|
||||
|
||||
@ -36,7 +36,7 @@ INSERT INTO `cloud`.`user` (id, uuid, username, password, account_id, firstname,
|
||||
-- Add system user with encrypted password=password
|
||||
INSERT INTO `cloud`.`user` (id, uuid, username, password, account_id, firstname,
|
||||
lastname, email, state, created) VALUES (2, UUID(), 'admin', '5f4dcc3b5aa765d61d8327deb882cf99',
|
||||
'2', 'Admin', 'User', 'admin@mailprovider.com', 'enabled', NOW());
|
||||
'2', 'Admin', 'User', 'admin@mailprovider.com', 'disabled', NOW());
|
||||
|
||||
-- Add configurations
|
||||
INSERT INTO `cloud`.`configuration` (category, instance, component, name, value)
|
||||
|
||||
@ -151,6 +151,9 @@ public class LDAPUserAuthenticator extends DefaultUserAuthenticator {
|
||||
@Override
|
||||
public boolean configure(String name, Map<String, Object> params)
|
||||
throws ConfigurationException {
|
||||
if (name == null) {
|
||||
name = "LDAP";
|
||||
}
|
||||
super.configure(name, params);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -59,8 +59,12 @@ public class MD5UserAuthenticator extends DefaultUserAuthenticator {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean configure(String name, Map<String, Object> params)
|
||||
throws ConfigurationException {
|
||||
if(name == null) {
|
||||
name = "MD5";
|
||||
}
|
||||
super.configure(name, params);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -28,7 +28,6 @@ import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.user.UserAccount;
|
||||
import com.cloud.user.dao.UserAccountDao;
|
||||
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
|
||||
|
||||
@ -43,45 +42,26 @@ public class PlainTextUserAuthenticator extends DefaultUserAuthenticator {
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Retrieving user: " + username);
|
||||
}
|
||||
|
||||
UserAccount user = _userAccountDao.getUserAccount(username, domainId);
|
||||
if (user == null) {
|
||||
s_logger.debug("Unable to find user with " + username + " in domain " + domainId);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
MessageDigest md5;
|
||||
try {
|
||||
md5 = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new CloudRuntimeException("Error", e);
|
||||
}
|
||||
md5.reset();
|
||||
BigInteger pwInt = new BigInteger(1, md5.digest(password.getBytes()));
|
||||
|
||||
// make sure our MD5 hash value is 32 digits long...
|
||||
StringBuffer sb = new StringBuffer();
|
||||
String pwStr = pwInt.toString(16);
|
||||
int padding = 32 - pwStr.length();
|
||||
for (int i = 0; i < padding; i++) {
|
||||
sb.append('0');
|
||||
}
|
||||
sb.append(pwStr);
|
||||
|
||||
|
||||
// Will: The MD5Authenticator is now a straight pass-through comparison of the
|
||||
// the passwords because we will not assume that the password passed in has
|
||||
// already been MD5 hashed. I am keeping the above code in case this requirement changes
|
||||
// or people need examples of how to MD5 hash passwords in java.
|
||||
if (!user.getPassword().equals(sb.toString())) {
|
||||
if (!user.getPassword().equals(password)) {
|
||||
s_logger.debug("Password does not match");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean configure(String name, Map<String, Object> params)
|
||||
throws ConfigurationException {
|
||||
if (name == null) {
|
||||
name = "PLAINTEXT";
|
||||
}
|
||||
super.configure(name, params);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -44,6 +44,9 @@ public class SHA256SaltedUserAuthenticator extends DefaultUserAuthenticator {
|
||||
@Override
|
||||
public boolean configure(String name, Map<String, Object> params)
|
||||
throws ConfigurationException {
|
||||
if (name == null) {
|
||||
name = "SHA256SALT";
|
||||
}
|
||||
super.configure(name, params);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -457,7 +457,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
|
||||
private Map<String, Boolean> _availableIdsMap;
|
||||
|
||||
List<UserAuthenticator> _userAuthenticators;
|
||||
private List<UserAuthenticator> _userAuthenticators;
|
||||
private List<UserAuthenticator> _userPasswordEncoders;
|
||||
|
||||
@Inject ClusterManager _clusterMgr;
|
||||
private String _hashKey = null;
|
||||
@ -474,6 +475,14 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
_userAuthenticators = authenticators;
|
||||
}
|
||||
|
||||
public List<UserAuthenticator> getUserPasswordEncoders() {
|
||||
return _userPasswordEncoders;
|
||||
}
|
||||
|
||||
public void setUserPasswordEncoders(List<UserAuthenticator> encoders) {
|
||||
_userPasswordEncoders = encoders;
|
||||
}
|
||||
|
||||
public List<HostAllocator> getHostAllocators() {
|
||||
return _hostAllocators;
|
||||
}
|
||||
@ -3342,7 +3351,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
// This means its a new account, set the password using the
|
||||
// authenticator
|
||||
|
||||
for (UserAuthenticator authenticator: _userAuthenticators) {
|
||||
for (UserAuthenticator authenticator: _userPasswordEncoders) {
|
||||
encodedPassword = authenticator.encode(password);
|
||||
if (encodedPassword != null) {
|
||||
break;
|
||||
|
||||
@ -222,6 +222,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
|
||||
@Inject VolumeManager volumeMgr;
|
||||
|
||||
private List<UserAuthenticator> _userAuthenticators;
|
||||
List<UserAuthenticator> _userPasswordEncoders;
|
||||
|
||||
private final ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("AccountChecker"));
|
||||
|
||||
@ -242,6 +243,14 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
|
||||
_userAuthenticators = authenticators;
|
||||
}
|
||||
|
||||
public List<UserAuthenticator> getUserPasswordEncoders() {
|
||||
return _userPasswordEncoders;
|
||||
}
|
||||
|
||||
public void setUserPasswordEncoders(List<UserAuthenticator> encoders) {
|
||||
_userPasswordEncoders = encoders;
|
||||
}
|
||||
|
||||
public List<SecurityChecker> getSecurityCheckers() {
|
||||
return _securityCheckers;
|
||||
}
|
||||
@ -947,7 +956,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
|
||||
|
||||
if (password != null) {
|
||||
String encodedPassword = null;
|
||||
for (Iterator<UserAuthenticator> en = _userAuthenticators.iterator(); en.hasNext();) {
|
||||
for (Iterator<UserAuthenticator> en = _userPasswordEncoders.iterator(); en.hasNext();) {
|
||||
UserAuthenticator authenticator = en.next();
|
||||
encodedPassword = authenticator.encode(password);
|
||||
if (encodedPassword != null) {
|
||||
@ -1733,7 +1742,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
|
||||
}
|
||||
|
||||
String encodedPassword = null;
|
||||
for (UserAuthenticator authenticator : _userAuthenticators) {
|
||||
for (UserAuthenticator authenticator : _userPasswordEncoders) {
|
||||
encodedPassword = authenticator.encode(password);
|
||||
if (encodedPassword != null) {
|
||||
break;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user