001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: https://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: https://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.ui.apps.user;
029
030import org.opencms.db.CmsUserSettings;
031import org.opencms.file.CmsObject;
032import org.opencms.file.CmsUser;
033import org.opencms.main.CmsException;
034import org.opencms.main.CmsLog;
035import org.opencms.main.OpenCms;
036import org.opencms.report.A_CmsReportThread;
037import org.opencms.report.I_CmsReport;
038import org.opencms.security.CmsPasswordEncryptionException;
039import org.opencms.security.CmsRole;
040import org.opencms.ui.A_CmsUI;
041import org.opencms.ui.apps.CmsFileExplorerConfiguration;
042import org.opencms.ui.apps.CmsPageEditorConfiguration;
043import org.opencms.ui.apps.Messages;
044import org.opencms.util.CmsStringUtil;
045import org.opencms.util.CmsUUID;
046
047import java.util.ArrayList;
048import java.util.Iterator;
049import java.util.List;
050
051import org.apache.commons.logging.Log;
052
053/**
054 * Class for the import user thread.<p>
055 */
056public class CmsImportUserThread extends A_CmsReportThread {
057
058    /** Log instance for this class. */
059    private static final Log LOG = CmsLog.getLog(CmsImportUserThread.class);
060
061    /**List of user. */
062    private List<CmsUser> m_userList;
063
064    /**List of roles. */
065    private List<CmsRole> m_roleList;
066
067    /**List of groups. */
068    private List<String> m_groupList;
069
070    /**Current ou. */
071    private String m_ou;
072
073    /**indicates if mail to user should be send. */
074    private boolean m_sendMail;
075
076    /**
077     * public constructor.<p>
078     *
079     * @param cms CmsObject
080     * @param ou ou name
081     * @param userList List of user to import
082     * @param groups groups to add user to
083     * @param roles roles to add user to
084     * @param sendmail send mail to user?
085     */
086    protected CmsImportUserThread(
087        CmsObject cms,
088        String ou,
089        List<CmsUser> userList,
090        List<String> groups,
091        List<CmsRole> roles,
092        boolean sendmail) {
093
094        super(cms, "importUser");
095        m_userList = userList == null ? new ArrayList<CmsUser>() : userList;
096        m_roleList = roles == null ? new ArrayList<CmsRole>() : roles;
097        m_groupList = groups == null ? new ArrayList<String>() : groups;
098        m_ou = ou;
099        m_sendMail = sendmail;
100        initHtmlReport(A_CmsUI.get().getLocale());
101    }
102
103    /**
104     * @see org.opencms.report.A_CmsReportThread#getReportUpdate()
105     */
106    @Override
107    public String getReportUpdate() {
108
109        return getReport().getReportUpdate();
110    }
111
112    /**
113     * @see java.lang.Thread#run()
114     */
115    @Override
116    public void run() {
117
118        getReport().println(Messages.get().container(Messages.RPT_USERIMPORT_BEGIN_0), I_CmsReport.FORMAT_HEADLINE);
119        getReport().println();
120        getReport().println(
121            Messages.get().container(Messages.RPT_USERIMPORT_FILE_CONTAINS_1, String.valueOf(m_userList.size())),
122            I_CmsReport.FORMAT_DEFAULT);
123
124        Iterator<CmsUser> itUsers = m_userList.iterator();
125        while (itUsers.hasNext()) {
126            CmsUser user = itUsers.next();
127            try {
128                importUser(user);
129            } catch (RuntimeException e) {
130                String userName = user == null ? "<null>" : String.valueOf(user.getName());
131                LOG.error("Unexpected error while importing user '" + userName + "' into OU '" + m_ou + "'.", e);
132                getReport().println(
133                    Messages.get().container(Messages.RPT_USERIMPORT_IMPORT_FAILED_1, userName),
134                    I_CmsReport.FORMAT_ERROR);
135            }
136        }
137        getReport().println(Messages.get().container(Messages.RPT_USERIMPORT_END_0), I_CmsReport.FORMAT_DEFAULT);
138    }
139
140    /**
141     * Checks if the given user name is already available inside the current ou.<p>
142     *
143     * @param userName the user name to check
144     * @return <code>true</code> if the user name is already available, otherwise return <code>false</code>
145     */
146    protected boolean isAlreadyAvailable(String userName) {
147
148        List<CmsUser> availableUsers;
149        try {
150            availableUsers = OpenCms.getOrgUnitManager().getUsers(getCms(), m_ou, false);
151        } catch (CmsException e) {
152            LOG.error("Unable to read users from OU '" + m_ou + "' while checking user '" + userName + "'.", e);
153            availableUsers = new ArrayList<CmsUser>();
154        }
155        Iterator<CmsUser> itAvailableUsers = availableUsers.iterator();
156        while (itAvailableUsers.hasNext()) {
157            if (userName.equals(itAvailableUsers.next().getSimpleName())) {
158                return true;
159            }
160        }
161        return false;
162    }
163
164    /**
165     * Adds the imported user to the selected groups.<p>
166     *
167     * @param createdUser the imported user
168     */
169    private void addGroups(CmsUser createdUser) {
170
171        Iterator<String> itGroups = m_groupList.iterator();
172        while (itGroups.hasNext()) {
173            String groupName = itGroups.next();
174            try {
175                getCms().addUserToGroup(createdUser.getName(), groupName);
176            } catch (CmsException e) {
177                LOG.error(
178                    "Unable to add imported user '" + createdUser.getName() + "' to group '" + groupName + "'.",
179                    e);
180                getReport().println(
181                    Messages.get().container(Messages.RPT_USERIMPORT_GROUP_FAILED_2, createdUser.getName(), groupName),
182                    I_CmsReport.FORMAT_WARNING);
183            }
184        }
185    }
186
187    /**
188     * Adds the imported user to the selected roles.<p>
189     *
190     * @param createdUser the imported user
191     */
192    private void addRoles(CmsUser createdUser) {
193
194        Iterator<CmsRole> itRoles = m_roleList.iterator();
195        while (itRoles.hasNext()) {
196            CmsRole role = itRoles.next();
197            try {
198                OpenCms.getRoleManager().addUserToRole(getCms(), role.forOrgUnit(m_ou), createdUser.getName());
199            } catch (CmsException e) {
200                LOG.error("Unable to add imported user '" + createdUser.getName() + "' to role '" + role + "'.", e);
201                getReport().println(
202                    Messages.get().container(Messages.RPT_USERIMPORT_ROLE_FAILED_2, createdUser.getName(), role),
203                    I_CmsReport.FORMAT_WARNING);
204            }
205        }
206    }
207
208    /**
209     * Imports a single user.<p>
210     *
211     * @param user the user data parsed from the CSV file
212     */
213    private void importUser(CmsUser user) {
214
215        if (user == null) {
216            LOG.error("Unable to import null user into OU '" + m_ou + "'.");
217            getReport().println(
218                Messages.get().container(Messages.RPT_USERIMPORT_IMPORT_EMPTY_RECORD_0),
219                I_CmsReport.FORMAT_ERROR);
220            return;
221        }
222
223        String userName = user.getName();
224        if (CmsStringUtil.isEmptyOrWhitespaceOnly(userName)) {
225            LOG.error("Unable to import user without name into OU '" + m_ou + "'.");
226            getReport().println(
227                Messages.get().container(Messages.RPT_USERIMPORT_IMPORT_EMPTY_NAME_0),
228                I_CmsReport.FORMAT_ERROR);
229            return;
230        }
231
232        if (isAlreadyAvailable(userName)) {
233            getReport().println(
234                Messages.get().container(Messages.RPT_USERIMPORT_IMPORT_ALREADY_IN_OU_1, userName),
235                I_CmsReport.FORMAT_ERROR);
236            return;
237        }
238
239        String sourcePassword = user.getPassword();
240        if (CmsStringUtil.isEmptyOrWhitespaceOnly(sourcePassword)) {
241            LOG.error("Unable to import user '" + userName + "': no password was supplied by the CSV import.");
242            getReport().println(
243                Messages.get().container(Messages.RPT_USERIMPORT_PASSWORD_EMPTY_1, userName),
244                I_CmsReport.FORMAT_ERROR);
245            return;
246        }
247
248        String password = sourcePassword;
249        String mailPassword = sourcePassword;
250        if (password.indexOf('_') == -1) {
251            try {
252                password = OpenCms.getPasswordHandler().digest(password);
253            } catch (CmsPasswordEncryptionException e) {
254                LOG.error("Unable to encrypt password for user '" + userName + "'.", e);
255                getReport().println(
256                    Messages.get().container(Messages.RPT_USERIMPORT_PASSWORD_ENCRYPTION_FAILED_1, userName),
257                    I_CmsReport.FORMAT_ERROR);
258                return;
259            }
260        } else {
261            password = password.substring(password.indexOf('_') + 1);
262            if (CmsStringUtil.isEmptyOrWhitespaceOnly(password)) {
263                LOG.error("Unable to import user '" + userName + "': encrypted password value is empty.");
264                getReport().println(
265                    Messages.get().container(Messages.RPT_USERIMPORT_PASSWORD_EMPTY_1, userName),
266                    I_CmsReport.FORMAT_ERROR);
267                return;
268            }
269            mailPassword = "your old password";
270        }
271
272        CmsUser createdUser;
273        try {
274            createdUser = getCms().importUser(
275                new CmsUUID().toString(),
276                m_ou + userName,
277                password,
278                user.getFirstname(),
279                user.getLastname(),
280                user.getEmail(),
281                user.getFlags(),
282                System.currentTimeMillis(),
283                user.getAdditionalInfo());
284        } catch (CmsException e) {
285            LOG.error("Unable to create user '" + userName + "' in OU '" + m_ou + "'.", e);
286            getReport().println(
287                Messages.get().container(Messages.RPT_USERIMPORT_IMPORT_CREATE_FAILED_1, userName),
288                I_CmsReport.FORMAT_ERROR);
289            return;
290        }
291
292        addGroups(createdUser);
293        addRoles(createdUser);
294        saveUserSettings(createdUser);
295
296        if (m_sendMail) {
297            try {
298                CmsUserEditDialog.sendMail(getCms(), mailPassword, createdUser, m_ou, true, false, true);
299            } catch (RuntimeException e) {
300                LOG.error(
301                    "User '" + createdUser.getName() + "' was created, but the notification email could not be sent.",
302                    e);
303                getReport().println(
304                    Messages.get().container(Messages.RPT_USERIMPORT_MAIL_FAILED_1, createdUser.getName()),
305                    I_CmsReport.FORMAT_WARNING);
306            }
307        }
308
309        getReport().println(
310            Messages.get().container(Messages.RPT_USERIMPORT_IMPORT_SUCCESFULL_1, createdUser.getName()),
311            I_CmsReport.FORMAT_OK);
312    }
313
314    /**
315     * Saves the default workplace settings for the imported user.<p>
316     *
317     * @param createdUser the imported user
318     */
319    private void saveUserSettings(CmsUser createdUser) {
320
321        try {
322            String startAppId = CmsPageEditorConfiguration.APP_ID;
323            if (OpenCms.getRoleManager().hasRole(getCms(), createdUser.getName(), CmsRole.WORKPLACE_USER)) {
324                startAppId = CmsFileExplorerConfiguration.APP_ID;
325            }
326            CmsUserSettings settings = new CmsUserSettings(createdUser);
327            settings.setStartView(startAppId);
328            settings.setStartProject("Offline");
329            settings.save(getCms());
330        } catch (CmsException e) {
331            LOG.error("Unable to save settings for imported user '" + createdUser.getName() + "'.", e);
332            getReport().println(
333                Messages.get().container(Messages.RPT_USERIMPORT_SETTINGS_FAILED_1, createdUser.getName()),
334                I_CmsReport.FORMAT_WARNING);
335        }
336    }
337}