001/*-
002 * #%L
003 * HAPI FHIR - Server Framework
004 * %%
005 * Copyright (C) 2014 - 2024 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.rest.server.interceptor.consent;
021
022import ca.uhn.fhir.interceptor.api.Pointcut;
023import ca.uhn.fhir.rest.api.server.RequestDetails;
024import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor;
025import ca.uhn.fhir.rest.server.interceptor.auth.IRuleApplier;
026import ca.uhn.fhir.rest.server.interceptor.auth.PolicyEnum;
027import org.hl7.fhir.instance.model.api.IBaseResource;
028import org.slf4j.Logger;
029import org.slf4j.LoggerFactory;
030
031/**
032 * Implement rule based search result filtering as a ConsentService.
033 *
034 * We have new rules that add fhir-query filters.
035 * We can't always merge these into the queries, this IConsentService
036 * removes bundle results that don't pass the filters.
037 * Otherwise, the final bundle result rule check will fail
038 * with a 403 on disallowed resources.
039 */
040public class RuleFilteringConsentService implements IConsentService {
041        private static final Logger ourLog = LoggerFactory.getLogger(RuleFilteringConsentService.class);
042        /** This happens during STORAGE_PREACCESS_RESOURCES */
043        private static final Pointcut CAN_SEE_POINTCUT = Pointcut.STORAGE_PREACCESS_RESOURCES;
044
045        /** Our delegate for consent verdicts */
046        protected final IRuleApplier myRuleApplier;
047
048        public RuleFilteringConsentService(IRuleApplier theRuleApplier) {
049                myRuleApplier = theRuleApplier;
050        }
051
052        /**
053         * Apply the rules active in our rule-applier, and drop resources that don't pass.
054         *
055         * @param theRequestDetails  The current request.
056         * @param theResource        The resource that will be exposed
057         * @param theContextServices Unused.
058         * @return REJECT if the rules don't ALLOW, PROCEED otherwise.
059         */
060        @Override
061        public ConsentOutcome canSeeResource(
062                        RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices) {
063                ourLog.trace("canSeeResource() {} {}", theRequestDetails, theResource);
064
065                // apply rules!  If yes, then yes!
066                AuthorizationInterceptor.Verdict ruleResult = myRuleApplier.applyRulesAndReturnDecision(
067                                theRequestDetails.getRestOperationType(), theRequestDetails, null, null, theResource, CAN_SEE_POINTCUT);
068                if (ruleResult.getDecision() == PolicyEnum.ALLOW) {
069                        // are these the right codes?
070                        return ConsentOutcome.PROCEED;
071                } else {
072                        return ConsentOutcome.REJECT;
073                }
074        }
075}