From 29b8869f206ddb59a8719baab1edd07ff8cb18a1 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Sat, 4 Oct 2025 18:41:32 +0200 Subject: [PATCH 1/3] Extended FHIR server user role config * FHIR server roles (CREATE, READ, UPDATE, DELETE, SEARCH, HISTORY, PERMANENT_DELETE, WEBSOCKET) can now be specified for specific FHIR resources. For example `- CREATE: [Organization, OrganizationAffiliation, Endpoint]` other examples see test setup docker-compose files. * Roles SEARCH, HISTORY and WEBSOCKET require users to have the READ role as well, if the User has no READ role for a specific resource, SEARCH, HISTORY and WEBSOCKET operations will filter out the resource type. * Removed identity parameter from ReferenceResolver methods. Implementation no longer uses identity filters when searching for resources in DB, user may not have role to search or read referenced resource but reference should be checked anyways. For example: Update role for QuestionnaireResponse but no search or read for Organization. * Some code cleanup. --- .../dsf/bpe/authentication/BpeServerRole.java | 14 +- .../authentication/IdentityProviderImpl.java | 5 +- .../spring/config/AuthenticationConfig.java | 6 +- .../common/auth/conf/AbstractIdentity.java | 2 +- .../auth/conf/AbstractIdentityProvider.java | 19 +- .../dev/dsf/common/auth/conf/DsfRole.java | 7 + .../dev/dsf/common/auth/conf/RoleConfig.java | 140 ++++++--- .../common/auth/conf/RoleConfigReader.java | 10 +- .../dev/dsf/common/auth/RoleConfigTest.java | 55 ++-- .../docker-compose.yml | 26 +- dsf-docker-test-setup/fhir/docker-compose.yml | 6 +- .../fhir/authentication/FhirServerRole.java | 20 +- .../authentication/FhirServerRoleImpl.java | 267 ++++++++++++++++++ .../authentication/IdentityProviderImpl.java | 8 +- .../AbstractAuthorizationRule.java | 132 ++++----- .../AbstractMetaTagAuthorizationRule.java | 29 +- .../fhir/authorization/AuthorizationRule.java | 33 +-- .../BinaryAuthorizationRule.java | 3 +- ...uestionnaireResponseAuthorizationRule.java | 17 +- .../authorization/RootAuthorizationRule.java | 16 +- .../authorization/TaskAuthorizationRule.java | 81 +++++- .../command/AbstractCommandWithResource.java | 12 +- .../dao/command/ReferencesHelperImpl.java | 17 +- ...tivityDefinitionHistoryIdentityFilter.java | 10 +- .../filter/BinaryHistoryIdentityFilter.java | 10 +- .../filter/BundleHistoryIdentityFilter.java | 10 +- .../CodeSystemHistoryIdentityFilter.java | 10 +- ...ocumentReferenceHistoryIdentityFilter.java | 10 +- .../filter/EndpointHistoryIdentityFilter.java | 10 +- .../filter/GroupHistoryIdentityFilter.java | 10 +- ...ealthcareServiceHistoryIdentityFilter.java | 10 +- .../filter/LibraryHistoryIdentityFilter.java | 10 +- .../filter/LocationHistoryIdentityFilter.java | 10 +- .../filter/MeasureHistoryIdentityFilter.java | 10 +- .../MeasureReportHistoryIdentityFilter.java | 10 +- .../NamingSystemHistoryIdentityFilter.java | 10 +- ...ationAffiliationHistoryIdentityFilter.java | 10 +- .../OrganizationHistoryIdentityFilter.java | 10 +- .../filter/PatientHistoryIdentityFilter.java | 10 +- .../PractitionerHistoryIdentityFilter.java | 10 +- ...PractitionerRoleHistoryIdentityFilter.java | 10 +- .../ProvenanceHistoryIdentityFilter.java | 10 +- .../QuestionnaireHistoryIdentityFilter.java | 10 +- ...ionnaireResponseHistoryIdentityFilter.java | 10 +- .../ResearchStudyHistoryIdentityFilter.java | 10 +- ...uctureDefinitionHistoryIdentityFilter.java | 10 +- .../SubscriptionHistoryIdentityFilter.java | 10 +- .../filter/TaskHistoryIdentityFilter.java | 10 +- .../filter/ValueSetHistoryIdentityFilter.java | 10 +- ...etaTagAuthorizationRoleIdentityFilter.java | 17 +- .../ActivityDefinitionIdentityFilter.java | 14 +- .../search/filter/BinaryIdentityFilter.java | 14 +- .../search/filter/BundleIdentityFilter.java | 14 +- .../filter/CodeSystemIdentityFilter.java | 14 +- .../DocumentReferenceIdentityFilter.java | 14 +- .../search/filter/EndpointIdentityFilter.java | 14 +- .../search/filter/GroupIdentityFilter.java | 14 +- .../HealthcareServiceIdentityFilter.java | 14 +- .../search/filter/LibraryIdentityFilter.java | 14 +- .../search/filter/LocationIdentityFilter.java | 14 +- .../search/filter/MeasureIdentityFilter.java | 14 +- .../filter/MeasureReportIdentityFilter.java | 14 +- .../filter/NamingSystemIdentityFilter.java | 14 +- ...OrganizationAffiliationIdentityFilter.java | 14 +- .../filter/OrganizationIdentityFilter.java | 14 +- .../search/filter/PatientIdentityFilter.java | 14 +- .../filter/PractitionerIdentityFilter.java | 14 +- .../PractitionerRoleIdentityFilter.java | 14 +- .../filter/ProvenanceIdentityFilter.java | 14 +- .../filter/QuestionnaireIdentityFilter.java | 14 +- .../QuestionnaireResponseIdentityFilter.java | 17 +- .../filter/ResearchStudyIdentityFilter.java | 14 +- .../StructureDefinitionIdentityFilter.java | 14 +- ...ctureDefinitionSnapshotIdentityFilter.java | 14 +- .../filter/SubscriptionIdentityFilter.java | 14 +- .../search/filter/TaskIdentityFilter.java | 20 +- .../search/filter/ValueSetIdentityFilter.java | 14 +- .../fhir/service/InitialDataLoaderImpl.java | 7 +- .../dsf/fhir/service/ReferenceResolver.java | 38 +-- .../fhir/service/ReferenceResolverImpl.java | 61 ++-- .../spring/config/AuthenticationConfig.java | 8 +- .../WebSocketSubscriptionManagerImpl.java | 21 +- .../impl/AbstractResourceServiceImpl.java | 9 +- .../dsf/fhir/websocket/ServerEndpoint.java | 9 +- .../authentication/IdentityProviderTest.java | 46 +-- .../fhir/dao/TestOrganizationIdentity.java | 6 +- .../fhir/integration/TaskIntegrationTest.java | 6 +- 87 files changed, 1216 insertions(+), 584 deletions(-) create mode 100644 dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authentication/FhirServerRoleImpl.java diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/authentication/BpeServerRole.java b/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/authentication/BpeServerRole.java index a2a108d28..aaa63e1ab 100644 --- a/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/authentication/BpeServerRole.java +++ b/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/authentication/BpeServerRole.java @@ -1,15 +1,21 @@ package dev.dsf.bpe.authentication; -import java.util.stream.Stream; - import dev.dsf.common.auth.conf.DsfRole; +import dev.dsf.common.auth.conf.RoleConfig.RoleKeyAndValues; public enum BpeServerRole implements DsfRole { ADMIN; - public static boolean isValid(String role) + public static BpeServerRole from(RoleKeyAndValues role) + { + return role != null && role.key() != null && !role.key().isBlank() && ADMIN.name().equals(role.key()) + && role.values().isEmpty() ? ADMIN : null; + } + + @Override + public boolean matches(DsfRole role) { - return role != null && !role.isBlank() && Stream.of(values()).map(Enum::name).anyMatch(n -> n.equals(role)); + return ADMIN.equals(role); } } diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/authentication/IdentityProviderImpl.java b/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/authentication/IdentityProviderImpl.java index a2dca5b19..db549054a 100644 --- a/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/authentication/IdentityProviderImpl.java +++ b/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/authentication/IdentityProviderImpl.java @@ -18,13 +18,14 @@ import dev.dsf.common.auth.conf.PractitionerIdentityImpl; import dev.dsf.common.auth.conf.RoleConfig; -public class IdentityProviderImpl extends AbstractIdentityProvider implements IdentityProvider, InitializingBean +public class IdentityProviderImpl extends AbstractIdentityProvider + implements IdentityProvider, InitializingBean { private static final Logger logger = LoggerFactory.getLogger(IdentityProviderImpl.class); private final LocalOrganizationAndEndpointProvider organizationAndEndpointProvider; - public IdentityProviderImpl(RoleConfig roleConfig, + public IdentityProviderImpl(RoleConfig roleConfig, LocalOrganizationAndEndpointProvider organizationAndEndpointProvider) { super(roleConfig); diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/spring/config/AuthenticationConfig.java b/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/spring/config/AuthenticationConfig.java index f8f99fca5..4c387ea24 100644 --- a/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/spring/config/AuthenticationConfig.java +++ b/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/spring/config/AuthenticationConfig.java @@ -41,10 +41,10 @@ public IdentityProvider identityProvider() } @Bean - public RoleConfig roleConfig() + public RoleConfig roleConfig() { - RoleConfig config = new RoleConfigReader().read(propertiesConfig.getRoleConfig(), - role -> BpeServerRole.isValid(role) ? BpeServerRole.valueOf(role) : null, _ -> null); + RoleConfig config = new RoleConfigReader().read(propertiesConfig.getRoleConfig(), + BpeServerRole::from, _ -> null); logger.info("Role config: {}", config.toString()); return config; diff --git a/dsf-common/dsf-common-auth/src/main/java/dev/dsf/common/auth/conf/AbstractIdentity.java b/dsf-common/dsf-common-auth/src/main/java/dev/dsf/common/auth/conf/AbstractIdentity.java index f7669279a..670d102a6 100644 --- a/dsf-common/dsf-common-auth/src/main/java/dev/dsf/common/auth/conf/AbstractIdentity.java +++ b/dsf-common/dsf-common-auth/src/main/java/dev/dsf/common/auth/conf/AbstractIdentity.java @@ -87,7 +87,7 @@ public Set getDsfRoles() @Override public boolean hasDsfRole(DsfRole dsfRole) { - return dsfRoles.contains(dsfRole); + return dsfRoles.stream().anyMatch(r -> r.matches(dsfRole)); } @Override diff --git a/dsf-common/dsf-common-auth/src/main/java/dev/dsf/common/auth/conf/AbstractIdentityProvider.java b/dsf-common/dsf-common-auth/src/main/java/dev/dsf/common/auth/conf/AbstractIdentityProvider.java index 46ac636aa..293e93909 100644 --- a/dsf-common/dsf-common-auth/src/main/java/dev/dsf/common/auth/conf/AbstractIdentityProvider.java +++ b/dsf-common/dsf-common-auth/src/main/java/dev/dsf/common/auth/conf/AbstractIdentityProvider.java @@ -41,16 +41,16 @@ import dev.dsf.common.auth.DsfOpenIdCredentials; import dev.dsf.common.auth.conf.RoleConfig.Mapping; -public abstract class AbstractIdentityProvider implements IdentityProvider, InitializingBean +public abstract class AbstractIdentityProvider implements IdentityProvider, InitializingBean { private static final Logger logger = LoggerFactory.getLogger(AbstractIdentityProvider.class); private static final String PRACTITIONER_IDENTIFIER_SYSTEM = "http://dsf.dev/sid/practitioner-identifier"; - private final RoleConfig roleConfig; + private final RoleConfig roleConfig; private final Set thumbprints; - public AbstractIdentityProvider(RoleConfig roleConfig) + public AbstractIdentityProvider(RoleConfig roleConfig) { this.roleConfig = roleConfig; @@ -81,7 +81,7 @@ public final Identity getIdentity(DsfOpenIdCredentials credentials) List rolesFromTokens = getRolesFromTokens(parsedIdToken, parsedAccessToken); List groupsFromTokens = getGroupsFromTokens(parsedIdToken, parsedAccessToken); - Set dsfRoles = getDsfRolesFor(practitioner.get(), null, rolesFromTokens, groupsFromTokens); + Set dsfRoles = getDsfRolesFor(practitioner.get(), null, rolesFromTokens, groupsFromTokens); Set practitionerRoles = getPractitionerRolesFor(practitioner.get(), null, rolesFromTokens, groupsFromTokens); @@ -187,19 +187,18 @@ private List getPropertyArray(Map map, String property) } // thumbprint from certificate, token roles and groups from jwt - protected final Set getDsfRolesFor(Practitioner practitioner, String thumbprint, List tokenRoles, + protected final Set getDsfRolesFor(Practitioner practitioner, String thumbprint, List tokenRoles, List tokenGroups) { List emailAddresses = practitioner.getIdentifier().stream() .filter(i -> PRACTITIONER_IDENTIFIER_SYSTEM.equals(i.getSystem()) && i.hasValue()) .map(Identifier::getValue).toList(); - Stream r1 = emailAddresses.stream().map(roleConfig::getDsfRolesForEmail).flatMap(List::stream); - Stream r2 = thumbprint == null ? Stream.empty() - : roleConfig.getDsfRolesForThumbprint(thumbprint).stream(); - Stream r3 = tokenRoles == null ? Stream.empty() + Stream r1 = emailAddresses.stream().map(roleConfig::getDsfRolesForEmail).flatMap(List::stream); + Stream r2 = thumbprint == null ? Stream.empty() : roleConfig.getDsfRolesForThumbprint(thumbprint).stream(); + Stream r3 = tokenRoles == null ? Stream.empty() : tokenRoles.stream().map(roleConfig::getDsfRolesForTokenRole).flatMap(List::stream); - Stream r4 = tokenGroups == null ? Stream.empty() + Stream r4 = tokenGroups == null ? Stream.empty() : tokenGroups.stream().map(roleConfig::getDsfRolesForTokenGroup).flatMap(List::stream); return Stream.of(r1, r2, r3, r4).flatMap(Function.identity()).distinct().collect(Collectors.toSet()); diff --git a/dsf-common/dsf-common-auth/src/main/java/dev/dsf/common/auth/conf/DsfRole.java b/dsf-common/dsf-common-auth/src/main/java/dev/dsf/common/auth/conf/DsfRole.java index 409e3f796..aa143409a 100644 --- a/dsf-common/dsf-common-auth/src/main/java/dev/dsf/common/auth/conf/DsfRole.java +++ b/dsf-common/dsf-common-auth/src/main/java/dev/dsf/common/auth/conf/DsfRole.java @@ -3,4 +3,11 @@ public interface DsfRole { String name(); + + /** + * @param role + * may be null + * @return true if same or superset of given role + */ + boolean matches(DsfRole role); } diff --git a/dsf-common/dsf-common-auth/src/main/java/dev/dsf/common/auth/conf/RoleConfig.java b/dsf-common/dsf-common-auth/src/main/java/dev/dsf/common/auth/conf/RoleConfig.java index 34cbf419e..399a05b63 100644 --- a/dsf-common/dsf-common-auth/src/main/java/dev/dsf/common/auth/conf/RoleConfig.java +++ b/dsf-common/dsf-common-auth/src/main/java/dev/dsf/common/auth/conf/RoleConfig.java @@ -14,7 +14,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class RoleConfig +public class RoleConfig { private static final Logger logger = LoggerFactory.getLogger(RoleConfig.class); @@ -34,7 +34,7 @@ public class RoleConfig private static final String EMAIL_PATTERN_STRING = "^[\\w!#$%&'*+/=?`{\\|}~^-]+(?:\\.[\\w!#$%&'*+/=?`{\\|}~^-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,6}$"; private static final Pattern EMAIL_PATTERN = Pattern.compile(EMAIL_PATTERN_STRING); - public static final class Mapping + public static final class Mapping { private final String name; @@ -43,11 +43,11 @@ public static final class Mapping private final List tokenRoles = new ArrayList<>(); private final List tokenGroups = new ArrayList<>(); - private final List dsfRoles = new ArrayList<>(); + private final List dsfRoles = new ArrayList<>(); private final List practitionerRoles = new ArrayList<>(); public Mapping(String name, List thumbprints, List emails, List tokenRoles, - List tokenGroups, List dsfRoles, List practitionerRoles) + List tokenGroups, List dsfRoles, List practitionerRoles) { this.name = name; @@ -91,7 +91,7 @@ public List getTokenGroups() return Collections.unmodifiableList(tokenGroups); } - public List getDsfRoles() + public List getDsfRoles() { return Collections.unmodifiableList(dsfRoles); } @@ -112,21 +112,40 @@ public String toString() } } - private final List entries = new ArrayList<>(); + public static record RoleKeyAndValues(String key, List values) + { + public RoleKeyAndValues(String key) + { + this(key, List.of()); + } + } + + public static interface DsfRoleFactory + { + /** + * @param roleKeyAndValues + * not null + * @return null if no role exists for the given key and values + */ + R create(RoleKeyAndValues roleKeyAndValues); + } + + private final List> entries = new ArrayList<>(); /** * @param config * parsed yaml * @param dsfRoleFactory - * factory should return null if the given string does not represent a valid role, the role - * needs to exists + * not null * @param practitionerRoleFactory - * factory should return null if the given string does not represent a valid code, the code - * or CodeSystem does not need to exist + * not null, factory should return null if the given string does not represent + * a valid code, the code or CodeSystem does not need to exist */ - public RoleConfig(Object config, Function dsfRoleFactory, - Function practitionerRoleFactory) + public RoleConfig(Object config, DsfRoleFactory dsfRoleFactory, Function practitionerRoleFactory) { + Objects.requireNonNull(dsfRoleFactory, "dsfRoleFactory"); + Objects.requireNonNull(practitionerRoleFactory, "practitionerRoleFactory"); + if (config != null && config instanceof List l) { l.forEach(mapping -> @@ -139,7 +158,7 @@ public RoleConfig(Object config, Function dsfRoleFactory, && mappingValues instanceof Map v) { List thumbprints = null, emails = null, tokenRoles = null, tokenGroups = null; - List dsfRoles = null; + List dsfRoles = null; List practitionerRoles = null; for (Entry property : v.entrySet()) @@ -153,7 +172,7 @@ public RoleConfig(Object config, Function dsfRoleFactory, { if (value == null || value.isBlank()) { - logger.warn("Ignoring empty of blank thumbprint in rule '{}'", + logger.warn("Ignoring empty or blank thumbprint in rule '{}'", mappingKey); return null; } @@ -166,7 +185,7 @@ else if (!THUMBPRINT_PATTERN.matcher(value.trim()).matches()) } else return value.trim(); - }).filter(g -> g != null).toList(); + }).filter(Objects::nonNull).toList(); break; case PROPERTY_EMAIL: @@ -174,7 +193,7 @@ else if (!THUMBPRINT_PATTERN.matcher(value.trim()).matches()) { if (value == null || value.isBlank()) { - logger.warn("Ignoring empty of blank email in rule '{}'", + logger.warn("Ignoring empty or blank email in rule '{}'", mappingKey); return null; } @@ -187,7 +206,7 @@ else if (!EMAIL_PATTERN.matcher(value.trim()).matches()) } else return value.trim(); - }).filter(g -> g != null).toList(); + }).filter(Objects::nonNull).toList(); break; case PROPERTY_TOKEN_ROLE: @@ -195,13 +214,13 @@ else if (!EMAIL_PATTERN.matcher(value.trim()).matches()) { if (value == null || value.isBlank()) { - logger.warn("Ignoring empty of blank token-role in rule '{}'", + logger.warn("Ignoring empty or blank token-role in rule '{}'", mappingKey); return null; } else return value.trim(); - }).filter(g -> g != null).toList(); + }).filter(Objects::nonNull).toList(); break; case PROPERTY_TOKEN_GROUP: @@ -209,32 +228,33 @@ else if (!EMAIL_PATTERN.matcher(value.trim()).matches()) { if (value == null || value.isBlank()) { - logger.warn("Ignoring empty of blank token-group in rule '{}'", + logger.warn("Ignoring empty or blank token-group in rule '{}'", mappingKey); return null; } else return value.trim(); - }).filter(g -> g != null).toList(); + }).filter(Objects::nonNull).toList(); break; case PROPERTY_DSF_ROLE: - dsfRoles = getValues(property.getValue()).stream().map(value -> + dsfRoles = getRoleKeyAndValues(property.getValue()).stream().map(value -> { - if (value == null || value.isBlank()) + if (value == null || value.key().isBlank()) { - logger.warn("Ignoring empty of blank dsf-role in rule '{}'", + logger.warn("Ignoring empty or blank dsf-role in rule '{}'", mappingKey); return null; } - DsfRole dsfRole = dsfRoleFactory.apply(value.trim()); + R dsfRole = dsfRoleFactory.create(value); if (dsfRole == null) - logger.warn("Unknown dsf-role '{}', ignoring value in rule '{}'", - value, mappingKey); + logger.warn( + "Unknown or malformed dsf-role '{}', ignoring value in rule '{}'", + value.key(), mappingKey); return dsfRole; - }).filter(r -> r != null).toList(); + }).filter(Objects::nonNull).toList(); break; case PROPERTY_PRACTITIONER_ROLE: @@ -255,7 +275,7 @@ else if (!EMAIL_PATTERN.matcher(value.trim()).matches()) value, mappingKey); return coding; - }).filter(r -> r != null).toList(); + }).filter(Objects::nonNull).toList(); break; default: @@ -266,14 +286,12 @@ else if (!EMAIL_PATTERN.matcher(value.trim()).matches()) } } - entries.add(new Mapping((String) mappingKey, thumbprints, emails, tokenRoles, tokenGroups, - dsfRoles, practitionerRoles)); + entries.add(new Mapping((String) mappingKey, thumbprints, emails, tokenRoles, + tokenGroups, dsfRoles, practitionerRoles)); } else if (mappingKey != null && mappingKey instanceof String && (mappingValues == null || !(mappingValues instanceof Map))) - { logger.warn("Ignoring invalid rule '{}', no value specified or value not map", mappingKey); - } else logger.warn("Ignoring invalid rule '{}'", Objects.toString(mappingKey)); }); @@ -284,46 +302,74 @@ else if (mappingKey != null && mappingKey instanceof String } } - @SuppressWarnings("unchecked") - private static List getValues(Object o) + private List getValues(Object o) { return switch (o) { case String s -> List.of(s); - case @SuppressWarnings("rawtypes") List l -> l; + case List l -> l.stream().filter(v -> v instanceof String).map(v -> (String) v).toList(); default -> List.of(); }; } - public List getEntries() + private List getRoleKeyAndValues(Object o) + { + return switch (o) + { + case String s -> List.of(new RoleKeyAndValues(s)); + case List l -> getRoleKeyAndValuesFromList(l); + default -> List.of(); + }; + } + + private List getRoleKeyAndValuesFromList(List l) + { + return l.stream().map(v -> switch (v) + { + case String s -> new RoleKeyAndValues(s); + case Map m when m.size() == 1 -> getRoleKeyAndValuesFromMap(m); + default -> null; + }).filter(Objects::nonNull).toList(); + } + + private RoleKeyAndValues getRoleKeyAndValuesFromMap(Map m) + { + return m.entrySet().stream().findFirst().filter(e -> e.getKey() instanceof String) + .filter(e -> e.getValue() instanceof List l && l.stream().allMatch(v -> v instanceof String)) + .map(e -> new RoleKeyAndValues((String) e.getKey(), ((List) e.getValue()).stream() + .filter(v -> v instanceof String).map(v -> (String) v).toList())) + .orElse(null); + } + + public List> getEntries() { return Collections.unmodifiableList(entries); } - public List getDsfRolesForThumbprint(String thumbprint) + public List getDsfRolesForThumbprint(String thumbprint) { return getDsfRoleFor(Mapping::getThumbprints, thumbprint); } - public List getDsfRolesForEmail(String email) + public List getDsfRolesForEmail(String email) { return getDsfRoleFor(Mapping::getEmails, email); } - public List getDsfRolesForTokenRole(String tokenRole) + public List getDsfRolesForTokenRole(String tokenRole) { return getDsfRoleFor(Mapping::getTokenRoles, tokenRole); } - public List getDsfRolesForTokenGroup(String tokenGroup) + public List getDsfRolesForTokenGroup(String tokenGroup) { return getDsfRoleFor(Mapping::getTokenGroups, tokenGroup); } - private List getDsfRoleFor(Function> values, String value) + private List getDsfRoleFor(Function, List> values, String value) { - return getEntries().stream().filter(m -> values.apply(m).contains(value)).flatMap(m -> m.getDsfRoles().stream()) - .toList(); + return getEntries().stream().filter(m -> values.apply(m).contains(value)).map(Mapping::getDsfRoles) + .flatMap(List::stream).toList(); } public List getPractitionerRolesForThumbprint(String thumbprint) @@ -346,10 +392,10 @@ public List getPractitionerRolesForTokenGroup(String tokenGroup) return getPractitionerRoleFor(Mapping::getTokenGroups, tokenGroup); } - private List getPractitionerRoleFor(Function> values, String value) + private List getPractitionerRoleFor(Function, List> values, String value) { - return getEntries().stream().filter(m -> values.apply(m).contains(value)) - .flatMap(m -> m.getPractitionerRoles().stream()).toList(); + return getEntries().stream().filter(m -> values.apply(m).contains(value)).map(Mapping::getPractitionerRoles) + .flatMap(List::stream).toList(); } @Override diff --git a/dsf-common/dsf-common-auth/src/main/java/dev/dsf/common/auth/conf/RoleConfigReader.java b/dsf-common/dsf-common-auth/src/main/java/dev/dsf/common/auth/conf/RoleConfigReader.java index 656063823..510eac4f1 100644 --- a/dsf-common/dsf-common-auth/src/main/java/dev/dsf/common/auth/conf/RoleConfigReader.java +++ b/dsf-common/dsf-common-auth/src/main/java/dev/dsf/common/auth/conf/RoleConfigReader.java @@ -7,9 +7,11 @@ import org.hl7.fhir.r4.model.Coding; import org.yaml.snakeyaml.Yaml; +import dev.dsf.common.auth.conf.RoleConfig.DsfRoleFactory; + public class RoleConfigReader { - public RoleConfig read(String config, Function dsfRoleFactory, + public RoleConfig read(String config, DsfRoleFactory dsfRoleFactory, Function practitionerRoleFactory) { Objects.requireNonNull(config, "config"); @@ -17,10 +19,10 @@ public RoleConfig read(String config, Function dsfRoleFactory, Objects.requireNonNull(practitionerRoleFactory, "practitionerRoleFactory"); Object o = yaml().load(config); - return new RoleConfig(o, dsfRoleFactory, practitionerRoleFactory); + return new RoleConfig(o, dsfRoleFactory, practitionerRoleFactory); } - public RoleConfig read(InputStream config, Function dsfRoleFactory, + public RoleConfig read(InputStream config, DsfRoleFactory dsfRoleFactory, Function practitionerRoleFactory) { Objects.requireNonNull(config, "config"); @@ -28,7 +30,7 @@ public RoleConfig read(InputStream config, Function dsfRoleFact Objects.requireNonNull(practitionerRoleFactory, "practitionerRoleFactory"); Object o = yaml().load(config); - return new RoleConfig(o, dsfRoleFactory, practitionerRoleFactory); + return new RoleConfig(o, dsfRoleFactory, practitionerRoleFactory); } protected Yaml yaml() diff --git a/dsf-common/dsf-common-auth/src/test/java/dev/dsf/common/auth/RoleConfigTest.java b/dsf-common/dsf-common-auth/src/test/java/dev/dsf/common/auth/RoleConfigTest.java index 3e5018b08..1eb7675e2 100644 --- a/dsf-common/dsf-common-auth/src/test/java/dev/dsf/common/auth/RoleConfigTest.java +++ b/dsf-common/dsf-common-auth/src/test/java/dev/dsf/common/auth/RoleConfigTest.java @@ -5,8 +5,8 @@ import static org.junit.Assert.assertTrue; import java.util.List; +import java.util.Set; import java.util.function.Function; -import java.util.stream.Stream; import org.hl7.fhir.r4.model.Coding; import org.junit.Test; @@ -17,18 +17,35 @@ import dev.dsf.common.auth.conf.DsfRole; import dev.dsf.common.auth.conf.RoleConfig; import dev.dsf.common.auth.conf.RoleConfig.Mapping; +import dev.dsf.common.auth.conf.RoleConfig.RoleKeyAndValues; public class RoleConfigTest { private static final Logger logger = LoggerFactory.getLogger(RoleConfigTest.class); - private static enum TestRole implements DsfRole + private static interface TestRole extends DsfRole { - foo, bar, baz; + List resourceTypes(); + } + + private static record TestRoleImpl(String name, List resourceTypes) implements TestRole + { + private static final Set VALID_ROLES = Set.of("foo", "bar", "baz"); + private static final Set VALID_RESOURCES = Set.of("Task", "QuestionnaireResponse"); - public static boolean isValid(String s) + public static TestRoleImpl create(RoleKeyAndValues keyAndValues) { - return Stream.of(values()).map(Enum::name).anyMatch(n -> n.equals(s)); + if (VALID_ROLES.contains(keyAndValues.key()) + && keyAndValues.values().stream().allMatch(VALID_RESOURCES::contains)) + return new TestRoleImpl(keyAndValues.key(), keyAndValues.values()); + else + return null; + } + + @Override + public boolean matches(DsfRole role) + { + return false; } } @@ -58,7 +75,7 @@ public void testRead() throws Exception email: someone@test.com dsf-role: - foo - - bar + - bar: [Task, QuestionnaireResponse] - invalid practitioner-role: http://test.org/fhir/CodeSystem/foo|bar - test2: @@ -88,8 +105,8 @@ public void testRead() throws Exception return null; }; - RoleConfig roles = new RoleConfig(new Yaml().load(document), - s -> TestRole.isValid(s) ? TestRole.valueOf(s) : null, practitionerRoleFactory); + RoleConfig roles = new RoleConfig(new Yaml().load(document), TestRoleImpl::create, + practitionerRoleFactory); roles.getEntries().forEach(e -> logger.debug(e.toString())); assertNotNull(roles.getEntries()); @@ -97,24 +114,28 @@ public void testRead() throws Exception assertMapping("foo", List.of( "f7f9ef095c5c246d3e8149729221e668b6ffd9a117fe23e2687658f6a203d31a0e769fb20dc2af6361306717116c700c5905a895a7311057af461c5d78a257b5"), - List.of(), List.of(), List.of(), List.of(TestRole.foo, TestRole.bar, TestRole.baz), List.of(), - roles.getEntries().get(0)); + List.of(), List.of(), List.of(), List.of(new TestRoleImpl("foo", List.of()), + new TestRoleImpl("bar", List.of()), new TestRoleImpl("baz", List.of())), + List.of(), roles.getEntries().get(0)); assertMapping("bar", List.of( "2d259cc15ee2fe57bc11e1322040ee9e045dd3efb83ed1cb0f393c3bdfecaf3f6506e5573fbc213a1025a7c3dfef101fc8d85ab069e5662d666ea970c7e0cbb6", "b52a8b63b030181b8b6bc9ca1e47279da4842ef7ab46c08de6c5713a4e8ecc2c1d7f8cd5c17fe4eb0fe43838ee4b020a88634ea47c520dcc7f5f966b66e69190"), - List.of("one@test.com", "two@test.com"), List.of(), List.of(), List.of(TestRole.foo, TestRole.baz), - List.of(), roles.getEntries().get(1)); + List.of("one@test.com", "two@test.com"), List.of(), List.of(), + List.of(new TestRoleImpl("foo", List.of()), new TestRoleImpl("baz", List.of())), List.of(), + roles.getEntries().get(1)); assertMapping("test1", List.of(), List.of("someone@test.com"), List.of(), List.of(), - List.of(TestRole.foo, TestRole.bar), + List.of(new TestRoleImpl("foo", List.of()), + new TestRoleImpl("bar", List.of("Task", "QuestionnaireResponse"))), List.of(new Coding().setSystem("http://test.org/fhir/CodeSystem/foo").setCode("bar")), roles.getEntries().get(2)); - assertMapping("test2", List.of(), List.of(), List.of("claim_a", "claim_b"), List.of(), List.of(TestRole.foo), - List.of(), roles.getEntries().get(3)); + assertMapping("test2", List.of(), List.of(), List.of("claim_a", "claim_b"), List.of(), + List.of(new TestRoleImpl("foo", List.of())), List.of(), roles.getEntries().get(3)); - assertMapping("test3", List.of(), List.of(), List.of(), List.of("group1"), List.of(TestRole.foo), + assertMapping("test3", List.of(), List.of(), List.of(), List.of("group1"), + List.of(new TestRoleImpl("foo", List.of())), List.of(new Coding().setSystem("http://test.org/fhir/CodeSystem/foo").setCode("bar"), new Coding().setSystem("http://test.org/fhir/CodeSystem/foo").setCode("baz")), roles.getEntries().get(4)); @@ -122,7 +143,7 @@ public void testRead() throws Exception private void assertMapping(String expectedName, List expectedThumbprints, List expectedEmails, List expectedTokenRoles, List expectedTokenGroups, List expectedDsfRoles, - List expectedPractionerRole, Mapping actual) + List expectedPractionerRole, Mapping actual) { assertNotNull(actual); assertEquals(expectedName, actual.getName()); diff --git a/dsf-docker-test-setup-3dic-ttp/docker-compose.yml b/dsf-docker-test-setup-3dic-ttp/docker-compose.yml index 917c85c5b..a89155913 100644 --- a/dsf-docker-test-setup-3dic-ttp/docker-compose.yml +++ b/dsf-docker-test-setup-3dic-ttp/docker-compose.yml @@ -171,13 +171,11 @@ services: thumbprint: ${WEBBROWSER_TEST_USER_THUMBPRINT} token-role: admin dsf-role: - - CREATE + - CREATE: [Task] - READ - - UPDATE - - DELETE + - UPDATE: [QuestionnaireResponse] - SEARCH - HISTORY - - PERMANENT_DELETE practitioner-role: - http://dsf.dev/fhir/CodeSystem/practitioner-role|DSF_ADMIN - bpe-oidc-auth-client: @@ -260,13 +258,13 @@ services: thumbprint: ${WEBBROWSER_TEST_USER_THUMBPRINT} token-role: admin dsf-role: - - CREATE + - CREATE: + - Task - READ - - UPDATE - - DELETE + - UPDATE: + - QuestionnaireResponse - SEARCH - HISTORY - - PERMANENT_DELETE practitioner-role: - http://dsf.dev/fhir/CodeSystem/practitioner-role|DSF_ADMIN DEV_DSF_SERVER_AUTH_TRUST_CLIENT_CERTIFICATE_CAS: /run/secrets/ca_chain.crt @@ -342,13 +340,11 @@ services: thumbprint: ${WEBBROWSER_TEST_USER_THUMBPRINT} token-role: admin dsf-role: - - CREATE + - CREATE: [Task] - READ - - UPDATE - - DELETE + - UPDATE: [QuestionnaireResponse] - SEARCH - HISTORY - - PERMANENT_DELETE practitioner-role: - http://dsf.dev/fhir/CodeSystem/practitioner-role|DSF_ADMIN DEV_DSF_SERVER_AUTH_TRUST_CLIENT_CERTIFICATE_CAS: /run/secrets/ca_chain.crt @@ -431,13 +427,11 @@ services: thumbprint: ${WEBBROWSER_TEST_USER_THUMBPRINT} token-role: admin dsf-role: - - CREATE + - CREATE: [Task] - READ - - UPDATE - - DELETE + - UPDATE: [QuestionnaireResponse] - SEARCH - HISTORY - - PERMANENT_DELETE practitioner-role: - http://dsf.dev/fhir/CodeSystem/practitioner-role|DSF_ADMIN DEV_DSF_SERVER_AUTH_TRUST_CLIENT_CERTIFICATE_CAS: /run/secrets/ca_chain.crt diff --git a/dsf-docker-test-setup/fhir/docker-compose.yml b/dsf-docker-test-setup/fhir/docker-compose.yml index df9efa838..0fc5f7176 100755 --- a/dsf-docker-test-setup/fhir/docker-compose.yml +++ b/dsf-docker-test-setup/fhir/docker-compose.yml @@ -73,13 +73,11 @@ services: - webbrowser_test_user: thumbprint: ${WEBBROWSER_TEST_USER_THUMBPRINT} dsf-role: - - CREATE + - CREATE: [Task] - READ - - UPDATE - - DELETE + - UPDATE: [QuestionnaireResponse] - SEARCH - HISTORY - - PERMANENT_DELETE practitioner-role: - http://dsf.dev/fhir/CodeSystem/practitioner-role|DSF_ADMIN DEV_DSF_SERVER_AUTH_TRUST_CLIENT_CERTIFICATE_CAS: /run/secrets/ca_chain.crt diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authentication/FhirServerRole.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authentication/FhirServerRole.java index f811fe70c..eb5fa1aa7 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authentication/FhirServerRole.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authentication/FhirServerRole.java @@ -1,22 +1,12 @@ package dev.dsf.fhir.authentication; -import java.util.EnumSet; -import java.util.Set; -import java.util.stream.Stream; +import java.util.List; + +import org.hl7.fhir.r4.model.ResourceType; import dev.dsf.common.auth.conf.DsfRole; -public enum FhirServerRole implements DsfRole +public interface FhirServerRole extends DsfRole { - CREATE, READ, UPDATE, DELETE, SEARCH, HISTORY, PERMANENT_DELETE, WEBSOCKET; - - public static final Set LOCAL_ORGANIZATION = EnumSet.of(CREATE, READ, UPDATE, DELETE, SEARCH, - HISTORY, PERMANENT_DELETE, WEBSOCKET); - public static final Set REMOTE_ORGANIZATION = EnumSet.of(CREATE, READ, UPDATE, DELETE, SEARCH, - HISTORY); - - public static boolean isValid(String role) - { - return role != null && !role.isBlank() && Stream.of(values()).map(Enum::name).anyMatch(n -> n.equals(role)); - } + List resourceTypes(); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authentication/FhirServerRoleImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authentication/FhirServerRoleImpl.java new file mode 100644 index 000000000..2b829d4b8 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authentication/FhirServerRoleImpl.java @@ -0,0 +1,267 @@ +package dev.dsf.fhir.authentication; + +import static dev.dsf.fhir.authentication.FhirServerRoleImpl.Operation.CREATE; +import static dev.dsf.fhir.authentication.FhirServerRoleImpl.Operation.DELETE; +import static dev.dsf.fhir.authentication.FhirServerRoleImpl.Operation.HISTORY; +import static dev.dsf.fhir.authentication.FhirServerRoleImpl.Operation.PERMANENT_DELETE; +import static dev.dsf.fhir.authentication.FhirServerRoleImpl.Operation.READ; +import static dev.dsf.fhir.authentication.FhirServerRoleImpl.Operation.SEARCH; +import static dev.dsf.fhir.authentication.FhirServerRoleImpl.Operation.UPDATE; +import static dev.dsf.fhir.authentication.FhirServerRoleImpl.Operation.WEBSOCKET; + +import java.util.EnumSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.hl7.fhir.r4.model.ActivityDefinition; +import org.hl7.fhir.r4.model.Binary; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.CodeSystem; +import org.hl7.fhir.r4.model.DocumentReference; +import org.hl7.fhir.r4.model.Endpoint; +import org.hl7.fhir.r4.model.Group; +import org.hl7.fhir.r4.model.HealthcareService; +import org.hl7.fhir.r4.model.Library; +import org.hl7.fhir.r4.model.Location; +import org.hl7.fhir.r4.model.Measure; +import org.hl7.fhir.r4.model.MeasureReport; +import org.hl7.fhir.r4.model.NamingSystem; +import org.hl7.fhir.r4.model.Organization; +import org.hl7.fhir.r4.model.OrganizationAffiliation; +import org.hl7.fhir.r4.model.Patient; +import org.hl7.fhir.r4.model.Practitioner; +import org.hl7.fhir.r4.model.PractitionerRole; +import org.hl7.fhir.r4.model.Provenance; +import org.hl7.fhir.r4.model.Questionnaire; +import org.hl7.fhir.r4.model.QuestionnaireResponse; +import org.hl7.fhir.r4.model.ResearchStudy; +import org.hl7.fhir.r4.model.Resource; +import org.hl7.fhir.r4.model.ResourceType; +import org.hl7.fhir.r4.model.StructureDefinition; +import org.hl7.fhir.r4.model.Subscription; +import org.hl7.fhir.r4.model.Task; +import org.hl7.fhir.r4.model.ValueSet; + +import dev.dsf.common.auth.conf.DsfRole; +import dev.dsf.common.auth.conf.RoleConfig.RoleKeyAndValues; + +public record FhirServerRoleImpl(Operation operation, List resourceTypes) implements FhirServerRole +{ + public static enum Operation + { + CREATE, READ, UPDATE, DELETE, SEARCH, HISTORY, PERMANENT_DELETE, WEBSOCKET; + + public FhirServerRole toFhirServerRoleAllResources() + { + return new FhirServerRoleImpl(this); + } + + public static boolean isValid(String operation) + { + return operation != null && !operation.isBlank() + && Stream.of(Operation.values()).map(Enum::name).anyMatch(n -> n.equals(operation)); + } + } + + public static final Set LOCAL_ORGANIZATION = EnumSet + .of(CREATE, READ, UPDATE, DELETE, SEARCH, HISTORY, PERMANENT_DELETE, WEBSOCKET).stream() + .map(Operation::toFhirServerRoleAllResources).collect(Collectors.toSet()); + + public static final Set REMOTE_ORGANIZATION = EnumSet + .of(CREATE, READ, UPDATE, DELETE, SEARCH, HISTORY).stream().map(Operation::toFhirServerRoleAllResources) + .collect(Collectors.toSet()); + + public static final Set INITIAL_DATA_LOADER = EnumSet.of(CREATE, DELETE, UPDATE).stream() + .map(Operation::toFhirServerRoleAllResources).collect(Collectors.toSet()); + + private static ResourceType forResourceClass(Class resourceClass) + { + if (ActivityDefinition.class.equals(resourceClass)) + return ResourceType.ActivityDefinition; + else if (Binary.class.equals(resourceClass)) + return ResourceType.Binary; + else if (Bundle.class.equals(resourceClass)) + return ResourceType.Bundle; + else if (CodeSystem.class.equals(resourceClass)) + return ResourceType.CodeSystem; + else if (DocumentReference.class.equals(resourceClass)) + return ResourceType.DocumentReference; + else if (Endpoint.class.equals(resourceClass)) + return ResourceType.Endpoint; + else if (Group.class.equals(resourceClass)) + return ResourceType.Group; + else if (HealthcareService.class.equals(resourceClass)) + return ResourceType.HealthcareService; + else if (Library.class.equals(resourceClass)) + return ResourceType.Library; + else if (Location.class.equals(resourceClass)) + return ResourceType.Location; + else if (Measure.class.equals(resourceClass)) + return ResourceType.Measure; + else if (MeasureReport.class.equals(resourceClass)) + return ResourceType.MeasureReport; + else if (NamingSystem.class.equals(resourceClass)) + return ResourceType.NamingSystem; + else if (OrganizationAffiliation.class.equals(resourceClass)) + return ResourceType.OrganizationAffiliation; + else if (Organization.class.equals(resourceClass)) + return ResourceType.Organization; + else if (Patient.class.equals(resourceClass)) + return ResourceType.Patient; + else if (Practitioner.class.equals(resourceClass)) + return ResourceType.Practitioner; + else if (PractitionerRole.class.equals(resourceClass)) + return ResourceType.PractitionerRole; + else if (Provenance.class.equals(resourceClass)) + return ResourceType.Provenance; + else if (Questionnaire.class.equals(resourceClass)) + return ResourceType.Questionnaire; + else if (QuestionnaireResponse.class.equals(resourceClass)) + return ResourceType.QuestionnaireResponse; + else if (ResearchStudy.class.equals(resourceClass)) + return ResourceType.ResearchStudy; + else if (StructureDefinition.class.equals(resourceClass)) + return ResourceType.StructureDefinition; + else if (Subscription.class.equals(resourceClass)) + return ResourceType.Subscription; + else if (Task.class.equals(resourceClass)) + return ResourceType.Task; + else if (ValueSet.class.equals(resourceClass)) + return ResourceType.ValueSet; + else + throw new IllegalArgumentException("Resource class '" + resourceClass.getName() + "' not supported"); + } + + public static FhirServerRole create(Class resourceClass) + { + return new FhirServerRoleImpl(CREATE, forResourceClass(resourceClass)); + } + + public static FhirServerRole read(Class resourceClass) + { + return read(forResourceClass(resourceClass)); + } + + public static FhirServerRole read(ResourceType resourceType) + { + return new FhirServerRoleImpl(READ, resourceType); + } + + public static FhirServerRole update(Class resourceClass) + { + return new FhirServerRoleImpl(UPDATE, forResourceClass(resourceClass)); + } + + public static FhirServerRole delete(Class resourceClass) + { + return new FhirServerRoleImpl(DELETE, forResourceClass(resourceClass)); + } + + public static FhirServerRole search(Class resourceClass) + { + return search(forResourceClass(resourceClass)); + } + + public static FhirServerRole search(ResourceType resourceType) + { + return new FhirServerRoleImpl(SEARCH, resourceType); + } + + public static FhirServerRole history(Class resourceClass) + { + return history(forResourceClass(resourceClass)); + } + + public static FhirServerRole history(ResourceType resourceType) + { + return new FhirServerRoleImpl(HISTORY, resourceType); + } + + public static FhirServerRole permanentDelete(Class resourceClass) + { + return permanentDelete(forResourceClass(resourceClass)); + } + + public static FhirServerRole permanentDelete(ResourceType resourceType) + { + return new FhirServerRoleImpl(PERMANENT_DELETE, resourceType); + } + + public static FhirServerRole websocket(Class resourceClass) + { + return new FhirServerRoleImpl(WEBSOCKET, forResourceClass(resourceClass)); + } + + private static final Set SUPPORTED_RESOURCES = Set.of(ResourceType.ActivityDefinition, ResourceType.Binary, + ResourceType.Bundle, ResourceType.CodeSystem, ResourceType.DocumentReference, ResourceType.Endpoint, + ResourceType.Group, ResourceType.HealthcareService, ResourceType.Library, ResourceType.Location, + ResourceType.Measure, ResourceType.MeasureReport, ResourceType.NamingSystem, + ResourceType.OrganizationAffiliation, ResourceType.Organization, ResourceType.Patient, + ResourceType.Practitioner, ResourceType.PractitionerRole, ResourceType.Provenance, + ResourceType.Questionnaire, ResourceType.QuestionnaireResponse, ResourceType.ResearchStudy, + ResourceType.StructureDefinition, ResourceType.Task, ResourceType.ValueSet).stream().map(Enum::name) + .collect(Collectors.toSet()); + + private static boolean isSupportedResource(String resource) + { + return resource != null && !resource.isBlank() && SUPPORTED_RESOURCES.contains(resource); + } + + public static FhirServerRoleImpl from(RoleKeyAndValues keyAndValues) + { + if (Operation.isValid(keyAndValues.key()) + && keyAndValues.values().stream().allMatch(FhirServerRoleImpl::isSupportedResource)) + { + Operation operation = Operation.valueOf(keyAndValues.key()); + List resourceTypes = keyAndValues.values().stream().map(ResourceType::valueOf).toList(); + + return new FhirServerRoleImpl(operation, resourceTypes); + } + else + return null; + } + + public FhirServerRoleImpl(Operation operation, List resourceTypes) + { + Objects.requireNonNull(operation, "operation"); + Objects.requireNonNull(resourceTypes, "resourceTypes"); + + this.operation = operation; + this.resourceTypes = resourceTypes; + } + + public FhirServerRoleImpl(Operation operation, ResourceType... resourceTypes) + { + this(operation, List.of(resourceTypes)); + } + + @Override + public String name() + { + return operation.name(); + } + + @Override + public boolean matches(DsfRole role) + { + if (this == role) + return true; + + return role instanceof FhirServerRoleImpl i + ? operation == i.operation && (resourceTypes.isEmpty() || resourceTypes.containsAll(i.resourceTypes)) + : false; + } + + @Override + public String toString() + { + if (!resourceTypes.isEmpty()) + return operation.name() + " " + + resourceTypes.stream().map(ResourceType::name).collect(Collectors.joining(", ", "[", "]")); + else + return operation.name(); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authentication/IdentityProviderImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authentication/IdentityProviderImpl.java index 93d683fdf..de64c9723 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authentication/IdentityProviderImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authentication/IdentityProviderImpl.java @@ -19,7 +19,8 @@ import dev.dsf.common.auth.conf.PractitionerIdentityImpl; import dev.dsf.common.auth.conf.RoleConfig; -public class IdentityProviderImpl extends AbstractIdentityProvider implements IdentityProvider, InitializingBean +public class IdentityProviderImpl extends AbstractIdentityProvider + implements IdentityProvider, InitializingBean { private static final Logger logger = LoggerFactory.getLogger(IdentityProviderImpl.class); @@ -27,7 +28,7 @@ public class IdentityProviderImpl extends AbstractIdentityProvider implements Id private final EndpointProvider endpointProvider; private final String localOrganizationIdentifierValue; - public IdentityProviderImpl(RoleConfig roleConfig, OrganizationProvider organizationProvider, + public IdentityProviderImpl(RoleConfig roleConfig, OrganizationProvider organizationProvider, EndpointProvider endpointProvider, String localOrganizationIdentifierValue) { super(roleConfig); @@ -73,7 +74,8 @@ public Identity getIdentity(X509Certificate[] certificates) boolean local = isLocalOrganization(o); Optional e = local ? getLocalEndpoint() : endpointProvider.getEndpoint(o, certificates[0]); - Set r = local ? FhirServerRole.LOCAL_ORGANIZATION : FhirServerRole.REMOTE_ORGANIZATION; + Set r = local ? FhirServerRoleImpl.LOCAL_ORGANIZATION + : FhirServerRoleImpl.REMOTE_ORGANIZATION; return new OrganizationIdentityImpl(local, o, e.orElse(null), r, certificates[0]); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AbstractAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AbstractAuthorizationRule.java index 8a1df0ed1..0da994d3b 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AbstractAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AbstractAuthorizationRule.java @@ -7,6 +7,7 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.UUID; import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent; @@ -22,6 +23,7 @@ import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.authentication.OrganizationProvider; import dev.dsf.fhir.authorization.read.ReadAccessHelper; import dev.dsf.fhir.dao.CodeSystemDao; @@ -52,6 +54,15 @@ public abstract class AbstractAuthorizationRule resourceType, DaoProvider daoProvider, String serverBase, ReferenceResolver referenceResolver, OrganizationProvider organizationProvider, ReadAccessHelper readAccessHelper, ParameterConverter parameterConverter) @@ -63,6 +74,15 @@ public AbstractAuthorizationRule(Class resourceType, DaoProvider daoProvider, this.organizationProvider = organizationProvider; this.readAccessHelper = readAccessHelper; this.parameterConverter = parameterConverter; + + createRole = FhirServerRoleImpl.create(resourceType); + readRole = FhirServerRoleImpl.read(resourceType); + updateRole = FhirServerRoleImpl.update(resourceType); + deleteRole = FhirServerRoleImpl.delete(resourceType); + historyRole = FhirServerRoleImpl.history(resourceType); + searchRole = FhirServerRoleImpl.search(resourceType); + permanentDeleteRole = FhirServerRoleImpl.permanentDelete(resourceType); + websocketRole = FhirServerRoleImpl.websocket(resourceType); } @Override @@ -230,60 +250,6 @@ private boolean hasCode(CodeSystem codeSystem, String cCode) .map(ConceptDefinitionComponent::getCode).anyMatch(c -> c.equals(cCode)); } - protected final boolean isCurrentIdentityPartOfReferencedOrganization(Connection connection, Identity identity, - String referenceLocation, Reference reference) - { - if (reference == null) - { - logger.warn("Null reference while checking if user part of referenced organization"); - - return false; - } - else - { - ResourceReference resReference = new ResourceReference(referenceLocation, reference, Organization.class); - - ReferenceType type = resReference.getType(serverBase); - if (!EnumSet.of(ReferenceType.LITERAL_INTERNAL, ReferenceType.LOGICAL).contains(type)) - { - logger.warn("Reference of type {} not supported while checking if user part of referenced organization", - type); - - return false; - } - - Optional resource = referenceResolver.resolveReference(identity, resReference, connection); - if (resource.isPresent() && resource.get() instanceof Organization) - { - // ignoring updates (version changes) to the organization id - boolean sameOrganization = identity.getOrganization().getIdElement().getIdPart() - .equals(resource.get().getIdElement().getIdPart()); - if (!sameOrganization) - logger.warn( - "Current user not part of organization {} while checking if user part of referenced organization", - resource.get().getIdElement().getValue()); - - return sameOrganization; - } - else - { - logger.warn( - "Reference to organization could not be resolved while checking if user part of referenced organization"); - - return false; - } - } - } - - protected final boolean isLocalOrganization(Organization organization) - { - if (organization == null || !organization.hasIdElement()) - return false; - - return organizationProvider.getLocalOrganization() - .map(localOrg -> localOrg.getIdElement().equals(organization.getIdElement())).orElse(false); - } - @SafeVarargs protected final Optional createIfLiteralInternalOrLogicalReference(String referenceLocation, Reference reference, Class... referenceTypes) @@ -315,16 +281,16 @@ public Optional reasonPermanentDeleteAllowed(Identity identity, R oldRes @Override public final Optional reasonSearchAllowed(Identity identity) { - if (identity.hasDsfRole(FhirServerRole.SEARCH)) + if (identity.hasDsfRole(searchRole)) { logger.info("Search of {} authorized for identity '{}'", getResourceTypeName(), identity.getName()); - return Optional.of("Identity has role " + FhirServerRole.SEARCH); + return Optional.of("Identity has role " + searchRole); } else { logger.warn("Search of {} unauthorized for identity '{}', no role {}", getResourceTypeName(), - identity.getName(), FhirServerRole.SEARCH); + identity.getName(), searchRole); return Optional.empty(); } @@ -333,16 +299,16 @@ public final Optional reasonSearchAllowed(Identity identity) @Override public final Optional reasonHistoryAllowed(Identity identity) { - if (identity.hasDsfRole(FhirServerRole.HISTORY)) + if (identity.hasDsfRole(historyRole)) { logger.info("History of {} authorized for identity '{}'", getResourceTypeName(), identity.getName()); - return Optional.of("Identity has role " + FhirServerRole.HISTORY); + return Optional.of("Identity has role " + historyRole); } else { logger.warn("History of {} unauthorized for identity '{}', no role {}", getResourceTypeName(), - identity.getName(), FhirServerRole.HISTORY); + identity.getName(), historyRole); return Optional.empty(); } @@ -354,20 +320,58 @@ public Optional reasonPermanentDeleteAllowed(Connection connection, Iden final String resourceId = oldResource.getIdElement().getIdPart(); final long resourceVersion = oldResource.getIdElement().getVersionIdPartAsLong(); - if (identity.isLocalIdentity() && identity.hasDsfRole(FhirServerRole.PERMANENT_DELETE) + if (identity.isLocalIdentity() && identity.hasDsfRole(permanentDeleteRole) && reasonDeleteAllowed(connection, identity, oldResource).isPresent()) { logger.info("Permanent delete of {}/{}/_history/{} authorized for identity '{}'", getResourceTypeName(), resourceId, resourceVersion, identity.getName()); - return Optional.of("Identity is local identity and has role " + FhirServerRole.PERMANENT_DELETE); + return Optional.of("Identity is local identity and has role " + permanentDeleteRole); } else { logger.warn( "Permanent delete of {}/{}/_history/{} unauthorized for identity '{}', not a local identity or no role {}", - getResourceTypeName(), resourceId, resourceVersion, identity.getName(), - FhirServerRole.PERMANENT_DELETE); + getResourceTypeName(), resourceId, resourceVersion, identity.getName(), permanentDeleteRole); + + return Optional.empty(); + } + } + + @Override + public Optional reasonWebsocketAllowed(Identity identity, R existingResource) + { + try (Connection connection = daoProvider.newReadOnlyAutoCommitTransaction()) + { + return reasonWebsocketAllowed(connection, identity, existingResource); + } + catch (SQLException e) + { + logger.debug("Error while accessing database", e); + logger.warn("Error while accessing database: {} - {}", e.getClass().getName(), e.getMessage()); + + throw new RuntimeException(e); + } + } + + private Optional reasonWebsocketAllowed(Connection connection, Identity identity, R existingResource) + { + final UUID resourceId = parameterConverter.toUuid(getResourceTypeName(), + existingResource.getIdElement().getIdPart()); + final long resourceVersion = existingResource.getIdElement().getVersionIdPartAsLong(); + + if (identity.isLocalIdentity() && identity.hasDsfRole(websocketRole)) + { + logger.info("Websocket access to {}/{}/_history/{} authorized for local identity '{}'", + getResourceTypeName(), resourceId.toString(), resourceVersion, identity.getName()); + + return Optional.of("Identity has role " + websocketRole); + } + else + { + logger.warn( + "Websocket access to {}/{}/_history/{} unauthorized for identity '{}', not a local identity or no role {}", + getResourceTypeName(), resourceId.toString(), resourceVersion, identity.getName(), websocketRole); return Optional.empty(); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AbstractMetaTagAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AbstractMetaTagAuthorizationRule.java index 4983a461c..b6df29c14 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AbstractMetaTagAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AbstractMetaTagAuthorizationRule.java @@ -10,10 +10,8 @@ import org.hl7.fhir.r4.model.Resource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.InitializingBean; import dev.dsf.common.auth.conf.Identity; -import dev.dsf.fhir.authentication.FhirServerRole; import dev.dsf.fhir.authentication.OrganizationProvider; import dev.dsf.fhir.authorization.read.ReadAccessHelper; import dev.dsf.fhir.dao.ReadAccessDao; @@ -23,7 +21,7 @@ import dev.dsf.fhir.service.ReferenceResolver; public abstract class AbstractMetaTagAuthorizationRule> - extends AbstractAuthorizationRule implements AuthorizationRule, InitializingBean + extends AbstractAuthorizationRule { private static final Logger logger = LoggerFactory.getLogger(AbstractMetaTagAuthorizationRule.class); @@ -49,7 +47,7 @@ protected final boolean hasValidReadAccessTag(Connection connection, Resource re @Override public final Optional reasonCreateAllowed(Connection connection, Identity identity, R newResource) { - if (identity.isLocalIdentity() && identity.hasDsfRole(FhirServerRole.CREATE)) + if (identity.isLocalIdentity() && identity.hasDsfRole(createRole)) { Optional errors = newResourceOkForCreate(connection, identity, newResource); if (errors.isEmpty()) @@ -58,7 +56,7 @@ public final Optional reasonCreateAllowed(Connection connection, Identit { logger.info("Create of {} authorized for identity '{}'", getResourceTypeName(), identity.getName()); - return Optional.of("Identity is local identity and has role " + FhirServerRole.CREATE); + return Optional.of("Identity is local identity and has role " + createRole); } else { @@ -77,7 +75,7 @@ public final Optional reasonCreateAllowed(Connection connection, Identit else { logger.warn("Create of {} unauthorized for identity '{}', not a local identity or no role {}", - getResourceTypeName(), identity.getName(), FhirServerRole.CREATE); + getResourceTypeName(), identity.getName(), createRole); return Optional.empty(); } @@ -94,7 +92,7 @@ public final Optional reasonReadAllowed(Connection connection, Identity existingResource.getIdElement().getIdPart()); final long resourceVersion = existingResource.getIdElement().getVersionIdPartAsLong(); - if (identity.hasDsfRole(FhirServerRole.READ)) + if (identity.hasDsfRole(readRole)) { try { @@ -119,7 +117,7 @@ public final Optional reasonReadAllowed(Connection connection, Identity getResourceTypeName(), resourceId.toString(), resourceVersion, identity.getName(), accessTypes.size() == 1 ? "tag" : "tags", tags); - return Optional.of("Identity has role " + FhirServerRole.READ + ", matching access " + return Optional.of("Identity has role " + readRole + ", matching access " + (accessTypes.size() == 1 ? "tag" : "tags") + " " + tags); } } @@ -134,7 +132,7 @@ public final Optional reasonReadAllowed(Connection connection, Identity else { logger.warn("Read of {}/{}/_history/{} unauthorized for identity '{}', no role {}", getResourceTypeName(), - resourceId.toString(), resourceVersion, identity.getName(), FhirServerRole.READ); + resourceId.toString(), resourceVersion, identity.getName(), readRole); return Optional.empty(); } @@ -149,7 +147,7 @@ public final Optional reasonUpdateAllowed(Connection connection, Identit final String resourceId = oldResource.getIdElement().getIdPart(); final long resourceVersion = oldResource.getIdElement().getVersionIdPartAsLong(); - if (identity.isLocalIdentity() && identity.hasDsfRole(FhirServerRole.UPDATE)) + if (identity.isLocalIdentity() && identity.hasDsfRole(updateRole)) { Optional errors = newResourceOkForUpdate(connection, identity, newResource); if (errors.isEmpty()) @@ -159,7 +157,7 @@ public final Optional reasonUpdateAllowed(Connection connection, Identit logger.info("Update of {}/{}/_history/{} authorized for identity '{}'", getResourceTypeName(), resourceId.toString(), resourceVersion, identity.getName()); - return Optional.of("Identity is local identity and has role " + FhirServerRole.UPDATE); + return Optional.of("Identity is local identity and has role " + updateRole); } else { @@ -181,8 +179,7 @@ public final Optional reasonUpdateAllowed(Connection connection, Identit { logger.warn( "Update of {}/{}/_history/{} unauthorized for identity '{}', not a local identity or no role {}", - getResourceTypeName(), resourceId.toString(), resourceVersion, identity.getName(), - FhirServerRole.UPDATE); + getResourceTypeName(), resourceId.toString(), resourceVersion, identity.getName(), updateRole); return Optional.empty(); } @@ -208,18 +205,18 @@ public final Optional reasonDeleteAllowed(Connection connection, Identit final String resourceId = oldResource.getIdElement().getIdPart(); final long resourceVersion = oldResource.getIdElement().getVersionIdPartAsLong(); - if (identity.isLocalIdentity() && identity.hasDsfRole(FhirServerRole.DELETE)) + if (identity.isLocalIdentity() && identity.hasDsfRole(deleteRole)) { logger.info("Delete of {}/{}/_history/{} authorized for identity '{}'", getResourceTypeName(), resourceId, resourceVersion, identity.getName()); - return Optional.of("Identity is local identity and has role " + FhirServerRole.DELETE); + return Optional.of("Identity is local identity and has role " + deleteRole); } else { logger.warn( "Delete of {}/{}/_history/{} unauthorized for identity '{}', not a local identity or no role {}", - getResourceTypeName(), resourceId, resourceVersion, identity.getName(), FhirServerRole.DELETE); + getResourceTypeName(), resourceId, resourceVersion, identity.getName(), deleteRole); return Optional.empty(); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AuthorizationRule.java index 5e3459159..3550ff194 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AuthorizationRule.java @@ -12,8 +12,6 @@ public interface AuthorizationRule Class getResourceType(); /** - * Override this method for non default behavior. Default: Not allowed. - * * @param identity * not null * @param newResource @@ -23,8 +21,6 @@ public interface AuthorizationRule Optional reasonCreateAllowed(Identity identity, R newResource); /** - * Override this method for non default behavior. Default: Not allowed. - * * @param connection * not null * @param identity @@ -36,8 +32,6 @@ public interface AuthorizationRule Optional reasonCreateAllowed(Connection connection, Identity identity, R newResource); /** - * Override this method for non default behavior. Default: Not allowed. - * * @param identity * not null * @param existingResource @@ -47,8 +41,6 @@ public interface AuthorizationRule Optional reasonReadAllowed(Identity identity, R existingResource); /** - * Override this method for non default behavior. Default: Not allowed. - * * @param connection * not null * @param identity @@ -60,8 +52,6 @@ public interface AuthorizationRule Optional reasonReadAllowed(Connection connection, Identity identity, R existingResource); /** - * Override this method for non default behavior. Default: Not allowed. - * * @param identity * not null * @param oldResource @@ -73,8 +63,6 @@ public interface AuthorizationRule Optional reasonUpdateAllowed(Identity identity, R oldResource, R newResource); /** - * Override this method for non default behavior. Default: Not allowed. - * * @param connection * not null * @param identity @@ -88,8 +76,6 @@ public interface AuthorizationRule Optional reasonUpdateAllowed(Connection connection, Identity identity, R oldResource, R newResource); /** - * Override this method for non default behavior. Default: Not allowed. - * * @param identity * not null * @param oldResource @@ -99,8 +85,6 @@ public interface AuthorizationRule Optional reasonDeleteAllowed(Identity identity, R oldResource); /** - * Override this method for non default behavior. Default: Not allowed. - * * @param connection * not null * @param identity @@ -112,8 +96,6 @@ public interface AuthorizationRule Optional reasonDeleteAllowed(Connection connection, Identity identity, R oldResource); /** - * Override this method for non default behavior. Default: Not allowed. - * * @param identity * not null * @return Reason as String in {@link Optional#of(Object)} if delete allowed @@ -121,8 +103,6 @@ public interface AuthorizationRule Optional reasonSearchAllowed(Identity identity); /** - * Override this method for non default behavior. Default: Not allowed. - * * @param identity * not null * @return Reason as String in {@link Optional#of(Object)} if delete allowed @@ -130,8 +110,6 @@ public interface AuthorizationRule Optional reasonHistoryAllowed(Identity identity); /** - * Override this method for non default behavior. Default: Not allowed. - * * @param identity * not null * @param oldResource @@ -141,8 +119,6 @@ public interface AuthorizationRule Optional reasonPermanentDeleteAllowed(Identity identity, R oldResource); /** - * Override this method for non default behavior. Default: Not allowed. - * * @param connection * not null * @param identity @@ -152,4 +128,13 @@ public interface AuthorizationRule * @return Reason as String in {@link Optional#of(Object)} if permanent delete allowed */ Optional reasonPermanentDeleteAllowed(Connection connection, Identity identity, R oldResource); + + /** + * @param identity + * not null + * @param existingResource + * not null + * @return Reason as String in {@link Optional#of(Object)} if websocket access to resource allowed + */ + Optional reasonWebsocketAllowed(Identity identity, R existingResource); } \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/BinaryAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/BinaryAuthorizationRule.java index 9b561e72e..9b0536cca 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/BinaryAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/BinaryAuthorizationRule.java @@ -77,8 +77,7 @@ private boolean hasValidSecurityContext(Connection connection, Identity identity { Optional ref = createIfLiteralInternalOrLogicalReference("Binary.securityContext", newResource.getSecurityContext()); - Optional securityContextOpt = ref - .flatMap(r -> referenceResolver.resolveReference(identity, r, connection)); + Optional securityContextOpt = ref.flatMap(r -> referenceResolver.resolveReference(r, connection)); return securityContextOpt.isPresent() && rules.containsKey(securityContextOpt.get().getClass()); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/QuestionnaireResponseAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/QuestionnaireResponseAuthorizationRule.java index a47fb36c4..26b67d1b9 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/QuestionnaireResponseAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/QuestionnaireResponseAuthorizationRule.java @@ -17,7 +17,6 @@ import org.slf4j.LoggerFactory; import dev.dsf.common.auth.conf.Identity; -import dev.dsf.fhir.authentication.FhirServerRole; import dev.dsf.fhir.authentication.OrganizationProvider; import dev.dsf.fhir.authorization.read.ReadAccessHelper; import dev.dsf.fhir.dao.QuestionnaireResponseDao; @@ -46,7 +45,7 @@ public QuestionnaireResponseAuthorizationRule(DaoProvider daoProvider, String se public Optional reasonCreateAllowed(Connection connection, Identity identity, QuestionnaireResponse newResource) { - if (identity.isLocalIdentity() && identity.hasDsfRole(FhirServerRole.CREATE)) + if (identity.isLocalIdentity() && identity.hasDsfRole(createRole)) { Optional errors = newResourceOk(newResource, EnumSet.of(QuestionnaireResponseStatus.INPROGRESS)); if (errors.isEmpty()) @@ -63,7 +62,7 @@ public Optional reasonCreateAllowed(Connection connection, Identity iden } else { - logger.warn("Create of QuestionnaireResponse unauthorized, not a local user"); + logger.warn("Create of QuestionnaireResponse unauthorized, not a local user or no create role"); return Optional.empty(); } } @@ -147,14 +146,14 @@ private Optional getItemAndValidate(QuestionnaireResponse newResource, S public Optional reasonReadAllowed(Connection connection, Identity identity, QuestionnaireResponse existingResource) { - if (identity.isLocalIdentity() && identity.hasDsfRole(FhirServerRole.READ)) + if (identity.isLocalIdentity() && identity.hasDsfRole(readRole)) { logger.info("Read of QuestionnaireResponse authorized for local user '{}'", identity.getName()); return Optional.of("task.restriction.recipient resolved and local user part of referenced organization"); } else { - logger.warn("Read of QuestionnaireResponse unauthorized, not a local user"); + logger.warn("Read of QuestionnaireResponse unauthorized, not a local user or no read role"); return Optional.empty(); } } @@ -163,7 +162,7 @@ public Optional reasonReadAllowed(Connection connection, Identity identi public Optional reasonUpdateAllowed(Connection connection, Identity identity, QuestionnaireResponse oldResource, QuestionnaireResponse newResource) { - if (identity.isLocalIdentity() && identity.hasDsfRole(FhirServerRole.UPDATE)) + if (identity.isLocalIdentity() && identity.hasDsfRole(updateRole)) { Optional errors = newResourceOk(newResource, EnumSet.of(QuestionnaireResponseStatus.COMPLETED, QuestionnaireResponseStatus.STOPPED)); @@ -189,7 +188,7 @@ public Optional reasonUpdateAllowed(Connection connection, Identity iden } else { - logger.warn("Update of QuestionnaireResponse unauthorized, not a local user"); + logger.warn("Update of QuestionnaireResponse unauthorized, not a local user or no update role"); return Optional.empty(); } } @@ -247,14 +246,14 @@ private boolean modificationsOk(QuestionnaireResponse oldResource, Questionnaire public Optional reasonDeleteAllowed(Connection connection, Identity identity, QuestionnaireResponse oldResource) { - if (identity.isLocalIdentity() && identity.hasDsfRole(FhirServerRole.DELETE)) + if (identity.isLocalIdentity() && identity.hasDsfRole(deleteRole)) { logger.info("Delete of QuestionnaireResponse authorized for local user '{}'", identity.getName()); return Optional.of("local user"); } else { - logger.warn("Delete of QuestionnaireResponse unauthorized, not a local user"); + logger.warn("Delete of QuestionnaireResponse unauthorized, not a local user or no delete role"); return Optional.empty(); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/RootAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/RootAuthorizationRule.java index 0db7a2ddb..3874db0be 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/RootAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/RootAuthorizationRule.java @@ -7,8 +7,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import dev.dsf.common.auth.conf.DsfRole; import dev.dsf.common.auth.conf.Identity; -import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class RootAuthorizationRule implements AuthorizationRule { @@ -78,15 +79,16 @@ public Optional reasonSearchAllowed(Identity identity) @Override public Optional reasonHistoryAllowed(Identity identity) { - if (identity.hasDsfRole(FhirServerRole.HISTORY)) + if (identity.getDsfRoles().stream().map(DsfRole::name) + .anyMatch(FhirServerRoleImpl.Operation.HISTORY.name()::equals)) { logger.info("History of root authorized for identity '{}'", identity.getName()); - return Optional.of("Identity has role " + FhirServerRole.HISTORY); + return Optional.of("Identity has role " + FhirServerRoleImpl.Operation.HISTORY); } else { logger.warn("History of root unauthorized for identity '{}', no role {}", identity.getName(), - FhirServerRole.HISTORY); + FhirServerRoleImpl.Operation.HISTORY); return Optional.empty(); } } @@ -102,4 +104,10 @@ public Optional reasonPermanentDeleteAllowed(Connection connection, Iden { throw new UnsupportedOperationException(); } + + @Override + public Optional reasonWebsocketAllowed(Identity identity, Resource existingResource) + { + throw new UnsupportedOperationException(); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/TaskAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/TaskAuthorizationRule.java index c2ab8fc6f..e12689633 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/TaskAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/TaskAuthorizationRule.java @@ -3,6 +3,7 @@ import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; +import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -19,6 +20,7 @@ import org.hl7.fhir.r4.model.Identifier; import org.hl7.fhir.r4.model.Organization; import org.hl7.fhir.r4.model.OrganizationAffiliation; +import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.model.StringType; import org.hl7.fhir.r4.model.Task; @@ -31,7 +33,6 @@ import dev.dsf.common.auth.conf.Identity; import dev.dsf.common.auth.conf.OrganizationIdentity; import dev.dsf.fhir.authentication.EndpointProvider; -import dev.dsf.fhir.authentication.FhirServerRole; import dev.dsf.fhir.authentication.OrganizationProvider; import dev.dsf.fhir.authorization.process.ProcessAuthorizationHelper; import dev.dsf.fhir.authorization.read.ReadAccessHelper; @@ -44,6 +45,7 @@ import dev.dsf.fhir.search.SearchQueryParameterError; import dev.dsf.fhir.service.ReferenceResolver; import dev.dsf.fhir.service.ResourceReference; +import dev.dsf.fhir.service.ResourceReference.ReferenceType; public class TaskAuthorizationRule extends AbstractAuthorizationRule { @@ -87,10 +89,64 @@ public void afterPropertiesSet() throws Exception Objects.requireNonNull(endpointProvider, "endpointProvider"); } + private boolean isCurrentIdentityPartOfReferencedOrganization(Connection connection, Identity identity, + String referenceLocation, Reference reference) + { + if (reference == null) + { + logger.warn("Null reference while checking if user part of referenced organization"); + + return false; + } + else + { + ResourceReference resReference = new ResourceReference(referenceLocation, reference, Organization.class); + + ReferenceType type = resReference.getType(serverBase); + if (!EnumSet.of(ReferenceType.LITERAL_INTERNAL, ReferenceType.LOGICAL).contains(type)) + { + logger.warn("Reference of type {} not supported while checking if user part of referenced organization", + type); + + return false; + } + + Optional resource = referenceResolver.resolveReference(resReference, connection); + if (resource.isPresent() && resource.get() instanceof Organization) + { + // ignoring updates (version changes) to the organization id + boolean sameOrganization = identity.getOrganization().getIdElement().getIdPart() + .equals(resource.get().getIdElement().getIdPart()); + if (!sameOrganization) + logger.warn( + "Current user not part of organization {} while checking if user part of referenced organization", + resource.get().getIdElement().getValue()); + + return sameOrganization; + } + else + { + logger.warn( + "Reference to organization could not be resolved while checking if user part of referenced organization"); + + return false; + } + } + } + + private boolean isLocalOrganization(Organization organization) + { + if (organization == null || !organization.hasIdElement()) + return false; + + return organizationProvider.getLocalOrganization() + .map(localOrg -> localOrg.getIdElement().equals(organization.getIdElement())).orElse(false); + } + @Override public Optional reasonCreateAllowed(Connection connection, Identity identity, Task newResource) { - if (identity.hasDsfRole(FhirServerRole.CREATE)) + if (identity.hasDsfRole(createRole)) { if (TaskStatus.DRAFT.equals(newResource.getStatus())) { @@ -173,8 +229,7 @@ else if (TaskStatus.REQUESTED.equals(newResource.getStatus())) } else { - logger.warn("Create of Task unauthorized for identity '{}', no role {}", identity.getName(), - FhirServerRole.CREATE); + logger.warn("Create of Task unauthorized for identity '{}', no role {}", identity.getName(), createRole); return Optional.empty(); } @@ -222,7 +277,7 @@ private Optional requestedTaskOk(Connection connection, Identity identit { ResourceReference reference = new ResourceReference("Task.restriction.recipient", newResource.getRestriction().getRecipientFirstRep(), Organization.class); - Optional recipient = referenceResolver.resolveReference(identity, reference, connection); + Optional recipient = referenceResolver.resolveReference(reference, connection); if (recipient.isPresent()) { if (recipient.get() instanceof Organization o) @@ -321,7 +376,7 @@ else if (newResource.getIdentifier().stream().filter(i -> NAMING_SYSTEM_TASK_IDE { ResourceReference reference = new ResourceReference("Task.requester", newResource.getRequester(), Organization.class); - Optional requester = referenceResolver.resolveReference(identity, reference, connection); + Optional requester = referenceResolver.resolveReference(reference, connection); if (requester.isPresent()) { if (requester.get() instanceof Organization o) @@ -350,7 +405,7 @@ else if (newResource.getIdentifier().stream().filter(i -> NAMING_SYSTEM_TASK_IDE { ResourceReference reference = new ResourceReference("Task.restriction.recipient", newResource.getRestriction().getRecipientFirstRep(), Organization.class); - Optional recipient = referenceResolver.resolveReference(identity, reference, connection); + Optional recipient = referenceResolver.resolveReference(reference, connection); if (recipient.isPresent()) { if (recipient.get() instanceof Organization o) @@ -645,7 +700,7 @@ public Optional reasonReadAllowed(Connection connection, Identity identi .toUuid(getResourceTypeName(), existingResource.getIdElement().getIdPart()).toString(); final long resourceVersion = existingResource.getIdElement().getVersionIdPartAsLong(); - if (identity.hasDsfRole(FhirServerRole.READ)) + if (identity.hasDsfRole(readRole)) { if (identity.isLocalIdentity() && isCurrentIdentityPartOfReferencedOrganization(connection, identity, "Task.restriction.recipient", existingResource.getRestriction().getRecipientFirstRep())) @@ -678,7 +733,7 @@ else if (isCurrentIdentityPartOfReferencedOrganization(connection, identity, "Ta else { logger.warn("Read of Task/{}/_history/{} unauthorized for identity '{}', no role {}", resourceId, - resourceVersion, identity.getName(), FhirServerRole.READ); + resourceVersion, identity.getName(), readRole); return Optional.empty(); } @@ -692,7 +747,7 @@ public Optional reasonUpdateAllowed(Connection connection, Identity iden .toUuid(getResourceTypeName(), oldResource.getIdElement().getIdPart()).toString(); final long oldResourceVersion = oldResource.getIdElement().getVersionIdPartAsLong(); - if (identity.hasDsfRole(FhirServerRole.UPDATE)) + if (identity.hasDsfRole(updateRole)) { if (identity.isLocalIdentity() && identity instanceof OrganizationIdentity) { @@ -920,7 +975,7 @@ else if (TaskStatus.INPROGRESS.equals(oldResource.getStatus()) else { logger.warn("Update of Task/{}/_history/{} unauthorized for identity '{}', no role {}", oldResourceId, - oldResourceVersion, identity.getName(), FhirServerRole.UPDATE); + oldResourceVersion, identity.getName(), updateRole); return Optional.empty(); } @@ -1008,7 +1063,7 @@ public Optional reasonDeleteAllowed(Connection connection, Identity iden .toUuid(getResourceTypeName(), oldResource.getIdElement().getIdPart()).toString(); final long oldResourceVersion = oldResource.getIdElement().getVersionIdPartAsLong(); - if (identity.hasDsfRole(FhirServerRole.DELETE)) + if (identity.hasDsfRole(deleteRole)) { if (identity.isLocalIdentity() && identity instanceof OrganizationIdentity) { @@ -1039,7 +1094,7 @@ public Optional reasonDeleteAllowed(Connection connection, Identity iden else { logger.warn("Delete of Task/{}/_history/{} unauthorized for identity '{}', no role {}", oldResourceId, - oldResourceVersion, identity.getName(), FhirServerRole.DELETE); + oldResourceVersion, identity.getName(), deleteRole); return Optional.empty(); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/dao/command/AbstractCommandWithResource.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/dao/command/AbstractCommandWithResource.java index 3a74cebb5..46f3079e2 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/dao/command/AbstractCommandWithResource.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/dao/command/AbstractCommandWithResource.java @@ -35,16 +35,8 @@ public AbstractCommandWithResource(int transactionPriority, int index, Identity this.exceptionHandler = exceptionHandler; this.parameterConverter = parameterConverter; - referencesHelper = createReferencesHelper(index, identity, serverBase, resource, responseGenerator, - referenceExtractor, referenceResolver); - } - - protected ReferencesHelper createReferencesHelper(int index, Identity identity, String serverBase, R resource, - ResponseGenerator responseGenerator, ReferenceExtractor referenceExtractor, - ReferenceResolver referenceResolver) - { - return new ReferencesHelperImpl<>(index, identity, resource, serverBase, referenceExtractor, referenceResolver, - responseGenerator); + referencesHelper = new ReferencesHelperImpl<>(index, resource, serverBase, referenceExtractor, + referenceResolver, responseGenerator); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/dao/command/ReferencesHelperImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/dao/command/ReferencesHelperImpl.java index 1890fafb4..447a3aaf1 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/dao/command/ReferencesHelperImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/dao/command/ReferencesHelperImpl.java @@ -16,7 +16,6 @@ import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.model.Type; -import dev.dsf.common.auth.conf.Identity; import dev.dsf.fhir.help.ResponseGenerator; import dev.dsf.fhir.service.ReferenceExtractor; import dev.dsf.fhir.service.ReferenceResolver; @@ -29,19 +28,16 @@ public final class ReferencesHelperImpl implements ReferencesHelper { private final int index; - private final Identity identity; private final R resource; private final String serverBase; private final ReferenceExtractor referenceExtractor; private final ReferenceResolver referenceResolver; private final ResponseGenerator responseGenerator; - public ReferencesHelperImpl(int index, Identity identity, R resource, String serverBase, - ReferenceExtractor referenceExtractor, ReferenceResolver referenceResolver, - ResponseGenerator responseGenerator) + public ReferencesHelperImpl(int index, R resource, String serverBase, ReferenceExtractor referenceExtractor, + ReferenceResolver referenceResolver, ResponseGenerator responseGenerator) { this.index = index; - this.identity = identity; this.resource = resource; this.serverBase = serverBase; this.referenceExtractor = referenceExtractor; @@ -136,7 +132,7 @@ private Optional resolveTemporary(ResourceReference reference, private Optional resolveConditional(ResourceReference reference, Connection connection, Consumer targetConsumer) { - Optional resolvedResource = referenceResolver.resolveReference(identity, reference, connection); + Optional resolvedResource = referenceResolver.resolveReference(reference, connection); if (resolvedResource.isPresent()) { Resource target = resolvedResource.get(); @@ -181,7 +177,7 @@ public void resolveLogicalReferences(Connection connection) throws WebApplicatio private Optional resolveLogicalReference(ResourceReference reference, Connection connection) { - Optional resolvedResource = referenceResolver.resolveReference(identity, reference, connection); + Optional resolvedResource = referenceResolver.resolveReference(reference, connection); if (resolvedResource.isPresent()) { Resource target = resolvedResource.get(); @@ -222,10 +218,9 @@ private Optional checkReference(ResourceReference reference, C case LITERAL_EXTERNAL, RELATED_ARTEFACT_LITERAL_EXTERNAL_URL, ATTACHMENT_LITERAL_EXTERNAL_URL -> referenceResolver.checkLiteralExternalReference(resource, reference, index); - case LOGICAL -> referenceResolver.checkLogicalReference(identity, resource, reference, connection, index); + case LOGICAL -> referenceResolver.checkLogicalReference(resource, reference, connection, index); - case CANONICAL -> - referenceResolver.checkCanonicalReference(identity, resource, reference, connection, index); + case CANONICAL -> referenceResolver.checkCanonicalReference(resource, reference, connection, index); // unknown URLs to non FHIR servers in related artifacts must not be checked case RELATED_ARTEFACT_UNKNOWN_URL, ATTACHMENT_UNKNOWN_URL -> Optional.empty(); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/ActivityDefinitionHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/ActivityDefinitionHistoryIdentityFilter.java index e555003cf..16f348530 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/ActivityDefinitionHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/ActivityDefinitionHistoryIdentityFilter.java @@ -1,19 +1,21 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.ActivityDefinition; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.ActivityDefinitionIdentityFilter; public class ActivityDefinitionHistoryIdentityFilter extends ActivityDefinitionIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = ActivityDefinition.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.ActivityDefinition); + private static final String RESOURCE_TYPE = ResourceType.ActivityDefinition.name(); public ActivityDefinitionHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/BinaryHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/BinaryHistoryIdentityFilter.java index aefedf6d6..e3537102f 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/BinaryHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/BinaryHistoryIdentityFilter.java @@ -1,18 +1,20 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.Binary; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.BinaryIdentityFilter; public class BinaryHistoryIdentityFilter extends BinaryIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = Binary.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.Binary); + private static final String RESOURCE_TYPE = ResourceType.Binary.name(); public BinaryHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/BundleHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/BundleHistoryIdentityFilter.java index 027f7232c..a43bff579 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/BundleHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/BundleHistoryIdentityFilter.java @@ -1,18 +1,20 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.BundleIdentityFilter; public class BundleHistoryIdentityFilter extends BundleIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = Bundle.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.Bundle); + private static final String RESOURCE_TYPE = ResourceType.Bundle.name(); public BundleHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/CodeSystemHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/CodeSystemHistoryIdentityFilter.java index dd2e59f7a..dcf0d4ba0 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/CodeSystemHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/CodeSystemHistoryIdentityFilter.java @@ -1,18 +1,20 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.CodeSystem; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.CodeSystemIdentityFilter; public class CodeSystemHistoryIdentityFilter extends CodeSystemIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = CodeSystem.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.CodeSystem); + private static final String RESOURCE_TYPE = ResourceType.CodeSystem.name(); public CodeSystemHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/DocumentReferenceHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/DocumentReferenceHistoryIdentityFilter.java index 7fe070511..cbd1332fb 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/DocumentReferenceHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/DocumentReferenceHistoryIdentityFilter.java @@ -1,19 +1,21 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.DocumentReference; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.DocumentReferenceIdentityFilter; public class DocumentReferenceHistoryIdentityFilter extends DocumentReferenceIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = DocumentReference.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.DocumentReference); + private static final String RESOURCE_TYPE = ResourceType.DocumentReference.name(); public DocumentReferenceHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/EndpointHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/EndpointHistoryIdentityFilter.java index 1d4aa641e..4b29edf03 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/EndpointHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/EndpointHistoryIdentityFilter.java @@ -1,18 +1,20 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.Endpoint; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.EndpointIdentityFilter; public class EndpointHistoryIdentityFilter extends EndpointIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = Endpoint.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.Endpoint); + private static final String RESOURCE_TYPE = ResourceType.Endpoint.name(); public EndpointHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/GroupHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/GroupHistoryIdentityFilter.java index f37c7c6df..d2d4296aa 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/GroupHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/GroupHistoryIdentityFilter.java @@ -1,18 +1,20 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.Group; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.GroupIdentityFilter; public class GroupHistoryIdentityFilter extends GroupIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = Group.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.Group); + private static final String RESOURCE_TYPE = ResourceType.Group.name(); public GroupHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/HealthcareServiceHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/HealthcareServiceHistoryIdentityFilter.java index 9b20762ee..afcc81091 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/HealthcareServiceHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/HealthcareServiceHistoryIdentityFilter.java @@ -1,19 +1,21 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.HealthcareService; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.HealthcareServiceIdentityFilter; public class HealthcareServiceHistoryIdentityFilter extends HealthcareServiceIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = HealthcareService.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.HealthcareService); + private static final String RESOURCE_TYPE = ResourceType.HealthcareService.name(); public HealthcareServiceHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/LibraryHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/LibraryHistoryIdentityFilter.java index ac4735709..aefa2dd34 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/LibraryHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/LibraryHistoryIdentityFilter.java @@ -1,18 +1,20 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.Library; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.LibraryIdentityFilter; public class LibraryHistoryIdentityFilter extends LibraryIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = Library.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.Library); + private static final String RESOURCE_TYPE = ResourceType.Library.name(); public LibraryHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/LocationHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/LocationHistoryIdentityFilter.java index b64107970..1470955fe 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/LocationHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/LocationHistoryIdentityFilter.java @@ -1,18 +1,20 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.Location; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.LocationIdentityFilter; public class LocationHistoryIdentityFilter extends LocationIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = Location.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.Location); + private static final String RESOURCE_TYPE = ResourceType.Location.name(); public LocationHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/MeasureHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/MeasureHistoryIdentityFilter.java index 8a5982cdc..1865efd09 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/MeasureHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/MeasureHistoryIdentityFilter.java @@ -1,18 +1,20 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.Measure; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.MeasureIdentityFilter; public class MeasureHistoryIdentityFilter extends MeasureIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = Measure.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.Measure); + private static final String RESOURCE_TYPE = ResourceType.Measure.name(); public MeasureHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/MeasureReportHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/MeasureReportHistoryIdentityFilter.java index 893be8d01..8d16db7c7 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/MeasureReportHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/MeasureReportHistoryIdentityFilter.java @@ -1,18 +1,20 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.MeasureReport; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.MeasureReportIdentityFilter; public class MeasureReportHistoryIdentityFilter extends MeasureReportIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = MeasureReport.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.MeasureReport); + private static final String RESOURCE_TYPE = ResourceType.MeasureReport.name(); public MeasureReportHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/NamingSystemHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/NamingSystemHistoryIdentityFilter.java index a4afe2665..ec1385c37 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/NamingSystemHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/NamingSystemHistoryIdentityFilter.java @@ -1,18 +1,20 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.NamingSystem; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.NamingSystemIdentityFilter; public class NamingSystemHistoryIdentityFilter extends NamingSystemIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = NamingSystem.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.NamingSystem); + private static final String RESOURCE_TYPE = ResourceType.NamingSystem.name(); public NamingSystemHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/OrganizationAffiliationHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/OrganizationAffiliationHistoryIdentityFilter.java index 2cd7a07c0..79022b61b 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/OrganizationAffiliationHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/OrganizationAffiliationHistoryIdentityFilter.java @@ -1,19 +1,21 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.OrganizationAffiliation; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.OrganizationAffiliationIdentityFilter; public class OrganizationAffiliationHistoryIdentityFilter extends OrganizationAffiliationIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = OrganizationAffiliation.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.OrganizationAffiliation); + private static final String RESOURCE_TYPE = ResourceType.OrganizationAffiliation.name(); public OrganizationAffiliationHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/OrganizationHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/OrganizationHistoryIdentityFilter.java index f5ad93995..329f952f2 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/OrganizationHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/OrganizationHistoryIdentityFilter.java @@ -1,18 +1,20 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.Organization; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.OrganizationIdentityFilter; public class OrganizationHistoryIdentityFilter extends OrganizationIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = Organization.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.Organization); + private static final String RESOURCE_TYPE = ResourceType.Organization.name(); public OrganizationHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/PatientHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/PatientHistoryIdentityFilter.java index 68e89c5a0..a76b7a809 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/PatientHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/PatientHistoryIdentityFilter.java @@ -1,18 +1,20 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.Patient; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.PatientIdentityFilter; public class PatientHistoryIdentityFilter extends PatientIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = Patient.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.Patient); + private static final String RESOURCE_TYPE = ResourceType.Patient.name(); public PatientHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/PractitionerHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/PractitionerHistoryIdentityFilter.java index a86aee2d5..8b0a94dac 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/PractitionerHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/PractitionerHistoryIdentityFilter.java @@ -1,18 +1,20 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.Practitioner; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.PractitionerIdentityFilter; public class PractitionerHistoryIdentityFilter extends PractitionerIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = Practitioner.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.Practitioner); + private static final String RESOURCE_TYPE = ResourceType.Practitioner.name(); public PractitionerHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/PractitionerRoleHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/PractitionerRoleHistoryIdentityFilter.java index e10b46c8d..5f07a9c7d 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/PractitionerRoleHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/PractitionerRoleHistoryIdentityFilter.java @@ -1,19 +1,21 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.PractitionerRole; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.PractitionerRoleIdentityFilter; public class PractitionerRoleHistoryIdentityFilter extends PractitionerRoleIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = PractitionerRole.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.PractitionerRole); + private static final String RESOURCE_TYPE = ResourceType.PractitionerRole.name(); public PractitionerRoleHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/ProvenanceHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/ProvenanceHistoryIdentityFilter.java index f6bbf8867..d8ceb4efd 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/ProvenanceHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/ProvenanceHistoryIdentityFilter.java @@ -1,18 +1,20 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.Provenance; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.ProvenanceIdentityFilter; public class ProvenanceHistoryIdentityFilter extends ProvenanceIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = Provenance.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.Provenance); + private static final String RESOURCE_TYPE = ResourceType.Provenance.name(); public ProvenanceHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/QuestionnaireHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/QuestionnaireHistoryIdentityFilter.java index 6eeedd657..7cd6902be 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/QuestionnaireHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/QuestionnaireHistoryIdentityFilter.java @@ -1,18 +1,20 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.Questionnaire; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.QuestionnaireIdentityFilter; public class QuestionnaireHistoryIdentityFilter extends QuestionnaireIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = Questionnaire.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.Questionnaire); + private static final String RESOURCE_TYPE = ResourceType.Questionnaire.name(); public QuestionnaireHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/QuestionnaireResponseHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/QuestionnaireResponseHistoryIdentityFilter.java index 5772f857a..8c7ac2b35 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/QuestionnaireResponseHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/QuestionnaireResponseHistoryIdentityFilter.java @@ -1,19 +1,21 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.QuestionnaireResponse; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.QuestionnaireResponseIdentityFilter; public class QuestionnaireResponseHistoryIdentityFilter extends QuestionnaireResponseIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = QuestionnaireResponse.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.QuestionnaireResponse); + private static final String RESOURCE_TYPE = ResourceType.QuestionnaireResponse.name(); public QuestionnaireResponseHistoryIdentityFilter(Identity identity) { - super(identity); + super(identity, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/ResearchStudyHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/ResearchStudyHistoryIdentityFilter.java index 7152ea7fd..65e5f016b 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/ResearchStudyHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/ResearchStudyHistoryIdentityFilter.java @@ -1,18 +1,20 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.ResearchStudy; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.ResearchStudyIdentityFilter; public class ResearchStudyHistoryIdentityFilter extends ResearchStudyIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = ResearchStudy.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.ResearchStudy); + private static final String RESOURCE_TYPE = ResourceType.ResearchStudy.name(); public ResearchStudyHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/StructureDefinitionHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/StructureDefinitionHistoryIdentityFilter.java index 25034aee3..0bc247e3c 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/StructureDefinitionHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/StructureDefinitionHistoryIdentityFilter.java @@ -1,19 +1,21 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.StructureDefinition; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.StructureDefinitionIdentityFilter; public class StructureDefinitionHistoryIdentityFilter extends StructureDefinitionIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = StructureDefinition.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.StructureDefinition); + private static final String RESOURCE_TYPE = ResourceType.StructureDefinition.name(); public StructureDefinitionHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/SubscriptionHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/SubscriptionHistoryIdentityFilter.java index 740021d42..4e7ce4eaf 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/SubscriptionHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/SubscriptionHistoryIdentityFilter.java @@ -1,18 +1,20 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.Subscription; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.SubscriptionIdentityFilter; public class SubscriptionHistoryIdentityFilter extends SubscriptionIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = Subscription.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.Subscription); + private static final String RESOURCE_TYPE = ResourceType.Subscription.name(); public SubscriptionHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/TaskHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/TaskHistoryIdentityFilter.java index 632f68bca..eca9e9627 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/TaskHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/TaskHistoryIdentityFilter.java @@ -1,18 +1,20 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.Task; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.TaskIdentityFilter; public class TaskHistoryIdentityFilter extends TaskIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = Task.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.Task); + private static final String RESOURCE_TYPE = ResourceType.Task.name(); public TaskHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/ValueSetHistoryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/ValueSetHistoryIdentityFilter.java index 5f33d5385..231fcca8e 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/ValueSetHistoryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/history/filter/ValueSetHistoryIdentityFilter.java @@ -1,18 +1,20 @@ package dev.dsf.fhir.history.filter; -import org.hl7.fhir.r4.model.ValueSet; +import org.hl7.fhir.r4.model.ResourceType; -import ca.uhn.fhir.model.api.annotation.ResourceDef; import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.search.filter.ValueSetIdentityFilter; public class ValueSetHistoryIdentityFilter extends ValueSetIdentityFilter implements HistoryIdentityFilter { - private static final String RESOURCE_TYPE = ValueSet.class.getAnnotation(ResourceDef.class).name(); + private static final FhirServerRole HISTORY_ROLE = FhirServerRoleImpl.history(ResourceType.ValueSet); + private static final String RESOURCE_TYPE = ResourceType.ValueSet.name(); public ValueSetHistoryIdentityFilter(Identity identity) { - super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN); + super(identity, HistoryIdentityFilter.RESOURCE_TABLE, HistoryIdentityFilter.RESOURCE_ID_COLUMN, HISTORY_ROLE); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/AbstractMetaTagAuthorizationRoleIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/AbstractMetaTagAuthorizationRoleIdentityFilter.java index 0bb51ade6..2ce10009a 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/AbstractMetaTagAuthorizationRoleIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/AbstractMetaTagAuthorizationRoleIdentityFilter.java @@ -10,19 +10,26 @@ abstract class AbstractMetaTagAuthorizationRoleIdentityFilter extends AbstractIdentityFilter { - AbstractMetaTagAuthorizationRoleIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + private final FhirServerRole operationRole; + private final FhirServerRole readRole; + + AbstractMetaTagAuthorizationRoleIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole, FhirServerRole readRole) { super(identity, resourceTable, resourceIdColumn); + + this.operationRole = operationRole; + this.readRole = readRole; } @Override public String getFilterQuery() { - if (identity.isLocalIdentity() && identity.hasDsfRole(FhirServerRole.READ)) + if (identity.isLocalIdentity() && identity.hasDsfRole(operationRole) && identity.hasDsfRole(readRole)) return "(SELECT count(*) FROM read_access WHERE read_access.resource_id = " + resourceTable + "." + resourceIdColumn + " AND read_access.resource_version = " + resourceTable + ".version" + " AND (read_access.organization_id = ? OR read_access.access_type = 'ALL' OR read_access.access_type = 'LOCAL')) > 0"; - else if (identity.hasDsfRole(FhirServerRole.READ)) + else if (identity.hasDsfRole(operationRole) && identity.hasDsfRole(readRole)) return "(SELECT count(*) FROM read_access WHERE read_access.resource_id = " + resourceTable + "." + resourceIdColumn + " AND read_access.resource_version = " + resourceTable + ".version" + " AND (read_access.organization_id = ? OR read_access.access_type = 'ALL')) > 0"; @@ -33,14 +40,14 @@ else if (identity.hasDsfRole(FhirServerRole.READ)) @Override public int getSqlParameterCount() { - return identity.hasDsfRole(FhirServerRole.READ) ? 1 : 0; + return identity.hasDsfRole(operationRole) && identity.hasDsfRole(readRole) ? 1 : 0; } @Override public void modifyStatement(int parameterIndex, int subqueryParameterIndex, PreparedStatement statement) throws SQLException { - if (identity.hasDsfRole(FhirServerRole.READ)) + if (identity.hasDsfRole(operationRole) && identity.hasDsfRole(readRole)) { String usersOrganizationId = identity.getOrganization().getIdElement().getIdPart(); statement.setObject(parameterIndex, toUuidObject(usersOrganizationId)); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/ActivityDefinitionIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/ActivityDefinitionIdentityFilter.java index f49b89a1c..239c94af5 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/ActivityDefinitionIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/ActivityDefinitionIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class ActivityDefinitionIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.ActivityDefinition); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.ActivityDefinition); + private static final String RESOURCE_TABLE = "current_activity_definitions"; private static final String RESOURCE_ID_COLUMN = "activity_definition_id"; public ActivityDefinitionIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public ActivityDefinitionIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public ActivityDefinitionIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/BinaryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/BinaryIdentityFilter.java index 84b1c4f79..7c237be34 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/BinaryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/BinaryIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class BinaryIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.Binary); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.Binary); + private static final String RESOURCE_TABLE = "current_binaries"; private static final String RESOURCE_ID_COLUMN = "binary_id"; public BinaryIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public BinaryIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public BinaryIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/BundleIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/BundleIdentityFilter.java index 094be7924..54dc48771 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/BundleIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/BundleIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class BundleIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.Bundle); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.Bundle); + private static final String RESOURCE_TABLE = "current_bundles"; private static final String RESOURCE_ID_COLUMN = "bundle_id"; public BundleIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public BundleIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public BundleIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/CodeSystemIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/CodeSystemIdentityFilter.java index 041efebf5..de7cb7503 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/CodeSystemIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/CodeSystemIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class CodeSystemIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.CodeSystem); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.CodeSystem); + private static final String RESOURCE_TABLE = "current_code_systems"; private static final String RESOURCE_ID_COLUMN = "code_system_id"; public CodeSystemIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public CodeSystemIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public CodeSystemIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/DocumentReferenceIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/DocumentReferenceIdentityFilter.java index c06d20e87..5c3d84254 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/DocumentReferenceIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/DocumentReferenceIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class DocumentReferenceIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.DocumentReference); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.DocumentReference); + private static final String RESOURCE_TABLE = "current_document_references"; private static String RESOURCE_ID_COLUMN = "document_reference_id"; public DocumentReferenceIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public DocumentReferenceIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public DocumentReferenceIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/EndpointIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/EndpointIdentityFilter.java index 9a78827ff..0d4a750de 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/EndpointIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/EndpointIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class EndpointIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.Endpoint); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.Endpoint); + private static final String RESOURCE_TABLE = "current_endpoints"; private static final String RESOURCE_ID_COLUMN = "endpoint_id"; public EndpointIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public EndpointIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public EndpointIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/GroupIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/GroupIdentityFilter.java index f32e8fdfe..d3cf19e17 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/GroupIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/GroupIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class GroupIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.Group); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.Group); + private static final String RESOURCE_TABLE = "current_groups"; private static final String RESOURCE_ID_COLUMN = "group_id"; public GroupIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public GroupIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public GroupIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/HealthcareServiceIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/HealthcareServiceIdentityFilter.java index 89e7d4d23..839c55f1e 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/HealthcareServiceIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/HealthcareServiceIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class HealthcareServiceIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.HealthcareService); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.HealthcareService); + private static final String RESOURCE_TABLE = "current_healthcare_services"; private static final String RESOURCE_ID_COLUMN = "healthcare_service_id"; public HealthcareServiceIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public HealthcareServiceIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public HealthcareServiceIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/LibraryIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/LibraryIdentityFilter.java index 859fccbb2..6a70007e2 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/LibraryIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/LibraryIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class LibraryIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.Library); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.Library); + private static final String RESOURCE_TABLE = "current_libraries"; private static final String RESOURCE_ID_COLUMN = "library_id"; public LibraryIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public LibraryIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public LibraryIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/LocationIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/LocationIdentityFilter.java index 5bc15afa8..cbb6f8c29 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/LocationIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/LocationIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class LocationIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.Location); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.Location); + private static final String RESOURCE_TABLE = "current_locations"; private static final String RESOURCE_ID_COLUMN = "location_id"; public LocationIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public LocationIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public LocationIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/MeasureIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/MeasureIdentityFilter.java index bb1544253..cc147c98a 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/MeasureIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/MeasureIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class MeasureIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.Measure); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.Measure); + private static final String RESOURCE_TABLE = "current_measures"; private static final String RESOURCE_ID_COLUMN = "measure_id"; public MeasureIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public MeasureIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public MeasureIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/MeasureReportIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/MeasureReportIdentityFilter.java index 77ef6341e..330a0974b 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/MeasureReportIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/MeasureReportIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class MeasureReportIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.MeasureReport); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.MeasureReport); + private static final String RESOURCE_TABLE = "current_measure_reports"; private static final String RESOURCE_ID_COLUMN = "measure_report_id"; public MeasureReportIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public MeasureReportIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public MeasureReportIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/NamingSystemIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/NamingSystemIdentityFilter.java index 16192fa01..5b5c1b263 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/NamingSystemIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/NamingSystemIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class NamingSystemIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.NamingSystem); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.NamingSystem); + private static final String RESOURCE_TABLE = "current_naming_systems"; private static final String RESOURCE_ID_COLUMN = "naming_system_id"; public NamingSystemIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public NamingSystemIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public NamingSystemIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/OrganizationAffiliationIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/OrganizationAffiliationIdentityFilter.java index 2068160a1..7ce25fd33 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/OrganizationAffiliationIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/OrganizationAffiliationIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class OrganizationAffiliationIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.OrganizationAffiliation); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.OrganizationAffiliation); + private static final String RESOURCE_TABLE = "current_organization_affiliations"; private static final String RESOURCE_ID_COLUMN = "organization_affiliation_id"; public OrganizationAffiliationIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public OrganizationAffiliationIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public OrganizationAffiliationIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/OrganizationIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/OrganizationIdentityFilter.java index d3d2f7682..8ccb2ccde 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/OrganizationIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/OrganizationIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class OrganizationIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.Organization); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.Organization); + private static final String RESOURCE_TABLE = "current_organizations"; private static final String RESOURCE_ID_COLUMN = "organization_id"; public OrganizationIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public OrganizationIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public OrganizationIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/PatientIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/PatientIdentityFilter.java index 12d527707..2b5f5d050 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/PatientIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/PatientIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class PatientIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.Patient); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.Patient); + private static final String RESOURCE_TABLE = "current_patients"; private static final String RESOURCE_ID_COLUMN = "patient_id"; public PatientIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public PatientIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public PatientIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/PractitionerIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/PractitionerIdentityFilter.java index 3e07fe8ff..e0efff55a 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/PractitionerIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/PractitionerIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class PractitionerIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.Practitioner); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.Practitioner); + private static final String RESOURCE_TABLE = "current_practitioners"; private static final String RESOURCE_ID_COLUMN = "practitioner_id"; public PractitionerIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public PractitionerIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public PractitionerIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/PractitionerRoleIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/PractitionerRoleIdentityFilter.java index 9e477fa2d..cd9e135ac 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/PractitionerRoleIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/PractitionerRoleIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class PractitionerRoleIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.PractitionerRole); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.PractitionerRole); + private static final String RESOURCE_TABLE = "current_practitioner_roles"; private static String RESOURCE_ID_COLUMN = "practitioner_role_id"; public PractitionerRoleIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public PractitionerRoleIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public PractitionerRoleIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/ProvenanceIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/ProvenanceIdentityFilter.java index 4b59d87f1..9a838d977 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/ProvenanceIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/ProvenanceIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class ProvenanceIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.Provenance); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.Provenance); + private static final String RESOURCE_TABLE = "current_provenances"; private static final String RESOURCE_ID_COLUMN = "provenance_id"; public ProvenanceIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public ProvenanceIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public ProvenanceIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/QuestionnaireIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/QuestionnaireIdentityFilter.java index 4f727f452..01a144561 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/QuestionnaireIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/QuestionnaireIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class QuestionnaireIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.Questionnaire); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.Questionnaire); + private static final String RESOURCE_TABLE = "current_questionnaires"; private static final String RESOURCE_ID_COLUMN = "questionnaire_id"; public QuestionnaireIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public QuestionnaireIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public QuestionnaireIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/QuestionnaireResponseIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/QuestionnaireResponseIdentityFilter.java index e231facee..c20d01246 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/QuestionnaireResponseIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/QuestionnaireResponseIdentityFilter.java @@ -3,21 +3,36 @@ import java.sql.PreparedStatement; import java.sql.SQLException; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class QuestionnaireResponseIdentityFilter extends AbstractIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.QuestionnaireResponse); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.QuestionnaireResponse); + + private final FhirServerRole operationRole; + public QuestionnaireResponseIdentityFilter(Identity identity) + { + this(identity, SEARCH_ROLE); + } + + public QuestionnaireResponseIdentityFilter(Identity identity, FhirServerRole operationRole) { super(identity, null, null); + + this.operationRole = operationRole; } @Override public String getFilterQuery() { // read allowed for local users - if (identity.isLocalIdentity() && identity.hasDsfRole(FhirServerRole.READ)) + if (identity.isLocalIdentity() && identity.hasDsfRole(operationRole) && identity.hasDsfRole(READ_ROLE)) return ""; // read not allowed for non local users diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/ResearchStudyIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/ResearchStudyIdentityFilter.java index 5d25eeaf7..dc23134b8 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/ResearchStudyIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/ResearchStudyIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class ResearchStudyIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.ResearchStudy); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.ResearchStudy); + private static final String RESOURCE_TABLE = "current_research_studies"; private static final String RESOURCE_ID_COLUMN = "research_study_id"; public ResearchStudyIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public ResearchStudyIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public ResearchStudyIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/StructureDefinitionIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/StructureDefinitionIdentityFilter.java index 81513764f..d3cbe155c 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/StructureDefinitionIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/StructureDefinitionIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class StructureDefinitionIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.StructureDefinition); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.StructureDefinition); + private static final String RESOURCE_TABLE = "current_structure_definitions"; private static final String RESOURCE_ID_COLUMN = "structure_definition_id"; public StructureDefinitionIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public StructureDefinitionIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public StructureDefinitionIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/StructureDefinitionSnapshotIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/StructureDefinitionSnapshotIdentityFilter.java index e619c79a3..a266aea8c 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/StructureDefinitionSnapshotIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/StructureDefinitionSnapshotIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class StructureDefinitionSnapshotIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.StructureDefinition); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.StructureDefinition); + private static final String RESOURCE_TABLE = "current_structure_definition_snapshots"; private static final String RESOURCE_ID_COLUMN = "structure_definition_snapshot_id"; public StructureDefinitionSnapshotIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public StructureDefinitionSnapshotIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public StructureDefinitionSnapshotIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/SubscriptionIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/SubscriptionIdentityFilter.java index 175597a12..b700a9a08 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/SubscriptionIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/SubscriptionIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class SubscriptionIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.Subscription); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.Subscription); + private static final String RESOURCE_TABLE = "current_subscriptions"; private static final String RESOURCE_ID_COLUMN = "subscription_id"; public SubscriptionIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public SubscriptionIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public SubscriptionIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/TaskIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/TaskIdentityFilter.java index 6fb8aebbc..0eecef93f 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/TaskIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/TaskIdentityFilter.java @@ -3,33 +3,39 @@ import java.sql.PreparedStatement; import java.sql.SQLException; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class TaskIdentityFilter extends AbstractIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.Task); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.Task); + private static final String RESOURCE_COLUMN = "task"; private final String resourceColumn; + private final FhirServerRole operationRole; public TaskIdentityFilter(Identity identity) { - super(identity, null, null); - - this.resourceColumn = RESOURCE_COLUMN; + this(identity, RESOURCE_COLUMN, SEARCH_ROLE); } - public TaskIdentityFilter(Identity identity, String resourceColumn) + public TaskIdentityFilter(Identity identity, String resourceColumn, FhirServerRole operationRole) { super(identity, null, null); this.resourceColumn = resourceColumn; + this.operationRole = operationRole; } @Override public String getFilterQuery() { - if (identity.hasDsfRole(FhirServerRole.READ)) + if (identity.hasDsfRole(operationRole) && identity.hasDsfRole(READ_ROLE)) { // TODO modify for requester = Practitioner or PractitionerRole return "(" + resourceColumn + "->'requester'->>'reference' = ? OR " + resourceColumn @@ -44,14 +50,14 @@ public String getFilterQuery() @Override public int getSqlParameterCount() { - return identity.hasDsfRole(FhirServerRole.READ) ? 4 : 0; + return identity.hasDsfRole(operationRole) && identity.hasDsfRole(READ_ROLE) ? 4 : 0; } @Override public void modifyStatement(int parameterIndex, int subqueryParameterIndex, PreparedStatement statement) throws SQLException { - if (identity.hasDsfRole(FhirServerRole.READ)) + if (identity.hasDsfRole(operationRole) && identity.hasDsfRole(READ_ROLE)) { if (subqueryParameterIndex == 1) statement.setString(parameterIndex, identity.getOrganization().getIdElement().getValue()); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/ValueSetIdentityFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/ValueSetIdentityFilter.java index 92ed1e555..dc4bb2852 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/ValueSetIdentityFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/filter/ValueSetIdentityFilter.java @@ -1,19 +1,27 @@ package dev.dsf.fhir.search.filter; +import org.hl7.fhir.r4.model.ResourceType; + import dev.dsf.common.auth.conf.Identity; +import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class ValueSetIdentityFilter extends AbstractMetaTagAuthorizationRoleIdentityFilter { + private static final FhirServerRole SEARCH_ROLE = FhirServerRoleImpl.search(ResourceType.ValueSet); + private static final FhirServerRole READ_ROLE = FhirServerRoleImpl.read(ResourceType.ValueSet); + private static final String RESOURCE_TABLE = "current_value_sets"; private static final String RESOURCE_ID_COLUMN = "value_set_id"; public ValueSetIdentityFilter(Identity identity) { - super(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN); + this(identity, RESOURCE_TABLE, RESOURCE_ID_COLUMN, SEARCH_ROLE); } - public ValueSetIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn) + public ValueSetIdentityFilter(Identity identity, String resourceTable, String resourceIdColumn, + FhirServerRole operationRole) { - super(identity, resourceTable, resourceIdColumn); + super(identity, resourceTable, resourceIdColumn, operationRole, READ_ROLE); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/InitialDataLoaderImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/InitialDataLoaderImpl.java index 6616c91df..c092dc5b0 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/InitialDataLoaderImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/InitialDataLoaderImpl.java @@ -1,6 +1,5 @@ package dev.dsf.fhir.service; -import java.util.EnumSet; import java.util.Objects; import org.hl7.fhir.r4.model.Bundle; @@ -13,7 +12,7 @@ import ca.uhn.fhir.context.FhirContext; import dev.dsf.common.auth.conf.Identity; import dev.dsf.common.auth.conf.OrganizationIdentityImpl; -import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.authorization.read.ReadAccessHelper; import dev.dsf.fhir.dao.command.CommandFactory; import dev.dsf.fhir.dao.command.CommandList; @@ -28,8 +27,8 @@ public class InitialDataLoaderImpl implements InitialDataLoader, InitializingBea Organization org = new Organization().setName("Initial Data Loader"); org.addIdentifier().setSystem(ReadAccessHelper.ORGANIZATION_IDENTIFIER_SYSTEM).setValue("initial.data.loader"); - INITIAL_DATA_LOADER = new OrganizationIdentityImpl(true, org, null, - EnumSet.of(FhirServerRole.CREATE, FhirServerRole.DELETE, FhirServerRole.UPDATE), null); + INITIAL_DATA_LOADER = new OrganizationIdentityImpl(true, org, null, FhirServerRoleImpl.INITIAL_DATA_LOADER, + null); } private static final Logger logger = LoggerFactory.getLogger(InitialDataLoaderImpl.class); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ReferenceResolver.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ReferenceResolver.java index 048d9e8ca..bc9103f8a 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ReferenceResolver.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ReferenceResolver.java @@ -6,8 +6,6 @@ import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.Resource; -import dev.dsf.common.auth.conf.Identity; - public interface ReferenceResolver { /** @@ -20,8 +18,6 @@ public interface ReferenceResolver boolean referenceCanBeResolved(ResourceReference reference, Connection connection); /** - * @param identity - * not null * @param reference * not null * @param connection @@ -33,7 +29,7 @@ public interface ReferenceResolver * {@link ResourceReference.ReferenceType#CONDITIONAL} or * {@link ResourceReference.ReferenceType#LOGICAL} */ - Optional resolveReference(Identity identity, ResourceReference reference, Connection connection); + Optional resolveReference(ResourceReference reference, Connection connection); /** * @param resource @@ -96,8 +92,6 @@ Optional checkLiteralExternalReference(Resource resource, Reso Integer bundleIndex) throws IllegalArgumentException; /** - * @param identity - * not null * @param resource * not null * @param resourceReference @@ -111,13 +105,10 @@ Optional checkLiteralExternalReference(Resource resource, Reso * if the reference is not of type {@link ResourceReference.ReferenceType#CONDITIONAL} * @see ResourceReference#getType(String) */ - Optional checkConditionalReference(Identity identity, Resource resource, - ResourceReference resourceReference, Connection connection, Integer bundleIndex) - throws IllegalArgumentException; + Optional checkConditionalReference(Resource resource, ResourceReference resourceReference, + Connection connection, Integer bundleIndex) throws IllegalArgumentException; /** - * @param identity - * not null * @param resource * not null * @param resourceReference @@ -129,12 +120,10 @@ Optional checkConditionalReference(Identity identity, Resource * if the reference is not of type {@link ResourceReference.ReferenceType#LOGICAL} * @see ResourceReference#getType(String) */ - Optional checkLogicalReference(Identity identity, Resource resource, - ResourceReference resourceReference, Connection connection) throws IllegalArgumentException; + Optional checkLogicalReference(Resource resource, ResourceReference resourceReference, + Connection connection) throws IllegalArgumentException; /** - * @param identity - * not null * @param resource * not null * @param resourceReference @@ -148,13 +137,10 @@ Optional checkLogicalReference(Identity identity, Resource res * if the reference is not of type {@link ResourceReference.ReferenceType#LOGICAL} * @see ResourceReference#getType(String) */ - Optional checkLogicalReference(Identity identity, Resource resource, - ResourceReference resourceReference, Connection connection, Integer bundleIndex) - throws IllegalArgumentException; + Optional checkLogicalReference(Resource resource, ResourceReference resourceReference, + Connection connection, Integer bundleIndex) throws IllegalArgumentException; /** - * @param identity - * not null * @param resource * not null * @param reference @@ -166,12 +152,10 @@ Optional checkLogicalReference(Identity identity, Resource res * if the reference is not of type {@link ResourceReference.ReferenceType#CANONICAL} * @see ResourceReference#getType(String) */ - Optional checkCanonicalReference(Identity identity, Resource resource, - ResourceReference reference, Connection connection) throws IllegalArgumentException; + Optional checkCanonicalReference(Resource resource, ResourceReference reference, + Connection connection) throws IllegalArgumentException; /** - * @param identity - * not null * @param resource * not null * @param reference @@ -185,6 +169,6 @@ Optional checkCanonicalReference(Identity identity, Resource r * if the reference is not of type {@link ResourceReference.ReferenceType#CANONICAL} * @see ResourceReference#getType(String) */ - Optional checkCanonicalReference(Identity identity, Resource resource, - ResourceReference reference, Connection connection, Integer bundleIndex) throws IllegalArgumentException; + Optional checkCanonicalReference(Resource resource, ResourceReference reference, + Connection connection, Integer bundleIndex) throws IllegalArgumentException; } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ReferenceResolverImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ReferenceResolverImpl.java index 035a5c226..801f8335e 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ReferenceResolverImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ReferenceResolverImpl.java @@ -22,7 +22,6 @@ import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; -import dev.dsf.common.auth.conf.Identity; import dev.dsf.fhir.client.ClientProvider; import dev.dsf.fhir.client.FhirWebserviceClient; import dev.dsf.fhir.dao.ResourceDao; @@ -95,9 +94,8 @@ public boolean referenceCanBeResolved(ResourceReference reference, Connection co } @Override - public Optional resolveReference(Identity identity, ResourceReference reference, Connection connection) + public Optional resolveReference(ResourceReference reference, Connection connection) { - Objects.requireNonNull(identity, "identity"); Objects.requireNonNull(reference, "reference"); Objects.requireNonNull(connection, "connection"); @@ -108,8 +106,8 @@ public Optional resolveReference(Identity identity, ResourceReference case LITERAL_EXTERNAL, RELATED_ARTEFACT_LITERAL_EXTERNAL_URL, ATTACHMENT_LITERAL_EXTERNAL_URL -> resolveLiteralExternalReference(reference); case CONDITIONAL, RELATED_ARTEFACT_CONDITIONAL_URL, ATTACHMENT_CONDITIONAL_URL -> - resolveConditionalReference(identity, reference, connection); - case LOGICAL -> resolveLogicalReference(identity, reference, connection); + resolveConditionalReference(reference, connection); + case LOGICAL -> resolveLogicalReference(reference, connection); default -> throw new IllegalArgumentException("Reference of type " + type + " not supported"); }; @@ -215,8 +213,7 @@ private Optional resolveLiteralExternalReference(ResourceReference ref } } - private Optional resolveConditionalReference(Identity identity, ResourceReference reference, - Connection connection) + private Optional resolveConditionalReference(ResourceReference reference, Connection connection) { Objects.requireNonNull(reference, "reference"); @@ -252,12 +249,11 @@ private Optional resolveConditionalReference(Identity identity, Resour return Optional.empty(); } - return search(identity, connection, d, reference, condition.getQueryParams(), referenceType); + return search(connection, d, reference, condition.getQueryParams(), referenceType); } } - private Optional resolveLogicalReference(Identity identity, ResourceReference reference, - Connection connection) + private Optional resolveLogicalReference(ResourceReference reference, Connection connection) { Objects.requireNonNull(reference, "reference"); throwIfReferenceTypeUnexpected(reference.getType(serverBase), ReferenceType.LOGICAL); @@ -283,13 +279,13 @@ private Optional resolveLogicalReference(Identity identity, ResourceRe } Identifier targetIdentifier = reference.getReference().getIdentifier(); - return search(identity, connection, d, reference, + return search(connection, d, reference, Map.of("identifier", List.of(targetIdentifier.getSystem() + "|" + targetIdentifier.getValue())), ReferenceType.LOGICAL); } } - private Optional search(Identity identity, Connection connection, ResourceDao referenceTargetDao, + private Optional search(Connection connection, ResourceDao referenceTargetDao, ResourceReference resourceReference, Map> queryParameters, ReferenceType referenceType) { if (Arrays.stream(SearchQuery.STANDARD_PARAMETERS).anyMatch(queryParameters::containsKey)) @@ -305,7 +301,7 @@ private Optional search(Identity identity, Connection connection, Reso .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); } - SearchQuery query = referenceTargetDao.createSearchQuery(identity, PageAndCount.single()); + SearchQuery query = referenceTargetDao.createSearchQueryWithoutUserFilter(PageAndCount.single()); query.configureParameters(queryParameters); List unsupportedQueryParameters = query.getUnsupportedQueryParameters(); @@ -462,10 +458,9 @@ public Optional checkLiteralExternalReference(Resource resourc } @Override - public Optional checkConditionalReference(Identity identity, Resource resource, - ResourceReference reference, Connection connection, Integer bundleIndex) throws IllegalArgumentException + public Optional checkConditionalReference(Resource resource, ResourceReference reference, + Connection connection, Integer bundleIndex) throws IllegalArgumentException { - Objects.requireNonNull(identity, "identity"); Objects.requireNonNull(resource, "resource"); Objects.requireNonNull(reference, "reference"); Objects.requireNonNull(connection, "connection"); @@ -489,7 +484,7 @@ public Optional checkConditionalReference(Identity identity, R responseGenerator.referenceTargetTypeNotSupportedByResource(bundleIndex, resource, reference)); // Resource target = - return search(identity, resource, bundleIndex, connection, d, reference, condition.getQueryParams(), true); + return search(resource, bundleIndex, connection, d, reference, condition.getQueryParams(), true); // TODO add literal reference for conditional reference somewhere else // reference.getReference().setIdentifier(null).setReferenceElement( @@ -500,17 +495,16 @@ public Optional checkConditionalReference(Identity identity, R } @Override - public Optional checkLogicalReference(Identity identity, Resource resource, - ResourceReference resourceReference, Connection connection) throws IllegalArgumentException + public Optional checkLogicalReference(Resource resource, ResourceReference resourceReference, + Connection connection) throws IllegalArgumentException { - return checkLogicalReference(identity, resource, resourceReference, connection, null); + return checkLogicalReference(resource, resourceReference, connection, null); } @Override - public Optional checkLogicalReference(Identity identity, Resource resource, - ResourceReference reference, Connection connection, Integer bundleIndex) throws IllegalArgumentException + public Optional checkLogicalReference(Resource resource, ResourceReference reference, + Connection connection, Integer bundleIndex) throws IllegalArgumentException { - Objects.requireNonNull(identity, "identity"); Objects.requireNonNull(resource, "resource"); Objects.requireNonNull(reference, "reference"); Objects.requireNonNull(connection, "connection"); @@ -532,7 +526,7 @@ public Optional checkLogicalReference(Identity identity, Resou Identifier targetIdentifier = reference.getReference().getIdentifier(); // Resource target = - return search(identity, resource, bundleIndex, connection, d, reference, + return search(resource, bundleIndex, connection, d, reference, Map.of("identifier", List.of(targetIdentifier.getSystem() + "|" + targetIdentifier.getValue())), true); @@ -547,8 +541,8 @@ public Optional checkLogicalReference(Identity identity, Resou // return Optional.empty(); } - private Optional search(Identity identity, Resource resource, Integer bundleIndex, - Connection connection, ResourceDao referenceTargetDao, ResourceReference resourceReference, + private Optional search(Resource resource, Integer bundleIndex, Connection connection, + ResourceDao referenceTargetDao, ResourceReference resourceReference, Map> queryParameters, boolean logicalNotConditional) { if (Arrays.stream(SearchQuery.STANDARD_PARAMETERS).anyMatch(queryParameters::containsKey)) @@ -564,7 +558,7 @@ private Optional search(Identity identity, Resource resource, .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); } - SearchQuery query = referenceTargetDao.createSearchQuery(identity, PageAndCount.exists()); + SearchQuery query = referenceTargetDao.createSearchQueryWithoutUserFilter(PageAndCount.exists()); query.configureParameters(queryParameters); List unsupportedQueryParameters = query.getUnsupportedQueryParameters(); @@ -604,17 +598,16 @@ else if (result.getTotal() == 1) } @Override - public Optional checkCanonicalReference(Identity identity, Resource resource, - ResourceReference reference, Connection connection) throws IllegalArgumentException + public Optional checkCanonicalReference(Resource resource, ResourceReference reference, + Connection connection) throws IllegalArgumentException { - return checkCanonicalReference(identity, resource, reference, connection, null); + return checkCanonicalReference(resource, reference, connection, null); } @Override - public Optional checkCanonicalReference(Identity identity, Resource resource, - ResourceReference reference, Connection connection, Integer bundleIndex) throws IllegalArgumentException + public Optional checkCanonicalReference(Resource resource, ResourceReference reference, + Connection connection, Integer bundleIndex) throws IllegalArgumentException { - Objects.requireNonNull(identity, "identity"); Objects.requireNonNull(resource, "resource"); Objects.requireNonNull(reference, "reference"); Objects.requireNonNull(connection, "connection"); @@ -636,7 +629,7 @@ public Optional checkCanonicalReference(Identity identity, Res return Optional.empty(); } - Optional referencedResource = referenceDao.flatMap(dao -> search(identity, connection, dao, reference, + Optional referencedResource = referenceDao.flatMap(dao -> search(connection, dao, reference, Map.of("url", List.of(reference.getCanonical().getValue())), ReferenceType.CANONICAL)); if (referencedResource.isPresent()) diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/AuthenticationConfig.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/AuthenticationConfig.java index d6e09ced8..22509b946 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/AuthenticationConfig.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/AuthenticationConfig.java @@ -13,6 +13,7 @@ import dev.dsf.fhir.authentication.EndpointProvider; import dev.dsf.fhir.authentication.EndpointProviderImpl; import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.authentication.IdentityProviderImpl; import dev.dsf.fhir.authentication.OrganizationProvider; import dev.dsf.fhir.authentication.OrganizationProviderImpl; @@ -53,11 +54,10 @@ public IdentityProvider identityProvider() } @Bean - public RoleConfig roleConfig() + public RoleConfig roleConfig() { - RoleConfig config = new RoleConfigReader().read(propertiesConfig.getRoleConfig(), - role -> FhirServerRole.isValid(role) ? FhirServerRole.valueOf(role) : null, - this::practionerRoleFactory); + RoleConfig config = new RoleConfigReader().read(propertiesConfig.getRoleConfig(), + FhirServerRoleImpl::from, this::practionerRoleFactory); logger.info("Role config: {}", config.toString()); return config; diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/subscription/WebSocketSubscriptionManagerImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/subscription/WebSocketSubscriptionManagerImpl.java index 9d9d29410..6b83e4d92 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/subscription/WebSocketSubscriptionManagerImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/subscription/WebSocketSubscriptionManagerImpl.java @@ -278,7 +278,7 @@ else if (Constants.CT_FHIR_XML_NEW.contentEquals(s.getChannel().getPayload())) // defensive copy because list could be changed by other threads while we are reading List remotes = new ArrayList<>(optRemotes.get()); - remotes.stream().filter(r -> userHasReadAccess(r, event)).forEach(r -> send(r, text)); + remotes.stream().filter(r -> userHasReadAndWebsocketAccess(r, event)).forEach(r -> send(r, text)); } private IParser newXmlParser() @@ -298,7 +298,7 @@ private IParser configureParser(IParser p) return p; } - private boolean userHasReadAccess(SessionIdAndRemoteAsync sessionAndRemote, Event event) + private boolean userHasReadAndWebsocketAccess(SessionIdAndRemoteAsync sessionAndRemote, Event event) { Optional> optRule = authorizationRuleProvider .getAuthorizationRule(event.getResourceType()); @@ -306,18 +306,23 @@ private boolean userHasReadAccess(SessionIdAndRemoteAsync sessionAndRemote, Even { @SuppressWarnings("unchecked") AuthorizationRule rule = (AuthorizationRule) optRule.get(); - Optional optReason = rule.reasonReadAllowed(sessionAndRemote.identity, event.getResource()); + Optional readAllowedReason = rule.reasonReadAllowed(sessionAndRemote.identity, event.getResource()); + Optional websocketAllowedReason = rule.reasonWebsocketAllowed(sessionAndRemote.identity, + event.getResource()); - if (optReason.isPresent()) + if (readAllowedReason.isPresent() && websocketAllowedReason.isPresent()) { - logger.info("Sending event {} to user {}, read of {} allowed {}", event.getClass().getSimpleName(), - sessionAndRemote.identity.getName(), event.getResourceType().getSimpleName(), optReason.get()); + logger.info("Sending event {} to user {}, websocket access and read of {} allowed {}, {}", + event.getClass().getSimpleName(), sessionAndRemote.identity.getName(), + event.getResourceType().getSimpleName(), websocketAllowedReason.get(), + readAllowedReason.isPresent()); return true; } else { - logger.warn("Skipping event {} for user {}, read of {} not allowed", event.getClass().getSimpleName(), - sessionAndRemote.identity.getName(), event.getResourceType().getSimpleName()); + logger.warn("Skipping event {} for user {}, websocket access or read of {} not allowed", + event.getClass().getSimpleName(), sessionAndRemote.identity.getName(), + event.getResourceType().getSimpleName()); return false; } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/webservice/impl/AbstractResourceServiceImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/webservice/impl/AbstractResourceServiceImpl.java index 3fcbc0d22..201df11c0 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/webservice/impl/AbstractResourceServiceImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/webservice/impl/AbstractResourceServiceImpl.java @@ -252,8 +252,7 @@ private void resolveLogicalReferences(Resource resource, Connection connection) private Optional resolveLogicalReference(Resource resource, ResourceReference reference, Connection connection) { - Optional resolvedResource = referenceResolver.resolveReference(getCurrentIdentity(), reference, - connection); + Optional resolvedResource = referenceResolver.resolveReference(reference, connection); if (resolvedResource.isPresent()) { Resource target = resolvedResource.get(); @@ -292,11 +291,9 @@ private Optional checkReference(Resource resource, Connection case LITERAL_EXTERNAL, RELATED_ARTEFACT_LITERAL_EXTERNAL_URL, ATTACHMENT_LITERAL_EXTERNAL_URL -> referenceResolver.checkLiteralExternalReference(resource, reference); - case LOGICAL -> - referenceResolver.checkLogicalReference(getCurrentIdentity(), resource, reference, connection); + case LOGICAL -> referenceResolver.checkLogicalReference(resource, reference, connection); - case CANONICAL -> - referenceResolver.checkCanonicalReference(getCurrentIdentity(), resource, reference, connection); + case CANONICAL -> referenceResolver.checkCanonicalReference(resource, reference, connection); // unknown URLs to non FHIR servers in related artifacts must not be checked case RELATED_ARTEFACT_UNKNOWN_URL, ATTACHMENT_UNKNOWN_URL -> Optional.empty(); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/websocket/ServerEndpoint.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/websocket/ServerEndpoint.java index 183077bef..4a8896917 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/websocket/ServerEndpoint.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/websocket/ServerEndpoint.java @@ -17,8 +17,9 @@ import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; +import dev.dsf.common.auth.conf.DsfRole; import dev.dsf.common.auth.conf.Identity; -import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; import dev.dsf.fhir.subscription.WebSocketSubscriptionManager; import jakarta.websocket.CloseReason; import jakarta.websocket.CloseReason.CloseCodes; @@ -56,11 +57,11 @@ public void afterPropertiesSet() throws Exception public void onOpen(Session session, EndpointConfig config) { Principal principal = session.getUserPrincipal(); - if (principal == null || !(principal instanceof Identity) - || !((Identity) principal).hasDsfRole(FhirServerRole.WEBSOCKET)) + if (principal == null || !(principal instanceof Identity) || !((Identity) principal).getDsfRoles().stream() + .map(DsfRole::name).anyMatch(FhirServerRoleImpl.Operation.WEBSOCKET.name()::equals)) { logger.warn("No user in session or user is missing role {}, closing websocket, session {}", - FhirServerRole.WEBSOCKET, session.getId()); + FhirServerRoleImpl.Operation.WEBSOCKET, session.getId()); try { session.close(new CloseReason(CloseCodes.VIOLATED_POLICY, "Forbidden")); diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/authentication/IdentityProviderTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/authentication/IdentityProviderTest.java index 60d95c6a8..89e01534c 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/authentication/IdentityProviderTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/authentication/IdentityProviderTest.java @@ -15,7 +15,6 @@ import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.time.Period; -import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.Optional; @@ -40,6 +39,7 @@ import dev.dsf.common.auth.conf.PractitionerIdentity; import dev.dsf.common.auth.conf.RoleConfig; import dev.dsf.common.auth.conf.RoleConfig.Mapping; +import dev.dsf.fhir.authentication.FhirServerRoleImpl.Operation; public class IdentityProviderTest { @@ -117,10 +117,10 @@ public class IdentityProviderTest private OrganizationProvider organizationProvider; private EndpointProvider endpointProvider; - private RoleConfig roleConfig; + private RoleConfig roleConfig; private DsfOpenIdCredentials credentials; - private IdentityProvider createIdentityProvider(List mappings) + private IdentityProvider createIdentityProvider(List> mappings) { when(roleConfig.getEntries()).thenReturn(mappings); @@ -132,16 +132,19 @@ private IdentityProvider createIdentityProvider(List mappings) return provider; } - private Mapping createMappingWithThumbprint(String thumbprint) + private Mapping createMappingWithThumbprint(String thumbprint) { - return new Mapping("test-mapping", List.of(thumbprint), List.of(), List.of(), List.of(), List.of(), List.of()); + return new Mapping("test-mapping", List.of(thumbprint), List.of(), List.of(), List.of(), + List.of(), List.of()); } - private Mapping createMappingWithEmail(String email) + private Mapping createMappingWithEmail(String email) { - return new Mapping("test-mapping", List.of(), List.of(email), List.of(), List.of(), List.of(), List.of()); + return new Mapping("test-mapping", List.of(), List.of(email), List.of(), List.of(), List.of(), + List.of()); } + @SuppressWarnings("unchecked") @Before public void before() throws Exception { @@ -194,7 +197,7 @@ public void testGetOrganizationIdentityByX509CertificateLocalOrganization() thro assertTrue(orgI.getCertificate().isPresent()); assertEquals(LOCAL_ORGANIZATION_CERTIFICATE, orgI.getCertificate().get()); assertEquals(LOCAL_ORGANIZATION_IDENTIFIER_VALUE, orgI.getDisplayName()); - assertEquals(FhirServerRole.LOCAL_ORGANIZATION, orgI.getDsfRoles()); + assertEquals(FhirServerRoleImpl.LOCAL_ORGANIZATION, orgI.getDsfRoles()); assertEquals(LOCAL_ORGANIZATION_IDENTIFIER_VALUE, orgI.getName()); assertEquals(LOCAL_ORGANIZATION, orgI.getOrganization()); assertEquals(LOCAL_ORGANIZATION_IDENTIFIER_VALUE, orgI.getOrganizationIdentifierValue().get()); @@ -225,7 +228,7 @@ public void testGetOrganizationIdentityByX509CertificateRemoteOrganization() thr assertTrue(orgI.getCertificate().isPresent()); assertEquals(REMOTE_ORGANIZATION_CERTIFICATE, orgI.getCertificate().get()); assertEquals(REMOTE_ORGANIZATION_IDENTIFIER_VALUE, orgI.getDisplayName()); - assertEquals(FhirServerRole.REMOTE_ORGANIZATION, orgI.getDsfRoles()); + assertEquals(FhirServerRoleImpl.REMOTE_ORGANIZATION, orgI.getDsfRoles()); assertEquals(REMOTE_ORGANIZATION_IDENTIFIER_VALUE, orgI.getName()); assertEquals(REMOTE_ORGANIZATION, orgI.getOrganization()); assertEquals(REMOTE_ORGANIZATION_IDENTIFIER_VALUE, orgI.getOrganizationIdentifierValue().get()); @@ -270,9 +273,10 @@ public void testGetPractitionerIdentityByX509Certificate() throws Exception when(organizationProvider.getOrganization(LOCAL_ORGANIZATION_CERTIFICATE)).thenReturn(Optional.empty()); when(organizationProvider.getLocalOrganization()).thenReturn(Optional.of(LOCAL_ORGANIZATION)); when(endpointProvider.getLocalEndpoint()).thenReturn(Optional.of(LOCAL_ENDPOINT)); - when(roleConfig.getDsfRolesForEmail(LOCAL_PRACTITIONER_MAIL)).thenReturn(List.of(FhirServerRole.CREATE)); + when(roleConfig.getDsfRolesForEmail(LOCAL_PRACTITIONER_MAIL)) + .thenReturn(List.of(Operation.CREATE.toFhirServerRoleAllResources())); when(roleConfig.getDsfRolesForThumbprint(LOCAL_PRACTITIONER_CERTIFICATE_THUMBPRINT)) - .thenReturn(List.of(FhirServerRole.DELETE)); + .thenReturn(List.of(Operation.DELETE.toFhirServerRoleAllResources())); when(roleConfig.getPractitionerRolesForEmail(LOCAL_PRACTITIONER_MAIL)).thenReturn(List.of(PRACTIONER_ROLE1)); when(roleConfig.getPractitionerRolesForThumbprint(LOCAL_PRACTITIONER_CERTIFICATE_THUMBPRINT)) .thenReturn(List.of(PRACTIONER_ROLE2)); @@ -289,7 +293,8 @@ public void testGetPractitionerIdentityByX509Certificate() throws Exception assertTrue(practitionerI.getCredentials().isEmpty()); assertEquals(LOCAL_PRACTITIONER_NAME_GIVEN + " " + LOCAL_PRACTITIONER_NAME_FAMILY, practitionerI.getDisplayName()); - assertEquals(EnumSet.of(FhirServerRole.CREATE, FhirServerRole.DELETE), practitionerI.getDsfRoles()); + assertEquals(Set.of(Operation.CREATE.toFhirServerRoleAllResources(), + Operation.DELETE.toFhirServerRoleAllResources()), practitionerI.getDsfRoles()); assertEquals(LOCAL_ORGANIZATION_IDENTIFIER_VALUE + "/" + LOCAL_PRACTITIONER_MAIL, practitionerI.getName()); assertEquals(LOCAL_ORGANIZATION, practitionerI.getOrganization()); assertEquals(LOCAL_ORGANIZATION_IDENTIFIER_VALUE, practitionerI.getOrganizationIdentifierValue().get()); @@ -362,11 +367,14 @@ public void testGetPractitionerIdentityByOpenIdCredentials() throws Exception Map.of("resource_access", Map.of(TOKEN_ROLE2_CLIENT, Map.of("roles", new String[] { TOKEN_ROLE2 })), "groups", new String[] { TOKEN_GROUP })); - when(roleConfig.getDsfRolesForEmail(LOCAL_PRACTITIONER_MAIL)).thenReturn(List.of(FhirServerRole.CREATE)); - when(roleConfig.getDsfRolesForTokenRole(TOKEN_ROLE1)).thenReturn(List.of(FhirServerRole.DELETE)); + when(roleConfig.getDsfRolesForEmail(LOCAL_PRACTITIONER_MAIL)) + .thenReturn(List.of(Operation.CREATE.toFhirServerRoleAllResources())); + when(roleConfig.getDsfRolesForTokenRole(TOKEN_ROLE1)) + .thenReturn(List.of(Operation.DELETE.toFhirServerRoleAllResources())); when(roleConfig.getDsfRolesForTokenRole(TOKEN_ROLE2_CLIENT + "." + TOKEN_ROLE2)) - .thenReturn(List.of(FhirServerRole.HISTORY)); - when(roleConfig.getDsfRolesForTokenGroup(TOKEN_GROUP)).thenReturn(List.of(FhirServerRole.PERMANENT_DELETE)); + .thenReturn(List.of(Operation.HISTORY.toFhirServerRoleAllResources())); + when(roleConfig.getDsfRolesForTokenGroup(TOKEN_GROUP)) + .thenReturn(List.of(Operation.PERMANENT_DELETE.toFhirServerRoleAllResources())); when(roleConfig.getPractitionerRolesForEmail(LOCAL_PRACTITIONER_MAIL)).thenReturn(List.of(PRACTIONER_ROLE1)); when(roleConfig.getPractitionerRolesForTokenRole(TOKEN_ROLE1)).thenReturn(List.of(PRACTIONER_ROLE2)); @@ -386,8 +394,10 @@ public void testGetPractitionerIdentityByOpenIdCredentials() throws Exception assertEquals(credentials, practitionerI.getCredentials().get()); assertEquals(LOCAL_PRACTITIONER_NAME_GIVEN + " " + LOCAL_PRACTITIONER_NAME_FAMILY, practitionerI.getDisplayName()); - assertEquals(EnumSet.of(FhirServerRole.CREATE, FhirServerRole.DELETE, FhirServerRole.HISTORY, - FhirServerRole.PERMANENT_DELETE), practitionerI.getDsfRoles()); + assertEquals(Set.of(new FhirServerRoleImpl(Operation.CREATE, List.of()), + new FhirServerRoleImpl(Operation.DELETE, List.of()), + new FhirServerRoleImpl(Operation.HISTORY, List.of()), + new FhirServerRoleImpl(Operation.PERMANENT_DELETE, List.of())), practitionerI.getDsfRoles()); assertEquals(LOCAL_ORGANIZATION_IDENTIFIER_VALUE + "/" + LOCAL_PRACTITIONER_MAIL, practitionerI.getName()); assertEquals(LOCAL_ORGANIZATION, practitionerI.getOrganization()); assertEquals(LOCAL_ORGANIZATION_IDENTIFIER_VALUE, practitionerI.getOrganizationIdentifierValue().get()); diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/TestOrganizationIdentity.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/TestOrganizationIdentity.java index 514241f89..ed1b7462e 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/TestOrganizationIdentity.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/TestOrganizationIdentity.java @@ -6,7 +6,7 @@ import dev.dsf.common.auth.conf.DsfRole; import dev.dsf.common.auth.conf.OrganizationIdentityImpl; -import dev.dsf.fhir.authentication.FhirServerRole; +import dev.dsf.fhir.authentication.FhirServerRoleImpl; public class TestOrganizationIdentity extends OrganizationIdentityImpl { @@ -17,11 +17,11 @@ private TestOrganizationIdentity(boolean localIdentity, Organization organizatio public static TestOrganizationIdentity local(Organization organization) { - return new TestOrganizationIdentity(true, organization, FhirServerRole.LOCAL_ORGANIZATION); + return new TestOrganizationIdentity(true, organization, FhirServerRoleImpl.LOCAL_ORGANIZATION); } public static TestOrganizationIdentity remote(Organization organization) { - return new TestOrganizationIdentity(false, organization, FhirServerRole.REMOTE_ORGANIZATION); + return new TestOrganizationIdentity(false, organization, FhirServerRoleImpl.REMOTE_ORGANIZATION); } } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/TaskIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/TaskIntegrationTest.java index f6f65650c..3e133c845 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/TaskIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/TaskIntegrationTest.java @@ -46,7 +46,6 @@ import dev.dsf.fhir.authentication.OrganizationProvider; import dev.dsf.fhir.dao.OrganizationDao; import dev.dsf.fhir.dao.TaskDao; -import dev.dsf.fhir.dao.TestOrganizationIdentity; import dev.dsf.fhir.dao.command.ReferencesHelperImpl; import dev.dsf.fhir.help.ResponseGenerator; import dev.dsf.fhir.service.ReferenceCleaner; @@ -1459,15 +1458,12 @@ private Bundle createBundle(TaskStatus createStatus, TaskStatus updateStatus, bo Task task = readTestTaskBinary("External_Test_Organization", "Test_Organization"); task.setStatus(createStatus); - OrganizationProvider organizationProvider = getSpringWebApplicationContext() - .getBean(OrganizationProvider.class); ReferenceExtractor referenceExtractor = getSpringWebApplicationContext().getBean(ReferenceExtractor.class); ReferenceResolver referenceResolver = getSpringWebApplicationContext().getBean(ReferenceResolver.class); ResponseGenerator responseGenerator = getSpringWebApplicationContext().getBean(ResponseGenerator.class); DataSource dataSource = getSpringWebApplicationContext().getBean("dataSource", DataSource.class); - ReferencesHelperImpl referencesHelper = new ReferencesHelperImpl<>(0, - TestOrganizationIdentity.local(organizationProvider.getLocalOrganization().get()), task, getBaseUrl(), + ReferencesHelperImpl referencesHelper = new ReferencesHelperImpl<>(0, task, getBaseUrl(), referenceExtractor, referenceResolver, responseGenerator); try (Connection connection = dataSource.getConnection()) { From 0ff5e904cbee6d51f901f869fcb63e7b4092488e Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Sat, 4 Oct 2025 22:01:48 +0200 Subject: [PATCH 2/3] code cleanup --- .../fhir/authorization/AbstractAuthorizationRule.java | 8 +++----- .../AbstractMetaTagAuthorizationRule.java | 10 +++++----- .../dsf/fhir/authorization/TaskAuthorizationRule.java | 9 +++------ 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AbstractAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AbstractAuthorizationRule.java index 0da994d3b..23f649f86 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AbstractAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AbstractAuthorizationRule.java @@ -7,7 +7,6 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.UUID; import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent; @@ -356,14 +355,13 @@ public Optional reasonWebsocketAllowed(Identity identity, R existingReso private Optional reasonWebsocketAllowed(Connection connection, Identity identity, R existingResource) { - final UUID resourceId = parameterConverter.toUuid(getResourceTypeName(), - existingResource.getIdElement().getIdPart()); + final String resourceId = existingResource.getIdElement().getIdPart(); final long resourceVersion = existingResource.getIdElement().getVersionIdPartAsLong(); if (identity.isLocalIdentity() && identity.hasDsfRole(websocketRole)) { logger.info("Websocket access to {}/{}/_history/{} authorized for local identity '{}'", - getResourceTypeName(), resourceId.toString(), resourceVersion, identity.getName()); + getResourceTypeName(), resourceId, resourceVersion, identity.getName()); return Optional.of("Identity has role " + websocketRole); } @@ -371,7 +369,7 @@ private Optional reasonWebsocketAllowed(Connection connection, Identity { logger.warn( "Websocket access to {}/{}/_history/{} unauthorized for identity '{}', not a local identity or no role {}", - getResourceTypeName(), resourceId.toString(), resourceVersion, identity.getName(), websocketRole); + getResourceTypeName(), resourceId, resourceVersion, identity.getName(), websocketRole); return Optional.empty(); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AbstractMetaTagAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AbstractMetaTagAuthorizationRule.java index b6df29c14..4cf305636 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AbstractMetaTagAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AbstractMetaTagAuthorizationRule.java @@ -155,22 +155,22 @@ public final Optional reasonUpdateAllowed(Connection connection, Identit if (modificationsOk(connection, oldResource, newResource)) { logger.info("Update of {}/{}/_history/{} authorized for identity '{}'", getResourceTypeName(), - resourceId.toString(), resourceVersion, identity.getName()); + resourceId, resourceVersion, identity.getName()); return Optional.of("Identity is local identity and has role " + updateRole); } else { logger.warn("Update of {}/{}/_history/{} unauthorized, modification not allowed", - getResourceTypeName(), resourceId.toString(), resourceVersion); + getResourceTypeName(), resourceId, resourceVersion); return Optional.empty(); } } else { - logger.warn("Update of {}/{}/_history/{} unauthorized, {}", getResourceTypeName(), - resourceId.toString(), resourceVersion, errors.get()); + logger.warn("Update of {}/{}/_history/{} unauthorized, {}", getResourceTypeName(), resourceId, + resourceVersion, errors.get()); return Optional.empty(); } @@ -179,7 +179,7 @@ public final Optional reasonUpdateAllowed(Connection connection, Identit { logger.warn( "Update of {}/{}/_history/{} unauthorized for identity '{}', not a local identity or no role {}", - getResourceTypeName(), resourceId.toString(), resourceVersion, identity.getName(), updateRole); + getResourceTypeName(), resourceId, resourceVersion, identity.getName(), updateRole); return Optional.empty(); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/TaskAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/TaskAuthorizationRule.java index e12689633..ce1ebb649 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/TaskAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/TaskAuthorizationRule.java @@ -696,8 +696,7 @@ private List getAffiliations(Connection connection, Str @Override public Optional reasonReadAllowed(Connection connection, Identity identity, Task existingResource) { - final String resourceId = parameterConverter - .toUuid(getResourceTypeName(), existingResource.getIdElement().getIdPart()).toString(); + final String resourceId = existingResource.getIdElement().getIdPart(); final long resourceVersion = existingResource.getIdElement().getVersionIdPartAsLong(); if (identity.hasDsfRole(readRole)) @@ -743,8 +742,7 @@ else if (isCurrentIdentityPartOfReferencedOrganization(connection, identity, "Ta public Optional reasonUpdateAllowed(Connection connection, Identity identity, Task oldResource, Task newResource) { - final String oldResourceId = parameterConverter - .toUuid(getResourceTypeName(), oldResource.getIdElement().getIdPart()).toString(); + final String oldResourceId = oldResource.getIdElement().getIdPart(); final long oldResourceVersion = oldResource.getIdElement().getVersionIdPartAsLong(); if (identity.hasDsfRole(updateRole)) @@ -1059,8 +1057,7 @@ private Predicate isBusinessKey() @Override public Optional reasonDeleteAllowed(Connection connection, Identity identity, Task oldResource) { - final String oldResourceId = parameterConverter - .toUuid(getResourceTypeName(), oldResource.getIdElement().getIdPart()).toString(); + final String oldResourceId = oldResource.getIdElement().getIdPart(); final long oldResourceVersion = oldResource.getIdElement().getVersionIdPartAsLong(); if (identity.hasDsfRole(deleteRole)) From 3a89d345c88f56447b48d31cc3aa940e7be50585 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Sat, 4 Oct 2025 23:35:27 +0200 Subject: [PATCH 3/3] new integration tests, resource validator workaround --- .../integration/AbstractIntegrationTest.java | 25 ++++++++++++- ...sQuestionnaireResponseIntegrationTest.java | 28 +++++++++++++++ .../fhir/integration/TaskIntegrationTest.java | 25 +++++++++++++ .../fhir/integration/X509Certificates.java | 36 ++++++++++++++++++- .../validation/ResourceValidatorImpl.java | 9 +++++ 5 files changed, 121 insertions(+), 2 deletions(-) diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/AbstractIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/AbstractIntegrationTest.java index 105227e66..41eb98bb5 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/AbstractIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/AbstractIntegrationTest.java @@ -114,6 +114,7 @@ public abstract class AbstractIntegrationTest extends AbstractDbTest private static FhirWebserviceClient webserviceClient; private static FhirWebserviceClient externalWebserviceClient; private static FhirWebserviceClient practitionerWebserviceClient; + private static FhirWebserviceClient minimalWebserviceClient; @BeforeClass public static void beforeClass() throws Exception @@ -147,6 +148,12 @@ public static void beforeClass() throws Exception certificates.getPractitionerClientCertificate().keyStore(), certificates.getPractitionerClientCertificate().keyStorePassword(), fhirContext, referenceCleaner); + logger.info("Creating minimal client ..."); + minimalWebserviceClient = createWebserviceClient(apiConnectorChannel.socket().getLocalPort(), + certificates.getMinimalClientCertificate().trustStore(), + certificates.getMinimalClientCertificate().keyStore(), + certificates.getMinimalClientCertificate().keyStorePassword(), fhirContext, referenceCleaner); + logger.info("Starting FHIR Server ..."); fhirServer = startFhirServer(statusConnectorChannel, apiConnectorChannel, baseUrl); @@ -212,7 +219,18 @@ private static JettyServer startFhirServer(ServerSocketChannel statusConnectorCh - HISTORY practitioner-role: - http://dsf.dev/fhir/CodeSystem/practitioner-role|DIC_USER - """, certificates.getPractitionerClientCertificate().certificateSha512ThumbprintHex())); + - minimal-test-user: + thumbprint: %s + dsf-role: + - CREATE: [Task] + - READ: &tqqr [Task, Questionnaire, QuestionnaireResponse] + - UPDATE: [QuestionnaireResponse] + - SEARCH: *tqqr + - HISTORY: *tqqr + practitioner-role: + - http://dsf.dev/fhir/CodeSystem/practitioner-role|DIC_USER + """, certificates.getPractitionerClientCertificate().certificateSha512ThumbprintHex(), + certificates.getMinimalClientCertificate().certificateSha512ThumbprintHex())); initParameters.put("dev.dsf.fhir.debug.log.message.dbStatement", "true"); KeyStore clientCertificateTrustStore = KeyStoreCreator @@ -382,6 +400,11 @@ protected static FhirWebserviceClient getPractitionerWebserviceClient() return practitionerWebserviceClient; } + protected static FhirWebserviceClient getMinimalWebserviceClient() + { + return minimalWebserviceClient; + } + protected static WebsocketClient getWebsocketClient() { Bundle bundle = getWebserviceClient().searchWithStrictHandling(Subscription.class, diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java index b1dc6d7bb..bd6a1bb81 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java @@ -199,4 +199,32 @@ public void testPostQuestionnaireResponseInTransactionBundleQuestionnaireDoesNot expectForbidden(() -> getWebserviceClient().postBundle(bundle)); } + + @Test + public void testQuestionnaireResponseQuestionnaireDisplayItemChangedWithMinimalUser() throws Exception + { + Questionnaire questionnaire = createQuestionnaireProfileVersion100("1.0.0"); + questionnaire.addItem().setLinkId("display-id").setType(Questionnaire.QuestionnaireItemType.DISPLAY) + .setText("Default Text Value"); + + QuestionnaireDao questionnaireDao = getSpringWebApplicationContext().getBean(QuestionnaireDao.class); + questionnaireDao.create(questionnaire); + + QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse("1.0.0"); + questionnaireResponse.addItem().setLinkId("display-id").setText("Default Text Value"); + + expectForbidden(() -> getMinimalWebserviceClient().create(questionnaireResponse)); + + QuestionnaireResponse created = getWebserviceClient().create(questionnaireResponse); + + created.getItem().stream().filter(i -> "display-id".equals(i.getLinkId())).findFirst() + .ifPresent(i -> i.setText("Response Test Value")); + created.setStatus(QuestionnaireResponse.QuestionnaireResponseStatus.COMPLETED); + + QuestionnaireResponse updated = getMinimalWebserviceClient().update(created); + + assertNotNull(updated); + assertNotNull(updated.getIdElement().getIdPart()); + assertNotNull(updated.getIdElement().getVersionIdPart()); + } } \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/TaskIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/TaskIntegrationTest.java index 3e133c845..688dc827a 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/TaskIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/TaskIntegrationTest.java @@ -695,6 +695,31 @@ public void testCreateTaskAllowedLocalUser() throws Exception assertNotNull(createdTask.getIdElement().getIdPart()); } + @Test + public void testCreateTaskAllowedMinimalUser() throws Exception + { + ActivityDefinition ad5 = readActivityDefinition("dsf-test-activity-definition5-1.0.xml"); + + expectForbidden(() -> getMinimalWebserviceClient().create(ad5)); + + ActivityDefinition createdAd1 = getWebserviceClient().create(ad5); + assertNotNull(createdAd1); + assertNotNull(createdAd1.getIdElement().getIdPart()); + + StructureDefinition testTaskProfile = readTestTaskProfile(); + + expectForbidden(() -> getMinimalWebserviceClient().create(testTaskProfile)); + + StructureDefinition createdTestTaskProfile = getWebserviceClient().create(testTaskProfile); + assertNotNull(createdTestTaskProfile); + assertNotNull(createdTestTaskProfile.getIdElement().getIdPart()); + + Task task = readTestTask("Test_Organization", "Test_Organization"); + Task createdTask = getMinimalWebserviceClient().create(task); + assertNotNull(createdTask); + assertNotNull(createdTask.getIdElement().getIdPart()); + } + @Test public void testCreateTaskAllowedLocalUserWithRole() throws Exception { diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/X509Certificates.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/X509Certificates.java index 8e3f8cd18..65368db2b 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/X509Certificates.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/X509Certificates.java @@ -72,6 +72,7 @@ public String certificateSha512ThumbprintHex() private CertificateAndPrivateKey serverCertificate; private CertificateAndPrivateKey clientCertificate; private CertificateAndPrivateKey practitionerClientCertificate; + private CertificateAndPrivateKey minimalClientCertificate; private CertificateAndPrivateKey externalClientCertificate; private Path caCertificateFile; @@ -81,6 +82,8 @@ public String certificateSha512ThumbprintHex() private Path externalClientCertificatePrivateKeyFile; private Path practitionerClientCertificateFile; private Path practitionerClientCertificatePrivateKeyFile; + private Path minimalClientCertificateFile; + private Path minimalClientCertificatePrivateKeyFile; private List filesToDelete; @@ -116,6 +119,11 @@ public CertificateAndPrivateKey getPractitionerClientCertificate() return practitionerClientCertificate; } + public CertificateAndPrivateKey getMinimalClientCertificate() + { + return minimalClientCertificate; + } + public X509Certificate getCaCertificate() { return caCertificate; @@ -156,6 +164,16 @@ public Path getPractitionerClientCertificatePrivateKeyFile() return practitionerClientCertificatePrivateKeyFile; } + public Path getMinimalClientCertificateFile() + { + return minimalClientCertificateFile; + } + + public Path getMinimalClientCertificatePrivateKeyFile() + { + return minimalClientCertificatePrivateKeyFile; + } + private void createX509Certificates() throws InvalidKeyException, NoSuchAlgorithmException, KeyStoreException, CertificateException, OperatorCreationException, IllegalStateException, IOException, InvalidKeySpecException { @@ -168,6 +186,8 @@ private void createX509Certificates() throws InvalidKeyException, NoSuchAlgorith Path externalClientCertificatePrivateKeyFile = Paths.get("target", UUID.randomUUID().toString() + ".pem"); Path practitionerClientCertificateFile = Paths.get("target", UUID.randomUUID().toString() + ".pem"); Path practitionerClientCertificatePrivateKeyFile = Paths.get("target", UUID.randomUUID().toString() + ".pem"); + Path minimalClientCertificateFile = Paths.get("target", UUID.randomUUID().toString() + ".pem"); + Path minimalClientCertificatePrivateKeyFile = Paths.get("target", UUID.randomUUID().toString() + ".pem"); CertificateAuthority ca = CertificateAuthority .builderSha384EcdsaSecp384r1("DE", null, null, null, null, "Junit Test CA") @@ -210,6 +230,15 @@ private void createX509Certificates() throws InvalidKeyException, NoSuchAlgorith .toFile(practitionerClientCertificatePrivateKeyFile); // practitioner client -- + // -- minimal client + CertificationRequestAndPrivateKey minimalClientRequest = CertificationRequest + .builder(ca, "DE", null, null, null, null, "minimal-client").generateKeyPair().build(); + X509Certificate minimalClientCertificate = ca.signClientCertificate(minimalClientRequest, Period.ofDays(1)); + PemWriter.writeCertificate(minimalClientCertificate, minimalClientCertificateFile); + PemWriter.writePrivateKey(minimalClientRequest.getPrivateKey()).asPkcs8().encryptedAes128(PASSWORD) + .toFile(minimalClientCertificatePrivateKeyFile); + // minimal client -- + this.caCertificate = caCertificate; this.serverCertificate = new CertificateAndPrivateKey(caCertificate, serverCertificate, serverRequest.getPrivateKey()); @@ -219,6 +248,8 @@ private void createX509Certificates() throws InvalidKeyException, NoSuchAlgorith externalClientRequest.getPrivateKey()); this.practitionerClientCertificate = new CertificateAndPrivateKey(caCertificate, practitionerClientCertificate, practitionerClientRequest.getPrivateKey()); + this.minimalClientCertificate = new CertificateAndPrivateKey(caCertificate, minimalClientCertificate, + minimalClientRequest.getPrivateKey()); this.caCertificateFile = caCertificateFile; this.clientCertificateFile = clientCertificateFile; @@ -227,10 +258,13 @@ private void createX509Certificates() throws InvalidKeyException, NoSuchAlgorith this.externalClientCertificatePrivateKeyFile = externalClientCertificatePrivateKeyFile; this.practitionerClientCertificateFile = practitionerClientCertificateFile; this.practitionerClientCertificatePrivateKeyFile = practitionerClientCertificatePrivateKeyFile; + this.minimalClientCertificateFile = minimalClientCertificateFile; + this.minimalClientCertificatePrivateKeyFile = minimalClientCertificatePrivateKeyFile; filesToDelete = List.of(caCertificateFile, clientCertificateFile, clientCertificatePrivateKeyFile, externalClientCertificateFile, externalClientCertificatePrivateKeyFile, - practitionerClientCertificateFile, practitionerClientCertificatePrivateKeyFile); + practitionerClientCertificateFile, practitionerClientCertificatePrivateKeyFile, + minimalClientCertificateFile, minimalClientCertificatePrivateKeyFile); } private void deleteX509Certificates() diff --git a/dsf-fhir/dsf-fhir-validation/src/main/java/dev/dsf/fhir/validation/ResourceValidatorImpl.java b/dsf-fhir/dsf-fhir-validation/src/main/java/dev/dsf/fhir/validation/ResourceValidatorImpl.java index 0049142a4..efed236fc 100755 --- a/dsf-fhir/dsf-fhir-validation/src/main/java/dev/dsf/fhir/validation/ResourceValidatorImpl.java +++ b/dsf-fhir/dsf-fhir-validation/src/main/java/dev/dsf/fhir/validation/ResourceValidatorImpl.java @@ -183,6 +183,7 @@ public ValidationResult validate(Resource resource) // TODO: remove after HAPI validator is fixed: https://github.com/hapifhir/org.hl7.fhir.core/issues/193 adaptDefaultSliceValidationErrorToWarning(result); + adaptQuestionnaireTextNotSameValidationErrorToWarning(result); return new ValidationResult(context, result.getMessages().stream().filter(m -> !(ResultSeverityEnum.WARNING.equals(m.getSeverity()) @@ -196,4 +197,12 @@ private void adaptDefaultSliceValidationErrorToWarning(ValidationResult result) && AT_DEFAULT_SLICE_PATTERN.matcher(m.getMessage()).matches()) .forEach(m -> m.setSeverity(ResultSeverityEnum.WARNING)); } + + private void adaptQuestionnaireTextNotSameValidationErrorToWarning(ValidationResult result) + { + result.getMessages().stream() + .filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) && m.getMessage() + .startsWith("If text exists, it must match the questionnaire definition for linkId")) + .forEach(m -> m.setSeverity(ResultSeverityEnum.WARNING)); + } }