Require explicit declaration of authorizationinterceptor operation rules
on whether the response is authorized or not
This commit is contained in:
parent
364b6cc5fd
commit
b41c222880
|
@ -34,11 +34,11 @@ public class PublicSecurityInterceptor extends AuthorizationInterceptor {
|
||||||
|
|
||||||
if (isBlank(authHeader)) {
|
if (isBlank(authHeader)) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.deny().operation().named(BaseJpaSystemProvider.MARK_ALL_RESOURCES_FOR_REINDEXING).onServer().andThen()
|
.deny().operation().named(BaseJpaSystemProvider.MARK_ALL_RESOURCES_FOR_REINDEXING).onServer().andAllowAllResponses().andThen()
|
||||||
.deny().operation().named(BaseTerminologyUploaderProvider.UPLOAD_EXTERNAL_CODE_SYSTEM).onServer().andThen()
|
.deny().operation().named(BaseTerminologyUploaderProvider.UPLOAD_EXTERNAL_CODE_SYSTEM).onServer().andAllowAllResponses().andThen()
|
||||||
.deny().operation().named(JpaConstants.OPERATION_EXPUNGE).onServer().andThen()
|
.deny().operation().named(JpaConstants.OPERATION_EXPUNGE).onServer().andAllowAllResponses().andThen()
|
||||||
.deny().operation().named(JpaConstants.OPERATION_EXPUNGE).onAnyType().andThen()
|
.deny().operation().named(JpaConstants.OPERATION_EXPUNGE).onAnyType().andAllowAllResponses().andThen()
|
||||||
.deny().operation().named(JpaConstants.OPERATION_EXPUNGE).onAnyInstance().andThen()
|
.deny().operation().named(JpaConstants.OPERATION_EXPUNGE).onAnyInstance().andAllowAllResponses().andThen()
|
||||||
.allowAll()
|
.allowAll()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,9 @@ package ca.uhn.fhir.rest.server.interceptor.auth;
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -108,5 +108,4 @@ abstract class BaseRule implements IAuthRule {
|
||||||
Verdict newVerdict() {
|
Verdict newVerdict() {
|
||||||
return new Verdict(myMode, this);
|
return new Verdict(myMode, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,9 @@ package ca.uhn.fhir.rest.server.interceptor.auth;
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -28,36 +28,36 @@ public interface IAuthRuleBuilderOperationNamed {
|
||||||
/**
|
/**
|
||||||
* Rule applies to invocations of this operation at the <code>server</code> level
|
* Rule applies to invocations of this operation at the <code>server</code> level
|
||||||
*/
|
*/
|
||||||
IAuthRuleBuilderRuleOpClassifierFinished onServer();
|
IAuthRuleBuilderOperationNamedAndScoped onServer();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rule applies to invocations of this operation at the <code>type</code> level
|
* Rule applies to invocations of this operation at the <code>type</code> level
|
||||||
*/
|
*/
|
||||||
IAuthRuleBuilderRuleOpClassifierFinished onType(Class<? extends IBaseResource> theType);
|
IAuthRuleBuilderOperationNamedAndScoped onType(Class<? extends IBaseResource> theType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rule applies to invocations of this operation at the <code>type</code> level on any type
|
* Rule applies to invocations of this operation at the <code>type</code> level on any type
|
||||||
*/
|
*/
|
||||||
IAuthRuleBuilderRuleOpClassifierFinished onAnyType();
|
IAuthRuleBuilderOperationNamedAndScoped onAnyType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rule applies to invocations of this operation at the <code>instance</code> level
|
* Rule applies to invocations of this operation at the <code>instance</code> level
|
||||||
*/
|
*/
|
||||||
IAuthRuleBuilderRuleOpClassifierFinished onInstance(IIdType theInstanceId);
|
IAuthRuleBuilderOperationNamedAndScoped onInstance(IIdType theInstanceId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rule applies to invocations of this operation at the <code>instance</code> level on any instance of the given type
|
* Rule applies to invocations of this operation at the <code>instance</code> level on any instance of the given type
|
||||||
*/
|
*/
|
||||||
IAuthRuleBuilderRuleOpClassifierFinished onInstancesOfType(Class<? extends IBaseResource> theType);
|
IAuthRuleBuilderOperationNamedAndScoped onInstancesOfType(Class<? extends IBaseResource> theType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rule applies to invocations of this operation at the <code>instance</code> level on any instance
|
* Rule applies to invocations of this operation at the <code>instance</code> level on any instance
|
||||||
*/
|
*/
|
||||||
IAuthRuleBuilderRuleOpClassifierFinished onAnyInstance();
|
IAuthRuleBuilderOperationNamedAndScoped onAnyInstance();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rule applies to invocations of this operation at any level (server, type or instance)
|
* Rule applies to invocations of this operation at any level (server, type or instance)
|
||||||
*/
|
*/
|
||||||
IAuthRuleBuilderRuleOpClassifierFinished atAnyLevel();
|
IAuthRuleBuilderOperationNamedAndScoped atAnyLevel();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package ca.uhn.fhir.rest.server.interceptor.auth;
|
||||||
|
|
||||||
|
public interface IAuthRuleBuilderOperationNamedAndScoped {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Responses for this operation will not be checked
|
||||||
|
*/
|
||||||
|
IAuthRuleBuilderRuleOpClassifierFinished andAllowAllResponses();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Responses for this operation must be authorized by other rules. For example, if this
|
||||||
|
* rule is authorizing the Patient $everything operation, there must be a separate
|
||||||
|
* rule (or rules) that actually authorize the user to read the
|
||||||
|
* resources being returned
|
||||||
|
*/
|
||||||
|
IAuthRuleBuilderRuleOpClassifierFinished andRequireExplicitResponseAuthorization();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -9,9 +9,9 @@ package ca.uhn.fhir.rest.server.interceptor.auth;
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -41,6 +41,7 @@ class OperationRule extends BaseRule implements IAuthRule {
|
||||||
private boolean myAppliesToAnyType;
|
private boolean myAppliesToAnyType;
|
||||||
private boolean myAppliesToAnyInstance;
|
private boolean myAppliesToAnyInstance;
|
||||||
private boolean myAppliesAtAnyLevel;
|
private boolean myAppliesAtAnyLevel;
|
||||||
|
private boolean myAllowAllResponses;
|
||||||
|
|
||||||
OperationRule(String theRuleName) {
|
OperationRule(String theRuleName) {
|
||||||
super(theRuleName);
|
super(theRuleName);
|
||||||
|
@ -50,6 +51,10 @@ class OperationRule extends BaseRule implements IAuthRule {
|
||||||
myAppliesAtAnyLevel = theAppliesAtAnyLevel;
|
myAppliesAtAnyLevel = theAppliesAtAnyLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void allowAllResponses() {
|
||||||
|
myAllowAllResponses = true;
|
||||||
|
}
|
||||||
|
|
||||||
void appliesToAnyInstance() {
|
void appliesToAnyInstance() {
|
||||||
myAppliesToAnyInstance = true;
|
myAppliesToAnyInstance = true;
|
||||||
}
|
}
|
||||||
|
@ -114,23 +119,32 @@ class OperationRule extends BaseRule implements IAuthRule {
|
||||||
case EXTENDED_OPERATION_INSTANCE:
|
case EXTENDED_OPERATION_INSTANCE:
|
||||||
if (myAppliesToAnyInstance || myAppliesAtAnyLevel) {
|
if (myAppliesToAnyInstance || myAppliesAtAnyLevel) {
|
||||||
applies = true;
|
applies = true;
|
||||||
} else if (theInputResourceId != null) {
|
} else {
|
||||||
if (myAppliesToIds != null) {
|
IIdType requestResourceId = null;
|
||||||
String instanceId = theInputResourceId.toUnqualifiedVersionless().getValue();
|
if (theInputResourceId != null) {
|
||||||
for (IIdType next : myAppliesToIds) {
|
requestResourceId = theInputResourceId;
|
||||||
if (next.toUnqualifiedVersionless().getValue().equals(instanceId)) {
|
}
|
||||||
applies = true;
|
if (requestResourceId == null && myAllowAllResponses) {
|
||||||
break;
|
requestResourceId = theRequestDetails.getId();
|
||||||
|
}
|
||||||
|
if (requestResourceId != null) {
|
||||||
|
if (myAppliesToIds != null) {
|
||||||
|
String instanceId = requestResourceId .toUnqualifiedVersionless().getValue();
|
||||||
|
for (IIdType next : myAppliesToIds) {
|
||||||
|
if (next.toUnqualifiedVersionless().getValue().equals(instanceId)) {
|
||||||
|
applies = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (myAppliesToInstancesOfType != null) {
|
||||||
if (myAppliesToInstancesOfType != null) {
|
// TODO: Convert to a map of strings and keep the result
|
||||||
// TODO: Convert to a map of strings and keep the result
|
for (Class<? extends IBaseResource> next : myAppliesToInstancesOfType) {
|
||||||
for (Class<? extends IBaseResource> next : myAppliesToInstancesOfType) {
|
String resName = ctx.getResourceDefinition(next).getName();
|
||||||
String resName = ctx.getResourceDefinition(next).getName();
|
if (resName.equals(requestResourceId .getResourceType())) {
|
||||||
if (resName.equals(theInputResourceId.getResourceType())) {
|
applies = true;
|
||||||
applies = true;
|
break;
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -416,6 +416,28 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
||||||
|
|
||||||
private class RuleBuilderRuleOperationNamed implements IAuthRuleBuilderOperationNamed {
|
private class RuleBuilderRuleOperationNamed implements IAuthRuleBuilderOperationNamed {
|
||||||
|
|
||||||
|
private class RuleBuilderOperationNamedAndScoped implements IAuthRuleBuilderOperationNamedAndScoped {
|
||||||
|
|
||||||
|
private final OperationRule myRule;
|
||||||
|
|
||||||
|
public RuleBuilderOperationNamedAndScoped(OperationRule theRule) {
|
||||||
|
myRule = theRule;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IAuthRuleBuilderRuleOpClassifierFinished andAllowAllResponses() {
|
||||||
|
myRule.allowAllResponses();
|
||||||
|
myRules.add(myRule);
|
||||||
|
return new RuleBuilderFinished(myRule);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IAuthRuleBuilderRuleOpClassifierFinished andRequireExplicitResponseAuthorization() {
|
||||||
|
myRules.add(myRule);
|
||||||
|
return new RuleBuilderFinished(myRule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private String myOperationName;
|
private String myOperationName;
|
||||||
|
|
||||||
RuleBuilderRuleOperationNamed(String theOperationName) {
|
RuleBuilderRuleOperationNamed(String theOperationName) {
|
||||||
|
@ -434,31 +456,28 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IAuthRuleBuilderRuleOpClassifierFinished onAnyInstance() {
|
public IAuthRuleBuilderOperationNamedAndScoped onAnyInstance() {
|
||||||
OperationRule rule = createRule();
|
OperationRule rule = createRule();
|
||||||
rule.appliesToAnyInstance();
|
rule.appliesToAnyInstance();
|
||||||
myRules.add(rule);
|
return new RuleBuilderOperationNamedAndScoped(rule);
|
||||||
return new RuleBuilderFinished(rule);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IAuthRuleBuilderRuleOpClassifierFinished atAnyLevel() {
|
public IAuthRuleBuilderOperationNamedAndScoped atAnyLevel() {
|
||||||
OperationRule rule = createRule();
|
OperationRule rule = createRule();
|
||||||
rule.appliesAtAnyLevel(true);
|
rule.appliesAtAnyLevel(true);
|
||||||
myRules.add(rule);
|
return new RuleBuilderOperationNamedAndScoped(rule);
|
||||||
return new RuleBuilderFinished(rule);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IAuthRuleBuilderRuleOpClassifierFinished onAnyType() {
|
public IAuthRuleBuilderOperationNamedAndScoped onAnyType() {
|
||||||
OperationRule rule = createRule();
|
OperationRule rule = createRule();
|
||||||
rule.appliesToAnyType();
|
rule.appliesToAnyType();
|
||||||
myRules.add(rule);
|
return new RuleBuilderOperationNamedAndScoped(rule);
|
||||||
return new RuleBuilderFinished(rule);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IAuthRuleBuilderRuleOpClassifierFinished onInstance(IIdType theInstanceId) {
|
public IAuthRuleBuilderOperationNamedAndScoped onInstance(IIdType theInstanceId) {
|
||||||
Validate.notNull(theInstanceId, "theInstanceId must not be null");
|
Validate.notNull(theInstanceId, "theInstanceId must not be null");
|
||||||
Validate.notBlank(theInstanceId.getResourceType(), "theInstanceId does not have a resource type");
|
Validate.notBlank(theInstanceId.getResourceType(), "theInstanceId does not have a resource type");
|
||||||
Validate.notBlank(theInstanceId.getIdPart(), "theInstanceId does not have an ID part");
|
Validate.notBlank(theInstanceId.getIdPart(), "theInstanceId does not have an ID part");
|
||||||
|
@ -467,36 +486,32 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
||||||
ArrayList<IIdType> ids = new ArrayList<>();
|
ArrayList<IIdType> ids = new ArrayList<>();
|
||||||
ids.add(theInstanceId);
|
ids.add(theInstanceId);
|
||||||
rule.appliesToInstances(ids);
|
rule.appliesToInstances(ids);
|
||||||
myRules.add(rule);
|
return new RuleBuilderOperationNamedAndScoped(rule);
|
||||||
return new RuleBuilderFinished(rule);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IAuthRuleBuilderRuleOpClassifierFinished onInstancesOfType(Class<? extends IBaseResource> theType) {
|
public IAuthRuleBuilderOperationNamedAndScoped onInstancesOfType(Class<? extends IBaseResource> theType) {
|
||||||
validateType(theType);
|
validateType(theType);
|
||||||
|
|
||||||
OperationRule rule = createRule();
|
OperationRule rule = createRule();
|
||||||
rule.appliesToInstancesOfType(toTypeSet(theType));
|
rule.appliesToInstancesOfType(toTypeSet(theType));
|
||||||
myRules.add(rule);
|
return new RuleBuilderOperationNamedAndScoped(rule);
|
||||||
return new RuleBuilderFinished(rule);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IAuthRuleBuilderRuleOpClassifierFinished onServer() {
|
public IAuthRuleBuilderOperationNamedAndScoped onServer() {
|
||||||
OperationRule rule = createRule();
|
OperationRule rule = createRule();
|
||||||
rule.appliesToServer();
|
rule.appliesToServer();
|
||||||
myRules.add(rule);
|
return new RuleBuilderOperationNamedAndScoped(rule);
|
||||||
return new RuleBuilderFinished(rule);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IAuthRuleBuilderRuleOpClassifierFinished onType(Class<? extends IBaseResource> theType) {
|
public IAuthRuleBuilderOperationNamedAndScoped onType(Class<? extends IBaseResource> theType) {
|
||||||
validateType(theType);
|
validateType(theType);
|
||||||
|
|
||||||
OperationRule rule = createRule();
|
OperationRule rule = createRule();
|
||||||
rule.appliesToTypes(toTypeSet(theType));
|
rule.appliesToTypes(toTypeSet(theType));
|
||||||
myRules.add(rule);
|
return new RuleBuilderOperationNamedAndScoped(rule);
|
||||||
return new RuleBuilderFinished(rule);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private HashSet<Class<? extends IBaseResource>> toTypeSet(Class<? extends IBaseResource> theType) {
|
private HashSet<Class<? extends IBaseResource>> toTypeSet(Class<? extends IBaseResource> theType) {
|
||||||
|
|
|
@ -572,7 +572,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().withAnyName().onServer().andThen()
|
.allow("RULE 1").operation().withAnyName().onServer().andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -598,7 +598,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class)
|
.allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class).andRequireExplicitResponseAuthorization()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -633,7 +633,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class).andThen()
|
.allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class).andRequireExplicitResponseAuthorization().andThen()
|
||||||
.allow("Rule 2").read().allResources().inCompartment("Patient", new IdDt("Patient/1")).andThen()
|
.allow("Rule 2").read().allResources().inCompartment("Patient", new IdDt("Patient/1")).andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
@ -671,7 +671,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class)
|
.allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class).andRequireExplicitResponseAuthorization()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -705,7 +705,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opName").onInstance(new IdDt("http://example.com/Patient/1/_history/2")).andThen()
|
.allow("RULE 1").operation().named("opName").onInstance(new IdDt("http://example.com/Patient/1/_history/2")).andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -764,7 +764,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opName").onAnyInstance().andThen()
|
.allow("RULE 1").operation().named("opName").onAnyInstance().andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -890,7 +890,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opName").onServer().andThen()
|
.allow("RULE 1").operation().named("opName").onServer().andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -937,7 +937,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opName").onType(Patient.class).andThen()
|
.allow("RULE 1").operation().named("opName").onType(Patient.class).andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1006,7 +1006,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opName").onAnyType().andThen()
|
.allow("RULE 1").operation().named("opName").onAnyType().andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -882,7 +882,7 @@ public class AuthorizationInterceptorDstu3Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().withAnyName().onServer().andThen()
|
.allow("RULE 1").operation().withAnyName().onServer().andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -908,7 +908,7 @@ public class AuthorizationInterceptorDstu3Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opName").atAnyLevel().andThen()
|
.allow("RULE 1").operation().named("opName").atAnyLevel().andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -964,7 +964,7 @@ public class AuthorizationInterceptorDstu3Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opNameBadOp").atAnyLevel().andThen()
|
.allow("RULE 1").operation().named("opNameBadOp").atAnyLevel().andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1020,7 +1020,7 @@ public class AuthorizationInterceptorDstu3Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class)
|
.allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class).andRequireExplicitResponseAuthorization()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1055,7 +1055,7 @@ public class AuthorizationInterceptorDstu3Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class).andThen()
|
.allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class).andRequireExplicitResponseAuthorization().andThen()
|
||||||
.allow("Rule 2").read().allResources().inCompartment("Patient", new IdType("Patient/1")).andThen()
|
.allow("Rule 2").read().allResources().inCompartment("Patient", new IdType("Patient/1")).andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
@ -1093,7 +1093,7 @@ public class AuthorizationInterceptorDstu3Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class)
|
.allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class).andRequireExplicitResponseAuthorization()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1127,7 +1127,7 @@ public class AuthorizationInterceptorDstu3Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opName").onInstance(new IdType("http://example.com/Patient/1/_history/2")).andThen()
|
.allow("RULE 1").operation().named("opName").onInstance(new IdType("http://example.com/Patient/1/_history/2")).andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1186,7 +1186,7 @@ public class AuthorizationInterceptorDstu3Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opName").onAnyInstance().andThen()
|
.allow("RULE 1").operation().named("opName").onAnyInstance().andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1311,7 +1311,7 @@ public class AuthorizationInterceptorDstu3Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opName").onServer().andThen()
|
.allow("RULE 1").operation().named("opName").onServer().andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1358,7 +1358,7 @@ public class AuthorizationInterceptorDstu3Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opName").onType(Patient.class).andThen()
|
.allow("RULE 1").operation().named("opName").onType(Patient.class).andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1427,7 +1427,7 @@ public class AuthorizationInterceptorDstu3Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opName").onAnyType().andThen()
|
.allow("RULE 1").operation().named("opName").onAnyType().andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1495,7 +1495,7 @@ public class AuthorizationInterceptorDstu3Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opName").onType(Organization.class).andThen()
|
.allow("RULE 1").operation().named("opName").onType(Organization.class).andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1554,7 +1554,7 @@ public class AuthorizationInterceptorDstu3Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opName").onType(Patient.class).forTenantIds("TENANTA").andThen()
|
.allow("RULE 1").operation().named("opName").onType(Patient.class).andRequireExplicitResponseAuthorization().forTenantIds("TENANTA").andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1591,7 +1591,7 @@ public class AuthorizationInterceptorDstu3Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("process-message").onType(MessageHeader.class).andThen()
|
.allow("RULE 1").operation().named("process-message").onType(MessageHeader.class).andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1630,7 +1630,7 @@ public class AuthorizationInterceptorDstu3Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class).withTester(new IAuthRuleTester() {
|
.allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class).andRequireExplicitResponseAuthorization().withTester(new IAuthRuleTester() {
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IIdType theInputResourceId, IBaseResource theInputResource) {
|
public boolean matches(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IIdType theInputResourceId, IBaseResource theInputResource) {
|
||||||
return theInputResourceId.getIdPart().equals("1");
|
return theInputResourceId.getIdPart().equals("1");
|
||||||
|
|
|
@ -36,11 +36,10 @@ import org.eclipse.jetty.servlet.ServletHolder;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.model.*;
|
import org.hl7.fhir.r4.model.*;
|
||||||
import org.junit.AfterClass;
|
import org.junit.*;
|
||||||
import org.junit.Before;
|
import org.springframework.util.Base64Utils;
|
||||||
import org.junit.BeforeClass;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -49,6 +48,7 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static javax.print.DocFlavor.READER.TEXT_HTML;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
@ -65,6 +65,7 @@ public class AuthorizationInterceptorR4Test {
|
||||||
private static List<Resource> ourReturn;
|
private static List<Resource> ourReturn;
|
||||||
private static Server ourServer;
|
private static Server ourServer;
|
||||||
private static RestfulServer ourServlet;
|
private static RestfulServer ourServlet;
|
||||||
|
private static String ourLastAcceptHeader;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void before() {
|
public void before() {
|
||||||
|
@ -76,6 +77,7 @@ public class AuthorizationInterceptorR4Test {
|
||||||
ourReturn = null;
|
ourReturn = null;
|
||||||
ourHitMethod = false;
|
ourHitMethod = false;
|
||||||
ourConditionalCreateId = "1123";
|
ourConditionalCreateId = "1123";
|
||||||
|
ourLastAcceptHeader = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Resource createCarePlan(Integer theId, String theSubjectId) {
|
private Resource createCarePlan(Integer theId, String theSubjectId) {
|
||||||
|
@ -922,7 +924,7 @@ public class AuthorizationInterceptorR4Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().withAnyName().onServer().andThen()
|
.allow("RULE 1").operation().withAnyName().onServer().andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -948,7 +950,7 @@ public class AuthorizationInterceptorR4Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opName").atAnyLevel().andThen()
|
.allow("RULE 1").operation().named("opName").atAnyLevel().andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1004,7 +1006,7 @@ public class AuthorizationInterceptorR4Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opNameBadOp").atAnyLevel().andThen()
|
.allow("RULE 1").operation().named("opNameBadOp").atAnyLevel().andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1060,7 +1062,7 @@ public class AuthorizationInterceptorR4Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class)
|
.allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class).andRequireExplicitResponseAuthorization()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1090,12 +1092,13 @@ public class AuthorizationInterceptorR4Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore
|
||||||
public void testOperationByInstanceOfTypeWithInvalidReturnValue() throws Exception {
|
public void testOperationByInstanceOfTypeWithInvalidReturnValue() throws Exception {
|
||||||
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class).andThen()
|
.allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class).andRequireExplicitResponseAuthorization().andThen()
|
||||||
.allow("Rule 2").read().allResources().inCompartment("Patient", new IdType("Patient/1")).andThen()
|
.allow("Rule 2").read().allResources().inCompartment("Patient", new IdType("Patient/1")).andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
@ -1133,7 +1136,7 @@ public class AuthorizationInterceptorR4Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class)
|
.allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class).andRequireExplicitResponseAuthorization()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1167,7 +1170,7 @@ public class AuthorizationInterceptorR4Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opName").onInstance(new IdType("http://example.com/Patient/1/_history/2")).andThen()
|
.allow("RULE 1").operation().named("opName").onInstance(new IdType("http://example.com/Patient/1/_history/2")).andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1226,7 +1229,7 @@ public class AuthorizationInterceptorR4Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opName").onAnyInstance().andThen()
|
.allow("RULE 1").operation().named("opName").onAnyInstance().andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1289,6 +1292,31 @@ public class AuthorizationInterceptorR4Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOperationInstanceLevelWithHtmlResponse() throws IOException {
|
||||||
|
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||||
|
@Override
|
||||||
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
|
return new RuleBuilder()
|
||||||
|
.allow("RULE 1").operation().named("binaryop").onInstancesOfType(Patient.class).andAllowAllResponses().andThen()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/2/$binaryop");
|
||||||
|
httpGet.addHeader(Constants.HEADER_ACCEPT, "text/html");
|
||||||
|
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
|
||||||
|
assertEquals("text/html", status.getEntity().getContentType().getValue());
|
||||||
|
assertEquals("<html>TAGS</html>", IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8));
|
||||||
|
assertEquals("text/html", ourLastAcceptHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOperationNotAllowedWithWritePermissiom() throws Exception {
|
public void testOperationNotAllowedWithWritePermissiom() throws Exception {
|
||||||
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||||
|
@ -1346,12 +1374,12 @@ public class AuthorizationInterceptorR4Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOperationServerLevel() throws Exception {
|
public void testOperationServerLevelAllowAllResponses() throws Exception {
|
||||||
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opName").onServer().andThen()
|
.allow("RULE 1").operation().named("opName").onServer().andAllowAllResponses().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1392,13 +1420,48 @@ public class AuthorizationInterceptorR4Test {
|
||||||
assertFalse(ourHitMethod);
|
assertFalse(ourHitMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOperationServerLevelRequireResponseAuthorization() throws Exception {
|
||||||
|
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||||
|
@Override
|
||||||
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
|
return new RuleBuilder()
|
||||||
|
.allow("RULE 1").operation().named("opName").onServer().andRequireExplicitResponseAuthorization().andThen()
|
||||||
|
.allow().read().instance("Observation/10").andThen()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
HttpGet httpGet;
|
||||||
|
HttpResponse status;
|
||||||
|
String response;
|
||||||
|
|
||||||
|
// Server
|
||||||
|
ourHitMethod = false;
|
||||||
|
ourReturn = Collections.singletonList(createObservation(10, "Patient/2"));
|
||||||
|
httpGet = new HttpGet("http://localhost:" + ourPort + "/$opName");
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
extractResponseAndClose(status);
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertTrue(ourHitMethod);
|
||||||
|
|
||||||
|
// Server
|
||||||
|
ourHitMethod = false;
|
||||||
|
ourReturn = Collections.singletonList(createObservation(99, "Patient/2"));
|
||||||
|
httpGet = new HttpGet("http://localhost:" + ourPort + "/$opName");
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
extractResponseAndClose(status);
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertTrue(ourHitMethod);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOperationTypeLevel() throws Exception {
|
public void testOperationTypeLevel() throws Exception {
|
||||||
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opName").onType(Patient.class).andThen()
|
.allow("RULE 1").operation().named("opName").onType(Patient.class).andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1467,7 +1530,7 @@ public class AuthorizationInterceptorR4Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opName").onAnyType().andThen()
|
.allow("RULE 1").operation().named("opName").onAnyType().andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1535,7 +1598,7 @@ public class AuthorizationInterceptorR4Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opName").onType(Organization.class).andThen()
|
.allow("RULE 1").operation().named("opName").onType(Organization.class).andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1594,7 +1657,7 @@ public class AuthorizationInterceptorR4Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("opName").onType(Patient.class).forTenantIds("TENANTA").andThen()
|
.allow("RULE 1").operation().named("opName").onType(Patient.class).andRequireExplicitResponseAuthorization().forTenantIds("TENANTA").andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1631,7 +1694,7 @@ public class AuthorizationInterceptorR4Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("RULE 1").operation().named("process-message").onType(MessageHeader.class).andThen()
|
.allow("RULE 1").operation().named("process-message").onType(MessageHeader.class).andRequireExplicitResponseAuthorization().andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1670,7 +1733,7 @@ public class AuthorizationInterceptorR4Test {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class).withTester(new IAuthRuleTester() {
|
.allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class).andRequireExplicitResponseAuthorization().withTester(new IAuthRuleTester() {
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IIdType theInputResourceId, IBaseResource theInputResource) {
|
public boolean matches(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IIdType theInputResourceId, IBaseResource theInputResource) {
|
||||||
return theInputResourceId.getIdPart().equals("1");
|
return theInputResourceId.getIdPart().equals("1");
|
||||||
|
@ -3264,6 +3327,7 @@ public class AuthorizationInterceptorR4Test {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class DummyPatientResourceProvider implements IResourceProvider {
|
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||||
|
|
||||||
|
|
||||||
@Create()
|
@Create()
|
||||||
public MethodOutcome create(@ResourceParam Patient theResource, @ConditionalUrlParam String theConditionalUrl, RequestDetails theRequestDetails) {
|
public MethodOutcome create(@ResourceParam Patient theResource, @ConditionalUrlParam String theConditionalUrl, RequestDetails theRequestDetails) {
|
||||||
|
|
||||||
|
@ -3303,6 +3367,26 @@ public class AuthorizationInterceptorR4Test {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(name = "$binaryop", idempotent = true)
|
||||||
|
public Binary binaryOp(
|
||||||
|
@IdParam IIdType theId,
|
||||||
|
@OperationParam(name = "PARAM3", min = 0, max = 1) List<org.hl7.fhir.r4.model.StringType> theParam3,
|
||||||
|
HttpServletRequest theServletRequest
|
||||||
|
) {
|
||||||
|
ourLastAcceptHeader = theServletRequest.getHeader(ca.uhn.fhir.rest.api.Constants.HEADER_ACCEPT);
|
||||||
|
|
||||||
|
Binary retVal = new Binary();
|
||||||
|
if (ourLastAcceptHeader.contains("html")) {
|
||||||
|
retVal.setContentType("text/html");
|
||||||
|
retVal.setContent("<html>TAGS</html>".getBytes(Charsets.UTF_8));
|
||||||
|
} else {
|
||||||
|
retVal.setContentType("application/weird");
|
||||||
|
retVal.setContent(new byte[]{0,0,1,1,2,2,3,3,0,0});
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<? extends IBaseResource> getResourceType() {
|
public Class<? extends IBaseResource> getResourceType() {
|
||||||
return Patient.class;
|
return Patient.class;
|
||||||
|
|
|
@ -19,14 +19,14 @@
|
||||||
<action type="add">
|
<action type="add">
|
||||||
Changed subscription processing, if the subscription criteria are straightforward (i.e. no
|
Changed subscription processing, if the subscription criteria are straightforward (i.e. no
|
||||||
chained references, qualifiers or prefixes) then attempt to match the incoming resource against
|
chained references, qualifiers or prefixes) then attempt to match the incoming resource against
|
||||||
the criteria in-memory. If the subscription criteria can't be matched in-memory, then the
|
the criteria in-memory. If the subscription criteria can't be matched in-memory, then the
|
||||||
server falls back to the original subscription matching process of querying the database. The
|
server falls back to the original subscription matching process of querying the database. The
|
||||||
in-memory matcher can be disabled by setting isEnableInMemorySubscriptionMatching to "false" in
|
in-memory matcher can be disabled by setting isEnableInMemorySubscriptionMatching to "false" in
|
||||||
DaoConfig (by default it is true). If isEnableInMemorySubscriptionMatching is "false", then all
|
DaoConfig (by default it is true). If isEnableInMemorySubscriptionMatching is "false", then all
|
||||||
subscription matching will query the database as before.
|
subscription matching will query the database as before.
|
||||||
</action>
|
</action>
|
||||||
<action type="add">
|
<action type="add">
|
||||||
Changed behaviour of FHIR Server to reject subscriptions with invalid criteria. If a Subscription
|
Changed behaviour of FHIR Server to reject subscriptions with invalid criteria. If a Subscription
|
||||||
is submitted with invalid criteria, the server returns HTTP 422 "Unprocessable Entity" and the
|
is submitted with invalid criteria, the server returns HTTP 422 "Unprocessable Entity" and the
|
||||||
Subscription is not persisted.
|
Subscription is not persisted.
|
||||||
</action>
|
</action>
|
||||||
|
@ -76,14 +76,15 @@
|
||||||
ResourceIndexedSearchParams, IdHelperService, SearcchParamExtractorService, and MatchUrlService.
|
ResourceIndexedSearchParams, IdHelperService, SearcchParamExtractorService, and MatchUrlService.
|
||||||
</action>
|
</action>
|
||||||
<action type="add">
|
<action type="add">
|
||||||
Replaced explicit @Bean construction in BaseConfig.java with @ComponentScan. Beans with state are annotated with
|
Replaced explicit @Bean construction in BaseConfig.java with @ComponentScan. Beans with state are annotated
|
||||||
@Component and stateless beans are annotated as @Service. Also changed SearchBuilder.java and the
|
with
|
||||||
|
@Component and stateless beans are annotated as @Service. Also changed SearchBuilder.java and the
|
||||||
three Subscriber classes into @Scope("protoype") so their dependencies can be @Autowired injected
|
three Subscriber classes into @Scope("protoype") so their dependencies can be @Autowired injected
|
||||||
as opposed to constructor parameters.
|
as opposed to constructor parameters.
|
||||||
</action>
|
</action>
|
||||||
<action type="fix">
|
<action type="fix">
|
||||||
A bug in the JPA resource reindexer was fixed: In many cases the reindexer would
|
A bug in the JPA resource reindexer was fixed: In many cases the reindexer would
|
||||||
mark reindexing jobs as deleted before they had actually completed, leading to
|
mark reindexing jobs as deleted before they had actually completed, leading to
|
||||||
some resources not actually being reindexed.
|
some resources not actually being reindexed.
|
||||||
</action>
|
</action>
|
||||||
<action type="change">
|
<action type="change">
|
||||||
|
@ -91,6 +92,11 @@
|
||||||
larger batches (20000 instead of 500) in order to reduce the amount of noise
|
larger batches (20000 instead of 500) in order to reduce the amount of noise
|
||||||
in the logs.
|
in the logs.
|
||||||
</action>
|
</action>
|
||||||
|
<action type="add">
|
||||||
|
AuthorizationInterceptor now allows arbitrary FHIR $operations to be authorized,
|
||||||
|
including support for either allowing the operation response to proceed unchallenged,
|
||||||
|
or authorizing the contents of the response.
|
||||||
|
</action>
|
||||||
</release>
|
</release>
|
||||||
<release version="3.6.0" date="2018-11-12" description="Food">
|
<release version="3.6.0" date="2018-11-12" description="Food">
|
||||||
<action type="add">
|
<action type="add">
|
||||||
|
|
Loading…
Reference in New Issue