Catalog alignment
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / user / UserBusinessLogic.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.openecomp.sdc.be.user;
22
23 import fj.data.Either;
24 import org.apache.commons.collections.CollectionUtils;
25 import org.apache.commons.lang3.StringUtils;
26 import org.apache.tinkerpop.gremlin.structure.Edge;
27 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
28 import org.openecomp.sdc.be.dao.api.ActionStatus;
29 import org.openecomp.sdc.be.dao.utils.UserStatusEnum;
30 import org.openecomp.sdc.be.facade.operations.UserOperation;
31 import org.openecomp.sdc.be.impl.ComponentsUtils;
32 import org.openecomp.sdc.be.model.LifecycleStateEnum;
33 import org.openecomp.sdc.be.model.User;
34 import org.openecomp.sdc.be.model.operations.impl.UserAdminOperation;
35 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
36 import org.openecomp.sdc.common.api.UserRoleEnum;
37 import org.openecomp.sdc.common.datastructure.UserContext;
38 import org.openecomp.sdc.common.kpi.api.ASDCKpiApi;
39 import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
40 import org.openecomp.sdc.common.log.wrappers.Logger;
41 import org.openecomp.sdc.common.util.ThreadLocalsHolder;
42 import org.openecomp.sdc.exception.ResponseFormat;
43
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.HashSet;
47 import java.util.List;
48 import java.util.Objects;
49 import java.util.stream.Collectors;
50
51 import static org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum.ADD_USER;
52 import static org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum.GET_USERS_LIST;
53 import static org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum.UPDATE_USER;
54
55 @org.springframework.stereotype.Component
56 public class UserBusinessLogic {
57
58     private static final Logger log = Logger.getLogger(UserBusinessLogic.class);
59     private static final String IN_CERTIFICATION_CHECKED_OUT = "in-certification/checked-out";
60     private static final String UNKNOWN = "UNKNOWN";
61     private static UserAdminValidator userAdminValidator = UserAdminValidator.getInstance();
62
63     private final UserAdminOperation userAdminOperation;
64     private final ComponentsUtils componentsUtils;
65     private final UserOperation facadeUserOperation;
66
67     public UserBusinessLogic(UserAdminOperation userAdminOperation, ComponentsUtils componentsUtils, UserOperation facadeUserOperation) {
68         this.userAdminOperation = userAdminOperation;
69         this.componentsUtils = componentsUtils;
70         this.facadeUserOperation = facadeUserOperation;
71     }
72
73     public User getUser(String userId, boolean inTransaction) {
74         Either<User, ActionStatus> result = userAdminOperation.getUserData(userId, inTransaction);
75         if (result.isRight()) {
76             handleUserAccessAuditing(userId, result.right().value());
77             throw new ByActionStatusComponentException(result.right().value(), userId);
78         }
79         User user = result.left().value();
80         if (user == null) {
81             handleUserAccessAuditing(userId, ActionStatus.GENERAL_ERROR);
82             throw new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR);
83         }
84         return user;
85     }
86
87     public User getUser(String userId) {
88         UserContext userContext = ThreadLocalsHolder.getUserContext();
89         if (Objects.isNull(userContext) || Objects.isNull(userContext.getUserId())) {
90             log.info("USER_NOT_FOUND, user=" + userId);
91             handleUserAccessAuditing(userId, ActionStatus.USER_NOT_FOUND);
92             throw new ByActionStatusComponentException(ActionStatus.USER_NOT_FOUND, userId);
93         }
94         if (Objects.isNull(userContext.getUserRoles())){
95             userContext.setUserRoles(new HashSet<>());
96         }
97         return convertUserContextToUser(userContext);
98     }
99
100     protected User convertUserContextToUser(UserContext userContext) {
101         User user = new User();
102         user.setUserId(userContext.getUserId());
103         user.setFirstName(userContext.getFirstName());
104         user.setLastName(userContext.getLastName());
105         boolean userHasRoles = userContext.getUserRoles().iterator().hasNext();
106         user.setRole(!userHasRoles ? null : userContext.getUserRoles().iterator().next());
107         user.setStatus(userHasRoles ? UserStatusEnum.ACTIVE : UserStatusEnum.INACTIVE);
108         return user;
109     }
110
111     public boolean hasActiveUser(String userId) {
112         UserContext userContext = ThreadLocalsHolder.getUserContext();
113         if (Objects.isNull(userContext) || Objects.isNull(userContext.getUserId()) ) {
114             handleUserAccessAuditing(userId, ActionStatus.USER_NOT_FOUND);
115             return false;
116         }
117         if (Objects.isNull(userContext.getUserRoles()) || userContext.getUserRoles().isEmpty()){
118             handleUserAccessAuditing(userId, ActionStatus.USER_INACTIVE);
119             return false;
120         }
121         return true;
122     }
123
124     public User createUser(String modifierUserId, User newUser) {
125
126         User modifier = getValidModifier(modifierUserId, newUser.getUserId(), AuditingActionEnum.ADD_USER);
127
128         // verify user not exist
129         String newUserId = newUser.getUserId();
130         Either<User, ActionStatus> eitherUserInDB = verifyNewUser(newUserId);
131         newUser.setStatus(UserStatusEnum.ACTIVE);
132
133         validateEmail(newUser);
134
135         validateRole(newUser);
136
137         // handle last login if user is import
138         if (newUser.getLastLoginTime() == null) {
139             newUser.setLastLoginTime(0L);
140         }
141
142         User createdUser;
143         if (ActionStatus.USER_INACTIVE.equals(eitherUserInDB.right().value())) { // user inactive - update state                                                                                  // exist
144             newUser.setLastLoginTime(0L);
145             createdUser = userAdminOperation.updateUserData(newUser);
146         } else { // user does not exist - create new user
147             if (!userAdminValidator.validateUserId(newUserId)) {
148                 log.debug("createUser method - user has invalid userId = {}", newUser.getUserId());
149                 throw new ByActionStatusComponentException(ActionStatus.INVALID_USER_ID, newUserId);
150             }
151             createdUser = userAdminOperation.saveUserData(newUser);
152         }
153         ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
154         handleAuditing(modifier, null, createdUser, responseFormat, AuditingActionEnum.ADD_USER);
155         getFacadeUserOperation().updateUserCache(UserOperationEnum.CREATE, createdUser.getUserId(), createdUser.getRole());
156         return createdUser;
157     }
158
159     private void validateRole(User newUser) {
160         if (newUser.getRole() == null || newUser.getRole().length() == 0) {
161             newUser.setRole(Role.DESIGNER.name());
162         } else {
163             if (!userAdminValidator.validateRole(newUser.getRole())) {
164                 log.debug("createUser method - user has invalid role = {}", newUser.getUserId());
165                 throw new ByActionStatusComponentException(ActionStatus.INVALID_ROLE, newUser.getRole());
166             }
167         }
168     }
169
170     private void validateEmail(User newUser) {
171         if (newUser.getEmail() != null && !userAdminValidator.validateEmail(newUser.getEmail())) {
172             log.debug("createUser method - user has invalid email = {}", newUser.getUserId());
173             throw new ByActionStatusComponentException(ActionStatus.INVALID_EMAIL_ADDRESS, newUser.getEmail());
174         }
175     }
176
177     private Either<User, ActionStatus> verifyNewUser(String newUserId) {
178         Either<User, ActionStatus> eitherUserInDB = getUserData(newUserId);
179         if (eitherUserInDB.isRight()) {
180             ActionStatus status = eitherUserInDB.right().value();
181             if (!ActionStatus.USER_NOT_FOUND.equals(status) && !ActionStatus.USER_INACTIVE.equals(status)) {
182                 componentsUtils.auditAdminUserActionAndThrowException(ADD_USER, null, null, null, status, newUserId);
183             }
184         } else {// User exist in DB
185             User userFromDb = eitherUserInDB.left().value();
186             if (userFromDb.getStatus() == UserStatusEnum.ACTIVE) {
187                 log.debug("createUser method - user with id {} already exist with id: {}", newUserId, userFromDb.getUserId());
188                 componentsUtils.auditAdminUserActionAndThrowException(ADD_USER, null, null, null, ActionStatus.USER_ALREADY_EXIST, newUserId);
189             }
190         }
191         return eitherUserInDB;
192     }
193
194     public Either<User, ActionStatus> verifyNewUserForPortal(String newUserId) {
195         Either<User, ActionStatus> eitherUserInDB = getUserData(newUserId);
196         if (eitherUserInDB.isRight()) {
197             ActionStatus status = eitherUserInDB.right().value();
198             if (!ActionStatus.USER_NOT_FOUND.equals(status) && !ActionStatus.USER_INACTIVE.equals(status)) {
199                 componentsUtils.auditAdminUserActionAndThrowException(ADD_USER, null, null, null, status, newUserId);
200             }
201         }
202
203         return eitherUserInDB;
204     }
205
206     private Either<User, ActionStatus> getUserData(String newUserId) {
207         if (newUserId == null) {
208             log.error(EcompLoggerErrorCode.DATA_ERROR, "", "","Create user - new user id is missing");
209             throw new ByActionStatusComponentException(ActionStatus.MISSING_INFORMATION);
210         }
211
212         return userAdminOperation.getUserData(newUserId, false);
213     }
214
215     public User updateUserRole(String modifierUserId, String userIdToUpdate, String userRole) {
216
217         User modifier = getValidModifier(modifierUserId, userIdToUpdate, UPDATE_USER);
218         User userToUpdate = getUser(userIdToUpdate, false);
219         validateChangeRoleToAllowedRoles(userRole);
220
221         List<Edge> userPendingTasks = userAdminOperation.getUserPendingTasksList(userToUpdate, getChangeRoleStateLimitations(userToUpdate));
222         if (!userPendingTasks.isEmpty()) {
223             log.debug("updateUserRole method - User cannot be updated, user have pending projects userId {}", userIdToUpdate);
224             String userInfo = userToUpdate.getFirstName() + " " + userToUpdate.getLastName() + '(' + userToUpdate.getUserId() + ')';
225             componentsUtils.auditAdminUserActionAndThrowException(UPDATE_USER, modifier, userToUpdate, null, ActionStatus.CANNOT_UPDATE_USER_WITH_ACTIVE_ELEMENTS, userInfo, IN_CERTIFICATION_CHECKED_OUT);
226         }
227
228         Role newRole = Role.valueOf(userRole);
229         User newUser = new User();
230         newUser.setRole(newRole.name());
231         newUser.setUserId(userIdToUpdate);
232
233         User updatedUser = userAdminOperation.updateUserData(newUser);
234         handleAuditing(modifier, userToUpdate, updatedUser, componentsUtils.getResponseFormat(ActionStatus.OK), UPDATE_USER);
235         getFacadeUserOperation().updateUserCache(UserOperationEnum.CHANGE_ROLE, updatedUser.getUserId(), updatedUser.getRole());
236         return updatedUser;
237     }
238
239     private void validateChangeRoleToAllowedRoles(String userRole) {
240         List<String> allowedRoles = Arrays.asList(UserRoleEnum.DESIGNER.getName(), UserRoleEnum.ADMIN.getName());
241         if (!allowedRoles.contains(userRole)){
242             throw new ByActionStatusComponentException(ActionStatus.INVALID_ROLE, userRole);
243         }
244     }
245
246     User getValidModifier(String modifierUserId, String userIdHandle, AuditingActionEnum actionEnum) {
247         if (modifierUserId == null) {
248             log.error(EcompLoggerErrorCode.DATA_ERROR, "", "", "user modifier is missing");
249             throw new ByActionStatusComponentException(ActionStatus.MISSING_INFORMATION);
250         }
251
252         User modifier = getUser(modifierUserId, false);
253         if (!modifier.getRole().equals(UserRoleEnum.ADMIN.getName())) {
254             log.debug("user is not admin. Id = {}", modifier.getUserId());
255             componentsUtils.auditAdminUserActionAndThrowException(actionEnum, modifier, null, null, ActionStatus.RESTRICTED_OPERATION);
256         }
257
258         if (modifier.getUserId().equals(userIdHandle)) {
259             log.debug("admin user cannot act on self. Id = {}", modifier.getUserId());
260             componentsUtils.auditAdminUserActionAndThrowException(actionEnum, modifier, null, null, ActionStatus.UPDATE_USER_ADMIN_CONFLICT);
261         }
262         return modifier;
263     }
264
265     public List<User> getAllAdminUsers() {
266         Either<List<User>, ActionStatus> response = userAdminOperation.getAllUsersWithRole(Role.ADMIN.name(), null);
267         if (response.isRight()) {
268             throw new ByActionStatusComponentException(response.right().value());
269         }
270         return response.left().value();
271     }
272
273     public List<User> getUsersList(String modifierAttId, List<String> roles, String rolesStr) {
274         if (modifierAttId == null) {
275             throw new ByActionStatusComponentException(ActionStatus.MISSING_INFORMATION);
276         }
277         User user = getUser(modifierAttId, false);
278         Either<List<User>, ResponseFormat> getResponse;
279         List<User> userList = new ArrayList<>();
280         if (!CollectionUtils.isEmpty(roles)) {
281             for (String role : roles) {
282                 if (!userAdminValidator.validateRole(role)) {
283                     componentsUtils.auditAdminUserActionAndThrowException(GET_USERS_LIST, user, null, null, ActionStatus.INVALID_ROLE, role);
284                 }
285                 getResponse = getUsersPerRole(role, user, rolesStr);
286                 userList.addAll(getResponse.left().value());
287             }
288         } else {
289             rolesStr = "All";
290             getResponse = getUsersPerRole(null, user, rolesStr);
291             userList.addAll(getResponse.left().value());
292         }
293         handleGetUsersListAuditing(user, componentsUtils.getResponseFormat(ActionStatus.OK), rolesStr);
294         return userList;
295     }
296
297     Either<List<User>, ResponseFormat> getUsersPerRole(String role, User user, String rolesStr) {
298         ResponseFormat responseFormat;
299         Either<List<User>, ActionStatus> response = userAdminOperation.getAllUsersWithRole(role, UserStatusEnum.ACTIVE.name());
300         if (response.isRight()) {
301             responseFormat = componentsUtils.getResponseFormat(response.right().value());
302             handleGetUsersListAuditing(user, responseFormat, rolesStr);
303             return Either.right(responseFormat);
304         }
305         List<User> users = response.left().value()
306                 .stream()
307                 .filter(u-> StringUtils.isNotEmpty(u.getUserId()))
308                 .collect(Collectors.toList());
309         return Either.left(users);
310     }
311
312     private void handleGetUsersListAuditing(User user, ResponseFormat responseFormat, String details) {
313         componentsUtils.auditGetUsersList(user, details, responseFormat);
314     }
315
316     private void handleAuditing(User modifier, User userBefore, User userAfter, ResponseFormat responseFormat, AuditingActionEnum actionName) {
317         componentsUtils.auditAdminUserAction(actionName, modifier, userBefore, userAfter, responseFormat);
318     }
319
320     private void handleUserAccessAuditing(User user, ResponseFormat responseFormat) {
321         componentsUtils.auditUserAccess(user, responseFormat);
322     }
323
324     private void handleUserAccessAuditing(String userId, ActionStatus status, String... params) {
325         componentsUtils.auditUserAccess(new User(userId), status, params);
326     }
327
328     public User authorize(User authUser) {
329         String userId = authUser.getUserId();
330         if (userId == null) {
331             log.debug("authorize method -  user id is missing");
332             throw new ByActionStatusComponentException(ActionStatus.MISSING_INFORMATION);
333         }
334
335         User user = getUser(userId, false);
336
337         String firstName = authUser.getFirstName();
338         if (firstName != null && !firstName.isEmpty() && !firstName.equals(user.getFirstName())) {
339             user.setFirstName(firstName);
340         }
341
342         String lastName = authUser.getLastName();
343         if (lastName != null && !lastName.isEmpty() && !lastName.equals(user.getLastName())) {
344             user.setLastName(lastName);
345         }
346
347         String email = authUser.getEmail();
348         if (email != null && !email.isEmpty() && !email.equals(user.getEmail())) {
349             user.setEmail(email);
350         }
351
352         // last login time stamp handle
353         user.setLastLoginTime();
354
355         User updatedUser = userAdminOperation.updateUserData(user);
356         Long lastLoginTime = user.getLastLoginTime();
357         if (lastLoginTime != null) {
358             updatedUser.setLastLoginTime(lastLoginTime);
359         } else {
360             updatedUser.setLastLoginTime(0L);
361         }
362
363         handleUserAccessAuditing(updatedUser.getUserId(), ActionStatus.OK);
364         ASDCKpiApi.countUsersAuthorizations();
365         return updatedUser;
366     }
367
368     /*
369      * The method updates user credentials only, the role is neglected The role updated through updateRole method
370      */
371     public Either<User, ResponseFormat> updateUserCredentials(User updatedUserCred) {
372
373         ResponseFormat responseFormat;
374
375         String userId = updatedUserCred.getUserId();
376
377         if (userId == null) {
378             updatedUserCred.setUserId(UNKNOWN);
379             log.debug("updateUserCredentials method - user header is missing");
380             responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_INFORMATION);
381             handleUserAccessAuditing(updatedUserCred, responseFormat);
382             return Either.right(responseFormat);
383         }
384
385         User user = getUser(userId, false);
386         String firstName = updatedUserCred.getFirstName();
387         if (firstName != null && !firstName.isEmpty() && !firstName.equals(user.getFirstName())) {
388             user.setFirstName(firstName);
389         }
390
391         String lastName = updatedUserCred.getLastName();
392         if (lastName != null && !lastName.isEmpty() && !lastName.equals(user.getLastName())) {
393             user.setLastName(lastName);
394         }
395
396         String email = updatedUserCred.getEmail();
397         if (email != null && !email.isEmpty() && !email.equals(user.getEmail())) {
398             user.setEmail(email);
399         }
400
401         if (updatedUserCred.getLastLoginTime() != null && user.getLastLoginTime() != null) {
402             if (updatedUserCred.getLastLoginTime() > user.getLastLoginTime()) {
403                 user.setLastLoginTime(updatedUserCred.getLastLoginTime());
404             }
405         } else if (updatedUserCred.getLastLoginTime() != null && user.getLastLoginTime() == null) {
406             user.setLastLoginTime(updatedUserCred.getLastLoginTime());
407         }
408
409         User updatedUser = userAdminOperation.updateUserData(user);
410         responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK);
411         handleUserAccessAuditing(updatedUser, responseFormat);
412         return Either.left(updatedUser);
413     }
414
415     private List<Object> getChangeRoleStateLimitations(User user) {
416         UserRoleEnum role = UserRoleEnum.valueOf(user.getRole());
417         List<Object> properties = new ArrayList<>();
418         switch (role) {
419             case DESIGNER:
420             case PRODUCT_STRATEGIST:
421             case PRODUCT_MANAGER:
422             case ADMIN:
423                 properties.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name());
424                 break;
425             case TESTER:
426                 // For tester we allow change role even if there are pending task (per US468155 in 1810)
427             default:
428         }
429         return properties;
430     }
431
432     public UserOperation getFacadeUserOperation() {
433         return facadeUserOperation;
434     }
435
436 }