001package ca.uhn.fhir.rest.server.interceptor.auth; 002 003/* 004 * #%L 005 * HAPI FHIR - Core Library 006 * %% 007 * Copyright (C) 2014 - 2017 University Health Network 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022import java.util.*; 023 024import org.apache.commons.lang3.Validate; 025import org.hl7.fhir.instance.model.api.IBaseResource; 026import org.hl7.fhir.instance.model.api.IIdType; 027 028import ca.uhn.fhir.model.primitive.IdDt; 029import ca.uhn.fhir.rest.api.RestOperationTypeEnum; 030 031public class RuleBuilder implements IAuthRuleBuilder { 032 033 private ArrayList<IAuthRule> myRules; 034 035 public RuleBuilder() { 036 myRules = new ArrayList<IAuthRule>(); 037 } 038 039 @Override 040 public IAuthRuleBuilderRule allow() { 041 return allow(null); 042 } 043 044 @Override 045 public IAuthRuleBuilderRule allow(String theRuleName) { 046 return new RuleBuilderRule(PolicyEnum.ALLOW, theRuleName); 047 } 048 049 @Override 050 public IAuthRuleBuilderRuleOpClassifierFinished allowAll() { 051 return allowAll(null); 052 } 053 054 @Override 055 public IAuthRuleBuilderRuleOpClassifierFinished allowAll(String theRuleName) { 056 myRules.add(new RuleImplOp(theRuleName).setOp(RuleOpEnum.ALLOW_ALL)); 057 return new RuleBuilderFinished(); 058 } 059 060 @Override 061 public List<IAuthRule> build() { 062 return myRules; 063 } 064 065 @Override 066 public IAuthRuleBuilderRule deny() { 067 return deny(null); 068 } 069 070 @Override 071 public IAuthRuleBuilderRule deny(String theRuleName) { 072 return new RuleBuilderRule(PolicyEnum.DENY, theRuleName); 073 } 074 075 @Override 076 public IAuthRuleBuilderRuleOpClassifierFinished denyAll() { 077 return denyAll(null); 078 } 079 080 @Override 081 public IAuthRuleBuilderRuleOpClassifierFinished denyAll(String theRuleName) { 082 myRules.add(new RuleImplOp(theRuleName).setOp(RuleOpEnum.DENY_ALL)); 083 return new RuleBuilderFinished(); 084 } 085 086 private class RuleBuilderFinished implements IAuthRuleFinished, IAuthRuleBuilderRuleOpClassifierFinished { 087 088 @Override 089 public IAuthRuleBuilder andThen() { 090 doBuildRule(); 091 return RuleBuilder.this; 092 } 093 094 @Override 095 public List<IAuthRule> build() { 096 doBuildRule(); 097 return myRules; 098 } 099 100 /** 101 * Subclasses may override 102 */ 103 protected void doBuildRule() { 104 // nothing 105 } 106 } 107 108 private class RuleBuilderRule implements IAuthRuleBuilderRule { 109 110 private PolicyEnum myRuleMode; 111 private String myRuleName; 112 private RuleOpEnum myRuleOp; 113 114 public RuleBuilderRule(PolicyEnum theRuleMode, String theRuleName) { 115 myRuleMode = theRuleMode; 116 myRuleName = theRuleName; 117 } 118 119 @Override 120 public IAuthRuleBuilderRuleConditional createConditional() { 121 return new RuleBuilderRuleConditional(RestOperationTypeEnum.CREATE); 122 } 123 124 @Override 125 public IAuthRuleBuilderRuleOp delete() { 126 myRuleOp = RuleOpEnum.DELETE; 127 return new RuleBuilderRuleOp(); 128 } 129 130 @Override 131 public IAuthRuleBuilderRuleConditional deleteConditional() { 132 return new RuleBuilderRuleConditional(RestOperationTypeEnum.DELETE); 133 } 134 135 @Override 136 public RuleBuilderFinished metadata() { 137 RuleImplOp rule = new RuleImplOp(myRuleName); 138 rule.setOp(RuleOpEnum.METADATA); 139 rule.setMode(myRuleMode); 140 myRules.add(rule); 141 return new RuleBuilderFinished(); 142 } 143 144 @Override 145 public IAuthRuleBuilderOperation operation() { 146 return new RuleBuilderRuleOperation(); 147 } 148 149 @Override 150 public IAuthRuleBuilderRuleOp read() { 151 myRuleOp = RuleOpEnum.READ; 152 return new RuleBuilderRuleOp(); 153 } 154 155 @Override 156 public IAuthRuleBuilderRuleTransaction transaction() { 157 myRuleOp = RuleOpEnum.TRANSACTION; 158 return new RuleBuilderRuleTransaction(); 159 } 160 161 @Override 162 public IAuthRuleBuilderRuleConditional updateConditional() { 163 return new RuleBuilderRuleConditional(RestOperationTypeEnum.UPDATE); 164 } 165 166 @Override 167 public IAuthRuleBuilderRuleOp write() { 168 myRuleOp = RuleOpEnum.WRITE; 169 return new RuleBuilderRuleOp(); 170 } 171 172 private class RuleBuilderRuleConditional implements IAuthRuleBuilderRuleConditional { 173 174 private AppliesTypeEnum myAppliesTo; 175 176 private Set<?> myAppliesToTypes; 177 private RestOperationTypeEnum myOperationType; 178 179 public RuleBuilderRuleConditional(RestOperationTypeEnum theOperationType) { 180 myOperationType = theOperationType; 181 } 182 183 @Override 184 public IAuthRuleBuilderRuleConditionalClassifier allResources() { 185 myAppliesTo = AppliesTypeEnum.ALL_RESOURCES; 186 return new RuleBuilderRuleConditionalClassifier(); 187 } 188 189 @Override 190 public IAuthRuleBuilderRuleConditionalClassifier resourcesOfType(Class<? extends IBaseResource> theType) { 191 Validate.notNull(theType, "theType must not be null"); 192 myAppliesTo = AppliesTypeEnum.TYPES; 193 myAppliesToTypes = Collections.singleton(theType); 194 return new RuleBuilderRuleConditionalClassifier(); 195 } 196 197 public class RuleBuilderRuleConditionalClassifier extends RuleBuilderFinished implements IAuthRuleBuilderRuleConditionalClassifier { 198 199 @Override 200 protected void doBuildRule() { 201 RuleImplConditional rule = new RuleImplConditional(myRuleName); 202 rule.setMode(myRuleMode); 203 rule.setOperationType(myOperationType); 204 rule.setAppliesTo(myAppliesTo); 205 rule.setAppliesToTypes(myAppliesToTypes); 206 myRules.add(rule); 207 208 } 209 } 210 211 } 212 213 private class RuleBuilderRuleOp implements IAuthRuleBuilderRuleOp { 214 215 private AppliesTypeEnum myAppliesTo; 216 private Set<?> myAppliesToTypes; 217 218 @Override 219 public IAuthRuleBuilderRuleOpClassifier allResources() { 220 myAppliesTo = AppliesTypeEnum.ALL_RESOURCES; 221 return new RuleBuilderRuleOpClassifier(); 222 } 223 224 @Override 225 public IAuthRuleBuilderRuleOpClassifier resourcesOfType(Class<? extends IBaseResource> theType) { 226 Validate.notNull(theType, "theType must not be null"); 227 myAppliesTo = AppliesTypeEnum.TYPES; 228 myAppliesToTypes = Collections.singleton(theType); 229 return new RuleBuilderRuleOpClassifier(); 230 } 231 232 private class RuleBuilderRuleOpClassifier implements IAuthRuleBuilderRuleOpClassifier { 233 234 private ClassifierTypeEnum myClassifierType; 235 private String myInCompartmentName; 236 private Collection<? extends IIdType> myInCompartmentOwners; 237 private List<IIdType> myAppliesToInstances; 238 239 /** 240 * Constructor 241 */ 242 public RuleBuilderRuleOpClassifier() { 243 super(); 244 } 245 246 /** 247 * Constructor 248 */ 249 public RuleBuilderRuleOpClassifier(List<IIdType> theAppliesToInstances) { 250 myAppliesToInstances = theAppliesToInstances; 251 myAppliesTo = AppliesTypeEnum.INSTANCES; 252 } 253 254 private IAuthRuleBuilderRuleOpClassifierFinished finished() { 255 256 RuleImplOp rule = new RuleImplOp(myRuleName); 257 rule.setMode(myRuleMode); 258 rule.setOp(myRuleOp); 259 rule.setAppliesTo(myAppliesTo); 260 rule.setAppliesToTypes(myAppliesToTypes); 261 rule.setAppliesToInstances(myAppliesToInstances); 262 rule.setClassifierType(myClassifierType); 263 rule.setClassifierCompartmentName(myInCompartmentName); 264 rule.setClassifierCompartmentOwners(myInCompartmentOwners); 265 myRules.add(rule); 266 267 return new RuleBuilderFinished(); 268 } 269 270 @Override 271 public IAuthRuleBuilderRuleOpClassifierFinished inCompartment(String theCompartmentName, Collection<? extends IIdType> theOwners) { 272 Validate.notBlank(theCompartmentName, "theCompartmentName must not be null"); 273 Validate.notNull(theOwners, "theOwners must not be null"); 274 Validate.noNullElements(theOwners, "theOwners must not contain any null elements"); 275 for (IIdType next : theOwners) { 276 validateOwner(next); 277 } 278 myClassifierType = ClassifierTypeEnum.IN_COMPARTMENT; 279 return finished(); 280 } 281 282 @Override 283 public IAuthRuleBuilderRuleOpClassifierFinished inCompartment(String theCompartmentName, IIdType theOwner) { 284 Validate.notBlank(theCompartmentName, "theCompartmentName must not be null"); 285 Validate.notNull(theOwner, "theOwner must not be null"); 286 validateOwner(theOwner); 287 myInCompartmentName = theCompartmentName; 288 myInCompartmentOwners = Collections.singletonList(theOwner); 289 myClassifierType = ClassifierTypeEnum.IN_COMPARTMENT; 290 return finished(); 291 } 292 293 private void validateOwner(IIdType theOwner) { 294 Validate.notBlank(theOwner.getIdPart(), "owner.getIdPart() must not be null or empty"); 295 Validate.notBlank(theOwner.getIdPart(), "owner.getResourceType() must not be null or empty"); 296 } 297 298 @Override 299 public IAuthRuleBuilderRuleOpClassifierFinished withAnyId() { 300 myClassifierType = ClassifierTypeEnum.ANY_ID; 301 return finished(); 302 } 303 304 } 305 306 @Override 307 public IAuthRuleFinished instance(String theId) { 308 Validate.notBlank(theId, "theId must not be null or empty"); 309 return instance(new IdDt(theId)); 310 } 311 312 @Override 313 public IAuthRuleFinished instance(IIdType theId) { 314 Validate.notNull(theId, "theId must not be null"); 315 Validate.notBlank(theId.getValue(), "theId.getValue() must not be null or empty"); 316 Validate.notBlank(theId.getIdPart(), "theId must contain an ID part"); 317 318 return new RuleBuilderRuleOpClassifier(Arrays.asList(theId)).finished(); 319 } 320 321 } 322 323 private class RuleBuilderRuleOperation implements IAuthRuleBuilderOperation { 324 325 @Override 326 public IAuthRuleBuilderOperationNamed named(String theOperationName) { 327 Validate.notBlank(theOperationName, "theOperationName must not be null or empty"); 328 return new RuleBuilderRuleOperationNamed(theOperationName); 329 } 330 331 @Override 332 public IAuthRuleBuilderOperationNamed withAnyName() { 333 return new RuleBuilderRuleOperationNamed(null); 334 } 335 336 private class RuleBuilderRuleOperationNamed implements IAuthRuleBuilderOperationNamed { 337 338 private String myOperationName; 339 340 public RuleBuilderRuleOperationNamed(String theOperationName) { 341 if (theOperationName != null && !theOperationName.startsWith("$")) { 342 myOperationName = '$' + theOperationName; 343 } else { 344 myOperationName = theOperationName; 345 } 346 } 347 348 private OperationRule createRule() { 349 OperationRule rule = new OperationRule(myRuleName); 350 rule.setOperationName(myOperationName); 351 rule.setMode(myRuleMode); 352 return rule; 353 } 354 355 @Override 356 public IAuthRuleBuilderRuleOpClassifierFinished onInstance(IIdType theInstanceId) { 357 Validate.notNull(theInstanceId, "theInstanceId must not be null"); 358 Validate.notBlank(theInstanceId.getResourceType(), "theInstanceId does not have a resource type"); 359 Validate.notBlank(theInstanceId.getIdPart(), "theInstanceId does not have an ID part"); 360 361 OperationRule rule = createRule(); 362 ArrayList<IIdType> ids = new ArrayList<IIdType>(); 363 ids.add(theInstanceId); 364 rule.appliesToInstances(ids); 365 myRules.add(rule); 366 return new RuleBuilderFinished(); 367 } 368 369 @Override 370 public IAuthRuleBuilderRuleOpClassifierFinished onServer() { 371 OperationRule rule = createRule(); 372 rule.appliesToServer(); 373 myRules.add(rule); 374 return new RuleBuilderFinished(); 375 } 376 377 @Override 378 public IAuthRuleBuilderRuleOpClassifierFinished onType(Class<? extends IBaseResource> theType) { 379 validateType(theType); 380 381 OperationRule rule = createRule(); 382 rule.appliesToTypes(toTypeSet(theType)); 383 myRules.add(rule); 384 return new RuleBuilderFinished(); 385 } 386 387 private void validateType(Class<? extends IBaseResource> theType) { 388 Validate.notNull(theType, "theType must not be null"); 389 } 390 391 @Override 392 public IAuthRuleBuilderRuleOpClassifierFinished onInstancesOfType(Class<? extends IBaseResource> theType) { 393 validateType(theType); 394 395 OperationRule rule = createRule(); 396 rule.appliesToInstancesOfType(toTypeSet(theType)); 397 myRules.add(rule); 398 return new RuleBuilderFinished(); 399 } 400 401 private HashSet<Class<? extends IBaseResource>> toTypeSet(Class<? extends IBaseResource> theType) { 402 HashSet<Class<? extends IBaseResource>> appliesToTypes = new HashSet<Class<? extends IBaseResource>>(); 403 appliesToTypes.add(theType); 404 return appliesToTypes; 405 } 406 407 @Override 408 public IAuthRuleFinished onAnyType() { 409 OperationRule rule = createRule(); 410 rule.appliesToAnyType(); 411 myRules.add(rule); 412 return new RuleBuilderFinished(); 413 } 414 415 @Override 416 public IAuthRuleFinished onAnyInstance() { 417 OperationRule rule = createRule(); 418 rule.appliesToAnyInstance(); 419 myRules.add(rule); 420 return new RuleBuilderFinished(); 421 } 422 423 } 424 425 } 426 427 private class RuleBuilderRuleTransaction implements IAuthRuleBuilderRuleTransaction { 428 429 @Override 430 public IAuthRuleBuilderRuleTransactionOp withAnyOperation() { 431 return new RuleBuilderRuleTransactionOp(); 432 } 433 434 private class RuleBuilderRuleTransactionOp implements IAuthRuleBuilderRuleTransactionOp { 435 436 @Override 437 public IAuthRuleBuilderRuleOpClassifierFinished andApplyNormalRules() { 438 RuleImplOp rule = new RuleImplOp(myRuleName); 439 rule.setMode(myRuleMode); 440 rule.setOp(myRuleOp); 441 rule.setTransactionAppliesToOp(TransactionAppliesToEnum.ANY_OPERATION); 442 myRules.add(rule); 443 return new RuleBuilderFinished(); 444 } 445 446 } 447 448 } 449 450 } 451 452}