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.auth;
021
022import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
023import ca.uhn.fhir.rest.api.server.RequestDetails;
024import jakarta.annotation.Nonnull;
025import jakarta.annotation.Nullable;
026import org.apache.commons.lang3.Validate;
027import org.hl7.fhir.instance.model.api.IBaseResource;
028import org.hl7.fhir.instance.model.api.IIdType;
029
030/**
031 * Allows user-supplied logic for authorization rules.
032 * <p>
033 * THIS IS AN EXPERIMENTAL API! Feedback is welcome, and this API
034 * may change.
035 *
036 * @since 3.4.0
037 */
038public interface IAuthRuleTester {
039        /**
040         * A request object to make this easier to extend.
041         */
042        class RuleTestRequest {
043                // fake record pattern
044                /** the mode of the calling rule context */
045                @Nonnull
046                public final PolicyEnum mode;
047                /**
048                 * The FHIR operation being performed.
049                 * Note that this is not necessarily the same as the value obtained from invoking
050                 * {@link RequestDetails#getRestOperationType()} on {@literal requestDetails}
051                 * because multiple operations can be nested within
052                 * an HTTP request using FHIR transaction and batch operations
053                 */
054                @Nonnull
055                public final RestOperationTypeEnum operation;
056
057                @Nonnull
058                public final RequestDetails requestDetails;
059
060                @Nullable
061                public final IIdType resourceId;
062
063                @Nullable
064                public final IBaseResource resource;
065                /** supplier for support services */
066                @Nonnull
067                public final IRuleApplier ruleApplier;
068
069                public RuleTestRequest(
070                                PolicyEnum theMode,
071                                @Nonnull RestOperationTypeEnum theOperation,
072                                @Nonnull RequestDetails theRequestDetails,
073                                @Nullable IIdType theResourceId,
074                                @Nullable IBaseResource theResource,
075                                @Nonnull IRuleApplier theRuleApplier) {
076                        Validate.notNull(theMode);
077                        Validate.notNull(theOperation);
078                        Validate.notNull(theRequestDetails);
079                        Validate.notNull(theRuleApplier);
080                        mode = theMode;
081                        operation = theOperation;
082                        requestDetails = theRequestDetails;
083                        resource = theResource;
084                        if (theResourceId == null && resource != null) {
085                                resourceId = resource.getIdElement();
086                        } else {
087                                resourceId = theResourceId;
088                        }
089                        ruleApplier = theRuleApplier;
090                }
091        }
092
093        /**
094         * User supplied logic called just before the parent rule renders a verdict on the operation
095         * or input resource.
096         *
097         * Returning true will allow the verdict continue.
098         * Returning false will block the verdict and cause the rule to abstain (i.e. return null).
099         *
100         * <p>
101         * THIS IS AN EXPERIMENTAL API! Feedback is welcome, and this API
102         * may change.
103         *
104         * @param theRequest The details of the operation or an INPUT resource to evaluate
105         * @return true if the verdict should continue
106         * @since 6.1.0
107         */
108        default boolean matches(RuleTestRequest theRequest) {
109                return this.matches(
110                                theRequest.operation, theRequest.requestDetails, theRequest.resourceId, theRequest.resource);
111        }
112
113        /**
114         * DO NOT IMPLEMENT - Old api.  {@link #matches(RuleTestRequest)} instead.
115         * @deprecated
116         */
117        @Deprecated(since = "6.1.0")
118        default boolean matches(
119                        RestOperationTypeEnum theOperation,
120                        RequestDetails theRequestDetails,
121                        IIdType theInputResourceId,
122                        IBaseResource theInputResource) {
123                return true;
124        }
125
126        /**
127         * User supplied logic called just before the parent rule renders a verdict on an output resource.
128         *
129         * Returning true will allow the verdict continue.
130         * Returning false will block the verdict and cause the rule to abstain (i.e. return null).
131         *
132         * <p>
133         * THIS IS AN EXPERIMENTAL API! Feedback is welcome, and this API
134         * may change.
135         *
136         * @param theRequest The details of the operation or an INPUT resource to evaluate
137         * @return true if the verdict should continue
138         * @since 6.1.0  */
139        default boolean matchesOutput(RuleTestRequest theRequest) {
140                return this.matchesOutput(theRequest.operation, theRequest.requestDetails, theRequest.resource);
141        }
142
143        /**
144         * DO NOT IMPLEMENT - Old api.  {@link #matches(RuleTestRequest)} instead.
145         * @deprecated
146         */
147        @Deprecated(since = "6.1.0")
148        default boolean matchesOutput(
149                        RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IBaseResource theOutputResource) {
150                return true;
151        }
152}