Entries from June 2008 ↓

Scheming for Method Schemas

Eric did a great post about how to retrieve the thing-type schemas programmatically. This code shows how to retrieve the methods reponse an request programmatically.

The gist is in the method call GetServiceDefinition, this call returns the list of method and only can work on the methods to retrieve the urls for the schema’s for that version’s request and response.

    protected void Page_Load(object sender, EventArgs e)
    {
        ApplicationConnection connection = base.DictionaryConnection;
        ServiceInfo serviceInfo = connection.GetServiceDefinition();
        List methodVersions =
            new List(
                serviceInfo.Methods.Count);
        foreach (HealthServiceMethodInfo method in serviceInfo.Methods)
        {
            SaveMethodXSD(method);
        }
    }

    void SaveMethodXSD(HealthServiceMethodInfo methods)
    {
        string directoryName = MapPath("platform");
        Directory.CreateDirectory(directoryName).CreateSubdirectory("web").CreateSubdirectory("methods");

        foreach (HealthServiceMethodVersionInfo method in methods.Versions)
        {
            if (!String.IsNullOrEmpty(method.RequestFileName))
            {
                SaveFile(method.RequestSchemaUrl.ToString(), method.RequestFileName);
            }
            if (!String.IsNullOrEmpty(method.ResponseFileName))
            {
                SaveFile(method.ResponseSchemaUrl.ToString(), method.ResponseFileName);
            }
        }
    }

    void SaveFile(string schemaUri, string name)
    {
        string filename = MapPath(@"platform\web\methods\" + name + ".xsd");
        using (StreamWriter writer = System.IO.File.CreateText(filename))
        {
            HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(schemaUri);
            using (HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse())
            {
                using (StreamReader httpResponseStream = new StreamReader(httpResponse.GetResponseStream()))
                {
                    writer.Write(httpResponseStream.ReadToEnd());
                }
            }
        }
    }

Note: the above snipped tries to save the schemas to a directory named platform\web\methods\.
PLEASE NOTE: By blogging software is capitalizing the code in a weird way. I dont know what’s up with dpSyntaxHighligher.

Lighting it up!

Alrite now that you have the firewood (application auth token) and the firestarter (user auth token) how can we start the fire (get details user’s record).

Well first of all congratulations! most of the hard part is done!! Just a few more nitty gritty tricks though! In order to get the details about a user’s health record, you need to use a method GetPersonInfo.

The XML for GetPersonInfo look like this:



  da9WYaQGEoseAYDOhJv2cwNIEVg=

GetPersonInfo 1 ASAAADNt1Jwbx85MgH9vkWzAINBxBWQFCtQ+osTzGw/I0Ty27OhKFCXUb83dxI5/M2mtGYymc1gKx6qwsWEtw31ZV/tyscJwmc5dNT2o2nYJcFTf1vfi/L4R5V68ckxFrd48Rz4jhU9Yg6lDhNTymCsJSDiVJCKLqKwcHcr/QSTsytRpVXBK7LpAVBicjC3OPGCEg4XE/UGwM7ZDAXlR4AR+emiHBaPOzSQD9iYMYxAyDBYZPde8N+rDv58zFw9pjDLJJIwvhXOOLahhFvX/n5DqwAb+BpdTlE19x5P/B67kKie/zDtEYWHEXHMhX+KNdvrxdm17l5pwt8JShIGimbXgAcZEFTiPVOW77mCgDxpc0U2ykcG7RVqXKTA3Gqt42OZf9aCuzq/J0wHOTLQvdx1ZYVOxo7+1TpMaW+13Fz5/jgOHR7hJZ/DPUIcKfCYdHS7phQ3r60nOReUl2qeq7rDvDmGQBWPjcCrT7CuQRSgZlyUpAav4DiFJtKh9U5DbJ5VW80dUAqcxamulklTxSR75Sb6v0X4T8B2zbfmVl+HtcupUIuz66Q== ASAAAE57vlXwS8VDupO6/FSWlMZR+OL02JQyhWvlesegc/J6f7XGgJq4xRW1WIWc7ZXufY9U1cAFeQMDF9pAvmNG1/1KGlp7FFFBdrUMk7gJLPpdTYkQeDMdp8UXcXNht+U6hJzpI7plchQKvpBMFeBj1XMOC15fLXRyfRFpD3RaIF66awgUVw== en US 2008-06-01T02:44:16.73Z 1800 0.9.1712.2902 1mWxpY+leClypXQzPvDBLFIBDpI=

So now do we go about concoting the seemingly complicated xml above. Well we already have the token and wctoken from our previous CreateAuthenticatedSession and Shell -redirect. Use the token for the auth-token in line 9 and the wctoken as user-token in line 10.

Most of the elements in the header section are straight forward. The one to comment about is hash-data (line 18). The hash in this case is SHA-1 hash of the info section. Matter of fact our info section is empty so that make sure that the SHA-1 hash is done right. In ruby i do it the following way (using OpenSSL):

  def self.doSha1(text)
    Base64.encode64(OpenSSL::Digest::SHA1.digest(text)).chomp
  end

Now the interesting part – whats this auth on line 2? Well auth is a HMAC of header (line 5-20) section. Remember we generated the shared secret in CreateAutheticatedSession method? Now use that secret to do a HMAC digest for the header. In ruby i do it the following way:

  def self.doHmac(secret, payload)
    key = Base64.decode64(secret)
    hashmac = OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new(key), key, payload)
    Base64.encode64(hashmac).chomp
  end

