001/*
002 * (C) Copyright 2011 Nuxeo SA (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 * Contributors:
016 * Nuxeo - initial API and implementation
017 */
018
019package org.nuxeo.ecm.user.invite;
020
021import java.util.Collections;
022import java.util.List;
023import java.util.Objects;
024import java.util.stream.Collectors;
025
026import org.apache.commons.logging.Log;
027import org.apache.commons.logging.LogFactory;
028import org.nuxeo.ecm.core.api.CoreSession;
029import org.nuxeo.ecm.core.api.DocumentModel;
030import org.nuxeo.ecm.core.api.NuxeoPrincipal;
031import org.nuxeo.ecm.platform.usermanager.UserConfig;
032import org.nuxeo.ecm.platform.usermanager.UserManager;
033import org.nuxeo.runtime.api.Framework;
034
035public class DefaultInvitationUserFactory implements InvitationUserFactory {
036
037    private static final Log log = LogFactory.getLog(DefaultInvitationUserFactory.class);
038
039    public static final String PASSWORD_KEY = "invitationPassword";
040
041    @Override
042    public void doPostUserCreation(CoreSession session, DocumentModel registrationDoc, NuxeoPrincipal user)
043            throws UserRegistrationException {
044        // Nothing to do in the default implementation
045    }
046
047    @Override
048    public NuxeoPrincipal doCreateUser(CoreSession session, DocumentModel registrationDoc,
049            UserRegistrationConfiguration configuration) throws UserRegistrationException {
050        UserManager userManager = Framework.getService(UserManager.class);
051
052        String email = (String) registrationDoc.getPropertyValue(configuration.getUserInfoEmailField());
053        if (email == null) {
054            throw new UserRegistrationException("Email address must be specififed");
055        }
056
057        String login = (String) registrationDoc.getPropertyValue(configuration.getUserInfoUsernameField());
058        NuxeoPrincipal user = userManager.getPrincipal(login);
059        if (user == null) {
060
061            if (!isSameTenant(registrationDoc, configuration)) {
062                throw new UserRegistrationException("Can only invite in same tenant");
063            }
064
065            List<String> groups = filterGroups(registrationDoc, configuration);
066
067            DocumentModel newUserDoc = userManager.getBareUserModel();
068            newUserDoc.setPropertyValue(UserConfig.USERNAME_COLUMN, login);
069            newUserDoc.setPropertyValue(UserConfig.PASSWORD_COLUMN,
070                    registrationDoc.getContextData(PASSWORD_KEY));
071            newUserDoc.setPropertyValue(UserConfig.FIRSTNAME_COLUMN,
072                    registrationDoc.getPropertyValue(configuration.getUserInfoFirstnameField()));
073            newUserDoc.setPropertyValue(UserConfig.LASTNAME_COLUMN,
074                    registrationDoc.getPropertyValue(configuration.getUserInfoLastnameField()));
075            newUserDoc.setPropertyValue(UserConfig.EMAIL_COLUMN,
076                    registrationDoc.getPropertyValue(configuration.getUserInfoEmailField()));
077            newUserDoc.setPropertyValue(UserConfig.COMPANY_COLUMN,
078                    registrationDoc.getPropertyValue(configuration.getUserInfoCompanyField()));
079            newUserDoc.setPropertyValue(UserConfig.GROUPS_COLUMN, groups.toArray());
080            newUserDoc.setPropertyValue(UserConfig.TENANT_ID_COLUMN,
081                    registrationDoc.getPropertyValue(configuration.getUserInfoTenantIdField()));
082            userManager.createUser(newUserDoc);
083            user = userManager.getPrincipal(login);
084
085            log.info("New user created:" + user.getName());
086        } else {
087            if (!email.equals(user.getEmail())) {
088                throw new UserRegistrationException("This login is not available");
089            }
090        }
091        return user;
092    }
093
094    /**
095     * Check that the user that initiated the registration is in the same tenant than the user it creates.
096     *
097     * @since 10.2
098     */
099    private boolean isSameTenant(DocumentModel registrationDoc, UserRegistrationConfiguration configuration) {
100        NuxeoPrincipal originatingPrincipal = getOriginatingPrincipal(registrationDoc);
101
102        if (originatingPrincipal == null) {
103            // Should never occur, but just in case.
104            return registrationDoc.getPropertyValue(configuration.getUserInfoTenantIdField()) == null;
105        }
106
107        if (originatingPrincipal.isAdministrator()) {
108            return true;
109        }
110        return Objects.equals(registrationDoc.getPropertyValue(configuration.getUserInfoTenantIdField()),
111                originatingPrincipal.getTenantId());
112    }
113
114    /**
115     * Filter group by computing the intersection of the group in the registration doc and the groups of the user that
116     * created the request. Administrators accept all groups.
117     *
118     * @since 10.2
119     */
120    @SuppressWarnings("unchecked")
121    protected List<String> filterGroups(DocumentModel registrationDoc, UserRegistrationConfiguration configuration) {
122        List<String> wantedGroup = (List<String>) registrationDoc.getPropertyValue(
123                configuration.getUserInfoGroupsField());
124
125        NuxeoPrincipal originatingPrincipal = getOriginatingPrincipal(registrationDoc);
126
127        if (originatingPrincipal == null) {
128            // Should never occur, but just in case.
129            return Collections.emptyList();
130        }
131
132        return wantedGroup.stream().filter(g -> acceptGroup(originatingPrincipal, g)).collect(Collectors.toList());
133
134    }
135
136    /**
137     * Returns the principal that created that registration document
138     *
139     * @since 10.2
140     */
141    private NuxeoPrincipal getOriginatingPrincipal(DocumentModel registrationDoc) {
142        String originatingUser = (String) registrationDoc.getPropertyValue(
143                UserInvitationComponent.PARAM_ORIGINATING_USER);
144        UserManager userManager = Framework.getService(UserManager.class);
145        return userManager.getPrincipal(originatingUser);
146    }
147
148    /**
149     * @since 10.2
150     */
151    protected boolean acceptGroup(NuxeoPrincipal originatingPrincipal, String groupName) {
152        return originatingPrincipal.isAdministrator() || originatingPrincipal.getAllGroups().contains(groupName);
153    }
154}