001/*
002 * (C) Copyright 2015-2019 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 *     Nicolas Chapurlat <nchapurlat@nuxeo.com>
018 */
019
020package org.nuxeo.ecm.platform.usermanager.io;
021
022import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
023import static org.nuxeo.ecm.core.io.registry.reflect.Instantiations.SINGLETON;
024import static org.nuxeo.ecm.core.io.registry.reflect.Priorities.REFERENCE;
025import static org.nuxeo.ecm.platform.usermanager.UserManagerImpl.USER_HAS_PARTIAL_CONTENT;
026
027import java.io.IOException;
028import java.io.OutputStream;
029import java.util.Collection;
030
031import javax.inject.Inject;
032
033import org.nuxeo.ecm.core.api.DocumentModel;
034import org.nuxeo.ecm.core.api.NuxeoGroup;
035import org.nuxeo.ecm.core.api.NuxeoPrincipal;
036import org.nuxeo.ecm.core.api.model.Property;
037import org.nuxeo.ecm.core.io.marshallers.json.ExtensibleEntityJsonWriter;
038import org.nuxeo.ecm.core.io.marshallers.json.OutputStreamWithJsonWriter;
039import org.nuxeo.ecm.core.io.marshallers.json.document.DocumentPropertyJsonWriter;
040import org.nuxeo.ecm.core.io.marshallers.json.enrichers.AbstractJsonEnricher;
041import org.nuxeo.ecm.core.io.registry.Writer;
042import org.nuxeo.ecm.core.io.registry.reflect.Setup;
043import org.nuxeo.ecm.directory.api.DirectoryService;
044import org.nuxeo.ecm.platform.usermanager.UserManager;
045
046import com.fasterxml.jackson.core.JsonGenerator;
047
048/**
049 * Convert {@link NuxeoPrincipal} to Json.
050 * <p>
051 * This marshaller is enrichable: register class implementing {@link AbstractJsonEnricher} and managing
052 * {@link NuxeoPrincipal}.
053 * </p>
054 * <p>
055 * This marshaller is also extensible: extend it and simply override
056 * {@link ExtensibleEntityJsonWriter#extend(Object, JsonGenerator)}.
057 * </p>
058 * <p>
059 * Format is:
060 *
061 * <pre>
062 * {@code
063 * {
064 *   "entity-type":"user",
065 *   "id":"USERNAME",
066 *   "properties":{   <- depending on the user schema / format is managed by {@link DocumentPropertyJsonWriter }
067 *     "firstName":"FIRSTNAME",
068 *     "lastName":"LASTNAME",
069 *     "username":"USERNAME",
070 *     "email":"user@mail.com",
071 *     "company":"COMPANY",
072 *     "password":"", <- ALWAYS EMPTY
073 *     "groups":[
074 *       "GROUP1 NAME OF THE USER",
075 *       "GROUP2 NAME OF THE USER",
076 *       ...
077 *     ]
078 *   },
079 *   "extendedGroups":[
080 *     {
081 *       "name":"GROUP1NAME",
082 *       "label":"GROUP1 DISPLAY NAME",
083 *       "url":"GROUP1 URL"
084 *     },
085 *     ...
086 *   ],
087 *   "isAdministrator":true|false,
088 *   "isAnonymous":false|false
089 *             <-- contextParameters if there are enrichers activated
090 *             <-- additional property provided by extend() method
091 * }
092 * }
093 * </pre>
094 *
095 * @since 7.2
096 */
097@Setup(mode = SINGLETON, priority = REFERENCE)
098public class NuxeoPrincipalJsonWriter extends ExtensibleEntityJsonWriter<NuxeoPrincipal> {
099
100    public static final String ENTITY_TYPE = "user";
101
102    @Inject
103    private UserManager userManager;
104
105    @Inject
106    private DirectoryService directoryService;
107
108    public NuxeoPrincipalJsonWriter() {
109        super(ENTITY_TYPE, NuxeoPrincipal.class);
110    }
111
112    @Override
113    protected void writeEntityBody(NuxeoPrincipal principal, JsonGenerator jg) throws IOException {
114        jg.writeStringField("id", principal.getName());
115        writeProperties(jg, principal);
116        writeExtendedGroups(jg, principal);
117        DocumentModel model = principal.getModel();
118        if (model != null && Boolean.TRUE.equals(model.getContextData(USER_HAS_PARTIAL_CONTENT))) {
119            jg.writeBooleanField("isPartial", true);
120        }
121        jg.writeBooleanField("isAdministrator", principal.isAdministrator());
122        jg.writeBooleanField("isAnonymous", principal.isAnonymous());
123    }
124
125    private void writeProperties(JsonGenerator jg, NuxeoPrincipal principal) throws IOException {
126        DocumentModel doc = principal.getModel();
127        if (doc == null) {
128            return;
129        }
130        String userSchema = userManager.getUserSchemaName();
131        Collection<Property> properties = doc.getPropertyObjects(userSchema);
132        if (properties.isEmpty()) {
133            return;
134        }
135        Writer<Property> propertyWriter = registry.getWriter(ctx, Property.class, APPLICATION_JSON_TYPE);
136        jg.writeObjectFieldStart("properties");
137        for (Property property : properties) {
138            String localName = property.getField().getName().getLocalName();
139            if (!localName.equals(getPasswordField())) {
140                jg.writeFieldName(localName);
141                OutputStream out = new OutputStreamWithJsonWriter(jg);
142                propertyWriter.write(property, Property.class, Property.class, APPLICATION_JSON_TYPE, out);
143            }
144        }
145        jg.writeEndObject();
146    }
147
148    private void writeExtendedGroups(JsonGenerator jg, NuxeoPrincipal principal) throws IOException {
149        jg.writeArrayFieldStart("extendedGroups");
150        for (String strGroup : principal.getAllGroups()) {
151            NuxeoGroup group = userManager.getGroup(strGroup);
152            String label = group == null ? strGroup : group.getLabel();
153            jg.writeStartObject();
154            jg.writeStringField("name", strGroup);
155            jg.writeStringField("label", label);
156            jg.writeStringField("url", "group/" + strGroup);
157            jg.writeEndObject();
158        }
159        jg.writeEndArray();
160    }
161
162    private String getPasswordField() {
163        String userDirectoryName = userManager.getUserDirectoryName();
164        return directoryService.getDirectory(userDirectoryName).getPasswordField();
165    }
166
167}