/* * Copyright (c) 2013 EMC Corporation * All Rights Reserved */ package com.emc.storageos.auth.local; import com.emc.storageos.auth.impl.LdapFailureHandler; import com.emc.storageos.auth.StorageOSAuthenticationHandler; import com.emc.storageos.coordinator.client.service.CoordinatorClient; import com.emc.storageos.model.property.PropertyInfo; import com.emc.storageos.coordinator.exceptions.CoordinatorException; import com.emc.storageos.security.authentication.StorageOSUser; import org.apache.commons.codec.digest.Crypt; import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Map; import com.emc.storageos.db.client.model.EncryptionProvider; /** * Class to handle authentication using basic username password credentials * stored in the database. */ public class StorageOSLocalAuthenticationHandler implements StorageOSAuthenticationHandler { private static final Logger _log = LoggerFactory.getLogger(StorageOSLocalAuthenticationHandler.class); // A reference to the coordinator client for retrieving/updating local user private CoordinatorClient _coordinatorClient; private Map<String, StorageOSUser> _localUsers; private EncryptionProvider _encryptionProvider; private static final String CRYPT_SHA_512 = "$6$"; public void setEncryptionProvider(EncryptionProvider encryptionProvider) { _encryptionProvider = encryptionProvider; } public void setLocalUsers(final Map<String, StorageOSUser> localUsers) { _localUsers = localUsers; } public void setCoordinatorClient(final CoordinatorClient coordinatorClient) { _coordinatorClient = coordinatorClient; } public StorageOSLocalAuthenticationHandler() { } /** * Verify that the user's password matches with the hashed and salted value stored. * Return false if user is not found. * * @param username the user * @param clearTextPassword the clear text password * @return true if user's password matches, otherwise false. */ public boolean verifyUserPassword(final String username, final String clearTextPassword) { if (clearTextPassword == null || clearTextPassword.isEmpty()) { _log.error("Login with blank password is not allowed"); return false; } String encpassword = null; PropertyInfo props = null; try { props = _coordinatorClient.getPropertyInfo(); } catch (CoordinatorException e) { _log.error("Access local user properties failed", e); return false; } if (props == null) { _log.error("Access local user properties failed"); return false; } encpassword = props.getProperty( "system_" + username + "_encpassword"); if (StringUtils.isBlank(encpassword)) { _log.error("No password set for user {} ", username); return false; } // A hashed value will start with the SHA-512 identifier ($6$) if (StringUtils.startsWith(encpassword, CRYPT_SHA_512)) { // Hash the clear text password and compare against the stored value String hashedValue = Crypt.crypt(clearTextPassword, encpassword); return encpassword.equals(hashedValue); } else { // Encrypt the clear text password and compare against the stored value String encryptedValue = encrypt(clearTextPassword); return encpassword.equals(encryptedValue); } } /** * Calls EncryptionProvider to encrypt a string and returns a Base64 encoded string representing the encrypted data. * * @param s the string to encrypt. * @return the encrypted (and Base64 encoded) string. */ private String encrypt(String s) { return _encryptionProvider.getEncryptedString(s); } @Override public boolean authenticate(final Credentials credentials) { UsernamePasswordCredentials creds = (UsernamePasswordCredentials) credentials; return verifyUserPassword(creds.getUserName(), creds.getPassword()); } public boolean exists(String username) { return _localUsers.containsKey(username); } @Override public boolean supports(final Credentials credentials) { return credentials != null && (UsernamePasswordCredentials.class.isAssignableFrom(credentials.getClass())) && exists(((UsernamePasswordCredentials) (credentials)).getUserName()); } @Override public void setFailureHandler(LdapFailureHandler failureHandler) { return; } }