001/* 002 * (C) Copyright 2013 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 * dmetzler 016 */ 017package org.nuxeo.ecm.restapi.jaxrs.io.usermanager; 018 019import java.io.IOException; 020import java.io.InputStream; 021import java.io.Serializable; 022import java.lang.annotation.Annotation; 023import java.lang.reflect.Type; 024import java.util.ArrayList; 025import java.util.List; 026 027import javax.ws.rs.Consumes; 028import javax.ws.rs.WebApplicationException; 029import javax.ws.rs.core.Context; 030import javax.ws.rs.core.MediaType; 031import javax.ws.rs.core.MultivaluedMap; 032import javax.ws.rs.core.Response; 033import javax.ws.rs.ext.MessageBodyReader; 034import javax.ws.rs.ext.Provider; 035 036import org.apache.commons.io.IOUtils; 037import org.apache.commons.logging.Log; 038import org.apache.commons.logging.LogFactory; 039import org.codehaus.jackson.JsonFactory; 040import org.codehaus.jackson.JsonParseException; 041import org.codehaus.jackson.JsonParser; 042import org.codehaus.jackson.JsonToken; 043import org.nuxeo.ecm.core.api.DocumentModel; 044import org.nuxeo.ecm.core.api.NuxeoException; 045import org.nuxeo.ecm.core.api.NuxeoPrincipal; 046import org.nuxeo.ecm.core.api.PropertyException; 047import org.nuxeo.ecm.platform.usermanager.NuxeoPrincipalImpl; 048import org.nuxeo.ecm.platform.usermanager.UserManager; 049import org.nuxeo.ecm.webengine.WebException; 050import org.nuxeo.runtime.api.Framework; 051 052/** 053 * Class that knows how to read NuxeoPrincipal from JSON 054 * 055 * @since 5.7.3 056 */ 057@Provider 058@Consumes({ "application/json+nxentity", "application/json" }) 059public class NuxeoPrincipalReader implements MessageBodyReader<NuxeoPrincipal> { 060 061 protected static final Log log = LogFactory.getLog(NuxeoPrincipalReader.class); 062 063 @Context 064 JsonFactory factory; 065 066 @Override 067 public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { 068 return NuxeoPrincipal.class.isAssignableFrom(type); 069 } 070 071 @Override 072 public NuxeoPrincipal readFrom(Class<NuxeoPrincipal> type, Type genericType, Annotation[] annotations, 073 MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) 074 throws IOException, WebApplicationException { 075 076 String content = IOUtils.toString(entityStream); 077 if (content.isEmpty()) { 078 throw new WebException("No content in request body", Response.Status.BAD_REQUEST.getStatusCode()); 079 } 080 081 return readRequest(content, httpHeaders); 082 083 } 084 085 /** 086 * @param content 087 * @param httpHeaders 088 * @return 089 * @since 5.7.3 090 */ 091 private NuxeoPrincipal readRequest(String content, MultivaluedMap<String, String> httpHeaders) { 092 try { 093 JsonParser jp = factory.createJsonParser(content); 094 return readJson(jp, httpHeaders); 095 } catch (NuxeoException | IOException e) { 096 throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR); 097 } 098 } 099 100 /** 101 * @param jp 102 * @param httpHeaders 103 * @param request2 104 * @return 105 * @throws IOException 106 * @throws JsonParseException 107 * @since 5.7.3 108 */ 109 static NuxeoPrincipal readJson(JsonParser jp, MultivaluedMap<String, String> httpHeaders) 110 throws JsonParseException, IOException { 111 JsonToken tok = jp.nextToken(); 112 113 // skip { 114 if (jp.getCurrentToken() == JsonToken.START_OBJECT) { 115 tok = jp.nextToken(); 116 } 117 String id = null; 118 119 UserManager um = Framework.getLocalService(UserManager.class); 120 DocumentModel userDoc = null; 121 String schema = um.getUserSchemaName(); 122 123 while (tok != JsonToken.END_OBJECT) { 124 String key = jp.getCurrentName(); 125 jp.nextToken(); 126 if ("id".equals(key)) { 127 id = jp.readValueAs(String.class); 128 129 NuxeoPrincipal principal = um.getPrincipal(id); 130 if (principal == null) { 131 userDoc = um.getBareUserModel(); 132 } else { 133 userDoc = principal.getModel(); 134 } 135 } else if ("extendedGroups".equals(key)) { 136 jp.readValueAsTree(); 137 } else if ("properties".equals(key)) { 138 readProperties(jp, userDoc, schema); 139 } else if ("entity-type".equals(key)) { 140 String entityType = jp.readValueAs(String.class); 141 if (!"user".equals(entityType)) { 142 throw new WebApplicationException(Response.Status.BAD_REQUEST); 143 } 144 } 145 tok = jp.nextToken(); 146 } 147 148 NuxeoPrincipal principal = new NuxeoPrincipalImpl(id); 149 principal.setModel(userDoc); 150 151 return principal; 152 153 } 154 155 protected static void readProperties(JsonParser jp, DocumentModel doc, String schemaName) throws PropertyException, 156 JsonParseException, IOException { 157 JsonToken tok = jp.nextToken(); 158 while (tok != JsonToken.END_OBJECT) { 159 160 String key = schemaName + ":" + jp.getCurrentName(); 161 tok = jp.nextToken(); 162 if (tok == JsonToken.START_ARRAY) { 163 doc.setPropertyValue(key, (Serializable) readArrayProperty(jp)); 164 } else if (tok == JsonToken.VALUE_NULL) { 165 doc.setPropertyValue(key, (String) null); 166 } else { 167 doc.setPropertyValue(key, jp.getText()); 168 } 169 tok = jp.nextToken(); 170 } 171 } 172 173 protected static List<Serializable> readArrayProperty(JsonParser jp) throws JsonParseException, IOException { 174 List<Serializable> list = new ArrayList<>(); 175 JsonToken tok = jp.nextToken(); 176 while (tok != JsonToken.END_ARRAY) { 177 if (tok == JsonToken.START_ARRAY) { 178 list.add((Serializable) readArrayProperty(jp)); 179 } else { 180 list.add(jp.getText()); 181 } 182 tok = jp.nextToken(); 183 } 184 return list; 185 } 186 187}