001/*
002 * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl-2.1.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Nicolas Chapurlat <nchapurlat@nuxeo.com>
016 */
017
018package org.nuxeo.ecm.platform.usermanager.io;
019
020import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
021import static org.nuxeo.ecm.core.io.registry.reflect.Instantiations.SINGLETON;
022import static org.nuxeo.ecm.core.io.registry.reflect.Priorities.REFERENCE;
023
024import java.io.IOException;
025import java.io.OutputStream;
026
027import javax.inject.Inject;
028
029import org.codehaus.jackson.JsonGenerator;
030import org.nuxeo.ecm.core.api.DocumentModel;
031import org.nuxeo.ecm.core.api.NuxeoGroup;
032import org.nuxeo.ecm.core.api.NuxeoPrincipal;
033import org.nuxeo.ecm.core.api.model.DocumentPart;
034import org.nuxeo.ecm.core.api.model.Property;
035import org.nuxeo.ecm.core.io.marshallers.json.ExtensibleEntityJsonWriter;
036import org.nuxeo.ecm.core.io.marshallers.json.OutputStreamWithJsonWriter;
037import org.nuxeo.ecm.core.io.marshallers.json.document.DocumentPropertyJsonWriter;
038import org.nuxeo.ecm.core.io.marshallers.json.enrichers.AbstractJsonEnricher;
039import org.nuxeo.ecm.core.io.registry.Writer;
040import org.nuxeo.ecm.core.io.registry.reflect.Setup;
041import org.nuxeo.ecm.directory.api.DirectoryService;
042import org.nuxeo.ecm.platform.usermanager.UserManager;
043
044import com.thoughtworks.xstream.io.json.JsonWriter;
045
046/**
047 * Convert {@link NuxeoPrincipal} to Json.
048 * <p>
049 * This marshaller is enrichable: register class implementing {@link AbstractJsonEnricher} and managing
050 * {@link NuxeoPrincipal}.
051 * </p>
052 * <p>
053 * This marshaller is also extensible: extend it and simply override
054 * {@link ExtensibleEntityJsonWriter#extend(NuxeoPrincipal, JsonWriter)}.
055 * </p>
056 * <p>
057 * Format is:
058 *
059 * <pre>
060 * {@code
061 * {
062 *   "entity-type":"user",
063 *   "id":"USERNAME",
064 *   "properties":{   <- depending on the user schema / format is managed by {@link DocumentPropertyJsonWriter}
065 *     "firstName":"FIRSTNAME",
066 *     "lastName":"LASTNAME",
067 *     "username":"USERNAME",
068 *     "email":"user@mail.com",
069 *     "company":"COMPANY",
070 *     "password":"", <- ALWAYS EMPTY
071 *     "groups":[
072 *       "GROUP1 NAME OF THE USER",
073 *       "GROUP2 NAME OF THE USER",
074 *       ...
075 *     ]
076 *   },
077 *   "extendedGroups":[
078 *     {
079 *       "name":"GROUP1NAME",
080 *       "label":"GROUP1 DISPLAY NAME",
081 *       "url":"GROUP1 URL"
082 *     },
083 *     ...
084 *   ],
085 *   "isAdministrator":true|false,
086 *   "isAnonymous":false|false
087 *             <-- contextParameters if there are enrichers activated
088 *             <-- additional property provided by extend() method
089 * }
090 * </pre>
091 *
092 * </p>
093 *
094 * @since 7.2
095 */
096@Setup(mode = SINGLETON, priority = REFERENCE)
097public class NuxeoPrincipalJsonWriter extends ExtensibleEntityJsonWriter<NuxeoPrincipal> {
098
099    public static final String ENTITY_TYPE = "user";
100
101    @Inject
102    private UserManager userManager;
103
104    @Inject
105    private DirectoryService directoryService;
106
107    public NuxeoPrincipalJsonWriter() {
108        super(ENTITY_TYPE, NuxeoPrincipal.class);
109    }
110
111    @Override
112    protected void writeEntityBody(NuxeoPrincipal principal, JsonGenerator jg) throws IOException {
113        jg.writeStringField("id", principal.getName());
114        writeProperties(jg, principal);
115        writeExtendedGroups(jg, principal);
116        jg.writeBooleanField("isAdministrator", principal.isAdministrator());
117        jg.writeBooleanField("isAnonymous", principal.isAnonymous());
118    }
119
120    private void writeProperties(JsonGenerator jg, NuxeoPrincipal principal) throws IOException {
121        DocumentModel doc = principal.getModel();
122        if (doc == null) {
123            return;
124        }
125        String userSchema = userManager.getUserSchemaName();
126        DocumentPart userPart = doc.getPart(userSchema);
127        if (userPart == null) {
128            return;
129        }
130        Writer<Property> propertyWriter = registry.getWriter(ctx, Property.class, APPLICATION_JSON_TYPE);
131        jg.writeObjectFieldStart("properties");
132        for (Property property : userPart.getChildren()) {
133            String localName = property.getField().getName().getLocalName();
134            jg.writeFieldName(localName);
135            if (localName.equals(getPasswordField())) {
136                jg.writeString("");
137            } else {
138                OutputStream out = new OutputStreamWithJsonWriter(jg);
139                propertyWriter.write(property, Property.class, Property.class, APPLICATION_JSON_TYPE, out);
140            }
141        }
142        jg.writeEndObject();
143    }
144
145    private void writeExtendedGroups(JsonGenerator jg, NuxeoPrincipal principal) throws IOException {
146        jg.writeArrayFieldStart("extendedGroups");
147        for (String strGroup : principal.getAllGroups()) {
148            NuxeoGroup group = userManager.getGroup(strGroup);
149            String label = group == null ? strGroup : group.getLabel();
150            jg.writeStartObject();
151            jg.writeStringField("name", strGroup);
152            jg.writeStringField("label", label);
153            jg.writeStringField("url", "group/" + strGroup);
154            jg.writeEndObject();
155        }
156        jg.writeEndArray();
157    }
158
159    private String getPasswordField() {
160        String userDirectoryName = userManager.getUserDirectoryName();
161        return directoryService.getDirectory(userDirectoryName).getPasswordField();
162    }
163
164}