001/* 002 * (C) Copyright 2016-2018 Nuxeo (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Michael Vachette 018 * Florent Guillaume 019 */ 020package org.nuxeo.ecm.automation.core.operations.users; 021 022import static org.nuxeo.ecm.platform.usermanager.UserConfig.COMPANY_COLUMN; 023import static org.nuxeo.ecm.platform.usermanager.UserConfig.EMAIL_COLUMN; 024import static org.nuxeo.ecm.platform.usermanager.UserConfig.FIRSTNAME_COLUMN; 025import static org.nuxeo.ecm.platform.usermanager.UserConfig.GROUPS_COLUMN; 026import static org.nuxeo.ecm.platform.usermanager.UserConfig.LASTNAME_COLUMN; 027import static org.nuxeo.ecm.platform.usermanager.UserConfig.PASSWORD_COLUMN; 028import static org.nuxeo.ecm.platform.usermanager.UserConfig.SCHEMA_NAME; 029import static org.nuxeo.ecm.platform.usermanager.UserConfig.TENANT_ID_COLUMN; 030import static org.nuxeo.ecm.platform.usermanager.UserConfig.USERNAME_COLUMN; 031 032import java.util.AbstractMap.SimpleEntry; 033import java.util.Arrays; 034import java.util.Map.Entry; 035 036import javax.servlet.http.HttpServletResponse; 037 038import org.apache.commons.lang3.StringUtils; 039import org.nuxeo.ecm.automation.OperationContext; 040import org.nuxeo.ecm.automation.OperationException; 041import org.nuxeo.ecm.automation.core.Constants; 042import org.nuxeo.ecm.automation.core.annotations.Context; 043import org.nuxeo.ecm.automation.core.annotations.Operation; 044import org.nuxeo.ecm.automation.core.annotations.OperationMethod; 045import org.nuxeo.ecm.automation.core.annotations.Param; 046import org.nuxeo.ecm.automation.core.util.Properties; 047import org.nuxeo.ecm.automation.core.util.StringList; 048import org.nuxeo.ecm.core.api.DocumentModel; 049import org.nuxeo.ecm.core.api.NuxeoException; 050import org.nuxeo.ecm.core.api.NuxeoPrincipal; 051import org.nuxeo.ecm.platform.usermanager.NuxeoPrincipalImpl; 052import org.nuxeo.ecm.platform.usermanager.UserManager; 053 054/** 055 * Operation to create or update a user. 056 * 057 * @since 9.1 058 */ 059@Operation(id = CreateOrUpdateUser.ID, // 060 aliases = { "Services.CreateUser" }, // 061 category = Constants.CAT_USERS_GROUPS, // 062 label = "Create or Update User", // 063 description = "Create or Update User.") 064public class CreateOrUpdateUser { 065 066 public static final String ID = "User.CreateOrUpdate"; 067 068 public static final String CREATE_OR_UPDATE = "createOrUpdate"; 069 070 public static final String CREATE = "create"; 071 072 public static final String UPDATE = "update"; 073 074 protected static final String USER_COLON = SCHEMA_NAME + ':'; 075 076 @Context 077 protected UserManager userManager; 078 079 @Context 080 protected OperationContext ctx; 081 082 @Param(name = "username") 083 protected String username; 084 085 @Param(name = "password", required = false) 086 protected String password; 087 088 @Param(name = "email", required = false) 089 protected String email; 090 091 @Param(name = "firstName", required = false) 092 protected String firstName; 093 094 @Param(name = "lastName", required = false) 095 protected String lastName; 096 097 @Param(name = "company", required = false) 098 protected String company; 099 100 @Param(name = "tenantId", required = false) 101 protected String tenantId; 102 103 @Param(name = "groups", required = false) 104 protected StringList groups; 105 106 @Param(name = "properties", required = false) 107 protected Properties properties = new Properties(); 108 109 @Param(name = "mode", required = false, values = { CREATE_OR_UPDATE, CREATE, UPDATE }) 110 protected String mode; 111 112 @OperationMethod 113 public void run() throws OperationException { 114 boolean create; 115 DocumentModel userDoc = userManager.getUserModel(username); 116 if (userDoc == null) { 117 if (UPDATE.equals(mode)) { 118 throw new OperationException("Cannot update non-existent user: " + username); 119 } 120 create = true; 121 userDoc = userManager.getBareUserModel(); 122 userDoc.setProperty(SCHEMA_NAME, USERNAME_COLUMN, username); 123 } else { 124 if (CREATE.equals(mode)) { 125 throw new OperationException("Cannot create already-existing user: " + username); 126 } 127 create = false; 128 129 // make sure the user can be updated 130 checkCanCreateOrUpdateUser(userDoc); 131 } 132 if (groups != null) { 133 userDoc.setProperty(SCHEMA_NAME, GROUPS_COLUMN, groups); 134 } 135 for (Entry<String, String> entry : Arrays.asList( // 136 new SimpleEntry<>(TENANT_ID_COLUMN, tenantId), // 137 new SimpleEntry<>(PASSWORD_COLUMN, password), // 138 new SimpleEntry<>(EMAIL_COLUMN, email), // 139 new SimpleEntry<>(FIRSTNAME_COLUMN, firstName), // 140 new SimpleEntry<>(LASTNAME_COLUMN, lastName), // 141 new SimpleEntry<>(COMPANY_COLUMN, company))) { 142 String key = entry.getKey(); 143 String value = entry.getValue(); 144 if (StringUtils.isNotBlank(value)) { 145 properties.put(key, value); 146 } 147 } 148 for (Entry<String, String> entry : properties.entrySet()) { 149 String key = entry.getKey(); 150 String value = entry.getValue(); 151 if (key.startsWith(USER_COLON)) { 152 key = key.substring(USER_COLON.length()); 153 } 154 userDoc.setProperty(SCHEMA_NAME, key, value); 155 } 156 157 // make sure the new user can be created or updated 158 checkCanCreateOrUpdateUser(userDoc); 159 160 if (create) { 161 userDoc = userManager.createUser(userDoc); 162 } else { 163 userManager.updateUser(userDoc); 164 userDoc = userManager.getUserModel(username); 165 } 166 } 167 168 protected void checkCanCreateOrUpdateUser(DocumentModel userDoc) { 169 NuxeoPrincipal currentUser = ctx.getPrincipal(); 170 if (!currentUser.isAdministrator() 171 && (!currentUser.isMemberOf("powerusers") || !canCreateOrUpdateUser(userDoc))) { 172 throw new NuxeoException("User is not allowed to create or edit users", HttpServletResponse.SC_FORBIDDEN); 173 } 174 } 175 176 protected boolean canCreateOrUpdateUser(DocumentModel userDoc) { 177 NuxeoPrincipal principal = new NuxeoPrincipalImpl((String) userDoc.getProperty(SCHEMA_NAME, USERNAME_COLUMN)); 178 principal.setModel(userDoc); 179 return userManager.getAdministratorsGroups().stream().noneMatch(principal.getAllGroups()::contains); 180 } 181 182}