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 org.apache.commons.lang3.builder.ToStringBuilder; 023import org.apache.commons.lang3.builder.ToStringStyle; 024 025/** 026 * Tester that a resource matches a provided query filter. 027 */ 028public class FhirQueryRuleTester implements IAuthRuleTester { 029 private final String myQueryParameters; 030 031 public FhirQueryRuleTester(String theQueryParameters) { 032 myQueryParameters = theQueryParameters; 033 } 034 035 @Override 036 public boolean matches(RuleTestRequest theRuleTestRequest) { 037 return checkMatch(theRuleTestRequest); 038 } 039 040 @Override 041 public boolean matchesOutput(RuleTestRequest theRuleTestRequest) { 042 return checkMatch(theRuleTestRequest); 043 } 044 045 private boolean checkMatch(RuleTestRequest theRuleTestRequest) { 046 // look for a matcher 047 IAuthorizationSearchParamMatcher matcher = theRuleTestRequest.ruleApplier.getSearchParamMatcher(); 048 if (matcher == null) { 049 theRuleTestRequest 050 .ruleApplier 051 .getTroubleshootingLog() 052 .warn("No matcher provided. Can't apply filter permission."); 053 return false; 054 } 055 056 // this is a bit weird. 057 // A tester narrows a rule -- i.e. a rule only applies if the main logic matches AND the testers all match 058 // But this rule would have matched without this tester, so true means abstain. 059 if (theRuleTestRequest.resource == null) { 060 // we aren't looking at a resource yet. treat as no-op 061 return true; 062 } 063 064 // we use the target type since the rule might apply to all types, a type set, or instances, and that has 065 // already been checked. 066 IAuthorizationSearchParamMatcher.MatchResult mr = matcher.match( 067 theRuleTestRequest.resource.fhirType() + "?" + myQueryParameters, theRuleTestRequest.resource); 068 069 switch (mr.match) { 070 case MATCH: 071 return true; 072 case UNSUPPORTED: 073 theRuleTestRequest 074 .ruleApplier 075 .getTroubleshootingLog() 076 .warn("Unsupported matcher expression {}: {}.", myQueryParameters, mr.unsupportedReason); 077 // unsupported doesn't match unless this is a deny request, and we need to be safe! 078 return (theRuleTestRequest.mode == PolicyEnum.DENY); 079 case NO_MATCH: 080 default: 081 return false; 082 } 083 } 084 085 @Override 086 public String toString() { 087 return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) 088 .append("filter", myQueryParameters) 089 .toString(); 090 } 091}