secret is the shared secret used for createauthenticationtoken.

Now the fun part,caveats:

  • Don’t leave any white spaces between you xml tags. HealthVault behaves weird sometime when their is white space.
  • If you are getting an error saying code 3 (which implied invalid xml) and you are sure that your xml is correct, then most likely your auth section or your hash-data section are not proper. Which in turn implies that your HMAC-ing or SHA-1 hashing is a little off. The best way to actually resolve this is to first write tiny parts which make sure that the HMAC /SHA-1 is same for a known successfully call. You can get the xml for such a call from HealthVault SDK, the process is described here. However for ease of testing i’m appending know good calls below.

PLEASE NOTE: Remove all the white-space between tags before testing your crypto functions to match the result seen here. I have put the white space for readability.

CreateAuthenticatedSessionToken (for SharedSecret)


CreateAuthenticatedSessionToken 1 05a059c9-c309-46af-9b86-b06d42510550 en US 2008-06-01T02:44:16.21Z 1800 0.9.1712.2902
05a059c9-c309-46af-9b86-b06d42510550 b2uCbONZDGj8jDYhz3e5PcJfugPQTHOsOvpZ6kA9uG5XzQXV+EHtXtTDAbwHbFyNozC1uR7uZwgi44pfgw4NyQp8LO2PwI9E7pOx/Ho7+6siY41sjI5+frhq2fcj8iljpG8EK07WGDuf4JeFg5yc8IWjHHtUwabpdPVJWYLi18+Gk7AaFfCuM1iQwFbBSWWMyckCe3V48JaCZcNVcS/XuJJovFdsM9QnZ1CwrQaaBB/evf1u1YGM3fXpVeCjVWPXpHiu3WWVVsJ5aURtCzGvXJe9R7Gh10sYDSG6wC/CJvcBSJlRCpacA1qds2gcMCBwO+iDCPY3I15+FbM0E9D+Qw== 05a059c9-c309-46af-9b86-b06d42510550 RXziN4RDYIu89cu+cOp4POLhKUCSUb0sPsV9yaz8m6BfJxjpDNUBRUF5MU3OJMJ7DH0FPXg8HFuahbvSz1HxG1Q6MlahpHAmUkXNBJ0zcrKvcH3+NiS3qD26FkpLXsvzjNv/QSxwqRMpYnDhY11RkUkOvz2M2Ybg9H5aEe7RpfYCYwEAudpj05J2KEFMP2WO1Q6Kz8hjIhf2QdswgzvLueUQ2ajG8Al9DvpGWLKl4dGNqnY1/FUnJOZq/nPivTYHYOcH/qpC5euWIt7bU6hXRehAIC9IYTbHG32jLBoIxhM79Wtj2sRdn4j3SBk/QVqQNXyPrAgFIzmtR7CSaN393A==

Successful GetPersonInfo using the above SharedSecret:


