Site doc updates

This commit is contained in:
jamesagnew 2016-04-21 07:15:01 -04:00
parent be865b0539
commit fcf0604e98
7 changed files with 123 additions and 13 deletions

View File

@ -2,33 +2,89 @@ package example;
import java.util.List;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor;
import ca.uhn.fhir.rest.server.interceptor.auth.IAuthRule;
import ca.uhn.fhir.rest.server.interceptor.auth.RuleBuilder;
public class AuthorizationInterceptors {
public class PatientResourceProvider implements IResourceProvider
{
@Override
public Class<? extends IBaseResource> getResourceType() {
return Patient.class;
}
public MethodOutcome create(@ResourceParam Patient thePatient, RequestDetails theRequestDetails) {
return new MethodOutcome(); // populate this
}
}
//START SNIPPET: patientAndAdmin
public class PatientAndAdminAuthorizationInterceptor extends AuthorizationInterceptor {
@Override
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
// Process authorization header - The following is a fake
// implementation. Obviously we'd want something more real
// for a production scenario.
//
// In this basic example we have two hardcoded bearer tokens,
// one which is for a user that has access to one patient, and
// another that has full access.
IdDt userIdPatientId = null;
boolean userIsAdmin = false;
String authHeader = theRequestDetails.getHeader("Authorization");
/*
* Process authorization header - The following is a fake
* implementation. Obviously we'd want something more real
* for a production scenario.
*/
if ("Bearer dfw98h38r".equals(authHeader)) {
// This user has access only to Patient/1 resources
userIdPatientId = new IdDt("Patient", 1L);
} else if ("Bearer 39ff939jgg".equals(authHeader)) {
// This user has access to everything
userIsAdmin = true;
} else {
// Throw an HTTP 401
throw new AuthenticationException("Missing or invalid Authorization header value");
}
// If the user is a specific patient, we create the following rule chain:
// Allow the user to read anything in their own patient compartment
// Allow the user to write anything in their own patient compartment
// If a client request doesn't pass either of the above, deny it
if (userIdPatientId != null) {
return new RuleBuilder()
.allow().read().allResources().inCompartment("Patient", userIdPatientId).andThen()
.allow().write().allResources().inCompartment("Patient", userIdPatientId).andThen()
.denyAll()
.build();
}
// If the authorization header was determined to be
Long callerIsPatientId = null;
// If the user is an admin, allow everything
if (userIsAdmin) {
return new RuleBuilder()
.allowAll()
.build();
}
// By default, deny everything. This should never get hit, but it's
// good to be defensive
return new RuleBuilder()
.deny("Rule 1").read().resourcesOfType(Patient.class).withAnyId().andThen()
.allowAll("Default Rule")
.denyAll()
.build();
}
}
//END SNIPPET: patientAndAdmin
}

View File

@ -49,6 +49,11 @@ import ca.uhn.fhir.util.CoverageIgnore;
* This class is a base class for interceptors which can be used to
* inspect requests and responses to determine whether the calling user
* has permission to perform the given action.
* <p>
* See the HAPI FHIR
* <a href="http://jamesagnew.github.io/hapi-fhir/doc_rest_server_security.html">Documentation on Server Security</a>
* for information on how to use this interceptor.
* </p>
*/
public class AuthorizationInterceptor extends InterceptorAdapter implements IServerOperationInterceptor, IRuleApplier {

View File

@ -97,8 +97,9 @@
<item name="Using RESTful Server" href="./doc_rest_server.html" />
<item name="RESTful Operations" href="./doc_rest_operations.html" />
<item name="Narrative Generator" href="./doc_narrative.html" />
<item name="CORS Support" href="./doc_cors.html" />
<item name="Interceptors (server)" href="./doc_rest_server_interceptor.html" />
<item name="Security" href="./doc_rest_server_security.html" />
<item name="CORS Support" href="./doc_cors.html" />
<item name="Web Testing UI" href="./doc_server_tester.html" />
<item name="JAX-RS Support" href="./doc_rest_server_jaxrs.html" />
</item>

View File

@ -143,7 +143,7 @@ $ mvn install]]></source>
</p>
<ul>
<li>
<a href="https://github.com/jamesagnew/hapi-fhir/blob/master/hapi-fhir-jpaserver-example/src/main/webapp/WEB-INF/hapi-fhir-server-database-config.xml"><b>hapi-fhir-server-database-config.xml</b></a>:
<a href="https://github.com/jamesagnew/hapi-fhir/blob/master/hapi-fhir-jpaserver-example/src/main/java/ca/uhn/fhir/jpa/demo/FhirServerConfig.java"><b>FhirServerConfig.java</b></a>:
Configures the database connection settings
</li>
</ul>

View File

@ -81,7 +81,9 @@
<p class="doc_info_bubble">
AuthorizationInterceptor is a new feature in HAPI FHIR, and has not yet
been heavily tested. Use with caution, and do lots of testing! We welcome
feedback and suggestions on this feature.
feedback and suggestions on this feature. In addition, this documentation is
not yet complete. More examples and details will be added soon! Please get in
touch if you'd like to help test, have suggestions, etc.
</p>
<p>
@ -96,6 +98,45 @@
might be detemrined to belong to an administrator user, and
could be declared to be allowed to do anything.
</p>
<p>
The AuthorizationInterceptor is used by subclassing it and then registering your
subclass with the <code>RestfulServer</code>. The following example shows a subclassed
interceptor implementing some basic rules:
</p>
<macro name="snippet">
<param name="id" value="patientAndAdmin" />
<param name="file" value="examples/src/main/java/example/AuthorizationInterceptors.java" />
</macro>
<subsection name="Using AuthorizationInterceptor in a REST Server">
<p>
The AuthorizationInterceptor works by examining the client request
in order to determine whether "write" operations are legal, and looks at
the response from the server in order to determine whether "read" operations
are legal.
</p>
<p>
This approach has limitations however: If a request has a conditional operation,
such as a delete operation which uses a search URL, or a create operation which
uses an <code>If-None-Exist</code> header, the interceptor will not know the
actual target until the server actually processes the request.
</p>
<p>
For better security, individual resource providers should notify interceptors
about their actual targets in the event of any "write" operations (create,
operations embedded in transactions, etc.)
</p>
<p>
The mechanism for doing this isn't yet fully documented, this will be improved
over the next release cycle (post 1.5). Please get in touch on our google group
if you want to help!
</p>
</subsection>
</section>
</body>

View File

@ -44,8 +44,9 @@
<li><a href="./doc_rest_server.html">Using RESTful Server</a></li>
<li><a href="./doc_rest_operations.html">RESTful Operations</a></li>
<li><a href="./doc_narrative.html">Narrative Generator</a></li>
<li><a href="./doc_cors.html">CORS Support</a></li>
<li><a href="./doc_rest_server_interceptor.html">Interceptors (server)</a></li>
<li><a href="./doc_rest_server_security.html">Security</a></li>
<li><a href="./doc_cors.html">CORS Support</a></li>
<li><a href="./doc_server_tester.html">Web Testing UI</a></li>
<li><a href="./doc_rest_server_jaxrs.html">JAX-RS Support</a></li>
</ul>

View File

@ -93,6 +93,12 @@
<a href="./doc_rest_server_security.html">Server Security Interceptor</a>
has been added.
</li>
<li>
The JPA server has been enhanced so that search results are now paged into
the database instead of simply to memory. This makes the server much more
scalable to supporting larger result sets, larger volumes of queries, and
operation across multiple nodes in a cluster.
</li>
</ul>
<p>
- <a href="https://github.com/jamesagnew/">James Agnew</a>