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