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.rest.api.server.RequestDetails; 023import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; 024import org.hl7.fhir.instance.model.api.IBaseResource; 025 026/** 027 * This interface is intended to be implemented as the user-defined contract for 028 * the {@link ConsentInterceptor}. 029 * <p> 030 * Note: Since HAPI FHIR 5.1.0, methods in this interface have default methods that return {@link ConsentOutcome#PROCEED} 031 * </p> 032 * <p> 033 * See <a href="https://hapifhir.io/hapi-fhir/docs/security/consent_interceptor.html">Consent Interceptor</a> for 034 * more information on this interceptor. 035 * </p> 036 */ 037public interface IConsentService { 038 039 /** 040 * This method is called when an operation is initially beginning, before any 041 * significant processing occurs. The service may use this method to decide 042 * whether the request needs to be reviewed further or not. 043 * 044 * @param theRequestDetails Contains details about the operation that is 045 * beginning, including details about the request type, 046 * URL, etc. Note that the RequestDetails has a generic 047 * Map (see {@link RequestDetails#getUserData()}) that 048 * can be used to store information and state to be 049 * passed between methods in the consent service. 050 * @param theContextServices An object passed in by the consent framework that 051 * provides utility functions relevant to acting on 052 * consent directives. 053 * @return An outcome object. See {@link ConsentOutcome} 054 */ 055 default ConsentOutcome startOperation( 056 RequestDetails theRequestDetails, IConsentContextServices theContextServices) { 057 return ConsentOutcome.PROCEED; 058 } 059 060 /** 061 * This method will be invoked once prior to invoking {@link #canSeeResource(RequestDetails, IBaseResource, IConsentContextServices)} 062 * and can be used to skip that phase. 063 * <p> 064 * If this method returns {@literal false} (default is {@literal true}) {@link #willSeeResource(RequestDetails, IBaseResource, IConsentContextServices)} 065 * will be invoked for this request, but {@link #canSeeResource(RequestDetails, IBaseResource, IConsentContextServices)} will not. 066 * </p> 067 * 068 * @param theRequestDetails Contains details about the operation that is 069 * beginning, including details about the request type, 070 * URL, etc. Note that the RequestDetails has a generic 071 * Map (see {@link RequestDetails#getUserData()}) that 072 * can be used to store information and state to be 073 * passed between methods in the consent service. 074 * @param theContextServices An object passed in by the consent framework that 075 * provides utility functions relevant to acting on 076 * consent directives. 077 * @return Returns {@literal false} to avoid calling {@link #canSeeResource(RequestDetails, IBaseResource, IConsentContextServices)} 078 * @since 6.0.0 079 */ 080 default boolean shouldProcessCanSeeResource( 081 RequestDetails theRequestDetails, IConsentContextServices theContextServices) { 082 return true; 083 } 084 085 /** 086 * This method is called if a user may potentially see a resource via READ 087 * operations, SEARCH operations, etc. This method may make decisions about 088 * whether or not the user should be permitted to see the resource. 089 * <p> 090 * Implementations should make no attempt to modify the returned result within 091 * this method. For modification use cases (e.g. masking for consent rules) the 092 * user should use the {@link #willSeeResource(RequestDetails, IBaseResource, IConsentContextServices)} 093 * method to actually make changes. This method is intended to only 094 * to make decisions. 095 * </p> 096 * <p> 097 * In addition, the {@link ConsentOutcome} must return one of the following 098 * statuses: 099 * </p> 100 * <ul> 101 * <li>{@link ConsentOperationStatusEnum#AUTHORIZED}: The resource will be returned to the client. If multiple consent service implementation are present, no further implementations will be invoked for this resource. {@link #willSeeResource(RequestDetails, IBaseResource, IConsentContextServices)} will not be invoked for this resource.</li> 102 * <li>{@link ConsentOperationStatusEnum#PROCEED}: The resource will be returned to the client.</li> 103 * <li>{@link ConsentOperationStatusEnum#REJECT}: The resource will be stripped from the response. If multiple consent service implementation are present, no further implementations will be invoked for this resource. {@link #willSeeResource(RequestDetails, IBaseResource, IConsentContextServices)} will not be invoked for this resource.</li> 104 * </ul> 105 * </p> 106 * <p> 107 * There are two methods the consent service may use to suppress or modify response resources: 108 * </p> 109 * <ul> 110 * <li>{@link #canSeeResource(RequestDetails, IBaseResource, IConsentContextServices)} should be used to remove resources from results in scenarios where it is important to not reveal existence of those resources. It is called prior to any paging logic, so result pages will still be normal sized even if results are filtered.</li> 111 * <li>{@link #willSeeResource(RequestDetails, IBaseResource, IConsentContextServices)} should be used to filter individual elements from resources, or to remove entire resources in cases where it is not important to conceal their existence. It is called after paging logic, so any resources removed by this method may result in abnormally sized result pages. However, removing resourced using this method may also perform better so it is preferable for use in cases where revealing resource existence is not a concern.</li> 112 * </ul> 113 * <p> 114 * <b>Performance note:</b> Note that this method should be efficient, since it will be called once 115 * for every resource potentially returned (e.g. by searches). If this method 116 * takes a significant amount of time to execute, performance on the server 117 * will suffer. 118 * </p> 119 * 120 * 121 * @param theRequestDetails Contains details about the operation that is 122 * beginning, including details about the request type, 123 * URL, etc. Note that the RequestDetails has a generic 124 * Map (see {@link RequestDetails#getUserData()}) that 125 * can be used to store information and state to be 126 * passed between methods in the consent service. 127 * @param theResource The resource that will be exposed 128 * @param theContextServices An object passed in by the consent framework that 129 * provides utility functions relevant to acting on 130 * consent directives. 131 * @return An outcome object. See {@link ConsentOutcome}. Note that this method is not allowed 132 * to modify the response object, so an error will be thrown if {@link ConsentOutcome#getResource()} 133 * returns a non-null response. 134 */ 135 default ConsentOutcome canSeeResource( 136 RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices) { 137 return ConsentOutcome.PROCEED; 138 } 139 140 /** 141 * This method is called if a user is about to see a resource, either completely 142 * or partially. In other words, if the user is going to see any part of this resource 143 * via READ operations, SEARCH operations, etc., this method is 144 * called. This method may modify the resource in order to filter/mask aspects of 145 * the contents, or even to enrich it. 146 * <p> 147 * The returning {@link ConsentOutcome} may optionally replace the resource 148 * with a different resource (including an OperationOutcome) by calling the 149 * resource property on the {@link ConsentOutcome}. 150 * </p> 151 * <p> 152 * In addition, the {@link ConsentOutcome} must return one of the following 153 * statuses: 154 * </p> 155 * <ul> 156 * <li>{@link ConsentOperationStatusEnum#AUTHORIZED}: The resource will be returned to the client. If multiple consent service implementation are present, no further implementations will be invoked for this resource.</li> 157 * <li>{@link ConsentOperationStatusEnum#PROCEED}: The resource will be returned to the client.</li> 158 * <li>{@link ConsentOperationStatusEnum#REJECT}: The resource will not be returned to the client. If multiple consent service implementation are present, no further implementations will be invoked for this resource.</li> 159 * </ul> 160 * 161 * @param theRequestDetails Contains details about the operation that is 162 * beginning, including details about the request type, 163 * URL, etc. Note that the RequestDetails has a generic 164 * Map (see {@link RequestDetails#getUserData()}) that 165 * can be used to store information and state to be 166 * passed between methods in the consent service. 167 * @param theResource The resource that will be exposed 168 * @param theContextServices An object passed in by the consent framework that 169 * provides utility functions relevant to acting on 170 * consent directives. 171 * @return An outcome object. See method documentation for a description. 172 * @see #canSeeResource(RequestDetails, IBaseResource, IConsentContextServices) for a description of the difference between these two methods. 173 */ 174 default ConsentOutcome willSeeResource( 175 RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices) { 176 return ConsentOutcome.PROCEED; 177 } 178 179 /** 180 * This method is called when an operation is complete. It can be used to perform 181 * any necessary cleanup, flush audit events, etc. 182 * <p> 183 * This method is not called if the request failed. {@link #completeOperationFailure(RequestDetails, BaseServerResponseException, IConsentContextServices)} 184 * will be called instead in that case. 185 * </p> 186 * 187 * @param theRequestDetails Contains details about the operation that is 188 * beginning, including details about the request type, 189 * URL, etc. Note that the RequestDetails has a generic 190 * Map (see {@link RequestDetails#getUserData()}) that 191 * can be used to store information and state to be 192 * passed between methods in the consent service. 193 * @param theContextServices An object passed in by the consent framework that 194 * provides utility functions relevant to acting on 195 * consent directives. 196 * @see #completeOperationFailure(RequestDetails, BaseServerResponseException, IConsentContextServices) 197 */ 198 default void completeOperationSuccess( 199 RequestDetails theRequestDetails, IConsentContextServices theContextServices) {} 200 201 /** 202 * This method is called when an operation is complete. It can be used to perform 203 * any necessary cleanup, flush audit events, etc. 204 * <p> 205 * This method will be called if the request did not complete successfully, instead of 206 * {@link #completeOperationSuccess(RequestDetails, IConsentContextServices)}. Typically this means that 207 * the operation failed and a failure is being returned to the client. 208 * </p> 209 * 210 * @param theRequestDetails Contains details about the operation that is 211 * beginning, including details about the request type, 212 * URL, etc. Note that the RequestDetails has a generic 213 * Map (see {@link RequestDetails#getUserData()}) that 214 * can be used to store information and state to be 215 * passed between methods in the consent service. 216 * @param theContextServices An object passed in by the consent framework that 217 * provides utility functions relevant to acting on 218 * consent directives. 219 * @see #completeOperationSuccess(RequestDetails, IConsentContextServices) 220 */ 221 default void completeOperationFailure( 222 RequestDetails theRequestDetails, 223 BaseServerResponseException theException, 224 IConsentContextServices theContextServices) {} 225}