001/* 002 * Copyright 2021 Anyware Services 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 */ 016package org.ametys.plugins.extraction.execution; 017 018import java.io.IOException; 019import java.util.Collection; 020import java.util.HashMap; 021import java.util.Map; 022import java.util.Set; 023 024import org.apache.avalon.framework.activity.Initializable; 025import org.apache.avalon.framework.component.Component; 026import org.apache.avalon.framework.service.ServiceException; 027import org.apache.avalon.framework.service.ServiceManager; 028import org.apache.avalon.framework.service.Serviceable; 029import org.apache.commons.io.FileUtils; 030import org.apache.commons.lang3.StringUtils; 031import org.apache.excalibur.source.Source; 032import org.apache.excalibur.source.SourceException; 033import org.apache.excalibur.source.SourceResolver; 034import org.apache.excalibur.source.TraversableSource; 035import org.apache.excalibur.source.impl.FileSource; 036 037import org.ametys.core.cache.AbstractCacheManager; 038import org.ametys.core.cache.Cache; 039import org.ametys.core.group.GroupIdentity; 040import org.ametys.core.right.ProfileAssignmentStorage.AnonymousOrAnyConnectedKeys; 041import org.ametys.core.right.ProfileAssignmentStorage.UserOrGroup; 042import org.ametys.core.right.ProfileAssignmentStorageExtensionPoint; 043import org.ametys.core.right.RightManager; 044import org.ametys.core.right.RightManager.RightResult; 045import org.ametys.core.ui.Callable; 046import org.ametys.core.user.CurrentUserProvider; 047import org.ametys.core.user.UserIdentity; 048import org.ametys.plugins.core.user.UserHelper; 049import org.ametys.plugins.extraction.ExtractionConstants; 050import org.ametys.plugins.extraction.ExtractionRightAssignmentContext; 051import org.ametys.runtime.i18n.I18nizableText; 052import org.ametys.runtime.plugin.component.AbstractLogEnabled; 053 054/** 055 * Object representing the extraction definition file content 056 */ 057public class ExtractionDAO extends AbstractLogEnabled implements Serviceable, Component, Initializable 058{ 059 /** The Avalon role */ 060 public static final String ROLE = ExtractionDAO.class.getName(); 061 062 /** Extraction author cache id */ 063 private static final String EXTRACTION_AUTHOR_CACHE = ExtractionDAO.class.getName() + "$extractionAuthor"; 064 065 private CurrentUserProvider _userProvider; 066 private RightManager _rightManager; 067 private SourceResolver _sourceResolver; 068 private ExtractionDefinitionReader _definitionReader; 069 private ProfileAssignmentStorageExtensionPoint _profileAssignmentStorageEP; 070 private CurrentUserProvider _currentUserProvider; 071 private AbstractCacheManager _cacheManager; 072 private UserHelper _userHelper; 073 private TraversableSource _root; 074 075 public void service(ServiceManager manager) throws ServiceException 076 { 077 _userProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE); 078 _rightManager = (RightManager) manager.lookup(RightManager.ROLE); 079 _sourceResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE); 080 _definitionReader = (ExtractionDefinitionReader) manager.lookup(ExtractionDefinitionReader.ROLE); 081 _profileAssignmentStorageEP = (ProfileAssignmentStorageExtensionPoint) manager.lookup(ProfileAssignmentStorageExtensionPoint.ROLE); 082 _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE); 083 _cacheManager = (AbstractCacheManager) manager.lookup(AbstractCacheManager.ROLE); 084 _userHelper = (UserHelper) manager.lookup(UserHelper.ROLE); 085 } 086 087 public void initialize() throws Exception 088 { 089 _root = (TraversableSource) _sourceResolver.resolveURI(ExtractionConstants.DEFINITIONS_DIR); 090 _cacheManager.createRequestCache(EXTRACTION_AUTHOR_CACHE, 091 new I18nizableText("plugin.extraction", "PLUGINS_EXTRACTION_CACHE_DEFINITION_AUTHOR_LABEL"), 092 new I18nizableText("plugin.extraction", "PLUGINS_EXTRACTION_CACHE_DEFINITION_AUTHOR_DESCRIPTION"), 093 true); 094 } 095 096 /** 097 * Get the root container properties 098 * @return The root container properties 099 * @throws IOException If an error occurred while reading folder 100 */ 101 @Callable 102 public Map<String, Object> getRootProperties() throws IOException 103 { 104 String rootURI = ExtractionConstants.DEFINITIONS_DIR; 105 TraversableSource rootDir = (TraversableSource) _sourceResolver.resolveURI(rootURI); 106 Map<String, Object> infos = getExtractionContainerProperties(rootDir); 107 return infos; 108 } 109 110 /** 111 * Get extraction container properties 112 * @param folder the source of the extraction container 113 * @return The extraction container properties 114 */ 115 public Map<String, Object> getExtractionContainerProperties(TraversableSource folder) 116 { 117 try 118 { 119 Map<String, Object> infos = new HashMap<>(); 120 121 UserIdentity currentUser = _userProvider.getUser(); 122 123 boolean canRead = hasReadRightOnExtractionContainer(currentUser, folder); 124 boolean canWrite = hasWriteRightOnExtractionContainer(currentUser, folder); 125 boolean canWriteParent = !_root.getURI().equals(folder.getURI()) && hasWriteRightOnExtractionContainer(currentUser, (TraversableSource) folder.getParent()); 126 127 infos.put("canRead", canRead); 128 129 // Used to check if a user have the right to rename this folder 130 infos.put("canRename", canWrite && canWriteParent); 131 132 // Used to check if a user have the right to add folders and extraction file inside this folder 133 infos.put("canWrite", canWrite); 134 135 // Used to check if a user have the right to delete and drag&drop this folder 136 infos.put("canEdit", canWrite && _hasWriteRightOnEachDescendant(currentUser, folder) && canWriteParent); 137 138 // Used to check if a user have the right to limit access to this folder 139 infos.put("canEditRight", hasAssignationRightOnExtractionContainer(currentUser, folder)); 140 141 // Used to filter folders 142 infos.put("displayForRead", canRead || canWrite || hasAnyReadableDescendant(currentUser, folder) || hasAnyWritableDescendant(currentUser, folder)); 143 infos.put("displayForWrite", canWrite || _hasAnyWriteDescendantFolder(currentUser, folder)); 144 infos.put("displayForRights", canWrite || hasAnyAssignableDescendant(currentUser, folder)); 145 146 return infos; 147 } 148 catch (SourceException e) 149 { 150 throw new RuntimeException("Cannot get properties of " + folder.getURI(), e); 151 } 152 } 153 /** 154 * Get extraction properties 155 * @param extraction the extraction 156 * @param file the source of the extraction 157 * @return The extraction properties 158 */ 159 public Map<String, Object> getExtractionProperties(Extraction extraction, TraversableSource file) 160 { 161 Map<String, Object> infos = new HashMap<>(); 162 163 UserIdentity currentUser = _userProvider.getUser(); 164 infos.put("descriptionId", extraction.getDescriptionId()); 165 infos.put("author", _userHelper.user2json(extraction.getAuthor())); 166 167 infos.put("canRead", hasReadRightOnExtraction(currentUser, file, extraction.getAuthor())); 168 infos.put("canWrite", hasWriteRightOnExtractionAndParent(currentUser, file, extraction.getAuthor(), file)); 169 infos.put("canEditRight", hasRightAffectationRightOnExtraction(currentUser, file, extraction.getAuthor())); 170 171 return infos; 172 } 173 174 /** 175 * Check if a folder has a descendant in read access for a given user 176 * @param userIdentity the user 177 * @param folder the source of the extraction container 178 * @return <code>true</code> if the folder has a descendant in read access, <code>false</code> otherwise 179 */ 180 public Boolean hasAnyReadableDescendant(UserIdentity userIdentity, TraversableSource folder) 181 { 182 boolean hasDescendant = hasReadRightOnExtractionContainer(userIdentity, folder); 183 if (hasDescendant) 184 { 185 return true; 186 } 187 try 188 { 189 if (folder.exists()) 190 { 191 for (TraversableSource child : (Collection<TraversableSource>) folder.getChildren()) 192 { 193 if (child.isCollection()) 194 { 195 hasDescendant = hasDescendant || hasAnyReadableDescendant(userIdentity, child); 196 } 197 else if (child.getName().endsWith(".xml")) 198 { 199 hasDescendant = hasDescendant || hasReadRightOnExtraction(userIdentity, child, getUserIdentityByExtractionPath((FileSource) child)); 200 } 201 if (hasDescendant) 202 { 203 return true; 204 } 205 } 206 } 207 } 208 catch (SourceException e) 209 { 210 throw new RuntimeException("Cannot list child elements of " + folder.getURI(), e); 211 } 212 return hasDescendant; 213 } 214 215 /** 216 * Check if a folder has descendant in write access for a given user 217 * @param userIdentity the user 218 * @param folder the source of the extraction container 219 * @return <code>true</code> if the folder has descendant in write access, <code>false</code> otherwise 220 */ 221 public Boolean hasAnyWritableDescendant(UserIdentity userIdentity, TraversableSource folder) 222 { 223 boolean hasDescendant = hasWriteRightOnExtractionContainer(userIdentity, folder); 224 if (hasDescendant) 225 { 226 return true; 227 } 228 try 229 { 230 if (folder.exists()) 231 { 232 for (TraversableSource child : (Collection<TraversableSource>) folder.getChildren()) 233 { 234 if (child.isCollection()) 235 { 236 hasDescendant = hasDescendant || hasAnyWritableDescendant(userIdentity, child); 237 } 238 else if (child.getName().endsWith(".xml")) 239 { 240 241 hasDescendant = hasDescendant || hasWriteRightOnExtractionAndParent(userIdentity, child, getUserIdentityByExtractionPath((FileSource) child), child); 242 } 243 if (hasDescendant) 244 { 245 return true; 246 } 247 } 248 } 249 } 250 catch (SourceException e) 251 { 252 throw new RuntimeException("Cannot list child elements of " + folder.getURI(), e); 253 } 254 return hasDescendant; 255 } 256 257 private Boolean _hasAnyWriteDescendantFolder(UserIdentity userIdentity, TraversableSource folder) 258 { 259 boolean hasDescendant = hasWriteRightOnExtractionContainer(userIdentity, folder); 260 if (hasDescendant) 261 { 262 return true; 263 } 264 try 265 { 266 if (folder.exists()) 267 { 268 for (TraversableSource child : (Collection<TraversableSource>) folder.getChildren()) 269 { 270 if (child.isCollection()) 271 { 272 hasDescendant = hasDescendant || _hasAnyWriteDescendantFolder(userIdentity, child); 273 } 274 if (hasDescendant) 275 { 276 return true; 277 } 278 } 279 } 280 } 281 catch (SourceException e) 282 { 283 throw new RuntimeException("Cannot list child elements of " + folder.getURI(), e); 284 } 285 return hasDescendant; 286 } 287 288 /** 289 * Check if a folder has descendant for a given user 290 * @param userIdentity the user 291 * @param folder the source of the extraction container 292 * @return <code>true</code> if the folder has descendant, <code>false</code> otherwise 293 */ 294 public Boolean hasAnyAssignableDescendant(UserIdentity userIdentity, TraversableSource folder) 295 { 296 boolean hasDescendant = hasAssignationRightOnExtractionContainer(userIdentity, folder); 297 if (hasDescendant) 298 { 299 return true; 300 } 301 try 302 { 303 if (folder.exists()) 304 { 305 for (TraversableSource child : (Collection<TraversableSource>) folder.getChildren()) 306 { 307 if (child.isCollection()) 308 { 309 hasDescendant = hasDescendant || hasAnyAssignableDescendant(userIdentity, child); 310 } 311 else if (child.getName().endsWith(".xml")) 312 { 313 hasDescendant = hasDescendant || hasRightAffectationRightOnExtraction(userIdentity, child, getUserIdentityByExtractionPath((FileSource) child)); 314 } 315 if (hasDescendant) 316 { 317 return true; 318 } 319 } 320 } 321 } 322 catch (SourceException e) 323 { 324 throw new RuntimeException("Cannot list child elements of " + folder.getURI(), e); 325 } 326 return hasDescendant; 327 } 328 329 /** 330 * Check if a user has read rights on an extraction container 331 * @param userIdentity the user 332 * @param folder the source of the extraction container 333 * @return <code>true</code> if the user has read rights on an extraction container, <code>false</code> otherwise 334 */ 335 public boolean hasReadRightOnExtractionContainer(UserIdentity userIdentity, TraversableSource folder) 336 { 337 return _rightManager.hasReadAccess(userIdentity, getExtractionRightPath(folder)); 338 } 339 340 /** 341 * Check if a user has write rights on an extraction container 342 * @param userIdentity the user 343 * @param folder the source of the extraction container 344 * @return <code>true</code> if the user has write rights on an extraction container, <code>false</code> otherwise 345 */ 346 public boolean hasWriteRightOnExtractionContainer(UserIdentity userIdentity, TraversableSource folder) 347 { 348 349 return _rightManager.hasRight(userIdentity, ExtractionConstants.MODIFY_EXTRACTION_RIGHT_ID, getExtractionRightPath(folder)) == RightResult.RIGHT_ALLOW; 350 } 351 352 /** 353 * Check if a user has write rights on an extraction container and each of his descendant 354 * @param userIdentity the user 355 * @param folder the source of the extraction container 356 * @return <code>true</code> if the user has write rights on an extraction container and each of his descendant, <code>false</code> otherwise 357 */ 358 private boolean _hasWriteRightOnEachDescendant(UserIdentity userIdentity, TraversableSource folder) 359 { 360 boolean hasRight = hasWriteRightOnExtractionContainer(userIdentity, folder); 361 if (!hasRight) 362 { 363 return false; 364 } 365 try 366 { 367 if (folder.exists()) 368 { 369 for (TraversableSource child : (Collection<TraversableSource>) folder.getChildren()) 370 { 371 if (child.isCollection()) 372 { 373 hasRight = hasRight && hasWriteRightOnExtractionContainer(userIdentity, child); 374 } 375 else if (child.getName().endsWith(".xml")) 376 { 377 378 hasRight = hasRight && hasWriteRightOnExtractionAndParent(userIdentity, child, getUserIdentityByExtractionPath((FileSource) child), child); 379 } 380 if (!hasRight) 381 { 382 return false; 383 } 384 } 385 } 386 } 387 catch (SourceException e) 388 { 389 throw new RuntimeException("Cannot list child elements of " + folder.getURI(), e); 390 } 391 return hasRight; 392 } 393 394 /** 395 * Check if a user has right affectation rights on an extraction container 396 * @param userIdentity the user 397 * @param folder the source of the extraction container 398 * @return <code>true</code> if the user have right affectation rights on an extraction container, <code>false</code> otherwise 399 */ 400 public boolean hasAssignationRightOnExtractionContainer(UserIdentity userIdentity, TraversableSource folder) 401 { 402 try 403 { 404 return _rightManager.hasRight(userIdentity, "Runtime_Rights_Rights_Handle", "/cms") == RightResult.RIGHT_ALLOW 405 || _hasWriteRightOnEachDescendant(userIdentity, folder) 406 && !_root.getURI().equals(folder.getURI()) 407 && hasWriteRightOnExtractionContainer(userIdentity, (TraversableSource) folder.getParent()); 408 } 409 catch (SourceException e) 410 { 411 throw new RuntimeException("Cannot get rights of extraction conatainer " + folder.getURI(), e); 412 } 413 } 414 415 /** 416 * Check if a user has read rights on an extraction 417 * @param userIdentity the user 418 * @param extraction the source for the extraction 419 * @param author the extraction author 420 * @return <code>true</code> if the user has read rights on an extraction, <code>false</code> otherwise 421 */ 422 public boolean hasReadRightOnExtraction(UserIdentity userIdentity, TraversableSource extraction, UserIdentity author) 423 { 424 return userIdentity.equals(author) || _rightManager.hasReadAccess(userIdentity, getExtractionRightPath(extraction)); 425 } 426 427 /** 428 * Check if a user has write rights on an extraction 429 * @param userIdentity the user 430 * @param extraction the source for the extraction 431 * @param author the extraction author 432 * @return <code>true</code> if the user has write rights on an extraction, <code>false</code> otherwise 433 */ 434 public boolean hasWriteRightOnExtraction(UserIdentity userIdentity, TraversableSource extraction, UserIdentity author) 435 { 436 return author != null && userIdentity.equals(author) 437 || _rightManager.hasRight(userIdentity, ExtractionConstants.MODIFY_EXTRACTION_RIGHT_ID, getExtractionRightPath(extraction)) == RightResult.RIGHT_ALLOW; 438 } 439 440 /** 441 * Check if a user has write rights on an extraction 442 * @param userIdentity the user 443 * @param extraction the source for the extraction 444 * @param author the extraction author 445 * @param file file 446 * @return <code>true</code> if the user has write rights on an extraction, <code>false</code> otherwise 447 */ 448 public boolean hasWriteRightOnExtractionAndParent(UserIdentity userIdentity, TraversableSource extraction, UserIdentity author, TraversableSource file) 449 { 450 try 451 { 452 return author != null && userIdentity.equals(author) 453 || _rightManager.hasRight(userIdentity, ExtractionConstants.MODIFY_EXTRACTION_RIGHT_ID, getExtractionRightPath(extraction)) == RightResult.RIGHT_ALLOW && hasWriteRightOnExtractionContainer(userIdentity, (TraversableSource) file.getParent()); 454 } 455 catch (SourceException e) 456 { 457 throw new RuntimeException("Cannot get rights of extraction " + file.getURI(), e); 458 } 459 } 460 461 /** 462 * Check if a user has right affectation rights on an extraction container 463 * @param userIdentity the user 464 * @param extraction the source for the extraction 465 * @param author the extraction author 466 * @return <code>true</code> if the user has right affectation rights on an extraction, <code>false</code> otherwise 467 */ 468 public boolean hasRightAffectationRightOnExtraction(UserIdentity userIdentity, TraversableSource extraction, UserIdentity author) 469 { 470 try 471 { 472 // If the user have the right to handle right on cms context, he can edit the rights of all extractions 473 if (_rightManager.hasRight(userIdentity, "Runtime_Rights_Rights_Handle", "/cms") == RightResult.RIGHT_ALLOW) 474 { 475 return true; 476 } 477 // If the user is the author of the extraction, he have all the rights on it 478 else if (author != null && userIdentity.equals(author)) 479 { 480 return true; 481 } 482 // Otherwise, check if the user have the rights on the extraction and the folder containing it. 483 else 484 { 485 return hasWriteRightOnExtraction(userIdentity, extraction, author) && hasWriteRightOnExtractionContainer(userIdentity, (TraversableSource) extraction.getParent()); 486 } 487 } 488 catch (SourceException e) 489 { 490 throw new RuntimeException("Cannot get rights of extraction " + extraction.getURI(), e); 491 } 492 } 493 494 /** 495 * Get the relative path of an extraction or an extraction container 496 * @param source The source of the extraction or extraction container 497 * @return the relative path 498 */ 499 public String getExtractionRightPath(Source source) 500 { 501 String relPath = source.getURI().substring(_root.getURI().length()); 502 503 if (relPath.endsWith("/")) 504 { 505 relPath = relPath.substring(0, relPath.length() - 1); 506 } 507 508 return StringUtils.isEmpty(relPath) ? ExtractionRightAssignmentContext.ROOT_CONTEXT_PREFIX : ExtractionRightAssignmentContext.ROOT_CONTEXT_PREFIX + "/" + relPath; 509 } 510 511 /** 512 * Get the absolute path of an extraction or an extraction from the context 513 * @param context The context 514 * @return the relative path 515 * @throws IOException if I/O error occurred. 516 */ 517 public String getExtractionAbsolutePathFromContext(String context) throws IOException 518 { 519 String relPath = StringUtils.substringAfter(context, ExtractionRightAssignmentContext.ROOT_CONTEXT_PREFIX); 520 521 return ExtractionConstants.DEFINITIONS_DIR + relPath; 522 } 523 524 /** 525 * Copy rights from one context to another one 526 * @param sourceContext the source context 527 * @param targetContext the target context 528 */ 529 public void copyRights(String sourceContext, String targetContext) 530 { 531 // Get the mapping between users and profiles 532 Map<UserIdentity, Map<UserOrGroup, Set<String>>> profilesForUsers = _profileAssignmentStorageEP.getProfilesForUsers(sourceContext, null); 533 // Copy allowed user assignment profiles to new context 534 profilesForUsers.entrySet() 535 .forEach(entry -> _copyAllowedUsers(entry.getKey(), entry.getValue().get(UserOrGroup.ALLOWED), targetContext)); 536 // Copy denied user assignment profiles to new context 537 profilesForUsers.entrySet() 538 .forEach(entry -> _copyDeniedUsers(entry.getKey(), entry.getValue().get(UserOrGroup.DENIED), targetContext)); 539 540 // Get the mapping between groups and profiles 541 Map<GroupIdentity, Map<UserOrGroup, Set<String>>> profilesForGroups = _profileAssignmentStorageEP.getProfilesForGroups(sourceContext, null); 542 // Copy allowed group assignment profiles to new context 543 profilesForGroups.entrySet() 544 .forEach(entry -> _copyAllowedGroups(entry.getKey(), entry.getValue().get(UserOrGroup.ALLOWED), targetContext)); 545 // Copy denied group assignment profiles to new context 546 profilesForGroups.entrySet() 547 .forEach(entry -> _copyDeniedGroups(entry.getKey(), entry.getValue().get(UserOrGroup.DENIED), targetContext)); 548 549 // Get the mapping between anonymous or any connected user and profiles 550 Map<AnonymousOrAnyConnectedKeys, Set<String>> profilesForAnonymousOrAnyConnectedUser = _profileAssignmentStorageEP.getProfilesForAnonymousAndAnyConnectedUser(sourceContext); 551 // Copy allowed anonymous user assignment profiles to new context 552 profilesForAnonymousOrAnyConnectedUser.get(AnonymousOrAnyConnectedKeys.ANONYMOUS_ALLOWED) 553 .forEach(profileId -> _profileAssignmentStorageEP.allowProfileToAnonymous(profileId, targetContext)); 554 // Copy denied anonymous user assignment profiles to new context 555 profilesForAnonymousOrAnyConnectedUser.get(AnonymousOrAnyConnectedKeys.ANONYMOUS_DENIED) 556 .forEach(profileId -> _profileAssignmentStorageEP.denyProfileToAnonymous(profileId, targetContext)); 557 // Copy allowed any connected user assignment profiles to new context 558 profilesForAnonymousOrAnyConnectedUser.get(AnonymousOrAnyConnectedKeys.ANYCONNECTEDUSER_ALLOWED) 559 .forEach(profileId -> _profileAssignmentStorageEP.allowProfileToAnyConnectedUser(profileId, targetContext)); 560 // Copy denied any connected user assignment profiles to new context 561 profilesForAnonymousOrAnyConnectedUser.get(AnonymousOrAnyConnectedKeys.ANYCONNECTEDUSER_DENIED) 562 .forEach(profileId -> _profileAssignmentStorageEP.denyProfileToAnyConnectedUser(profileId, targetContext)); 563 } 564 565 private void _copyAllowedUsers(UserIdentity userIdentity, Set<String> profiles, String context) 566 { 567 profiles.forEach(profile -> _profileAssignmentStorageEP.allowProfileToUser(userIdentity, profile, context)); 568 } 569 570 private void _copyDeniedUsers(UserIdentity userIdentity, Set<String> profiles, String context) 571 { 572 profiles.forEach(profile -> _profileAssignmentStorageEP.denyProfileToUser(userIdentity, profile, context)); 573 } 574 575 private void _copyAllowedGroups(GroupIdentity groupIdentity, Set<String> profiles, String context) 576 { 577 profiles.forEach(profile -> _profileAssignmentStorageEP.allowProfileToGroup(groupIdentity, profile, context)); 578 } 579 580 private void _copyDeniedGroups(GroupIdentity groupIdentity, Set<String> profiles, String context) 581 { 582 profiles.forEach(profile -> _profileAssignmentStorageEP.denyProfileToGroup(groupIdentity, profile, context)); 583 } 584 585 586 /** 587 * Delete rights from a context 588 * @param context the context 589 */ 590 public void deleteRights(String context) 591 { 592 // Get the mapping between users and profiles 593 Map<UserIdentity, Map<UserOrGroup, Set<String>>> profilesForUsers = _profileAssignmentStorageEP.getProfilesForUsers(context, null); 594 // Copy allowed user assignment profiles to new context 595 profilesForUsers.entrySet() 596 .forEach(entry -> _removeAllowedUsers(entry.getKey(), entry.getValue().get(UserOrGroup.ALLOWED), context)); 597 // Copy denied user assignment profiles to new context 598 profilesForUsers.entrySet() 599 .forEach(entry -> _removeDeniedUsers(entry.getKey(), entry.getValue().get(UserOrGroup.DENIED), context)); 600 601 // Get the mapping between groups and profiles 602 Map<GroupIdentity, Map<UserOrGroup, Set<String>>> profilesForGroups = _profileAssignmentStorageEP.getProfilesForGroups(context, null); 603 // Copy allowed group assignment profiles to new context 604 profilesForGroups.entrySet() 605 .forEach(entry -> _removeAllowedGroups(entry.getKey(), entry.getValue().get(UserOrGroup.ALLOWED), context)); 606 // Copy denied group assignment profiles to new context 607 profilesForGroups.entrySet() 608 .forEach(entry -> _removeDeniedGroups(entry.getKey(), entry.getValue().get(UserOrGroup.DENIED), context)); 609 610 // Get the mapping between anonymous or any connected user and profiles 611 Map<AnonymousOrAnyConnectedKeys, Set<String>> profilesForAnonymousOrAnyConnectedUser = _profileAssignmentStorageEP.getProfilesForAnonymousAndAnyConnectedUser(context); 612 // Copy allowed anonymous user assignment profiles to new context 613 profilesForAnonymousOrAnyConnectedUser.get(AnonymousOrAnyConnectedKeys.ANONYMOUS_ALLOWED) 614 .forEach(profileId -> _profileAssignmentStorageEP.removeAllowedProfileFromAnonymous(profileId, context)); 615 // Copy denied anonymous user assignment profiles to new context 616 profilesForAnonymousOrAnyConnectedUser.get(AnonymousOrAnyConnectedKeys.ANONYMOUS_DENIED) 617 .forEach(profileId -> _profileAssignmentStorageEP.removeDeniedProfileFromAnonymous(profileId, context)); 618 // Copy allowed any connected user assignment profiles to new context 619 profilesForAnonymousOrAnyConnectedUser.get(AnonymousOrAnyConnectedKeys.ANYCONNECTEDUSER_ALLOWED) 620 .forEach(profileId -> _profileAssignmentStorageEP.removeAllowedProfileFromAnyConnectedUser(profileId, context)); 621 // Copy denied any connected user assignment profiles to new context 622 profilesForAnonymousOrAnyConnectedUser.get(AnonymousOrAnyConnectedKeys.ANYCONNECTEDUSER_DENIED) 623 .forEach(profileId -> _profileAssignmentStorageEP.removeDeniedProfileFromAnyConnectedUser(profileId, context)); 624 } 625 626 private void _removeAllowedUsers(UserIdentity userIdentity, Set<String> profiles, String context) 627 { 628 profiles.forEach(profile -> _profileAssignmentStorageEP.removeAllowedProfileFromUser(userIdentity, profile, context)); 629 } 630 631 private void _removeDeniedUsers(UserIdentity userIdentity, Set<String> profiles, String context) 632 { 633 profiles.forEach(profile -> _profileAssignmentStorageEP.removeDeniedProfileFromUser(userIdentity, profile, context)); 634 } 635 636 private void _removeAllowedGroups(GroupIdentity groupIdentity, Set<String> profiles, String context) 637 { 638 profiles.forEach(profile -> _profileAssignmentStorageEP.removeAllowedProfileFromGroup(groupIdentity, profile, context)); 639 } 640 641 private void _removeDeniedGroups(GroupIdentity groupIdentity, Set<String> profiles, String context) 642 { 643 profiles.forEach(profile -> _profileAssignmentStorageEP.removeDeniedProfileFromGroup(groupIdentity, profile, context)); 644 } 645 646 /** 647 * Move an extraction file or folder inside a given directory 648 * 649 * @param srcRelPath The relative URI of file/folder to move 650 * @param parentRelPath The URI relative of parent target file 651 * @return a result map with the name and uri of moved file in case of 652 * success. 653 * @throws IOException If an error occurred manipulating the source 654 */ 655 @Callable (right = ExtractionConstants.MODIFY_EXTRACTION_RIGHT_ID) 656 public Map<String, Object> moveExtractionDefinitionFile(String srcRelPath, String parentRelPath) throws IOException 657 { 658 Map<String, Object> result = new HashMap<>(); 659 660 FileSource rootParametersFileSource = null; 661 FileSource srcFileSource = null; 662 FileSource parentFileSource = null; 663 try 664 { 665 String rootParametersFolder = "context://WEB-INF/param/extraction/definitions/"; 666 667 rootParametersFileSource = (FileSource) _sourceResolver.resolveURI(rootParametersFolder); 668 srcFileSource = (FileSource) _sourceResolver.resolveURI(rootParametersFolder + srcRelPath); 669 parentFileSource = (FileSource) _sourceResolver.resolveURI(rootParametersFolder + parentRelPath); 670 if (!StringUtils.startsWith(srcFileSource.getURI(), rootParametersFileSource.getURI()) || !StringUtils.startsWith(parentFileSource.getURI(), rootParametersFileSource.getURI())) 671 { 672 result.put("success", false); 673 result.put("error", "no-exists"); 674 675 getLogger().error("User '" + _currentUserProvider.getUser() + " tried to move parameter file outside of the \"WEB-INF/param\" root directory."); 676 677 return result; 678 } 679 680 String sourceContext = ExtractionRightAssignmentContext.ROOT_CONTEXT_PREFIX + "/" + srcRelPath; 681 String targetContext = ExtractionRightAssignmentContext.ROOT_CONTEXT_PREFIX + "/" + parentRelPath + (StringUtils.isEmpty(parentRelPath) ? "" : "/") + srcFileSource.getName(); 682 683 result = moveSource(rootParametersFolder + srcRelPath, rootParametersFolder + parentRelPath, sourceContext, targetContext); 684 685 if (result.containsKey("uri")) 686 { 687 String newURI = (String) result.get("uri"); 688 String path = newURI.substring(rootParametersFolder.length()); 689 result.put("path", path); 690 } 691 } 692 finally 693 { 694 _sourceResolver.release(rootParametersFileSource); 695 _sourceResolver.release(srcFileSource); 696 _sourceResolver.release(parentFileSource); 697 } 698 699 return result; 700 } 701 702 /** 703 * Move a file or folder 704 * 705 * @param srcUri The URI of file/folder to move 706 * @param parentTargetUri The URI of parent target file 707 * @param sourceContext the source context 708 * @param targetContext the target context 709 * @return a result map with the name and uri of moved file in case of 710 * success. 711 * @throws IOException If an error occurred manipulating the source 712 */ 713 public Map<String, Object> moveSource(String srcUri, String parentTargetUri, String sourceContext, String targetContext) throws IOException 714 { 715 Map<String, Object> result = new HashMap<>(); 716 717 FileSource srcFile = (FileSource) _sourceResolver.resolveURI(srcUri); 718 719 if (!srcFile.exists()) 720 { 721 result.put("success", false); 722 result.put("error", "no-exists"); 723 return result; 724 } 725 726 FileSource parentDargetDir = (FileSource) _sourceResolver.resolveURI(parentTargetUri); 727 String fileName = srcFile.getName(); 728 FileSource targetFile = (FileSource) _sourceResolver.resolveURI(parentTargetUri + (fileName.length() > 0 ? "/" + fileName : "")); 729 730 if (targetFile.exists()) 731 { 732 result.put("msg", "already-exists"); 733 return result; 734 } 735 736 copyRightsRecursively(sourceContext, targetContext, srcFile); 737 FileUtils.moveToDirectory(srcFile.getFile(), parentDargetDir.getFile(), false); 738 deleteRightsRecursively(sourceContext, targetFile); 739 740 result.put("success", true); 741 result.put("name", targetFile.getName()); 742 result.put("uri", targetFile.getURI()); 743 744 return result; 745 } 746 747 /** 748 * Copy rights from one context to another one 749 * @param sourceContext the source context 750 * @param targetContext the target context 751 * @param file the source of the file to copy 752 */ 753 public void copyRightsRecursively(String sourceContext, String targetContext, TraversableSource file) 754 { 755 copyRights(sourceContext, targetContext); 756 if (file.isCollection()) 757 { 758 try 759 { 760 for (TraversableSource child : (Collection<TraversableSource>) file.getChildren()) 761 { 762 copyRightsRecursively(sourceContext + "/" + child.getName(), targetContext + "/" + child.getName(), child); 763 } 764 } 765 catch (SourceException e) 766 { 767 throw new RuntimeException("Cannot list child elements of " + file.getURI(), e); 768 } 769 } 770 } 771 772 /** 773 * Copy rights from one context to another one 774 * @param context the context 775 * @param file the source of the file to copy 776 */ 777 public void deleteRightsRecursively(String context, TraversableSource file) 778 { 779 deleteRights(context); 780 if (file.isCollection()) 781 { 782 try 783 { 784 for (TraversableSource child : (Collection<TraversableSource>) file.getChildren()) 785 { 786 deleteRightsRecursively(context + "/" + child.getName(), child); 787 } 788 } 789 catch (SourceException e) 790 { 791 throw new RuntimeException("Cannot list child elements of " + file.getURI(), e); 792 } 793 } 794 } 795 796 /** 797 * get the author of extraction 798 * @param extractionPath the path of the extraction 799 * @return the author 800 */ 801 public UserIdentity getUserIdentityByExtractionPath(FileSource extractionPath) 802 { 803 return _getExtractionAuthorCache().get(extractionPath, path -> _getUserIdentityByExtractionFile(path)); 804 805 } 806 807 private UserIdentity _getUserIdentityByExtractionFile(FileSource extractionPath) 808 { 809 try 810 { 811 Extraction extraction = _definitionReader.readExtractionDefinitionFile(extractionPath.getFile()); 812 return extraction.getAuthor(); 813 } 814 catch (Exception e) 815 { 816 throw new RuntimeException("Cannot read extraction " + extractionPath, e); 817 } 818 } 819 private Cache<FileSource, UserIdentity> _getExtractionAuthorCache() 820 { 821 return this._cacheManager.get(EXTRACTION_AUTHOR_CACHE); 822 } 823}