001/* 002 * (C) Copyright 2006-2015 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 * Florent Guillaume 018 */ 019package org.nuxeo.ecm.core.opencmis.impl.server; 020 021import static org.apache.chemistry.opencmis.commons.BasicPermissions.ALL; 022import static org.apache.chemistry.opencmis.commons.BasicPermissions.READ; 023import static org.apache.chemistry.opencmis.commons.BasicPermissions.WRITE; 024import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_ADD_POLICY_OBJECT; 025import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_ADD_POLICY_POLICY; 026import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_ADD_TO_FOLDER_FOLDER; 027import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_ADD_TO_FOLDER_OBJECT; 028import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_APPLY_ACL_OBJECT; 029import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_CANCEL_CHECKOUT_DOCUMENT; 030import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_CHECKIN_DOCUMENT; 031import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_CHECKOUT_DOCUMENT; 032import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_CREATE_DOCUMENT_FOLDER; 033import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_CREATE_FOLDER_FOLDER; 034import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_CREATE_RELATIONSHIP_SOURCE; 035import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_CREATE_RELATIONSHIP_TARGET; 036import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_DELETE_CONTENT_DOCUMENT; 037import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_DELETE_OBJECT; 038import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_DELETE_TREE_FOLDER; 039import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_GET_ACL_OBJECT; 040import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_GET_ALL_VERSIONS_VERSION_SERIES; 041import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_GET_APPLIED_POLICIES_OBJECT; 042import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_GET_CHILDREN_FOLDER; 043import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_GET_DESCENDENTS_FOLDER; 044import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_GET_FOLDER_PARENT_OBJECT; 045import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_GET_OBJECT_RELATIONSHIPS_OBJECT; 046import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_GET_PARENTS_FOLDER; 047import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_GET_PROPERTIES_OBJECT; 048import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_MOVE_OBJECT; 049import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_MOVE_SOURCE; 050import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_MOVE_TARGET; 051import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_REMOVE_FROM_FOLDER_FOLDER; 052import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_REMOVE_FROM_FOLDER_OBJECT; 053import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_REMOVE_POLICY_OBJECT; 054import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_REMOVE_POLICY_POLICY; 055import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_SET_CONTENT_DOCUMENT; 056import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_UPDATE_PROPERTIES_OBJECT; 057import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_VIEW_CONTENT_OBJECT; 058 059import java.lang.reflect.Field; 060import java.math.BigInteger; 061import java.util.ArrayList; 062import java.util.Arrays; 063import java.util.Collections; 064import java.util.HashMap; 065import java.util.HashSet; 066import java.util.LinkedList; 067import java.util.List; 068import java.util.Map; 069import java.util.Map.Entry; 070import java.util.Set; 071 072import javax.servlet.http.HttpServletRequest; 073 074import org.apache.chemistry.opencmis.commons.data.ExtensionFeature; 075import org.apache.chemistry.opencmis.commons.data.PermissionMapping; 076import org.apache.chemistry.opencmis.commons.data.RepositoryInfo; 077import org.apache.chemistry.opencmis.commons.definitions.PermissionDefinition; 078import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionContainer; 079import org.apache.chemistry.opencmis.commons.enums.AclPropagation; 080import org.apache.chemistry.opencmis.commons.enums.BaseTypeId; 081import org.apache.chemistry.opencmis.commons.enums.CapabilityAcl; 082import org.apache.chemistry.opencmis.commons.enums.CapabilityChanges; 083import org.apache.chemistry.opencmis.commons.enums.CapabilityContentStreamUpdates; 084import org.apache.chemistry.opencmis.commons.enums.CapabilityJoin; 085import org.apache.chemistry.opencmis.commons.enums.CapabilityQuery; 086import org.apache.chemistry.opencmis.commons.enums.CapabilityRenditions; 087import org.apache.chemistry.opencmis.commons.enums.CmisVersion; 088import org.apache.chemistry.opencmis.commons.enums.SupportedPermissions; 089import org.apache.chemistry.opencmis.commons.impl.dataobjects.AclCapabilitiesDataImpl; 090import org.apache.chemistry.opencmis.commons.impl.dataobjects.CreatablePropertyTypesImpl; 091import org.apache.chemistry.opencmis.commons.impl.dataobjects.NewTypeSettableAttributesImpl; 092import org.apache.chemistry.opencmis.commons.impl.dataobjects.PermissionDefinitionDataImpl; 093import org.apache.chemistry.opencmis.commons.impl.dataobjects.PermissionMappingDataImpl; 094import org.apache.chemistry.opencmis.commons.impl.dataobjects.RepositoryCapabilitiesImpl; 095import org.apache.chemistry.opencmis.commons.impl.dataobjects.RepositoryInfoImpl; 096import org.apache.chemistry.opencmis.commons.server.CallContext; 097 098import org.nuxeo.common.Environment; 099import org.nuxeo.ecm.core.api.security.PermissionProvider; 100import org.nuxeo.ecm.core.api.security.SecurityConstants; 101import org.nuxeo.ecm.core.opencmis.impl.util.TypeManagerImpl; 102import org.nuxeo.ecm.core.schema.DocumentType; 103import org.nuxeo.ecm.core.schema.SchemaManager; 104import org.nuxeo.ecm.core.schema.types.CompositeType; 105import org.nuxeo.ecm.core.security.DefaultPermissionProvider; 106import org.nuxeo.ecm.core.security.PermissionVisibilityDescriptor; 107import org.nuxeo.runtime.api.Framework; 108 109/** 110 * Information about a Nuxeo repository. 111 */ 112public class NuxeoRepository { 113 114 /** 115 * @deprecated Since 7.10. Use {@link Environment#DISTRIBUTION_VERSION} 116 */ 117 @Deprecated 118 public static final String NUXEO_VERSION_PROP = Environment.DISTRIBUTION_VERSION; 119 120 public static final String NUXEO_URL_PROP = "nuxeo.url"; 121 122 public static final String SUPPORTS_JOINS_PROP = "org.nuxeo.cmis.joins"; 123 124 public static final String ELASTICSEARCH_PROP = "org.nuxeo.cmis.elasticsearch"; 125 126 private static final String NUXEO_CONTEXT_PATH_PROP = "org.nuxeo.ecm.contextPath"; 127 128 private static final String NUXEO_CONTEXT_PATH_DEFAULT = "/nuxeo"; 129 130 private static final String X_FORWARDED_HOST = "x-forwarded-host"; 131 132 private static final String NUXEO_VH_HEADER = "nuxeo-virtual-host"; 133 134 private static final String VH_PARAM = "nuxeo.virtual.host"; 135 136 public static final String NUXEO_READ_REMOVE = "ReadRemove"; 137 138 protected final String repositoryId; 139 140 protected final String rootFolderId; 141 142 protected boolean supportsJoins; 143 144 protected boolean useElasticsearch; 145 146 protected Map<CmisVersion, TypeManagerImpl> typeManagerByCmisVersion = new HashMap<>(); 147 148 public NuxeoRepository(String repositoryId, String rootFolderId) { 149 this.repositoryId = repositoryId; 150 this.rootFolderId = rootFolderId; 151 if (Framework.isBooleanPropertyTrue(SUPPORTS_JOINS_PROP)) { 152 setSupportsJoins(true); 153 } 154 if (Framework.isBooleanPropertyTrue(ELASTICSEARCH_PROP)) { 155 setUseElasticsearch(true); 156 } 157 } 158 159 public void setSupportsJoins(boolean supportsJoins) { 160 this.supportsJoins = supportsJoins; 161 } 162 163 public boolean supportsJoins() { 164 return supportsJoins; 165 } 166 167 public void setUseElasticsearch(boolean useElasticsearch) { 168 this.useElasticsearch = useElasticsearch; 169 } 170 171 public boolean useElasticsearch() { 172 return useElasticsearch; 173 } 174 175 public String getId() { 176 return repositoryId; 177 } 178 179 // no need to have it synchronized 180 public TypeManagerImpl getTypeManager(CmisVersion cmisVersion) { 181 TypeManagerImpl typeManager = typeManagerByCmisVersion.get(cmisVersion); 182 if (typeManager == null) { 183 typeManager = initializeTypes(cmisVersion); 184 typeManagerByCmisVersion.put(cmisVersion, typeManager); 185 } 186 return typeManager; 187 } 188 189 protected TypeManagerImpl initializeTypes(CmisVersion cmisVersion) { 190 SchemaManager schemaManager = Framework.getService(SchemaManager.class); 191 // scan the types to find super/inherited relationships 192 Map<String, List<String>> typesChildren = new HashMap<>(); 193 for (DocumentType dt : schemaManager.getDocumentTypes()) { 194 org.nuxeo.ecm.core.schema.types.Type st = dt.getSuperType(); 195 if (st == null) { 196 continue; 197 } 198 String name = st.getName(); 199 List<String> siblings = typesChildren.get(name); 200 if (siblings == null) { 201 siblings = new LinkedList<>(); 202 typesChildren.put(name, siblings); 203 } 204 siblings.add(dt.getName()); 205 } 206 // convert the transitive closure for Folder and Document subtypes 207 Set<String> done = new HashSet<>(); 208 TypeManagerImpl typeManager = new TypeManagerImpl(); 209 typeManager.addTypeDefinition(NuxeoTypeHelper.constructCmisBase(BaseTypeId.CMIS_DOCUMENT, schemaManager, cmisVersion)); 210 typeManager.addTypeDefinition(NuxeoTypeHelper.constructCmisBase(BaseTypeId.CMIS_FOLDER, schemaManager, cmisVersion)); 211 typeManager.addTypeDefinition(NuxeoTypeHelper.constructCmisBase(BaseTypeId.CMIS_RELATIONSHIP, schemaManager, cmisVersion)); 212 if (cmisVersion != CmisVersion.CMIS_1_0) { 213 typeManager.addTypeDefinition(NuxeoTypeHelper.constructCmisBase(BaseTypeId.CMIS_SECONDARY, schemaManager, cmisVersion)); 214 } 215 addTypesRecursively(typeManager, NuxeoTypeHelper.NUXEO_DOCUMENT, typesChildren, done, schemaManager, cmisVersion); 216 addTypesRecursively(typeManager, NuxeoTypeHelper.NUXEO_FOLDER, typesChildren, done, schemaManager, cmisVersion); 217 addTypesRecursively(typeManager, NuxeoTypeHelper.NUXEO_RELATION, typesChildren, done, schemaManager, cmisVersion); 218 if (cmisVersion != CmisVersion.CMIS_1_0) { 219 addSecondaryTypes(typeManager, schemaManager, cmisVersion); 220 } 221 return typeManager; 222 } 223 224 protected void addTypesRecursively(TypeManagerImpl typeManager, String name, 225 Map<String, List<String>> typesChildren, Set<String> done, SchemaManager schemaManager, 226 CmisVersion cmisVersion) { 227 if (done.contains(name)) { 228 return; 229 } 230 done.add(name); 231 DocumentType dt = schemaManager.getDocumentType(name); 232 String parentTypeId = NuxeoTypeHelper.getParentTypeId(dt); 233 if (parentTypeId != null) { 234 TypeDefinitionContainer parentType = typeManager.getTypeById(parentTypeId); 235 if (parentType == null) { 236 // if parent was ignored, reparent under cmis:document 237 parentTypeId = BaseTypeId.CMIS_DOCUMENT.value(); 238 } else { 239 if (parentType.getTypeDefinition().getBaseTypeId() != BaseTypeId.CMIS_FOLDER && dt.isFolder()) { 240 // reparent Folderish but child of Document under 241 // cmis:folder 242 parentTypeId = BaseTypeId.CMIS_FOLDER.value(); 243 } 244 } 245 typeManager.addTypeDefinition(NuxeoTypeHelper.constructDocumentType(dt, parentTypeId, cmisVersion)); 246 } 247 // recurse in children 248 List<String> children = typesChildren.get(name); 249 if (children == null) { 250 return; 251 } 252 for (String sub : children) { 253 addTypesRecursively(typeManager, sub, typesChildren, done, schemaManager, cmisVersion); 254 } 255 } 256 257 protected void addSecondaryTypes(TypeManagerImpl typeManager, SchemaManager schemaManager, 258 CmisVersion cmisVersion) { 259 for (CompositeType type : schemaManager.getFacets()) { 260 typeManager.addTypeDefinition(NuxeoTypeHelper.constructSecondaryType(type, cmisVersion), false); 261 } 262 } 263 264 public String getRootFolderId() { 265 return rootFolderId; 266 } 267 268 public RepositoryInfo getRepositoryInfo(String latestChangeLogToken, CallContext callContext) { 269 CmisVersion cmisVersion = callContext.getCmisVersion(); 270 271 RepositoryInfoImpl repositoryInfo = new RepositoryInfoImpl(); 272 repositoryInfo.setId(repositoryId); 273 repositoryInfo.setName("Nuxeo Repository " + repositoryId); 274 repositoryInfo.setDescription("Nuxeo Repository " + repositoryId); 275 repositoryInfo.setCmisVersionSupported(cmisVersion.value()); 276 repositoryInfo.setPrincipalAnonymous("Guest"); // TODO 277 repositoryInfo.setPrincipalAnyone(SecurityConstants.EVERYONE); 278 repositoryInfo.setThinClientUri(getBaseURL(callContext)); 279 repositoryInfo.setChangesIncomplete(Boolean.FALSE); 280 repositoryInfo.setChangesOnType(Arrays.asList(BaseTypeId.CMIS_DOCUMENT, BaseTypeId.CMIS_FOLDER)); 281 repositoryInfo.setLatestChangeLogToken(latestChangeLogToken); 282 repositoryInfo.setVendorName("Nuxeo"); 283 repositoryInfo.setProductName("Nuxeo OpenCMIS Connector"); 284 String version = Framework.getProperty(Environment.DISTRIBUTION_VERSION, "5.5 dev"); 285 repositoryInfo.setProductVersion(version); 286 repositoryInfo.setRootFolder(rootFolderId); 287 repositoryInfo.setExtensionFeature(Collections.<ExtensionFeature> emptyList()); 288 289 // capabilities 290 291 RepositoryCapabilitiesImpl caps = new RepositoryCapabilitiesImpl(); 292 caps.setAllVersionsSearchable(Boolean.TRUE); 293 caps.setCapabilityAcl(CapabilityAcl.MANAGE); 294 caps.setCapabilityChanges(CapabilityChanges.OBJECTIDSONLY); 295 caps.setCapabilityContentStreamUpdates(CapabilityContentStreamUpdates.PWCONLY); 296 caps.setCapabilityJoin(supportsJoins ? CapabilityJoin.INNERANDOUTER : CapabilityJoin.NONE); 297 caps.setCapabilityQuery(CapabilityQuery.BOTHCOMBINED); 298 caps.setCapabilityRendition(CapabilityRenditions.READ); 299 caps.setIsPwcSearchable(Boolean.TRUE); 300 caps.setIsPwcUpdatable(Boolean.TRUE); 301 caps.setSupportsGetDescendants(Boolean.TRUE); 302 caps.setSupportsGetFolderTree(Boolean.TRUE); 303 caps.setSupportsMultifiling(Boolean.FALSE); 304 caps.setSupportsUnfiling(Boolean.FALSE); 305 caps.setSupportsVersionSpecificFiling(Boolean.FALSE); 306 caps.setNewTypeSettableAttributes(new NewTypeSettableAttributesImpl()); 307 caps.setCreatablePropertyTypes(new CreatablePropertyTypesImpl()); 308 repositoryInfo.setCapabilities(caps); 309 310 // ACL capabilities 311 312 AclCapabilitiesDataImpl aclCaps = new AclCapabilitiesDataImpl(); 313 aclCaps.setAclPropagation(AclPropagation.PROPAGATE); 314 aclCaps.setSupportedPermissions(SupportedPermissions.REPOSITORY); 315 316 List<PermissionDefinition> permDefs = new ArrayList<>(); 317 addPermissionDefinitions(permDefs); 318 aclCaps.setPermissionDefinitionData(permDefs); 319 320 Map<String, PermissionMapping> permMap = new HashMap<>(); 321 addPermissionMapping(permMap, CAN_GET_DESCENDENTS_FOLDER, READ); 322 addPermissionMapping(permMap, CAN_GET_CHILDREN_FOLDER, READ); 323 addPermissionMapping(permMap, CAN_GET_PARENTS_FOLDER, READ); 324 addPermissionMapping(permMap, CAN_GET_FOLDER_PARENT_OBJECT, READ); 325 addPermissionMapping(permMap, CAN_CREATE_DOCUMENT_FOLDER, WRITE); 326 addPermissionMapping(permMap, CAN_CREATE_FOLDER_FOLDER, WRITE); 327 // no CAN_CREATE_POLICY_FOLDER due to spec bug 328 addPermissionMapping(permMap, CAN_CREATE_RELATIONSHIP_SOURCE, READ); 329 addPermissionMapping(permMap, CAN_CREATE_RELATIONSHIP_TARGET, READ); 330 addPermissionMapping(permMap, CAN_GET_PROPERTIES_OBJECT, READ); 331 addPermissionMapping(permMap, CAN_VIEW_CONTENT_OBJECT, READ); 332 addPermissionMapping(permMap, CAN_UPDATE_PROPERTIES_OBJECT, WRITE); 333 addPermissionMapping(permMap, CAN_MOVE_OBJECT, WRITE); 334 addPermissionMapping(permMap, CAN_MOVE_TARGET, WRITE); 335 addPermissionMapping(permMap, CAN_MOVE_SOURCE, WRITE); 336 addPermissionMapping(permMap, CAN_DELETE_OBJECT, WRITE); 337 addPermissionMapping(permMap, CAN_DELETE_TREE_FOLDER, WRITE); 338 addPermissionMapping(permMap, CAN_SET_CONTENT_DOCUMENT, WRITE); 339 addPermissionMapping(permMap, CAN_DELETE_CONTENT_DOCUMENT, WRITE); 340 addPermissionMapping(permMap, CAN_ADD_TO_FOLDER_OBJECT, WRITE); 341 addPermissionMapping(permMap, CAN_ADD_TO_FOLDER_FOLDER, WRITE); 342 addPermissionMapping(permMap, CAN_REMOVE_FROM_FOLDER_OBJECT, WRITE); 343 addPermissionMapping(permMap, CAN_REMOVE_FROM_FOLDER_FOLDER, WRITE); 344 addPermissionMapping(permMap, CAN_CHECKOUT_DOCUMENT, WRITE); 345 addPermissionMapping(permMap, CAN_CANCEL_CHECKOUT_DOCUMENT, WRITE); 346 addPermissionMapping(permMap, CAN_CHECKIN_DOCUMENT, WRITE); 347 addPermissionMapping(permMap, CAN_GET_ALL_VERSIONS_VERSION_SERIES, READ); 348 addPermissionMapping(permMap, CAN_GET_OBJECT_RELATIONSHIPS_OBJECT, READ); 349 addPermissionMapping(permMap, CAN_ADD_POLICY_OBJECT, WRITE); 350 addPermissionMapping(permMap, CAN_ADD_POLICY_POLICY, WRITE); 351 addPermissionMapping(permMap, CAN_REMOVE_POLICY_OBJECT, WRITE); 352 addPermissionMapping(permMap, CAN_REMOVE_POLICY_POLICY, WRITE); 353 addPermissionMapping(permMap, CAN_GET_APPLIED_POLICIES_OBJECT, READ); 354 addPermissionMapping(permMap, CAN_GET_ACL_OBJECT, READ); 355 addPermissionMapping(permMap, CAN_APPLY_ACL_OBJECT, ALL); 356 aclCaps.setPermissionMappingData(permMap); 357 358 repositoryInfo.setAclCapabilities(aclCaps); 359 360 return repositoryInfo; 361 } 362 363 @SuppressWarnings("unchecked") 364 protected static void addPermissionDefinitions(List<PermissionDefinition> permDefs) { 365 addPermissionDefinition(permDefs, READ, "Read"); // = Nuxeo Read 366 addPermissionDefinition(permDefs, WRITE, "Write"); // = Nuxeo ReadWrite 367 addPermissionDefinition(permDefs, ALL, "All"); // = Nuxeo Everything 368 addPermissionDefinition(permDefs, NUXEO_READ_REMOVE, "Remove"); 369 370 Set<String> done = new HashSet<>(); 371 done.add(SecurityConstants.READ); 372 done.add(SecurityConstants.READ_WRITE); 373 done.add(SecurityConstants.EVERYTHING); 374 done.add(NUXEO_READ_REMOVE); 375 376 /* 377 * Add Nuxeo-specific permissions registered through the permissionsVisibility extension point. 378 */ 379 380 DefaultPermissionProvider permissionProvider = (DefaultPermissionProvider) Framework.getService(PermissionProvider.class); 381 permissionProvider.getUserVisiblePermissionDescriptors(); // init var 382 Map<String, PermissionVisibilityDescriptor> map; 383 try { 384 Field f; 385 f = DefaultPermissionProvider.class.getDeclaredField("mergedPermissionsVisibility"); 386 f.setAccessible(true); 387 map = (Map<String, PermissionVisibilityDescriptor>) f.get(permissionProvider); 388 } catch (NoSuchFieldException | SecurityException | IllegalAccessException e) { 389 throw new RuntimeException(e); 390 } 391 // iterate for all types regisited, not just the default "" 392 for (Entry<String, PermissionVisibilityDescriptor> en : map.entrySet()) { 393 for (String permission : en.getValue().getSortedItems()) { 394 if (!done.add(permission)) { 395 continue; 396 } 397 addPermissionDefinition(permDefs, permission, permission); 398 } 399 } 400 } 401 402 protected static void addPermissionDefinition(List<PermissionDefinition> permDefs, String permission, 403 String description) { 404 PermissionDefinitionDataImpl pd = new PermissionDefinitionDataImpl(); 405 pd.setId(permission); 406 pd.setDescription(description); 407 permDefs.add(pd); 408 } 409 410 protected static void addPermissionMapping(Map<String, PermissionMapping> permMap, String key, String permission) { 411 PermissionMappingDataImpl pm = new PermissionMappingDataImpl(); 412 pm.setKey(key); 413 pm.setPermissions(Collections.singletonList(permission)); 414 permMap.put(key, pm); 415 } 416 417 /** Returns the server base URL (including context). */ 418 private static String getBaseURL(CallContext callContext) { 419 HttpServletRequest request = (HttpServletRequest) callContext.get(CallContext.HTTP_SERVLET_REQUEST); 420 if (request != null) { 421 String baseURL = getServerURL(request); 422 String contextPath = request.getContextPath(); 423 if (contextPath == null) { 424 contextPath = Framework.getProperty(NUXEO_CONTEXT_PATH_PROP, NUXEO_CONTEXT_PATH_DEFAULT); 425 } 426 // add context path 427 return baseURL + contextPath + '/'; 428 } else { 429 return Framework.getProperty(NUXEO_URL_PROP); 430 } 431 } 432 433 /** 434 * Returns the server URL according to virtual hosting headers (without trailing slash). 435 */ 436 private static String getServerURL(HttpServletRequest request) { 437 String url = null; 438 // Detect Nuxeo specific header for VH 439 String nuxeoVH = request.getHeader(NUXEO_VH_HEADER); 440 if (nuxeoVH == null) { 441 nuxeoVH = Framework.getProperty(VH_PARAM); 442 } 443 if (nuxeoVH != null && nuxeoVH.startsWith("http")) { 444 url = nuxeoVH; 445 } else { 446 // default values 447 String scheme = request.getScheme(); 448 String serverName = request.getServerName(); 449 int serverPort = request.getServerPort(); 450 // Detect virtual hosting based in standard header 451 String forwardedHost = request.getHeader(X_FORWARDED_HOST); 452 if (forwardedHost != null) { 453 if (forwardedHost.contains(":")) { 454 String[] split = forwardedHost.split(":"); 455 serverName = split[0]; 456 serverPort = Integer.parseInt(split[1]); 457 } else { 458 serverName = forwardedHost; 459 serverPort = 80; // fallback 460 } 461 } 462 url = buildURL(scheme, serverName, serverPort); 463 } 464 // strip trailing slash 465 if (url.endsWith("/")) { 466 url = url.substring(0, url.length() - 1); 467 } 468 return url; 469 } 470 471 /** Builds an URL (without trailing slash). */ 472 private static String buildURL(String scheme, String serverName, int serverPort) { 473 StringBuilder sb = new StringBuilder(); 474 sb.append(scheme); 475 sb.append("://"); 476 sb.append(serverName); 477 if (serverPort != 0) { 478 if ("http".equals(scheme) && serverPort != 80 || "https".equals(scheme) && serverPort != 443) { 479 sb.append(':'); 480 sb.append(serverPort); 481 } 482 } 483 return sb.toString(); 484 } 485 486}