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