Monday, September 24, 2012

ABBI Security

Designing for Security is incredibly important.  As John Moehrke will often tell you, you shouldn't be adding it as an afterthought.  The key to securing the ABBI Protocol that I'm proposing are the two URLs it exposed.  These are originally specified by the IHE Mobile Access to Health Documents profile (and will be subtly modified in my proposal):

Search: https://<location>/net.ihe/DocumentDossier/search[.atom|.json]
Document Access: https://<location>/net.ihe/Document/<entryUUID>/

The first is the search URL which returns the atom feed or json representation, and the second is used to access possibly transformed document content.  These two URLs must be secured using SSL (ideally TLS, but I'm not going to require that for other reasons), and the user (the patient) must also somehow "log in" to the application.  

Securing my web application ought to be straighforward.  I'm using Tomcat, JSP and Servlets, and web application security is pretty much built in to the deployment model.  I identify the resources that need to be secured (the two I mentioned above) in a <security-constraint> element in my deployment descriptor:

<security-constraint>
  <web-resource-collection>
    <web-resource-name>SecurePages</web-resource-name>
    <description>Security constraint for ABBI Resources</description>
    <url-pattern>/net.ihe/*</url-pattern>
  </web-resource-collection>
 ...


Indicate the required user role:
 ...

  <auth-constraint>
    <description>only let users login </description>
    <role-name>user</role-name>
  </auth-constraint>
 ...



Specify the degree of content protection needed:
 ...


  <user-data-constraint>
    <description>SSL required (Change to NONE for testing ONLY)</description>
    <transport-guarantee>CONFIDENTIAL</transport-guarantee>
  </user-data-constraint>
 ...



And lastly indicate how the user is to login:
 ...


  <login-config>
    <auth-method>?</auth-method>
  </login-config>
</security-constraint>




Now here is where it gets tricky.  To demonstrate how logins are secured, I want to use OAuth.  I'm not going to use OAuth 2.0 just yet (because it is harder to demonstrate).  My first step will just be to demonstrate secure access via OAuth 1.0, as employed by Twitter.

Unlike common authentication protocols, these don't typically deal with usernames and passwords.  Instead, the OAuth protocol deals with three separate sets of credentials.  The first set belong to the application (e.g., my ABBI Server), and are simply used to request a temporary set of credentials (which are the second set). That second set of credentials are sent by my server to the by the end user's credential holder site (in this case Twitter), to authorize my application.  Twitter returns to my server the final set of credentials, which are what my ABBI server uses to perform requests on the user's behalf.

All I will be doing with those credentials is getting back the user's Twitter handle, and that only to demonstrate that I've successfully authorized my application.

I have four choices for how to enable the user to log in.  These are:
  • BASIC: Uses HTTP-Authorization headers and the Basic Authentication method.
  • DIGEST: Uses HTTP-Authorization headers and the Digest Authentication method.
  • FORM: Uses form based authentication with specified parameters for 
  • CLIENT-CERT: Authenticates using a client certificate

None of these is a perfect match for what I want, but of the four, FORM is the closest to what I need. Here's a classic example of a login page:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Login Test: Login Form</title>
</head>
<h1>Login Form</h1>
  Welcome to the login page.
    <form method="POST" action="j_security_check">
      Username: <input type="text" name="j_username"><br />
      Password: <input type="password" name="j_password"><br />
 <br />
      <input type="submit" value="Login">
      <input type="reset" value="Reset">
    </form>
</html>


Clearly, that isn't the "OAuth" way.  So there's a bunch of stuff I need to do to hack this into what I want. Here's how I think I can make it work: 
  1. In my ABBI Server, I'll send a POST Request to Twitter's request_token URL.  It's authorization header will contain my application's "login credentials".  
  2. Twitter will respond to my server with three parameters containing the credentials needed to authorize the application.  These will become part of a URL request that will appear within a frame and/or dialog the my server will create in the page and which will be launched for the user. 
  3. After the user logs in to Twitter, the Twitter authentication page will redirect the user back to my application (in that frame and/or dialog), passing back appropriate application access credentials.  
  4. My server will store the application access credentials, and will send back some sort of fake values for j_username and j_password that will make my web application server happy.

I ought to be able to create a form that will do the necessary, which means I can insert the following for the login-config portion.

  <login-config>
    <auth-method>FORM</auth-method>
    <realm-name>ABBI</realm-name>
    <form-login-config>
        <form-login-page>/login.jsp</form-login-page>
        <form-error-page>/lerror.jsp</form-error-page>
    </form-login-config>
  </login-config>



This step is probably going to take me a bit of time, because I've never done it before, and there are lot of tricky bits.

There's a bunch of easy stuff that follows this step, but I'm taking the approach that I need to work on the hard stuff first.  While OAuth isn't rocket science, it certainly qualifies as the most risky component of my prototype right now.  Everything else is pretty-much "rote" programming that I know can be done, even if I haven't written the code yet.  This is the one part that I'm not so sure about.  Even though it isn't using the same version of OAuth that RHEx has specified, I feel comfortable enough that if I can demonstrate OAuth 1.0, that eventually, I'll be able to plug into 2.0.  That's just an incremental refinement.

For demonstration purposes, I'll need to link the Twitter account to a patient identifier.  In real life, the application would get that via an API call to the service protected by the OAuth access credentials.  This could also be done using PIX/PDQ.  The provider offering the service would request the user to supply a user id (e.g., a Twitter account) that only they had access to.  That service would register that identifier with a master patient index.  When the user "logged-in" to the ABBI service, we'd get the account identifier that they logged in with, and query the master patient index using PIX to get the associated patient identifier that the registry used to provide access to the patient records.

As I finish this, I realize that I need to do a security risk assessment for this application.  Sounds like another blog post.

  -- Keith

0 comments:

Post a Comment