Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/main/java/org/ohdsi/webapi/service/CDMResultsService.java
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ public JobExecutionResource warmCache(@PathVariable("sourceKey") final String so
* @return The job execution resource
*/
@GetMapping(value = "/{sourceKey}/refreshCache", produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("isPermitted('write:source') or hasSourceAccess(#sourceKey, WRITE)")
@PreAuthorize("isPermitted('admin:cache')")
public JobExecutionResource refreshCache(@PathVariable("sourceKey") final String sourceKey) {
Source source = getSourceRepository().findBySourceKey(sourceKey);
JobExecutionResource jobExecutionResource = jobService.findJobByName(Constants.WARM_CACHE, getWarmCacheJobName(String.valueOf(source.getSourceId()),sourceKey));
Expand All @@ -292,7 +292,7 @@ public JobExecutionResource refreshCache(@PathVariable("sourceKey") final String
*/
@PostMapping(value = "/{sourceKey}/clearCache")
@Transactional()
@PreAuthorize("isPermitted('write:source') or hasSourceAccess(#sourceKey, WRITE)")
@PreAuthorize("isPermitted('admin:cache')")
public void clearCacheForSource(@PathVariable("sourceKey") final String sourceKey) {
Source source = getSourceRepository().findBySourceKey(sourceKey);
cacheService.clearCache(source);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1058,7 +1058,7 @@ private void addRelationships(final Map<Long, RelatedConcept> concepts, final Re
* @param sourceKey The source containing the vocabulary
* @return The vocabulary info
*/
@PreAuthorize("isAnyPermitted(anyOf('read:source','write:source')) or hasSourceAccess(#sourceKey, READ)")
@PreAuthorize("isAnyPermitted(anyOf('read:source','write:source','admin:source')) or hasSourceAccess(#sourceKey, READ)")
@GetMapping(value = "/{sourceKey}/info",
produces = MediaType.APPLICATION_JSON_VALUE)
public VocabularyInfo getInfo(@PathVariable("sourceKey") String sourceKey) {
Expand Down
54 changes: 10 additions & 44 deletions src/main/java/org/ohdsi/webapi/source/SourceService.java
Original file line number Diff line number Diff line change
Expand Up @@ -231,28 +231,6 @@ public ResponseEntity<SourceInfo> createSource(
throw new SourceDuplicateKeyException("The source key has been already used.");
}
Source sourceEntity = conversionService.convert(source, Source.class);
if (sourceEntity.getDaimons() != null) {
// First source should get priority = 1
Iterable<Source> sources = sourceRepository.findAll();
sourceEntity.getDaimons()
.stream()
.filter(sd -> sd.getPriority() <= 0)
.filter(sd -> {
boolean accept = true;
// Check if source daimon of given type with priority > 0 already exists in other sources
for (Source innerSource : sources) {
accept = !innerSource.getDaimons()
.stream()
.anyMatch(innerDaimon -> innerDaimon.getPriority() > 0
&& innerDaimon.getDaimonType().equals(sd.getDaimonType()));
if (!accept) {
break;
}
}
return accept;
})
.forEach(sd -> sd.setPriority(1));
}
Source original = new Source();
original.setSourceDialect(sourceEntity.getSourceDialect());
setKeyfileData(sourceEntity, original, keyfile);
Expand Down Expand Up @@ -312,10 +290,11 @@ public ResponseEntity<SourceInfo> updateSource(
updated.setModifiedBy(getCurrentUserEntity());
updated.setModifiedDate(new Date());

reuseDeletedDaimons(updated, existingSource);
reuseExistingDaimonIds(updated, existingSource);

List<SourceDaimon> removed = existingSource.getDaimons().stream()
.filter(d -> !updated.getDaimons().contains(d))
.filter(existingDaimon -> updated.getDaimons().stream()
.noneMatch(updatedDaimon -> existingDaimon.getDaimonType() == updatedDaimon.getDaimonType()))
.collect(Collectors.toList());
// Delete MUST be called after fetching user or source data to prevent autoflush (see DefaultPersistEventListener.onPersist)
sourceDaimonRepository.deleteAll(removed);
Expand Down Expand Up @@ -505,28 +484,15 @@ protected UserEntity getCurrentUserEntity() {
return userRepository.findById(authorizationService.getAuthenticatedPrincipal().getUserId()).orElseThrow();
}

private void reuseDeletedDaimons(Source updated, Source source) {
List<SourceDaimon> daimons = updated.getDaimons().stream().filter(d -> source.getDaimons().contains(d))
.collect(Collectors.toList());
List<SourceDaimon> newDaimons = updated.getDaimons().stream().filter(d -> !source.getDaimons().contains(d))
.collect(Collectors.toList());
private void reuseExistingDaimonIds(Source updated, Source existing) {
List<SourceDaimon> existingDaimons = sourceDaimonRepository.findBySource(existing);

List<SourceDaimon> allDaimons = sourceDaimonRepository.findBySource(source);

for (SourceDaimon newSourceDaimon : newDaimons) {
Optional<SourceDaimon> reusedDaimonOpt = allDaimons.stream()
.filter(d -> d.equals(newSourceDaimon))
.findFirst();
if (reusedDaimonOpt.isPresent()) {
SourceDaimon reusedDaimon = reusedDaimonOpt.get();
reusedDaimon.setPriority(newSourceDaimon.getPriority());
reusedDaimon.setTableQualifier(newSourceDaimon.getTableQualifier());
daimons.add(reusedDaimon);
} else {
daimons.add(newSourceDaimon);
}
for (SourceDaimon updatedDaimon : updated.getDaimons()) {
existingDaimons.stream()
.filter(existingDaimon -> existingDaimon.getDaimonType() == updatedDaimon.getDaimonType())
.findFirst()
.ifPresent(existingDaimon -> updatedDaimon.setSourceDaimonId(existingDaimon.getSourceDaimonId()));
}
updated.setDaimons(daimons);
}

private void transformIfRequired(Source source) {
Expand Down
20 changes: 20 additions & 0 deletions src/test/java/org/ohdsi/webapi/test/SourceAccessIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,26 @@ public void limitedUserDeniedGlobalCdmResultsCacheClear() {
);
}

@Test
public void limitedUserDeniedSourceCdmResultsCacheClear() {
ResponseEntity<String> r = postAsLimitedUser("/cdmresults/" + SOURCE_KEY + "/clearCache");
assertEquals(
"Limited user (no admin:cache permission) should be denied with 403 Forbidden on source CDMResults cache clear",
HttpStatus.FORBIDDEN,
HttpStatus.valueOf(r.getStatusCode().value())
);
}

@Test
public void limitedUserDeniedSourceCdmResultsCacheRefresh() {
ResponseEntity<String> r = getAsLimitedUser("/cdmresults/" + SOURCE_KEY + "/refreshCache");
assertEquals(
"Limited user (no admin:cache permission) should be denied with 403 Forbidden on source CDMResults cache refresh",
HttpStatus.FORBIDDEN,
HttpStatus.valueOf(r.getStatusCode().value())
);
}

/**
* A limited user (authenticated, but with no source grant) must receive
* HTTP 403 Forbidden when accessing the source-scoped EvidenceService info
Expand Down
Loading