/* * Copyright 2014-2016 CyberVision, Inc. * * 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.kaaproject.kaa.server.admin.services; import static org.kaaproject.kaa.server.admin.services.util.Utils.getCurrentUser; import static org.kaaproject.kaa.server.admin.shared.util.Utils.isEmpty; import org.apache.commons.lang.RandomStringUtils; import org.kaaproject.kaa.common.dto.KaaAuthorityDto; import org.kaaproject.kaa.common.dto.admin.AuthResultDto; import org.kaaproject.kaa.common.dto.admin.AuthResultDto.Result; import org.kaaproject.kaa.common.dto.admin.ResultCode; import org.kaaproject.kaa.server.admin.services.dao.UserFacade; import org.kaaproject.kaa.server.admin.services.entity.AuthUserDto; import org.kaaproject.kaa.server.admin.services.entity.Authority; import org.kaaproject.kaa.server.admin.services.entity.User; import org.kaaproject.kaa.server.admin.services.messaging.MessagingService; import org.kaaproject.kaa.server.admin.shared.services.KaaAdminServiceException; import org.kaaproject.kaa.server.admin.shared.services.KaaAuthService; import org.kaaproject.kaa.server.admin.shared.services.ServiceErrorCode; import org.kaaproject.kaa.server.admin.shared.util.UrlParams; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.Collection; @Service("kaaAuthService") public class KaaAuthServiceImpl implements KaaAuthService { private static final String ANONYMOUS_USER = "anonymousUser"; @Autowired private UserFacade userFacade; @Autowired private MessagingService messagingService; private PasswordEncoder passwordEncoder; private static boolean isLoggedIn(Authentication authentication) { if (authentication != null) { Object principal = authentication.getPrincipal(); if (principal != null) { String userName; if (principal instanceof AuthUserDto) { userName = ((AuthUserDto) principal).getUsername(); } else { return false; } return !userName.equals(ANONYMOUS_USER); } else { return false; } } else { return false; } } public void setPasswordEncoder(PasswordEncoder passwordEncoder) { this.passwordEncoder = passwordEncoder; } @Override public AuthResultDto checkAuth() throws Exception { AuthResultDto result = new AuthResultDto(); Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (!isLoggedIn(authentication)) { if (userFacade.isAuthorityExists(KaaAuthorityDto.KAA_ADMIN.name())) { result.setAuthResult(Result.NOT_LOGGED_IN); } else { result.setAuthResult(Result.KAA_ADMIN_NOT_EXISTS); } } else { AuthUserDto authUser = (AuthUserDto) authentication.getPrincipal(); result.setAuthResult(Result.OK); result.setAuthority(authUser.getAuthority()); result.setTenantId(authUser.getTenantId()); result.setUsername(authUser.getUsername()); String displayName = authUser.getUsername(); if (!isEmpty(authUser.getFirstName()) || !isEmpty(authUser.getLastName())) { String name = authUser.getFirstName() + " " + authUser.getLastName(); displayName += " (" + name.trim() + ")"; } result.setDisplayName(displayName); } return result; } /** * Create Kaa admin. * * @param username the Kaa admin username * @param password the Kaa admin password * @throws KaaAdminServiceException if bad password strength detected */ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public void createKaaAdmin(String username, String password) throws KaaAdminServiceException { org.kaaproject.kaa.server.admin.services.entity.User userEntity = new org.kaaproject.kaa.server.admin.services.entity.User(); if (!checkPasswordStrength(password)) { throw new KaaAdminServiceException( "Bad password strength. Password length must be greater than 5 characters.", ServiceErrorCode.GENERAL_ERROR); } userEntity.setUsername(username); userEntity.setPassword(passwordEncoder.encode(password)); userEntity.setEnabled(true); userEntity.setTempPassword(false); Authority authority = new Authority(); authority.setAuthority(KaaAuthorityDto.KAA_ADMIN.name()); authority.setUser(userEntity); Collection<Authority> authorities = new ArrayList<Authority>(); authorities.add(authority); userEntity.setAuthorities(authorities); userFacade.save(userEntity); } /** * Change password. * * @param username the username * @param oldPassword the oldPassword * @param newPassword the newPassword * @return the result code * @throws Exception the exception */ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public ResultCode changePassword(String username, String oldPassword, String newPassword) throws Exception { User userEntity = userFacade.findByUserName(username); boolean firstTimeLogin = userEntity.isTempPassword(); if (userEntity == null) { return ResultCode.USER_NOT_FOUND; } if (!firstTimeLogin) { User currentUser = userFacade.findById(Long.valueOf(getCurrentUser().getExternalUid())); if (!currentUser.equals(userEntity)) { return ResultCode.PERMISSION_DENIED; } } if (!passwordEncoder.matches(oldPassword, userEntity.getPassword())) { return ResultCode.OLD_PASSWORD_MISMATCH; } if (!checkPasswordStrength(newPassword)) { return ResultCode.BAD_PASSWORD_STRENGTH; } userEntity.setPassword(passwordEncoder.encode(newPassword)); userEntity.setTempPassword(false); userFacade.save(userEntity); return ResultCode.OK; } private boolean checkPasswordStrength(String password) { return password.length() >= 6; } /** * Check user name occupied. * * @param username the username * @param userId the user ID. * @return the result code * @throws Exception the exception */ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public ResultCode checkUserNameOccupied(String username, Long userId) throws Exception { User userEntity = userFacade.checkUserNameOccupied(username, userId); if (userEntity == null) { return ResultCode.OK; } else { return ResultCode.USERNAME_EXISTS; } } /** * Check email occupied. * * @param email the email. * @param userId the user ID * @return the result code * @throws Exception the exception */ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public ResultCode checkEmailOccupied(String email, Long userId) throws Exception { User userEntity = userFacade.checkEmailOccupied(email, userId); if (userEntity == null) { return ResultCode.OK; } else { return ResultCode.EMAIL_EXISTS; } } @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public ResultCode checkUsernameOrEmailExists(String usernameOrEmail) throws Exception { return checkUserAndEmailExists(userFacade.findByUsernameOrMail(usernameOrEmail)); } /** * Send password reset link by email. * * @param usernameOrEmail the username or email * @return the result code * @throws Exception the exception */ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public ResultCode sendPasswordResetLinkByEmail(String usernameOrEmail) throws Exception { User userEntity = userFacade.findByUsernameOrMail(usernameOrEmail); ResultCode result = checkUserAndEmailExists(userEntity); if (result == ResultCode.OK) { String passwordResetHash = RandomStringUtils.randomAlphanumeric( UrlParams.PASSWORD_RESET_HASH_LENGTH); userEntity.setPasswordResetHash(passwordResetHash); userFacade.save(userEntity); messagingService.sendPasswordResetLink( passwordResetHash, userEntity.getUsername(), userEntity.getMail()); } return result; } private ResultCode checkUserAndEmailExists(User userEntity) { if (userEntity == null) { return ResultCode.USER_OR_EMAIL_NOT_FOUND; } else if (isEmpty(userEntity.getMail())) { return ResultCode.USER_EMAIL_NOT_DEFINED; } else { return ResultCode.OK; } } /** * Reset password by reset hash. * * @param passwordResetHash the reset hash * @return the result code */ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public ResultCode resetPasswordByResetHash(String passwordResetHash) throws Exception { User userEntity = userFacade.findByPasswordResetHash(passwordResetHash); if (userEntity == null) { return ResultCode.USER_NOT_FOUND; } else if (isEmpty(userEntity.getMail())) { return ResultCode.USER_EMAIL_NOT_DEFINED; } userEntity.setPasswordResetHash(null); String generatedPassword = RandomStringUtils.randomAlphanumeric( User.TEMPORARY_PASSWORD_LENGTH); userEntity.setPassword(passwordEncoder.encode(generatedPassword)); userEntity.setTempPassword(true); userFacade.save(userEntity); messagingService.sendPasswordAfterReset( userEntity.getUsername(), generatedPassword, userEntity.getMail()); return ResultCode.OK; } }