package io.cattle.platform.iaas.api.auth.dao.impl; import static io.cattle.platform.core.model.tables.AccountTable.*; import static io.cattle.platform.core.model.tables.CredentialTable.*; import io.cattle.platform.api.auth.Policy; import io.cattle.platform.core.constants.AccountConstants; import io.cattle.platform.core.constants.CommonStatesConstants; import io.cattle.platform.core.constants.CredentialConstants; import io.cattle.platform.core.dao.AccountDao; import io.cattle.platform.core.dao.GenericResourceDao; import io.cattle.platform.core.model.Account; import io.cattle.platform.core.model.Credential; import io.cattle.platform.db.jooq.dao.impl.AbstractJooqDao; import io.cattle.platform.framework.encryption.EncryptionConstants; import io.cattle.platform.iaas.api.auth.SecurityConstants; import io.cattle.platform.iaas.api.auth.dao.PasswordDao; import io.cattle.platform.iaas.api.auth.integration.local.ChangePassword; import io.cattle.platform.iaas.api.auth.integration.local.LocalAuthConstants; import io.cattle.platform.object.ObjectManager; import io.cattle.platform.object.util.DataAccessor; import io.github.ibuildthecloud.gdapi.exception.ClientVisibleException; import io.github.ibuildthecloud.gdapi.util.ResponseCodes; import io.github.ibuildthecloud.gdapi.util.TransformationService; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.inject.Inject; import org.apache.commons.lang3.StringUtils; public class PasswordDaoImpl extends AbstractJooqDao implements PasswordDao { @Inject ObjectManager objectManager; @Inject GenericResourceDao resourceDao; @Inject TransformationService transformationService; @Inject AccountDao accountDao; @Override public Credential changePassword(Credential password, ChangePassword changePassword, Policy policy) { if (policy.isOption(Policy.AUTHORIZED_FOR_ALL_ACCOUNTS) || transformationService.compare(changePassword.getOldSecret(), password.getSecretValue())){ password.setSecretValue(transformationService.transform(changePassword.getNewSecret(), EncryptionConstants.HASH)); password = objectManager.persist(password); return password; } throw new ClientVisibleException(ResponseCodes.BAD_REQUEST, "InvalidOldPassword"); } @Override public Credential createAdminAccountAndPassword(String username, String password, String name) { if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) { throw new ClientVisibleException(ResponseCodes.BAD_REQUEST, "UserCredentialCreation", "Cannot have blank username or password.", null); } Account account; if (create().selectFrom(CREDENTIAL) .where(CREDENTIAL.PUBLIC_VALUE.eq(username) .and(CREDENTIAL.STATE.eq(CommonStatesConstants.ACTIVE) .and(CREDENTIAL.KIND.eq(CredentialConstants.KIND_PASSWORD)))).fetchAny() != null){ throw new ClientVisibleException(ResponseCodes.CONFLICT, "UsernameIsTaken", "Username: " + username +" is taken", null); } account = create() .selectFrom(ACCOUNT) .where(ACCOUNT.STATE.in(accountDao.getAccountActiveStates()) .and(ACCOUNT.KIND.eq(AccountConstants.ADMIN_KIND))) .orderBy(ACCOUNT.ID.asc()).limit(1).fetchOne(); Date now = new Date(System.currentTimeMillis()); create().update(CREDENTIAL).set(CREDENTIAL.STATE, CommonStatesConstants.PURGED) .set(CREDENTIAL.REMOVED, now) .set(CREDENTIAL.REMOVE_TIME, now) .where(CREDENTIAL.ACCOUNT_ID.eq(account.getId()) .and(CREDENTIAL.KIND.eq("password"))) .execute(); if (StringUtils.isNotEmpty(name)) { account.setName(name); } Map<Object, Object> properties = new HashMap<>(); properties.put(CREDENTIAL.PUBLIC_VALUE, username); properties.put(CREDENTIAL.SECRET_VALUE, transformationService.transform(password, EncryptionConstants.HASH)); properties.put(CREDENTIAL.KIND, LocalAuthConstants.PASSWORD); properties.put(CREDENTIAL.ACCOUNT_ID, account.getId()); properties.put(CREDENTIAL.STATE, CommonStatesConstants.ACTIVE); DataAccessor.fields(account).withKey(SecurityConstants.HAS_LOGGED_IN).set(true); objectManager.persist(account); return objectManager.create(Credential.class, objectManager.convertToPropertiesFor(Credential.class, properties)); } @Override public boolean isUnique(final Credential credential) { if (StringUtils.isNotBlank(credential.getPublicValue()) && CredentialConstants.CREDENTIAL_TYPES_TO_FILTER.contains(credential.getKind())) { List<Credential> credentials = create().selectFrom(CREDENTIAL) .where(CREDENTIAL.REMOVED.isNull() .and(CREDENTIAL.PUBLIC_VALUE.equalIgnoreCase(credential.getPublicValue()) .and(CREDENTIAL.KIND.equalIgnoreCase(credential.getKind())))).fetchInto (Credential.class); return credentials.isEmpty(); } return true; } @Override public void verifyUsernamePassword(String username, String password, String name) { Credential credential = create() .selectFrom(CREDENTIAL) .where(CREDENTIAL.STATE.eq(CommonStatesConstants.ACTIVE)) .and(CREDENTIAL.PUBLIC_VALUE.eq(username) .and(CREDENTIAL.KIND.equalIgnoreCase(CredentialConstants.KIND_PASSWORD))) .fetchOne(); if (credential == null) { createAdminAccountAndPassword(username, password, name); } else { if (!transformationService.compare(password, credential.getSecretValue())) { throw new ClientVisibleException(ResponseCodes.UNAUTHORIZED, "IncorrectPassword", "Username: " + username + " is taken and provided password is incorrect.", null); } } } }