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