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