/*
* Copyright 2013-2017 Simba Open Source
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.simbasecurity.core.service;
import org.apache.commons.lang.time.DateUtils;
import org.jasypt.exceptions.EncryptionOperationNotPossibleException;
import org.jasypt.util.password.PasswordEncryptor;
import org.simbasecurity.core.audit.Audit;
import org.simbasecurity.core.audit.AuditLogEventFactory;
import org.simbasecurity.core.audit.AuditMessages;
import org.simbasecurity.core.config.SimbaConfigurationParameter;
import org.simbasecurity.core.config.ConfigurationService;
import org.simbasecurity.core.domain.Status;
import org.simbasecurity.core.domain.User;
import org.simbasecurity.core.domain.repository.UserRepository;
import org.simbasecurity.core.exception.SimbaException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import static org.simbasecurity.core.exception.SimbaMessageKey.USER_DOESNT_EXISTS;
@Service
@Transactional(noRollbackFor = EncryptionOperationNotPossibleException.class)
public class CredentialServiceImpl implements CredentialService {
@Autowired private ConfigurationService configurationService;
@Autowired private UserRepository userRepository;
@Autowired private Audit audit;
@Autowired private AuditLogEventFactory auditLogEventFactory;
@Override
public boolean checkCredentials(String username, String password) {
User user = userRepository.findByName(username);
return user != null && !user.isDatabaseLoginBlocked() && checkPassword(password,user);
}
private boolean checkPassword(String password, User user) {
boolean result = user.checkPassword(password);
if(!result){
audit.log(auditLogEventFactory.createEventForUserPasswordForm(user.getUserName(), AuditMessages.WRONG_PASSWORD));
}
return result;
}
@Override
public boolean checkCredentialsWithSHA1EncryptorAndReEncrypt(String username, String password) {
User user = userRepository.findByName(username);
return user != null && !user.isDatabaseLoginBlocked() && user.checkPasswordWithSHA1EncryptorAndReEncrypt(password);
}
@Override
public boolean checkCredentials(String username, String password, PasswordEncryptor encryptor, boolean reEncrypt) {
User user = userRepository.findByName(username);
return user != null && !user.isDatabaseLoginBlocked() && user.checkPassword(password, encryptor, reEncrypt);
}
@Override
public void resetInvalidLoginCount(String userName) {
User user = findUser(userName);
user.resetInvalidLoginCount();
}
@Override
public boolean increaseInvalidLoginCountAndBlockAccount(String username) {
User user = userRepository.findByName(username);
boolean accountBlocked = false;
if (user != null) {
int invalidLoginCount = user.increaseInvalidLoginCount();
Integer maxInvalidLoginCount = configurationService.getValue(SimbaConfigurationParameter.INVALID_LOGIN_MAX_COUNT);
if (invalidLoginCount >= maxInvalidLoginCount) {
user.setStatus(Status.BLOCKED);
accountBlocked = true;
}
}
return accountBlocked;
}
@Override
public boolean checkUserExists(String userName) {
User user = userRepository.findByName(userName);
return user != null;
}
@Override
public boolean checkUserStatus(String userName, Status requiredStatus) {
User user = findUser(userName);
return requiredStatus.equals(user.getStatus());
}
@Override
public boolean mustChangePasswordOnNextLogon(String userName) {
User user = findUser(userName);
return user.isChangePasswordOnNextLogon();
}
@Override
public void markUsersForPasswordChange() {
Collection<User> allUsers = userRepository.findAll();
int passwordLifeTime = configurationService.getValue(SimbaConfigurationParameter.PASSWORD_LIFE_TIME);
Date today = DateUtils.truncate(new Date(), Calendar.DAY_OF_MONTH);
for (User user : allUsers) {
Date changeDate = user.getDateOfLastPasswordChange();
if (changeDate == null) {
changeDate = new Date(0);
}
Date lastDateForNextChange = DateUtils.addDays(changeDate, passwordLifeTime);
if (user.isPasswordChangeRequired() && today.after(lastDateForNextChange)) {
user.setChangePasswordOnNextLogon(true);
}
}
}
@Override
public boolean changePasswordAuthorized(String userName, String oldPassword, String newPassword) {
User user = findUser(userName);
return user.changePasswordAuthorized(oldPassword, newPassword);
}
@Override
public boolean changePasswordAuthorizedAndDisablePasswordExpire(String userName, String oldPassword, String newPassword) {
User user = findUser(userName);
user.setPasswordChangeRequired(false);
user.setChangePasswordOnNextLogon(false);
return user.changePasswordAuthorized(oldPassword, newPassword);
}
@Override
@Transactional(noRollbackFor = SimbaException.class)
public void changePassword(String userName, String newPassword, String newPasswordConfirmation) {
User user = findUser(userName);
user.changePassword(newPassword, newPasswordConfirmation);
}
@Override
public String getSuccessURL(String userName) {
User user = findUser(userName);
return user.getSuccessURL();
}
@Override
public String getPasswordHash(String username) {
return findUser(username).getPasswordHash();
}
private User findUser(String userName) {
User user = userRepository.findByName(userName);
if (user == null) {
audit.log(auditLogEventFactory.createEventForUserPasswordForm(userName, USER_DOESNT_EXISTS.name()));
throw new SimbaException(USER_DOESNT_EXISTS, userName);
}
return user;
}
}