da9WYaQGEoseAYDOhJv2cwNIEVg=
GetPersonInfo 1 ASAAADNt1Jwbx85MgH9vkWzAINBxBWQFCtQ+osTzGw/I0Ty27OhKFCXUb83dxI5/M2mtGYymc1gKx6qwsWEtw31ZV/tyscJwmc5dNT2o2nYJcFTf1vfi/L4R5V68ckxFrd48Rz4jhU9Yg6lDhNTymCsJSDiVJCKLqKwcHcr/QSTsytRpVXBK7LpAVBicjC3OPGCEg4XE/UGwM7ZDAXlR4AR+emiHBaPOzSQD9iYMYxAyDBYZPde8N+rDv58zFw9pjDLJJIwvhXOOLahhFvX/n5DqwAb+BpdTlE19x5P/B67kKie/zDtEYWHEXHMhX+KNdvrxdm17l5pwt8JShIGimbXgAcZEFTiPVOW77mCgDxpc0U2ykcG7RVqXKTA3Gqt42OZf9aCuzq/J0wHOTLQvdx1ZYVOxo7+1TpMaW+13Fz5/jgOHR7hJZ/DPUIcKfCYdHS7phQ3r60nOReUl2qeq7rDvDmGQBWPjcCrT7CuQRSgZlyUpAav4DiFJtKh9U5DbJ5VW80dUAqcxamulklTxSR75Sb6v0X4T8B2zbfmVl+HtcupUIuz66Q== ASAAAE57vlXwS8VDupO6/FSWlMZR+OL02JQyhWvlesegc/J6f7XGgJq4xRW1WIWc7ZXufY9U1cAFeQMDF9pAvmNG1/1KGlp7FFFBdrUMk7gJLPpdTYkQeDMdp8UXcXNht+U6hJzpI7plchQKvpBMFeBj1XMOC15fLXRyfRFpD3RaIF66awgUVw== enUS2008-06-01T02:44:16.73Z 18000.9.1712.29021mWxpY+leClypXQzPvDBLFIBDpI=

Sweet!!! you wanna check out th lighted application? Well its live… (Please Note: it will prompt you yo sign in with HealthVault id, its still rough around edges and doesn’t deal with corner cases).

So lets see your LAMPR application lighted up soon..

Next time: How to do offline access and use PutThings

Doing User Authentication with HealthVault

My previous post with regards to writing the HealthVault Ruby Library demonstrated how one goes about authentication their application with HealthVault. Now that you have successfully gotten HealthVault to trust your application how do you make sure that the user who logs in is a valid user. In the HealthVault lingo this is called user authentication.

To successfully do a user authentication, an application must:

  • Redirect the user to HealthVault shell sign-in page.
  • Receive a token identifying the current user on a pre-registered URL with HealthVault, and use that token to do any user related transactions with HealthVault hence onwards. This token is valid for 20 minutes.

Now, in code it looks like follows lets assume that you application has a pre-registered URL of http://localhost:3000/healthvault/redirect. When a user wants to login, you actually redirect them to HealthVault shell (http://account.healthvault-ppe.com/redirect.aspx) in the following way:

redirect_to "https://account.healthvault-ppe.com/redirect.aspx?target=AUTH&targetqs=?appid=05a059c9-c309-46af-9b86-b06d42510550%26redirect%3dhttp%253a%252f%252flocalhost%253a3000%252fhealthvault%252fredirect"

Note the parameters target, appid & redirect in the above URL.

The above redirection once successful will send the user to the page http://localhost:3000/healthvault/redirect. On this page you should read the wctoken from the URL query-string. In ruby I do this the following way:

  def redirect
    if (request.query_parameters["target"] == "AppAuthSuccess")
      session[:wctoken] = request.query_parameters["wctoken"]
      redirect_to :controller => 'healthvault', :action => 'index'
    end
  end

Voila!! you have the much needed wctoken. In the next article we will what can we do with this magic wctoken!

Next time: Putting it all together!

Curious about whats under the HealthVault SDK’s hood?

HealthVault SDK provides a very useful feature to check under its hood! One can turn-on the tracing for the SDK very easily. The trace log is very helpful for

  • Debugging the SDK
  • Looking at the raw-xml exchanged between your application and HealthVault platform. The Raw XML in turn is very useful if you are:
    • Trying to write-xml in the thing types
    • Trying to write a HealthVault wrapper library in you favorite language
    • Just curious to look under the hood:)

To look at the trace log add the following in configuration section of your web.config. One you run you application with settings below, a sdk.log file will be generated in the base directory of the website. You can also provide an absolute path for sdk.log to a directory where you web process has a write access.

  
    
      

          
          
        
      
    
    
      
      
      
      
    
  

NOTE: In case the file doesn’t get generated, make sure your web process has write access to the directory sdk.log is getting generated in.