1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>AuthSub in .NET</title>
</head>
<body>
<!-- Article Begins -->
<h1>Using AuthSub with the .NET Client Library</h1>
<em>Jeff Fisher, Google data APIs team
<br/>August 2007</em>
<ul>
<li><a href="#introduction">Introduction: Why is AuthSub Important?</a></li>
<li><a href="#handlingauth">Handling Authentication</a></li>
<li><a href="#secureauthsub">Secure (Registered) AuthSub</a></li>
<li><a href="#completecode">Complete Code Listing</a></li>
<li><a href="#conclusion">Conclusion</a></li>
</ul>
<h3><a name="introduction">Introduction: Why is AuthSub Important?</a></h3>
<p class="para">The great thing about the Google data APIs ("GData" for short) is how they allow developers
to build applications that interact with Google services. More specifically, they allow
you to access private user data for use in your application. The APIs enable you to
write applications to synchronize, import, export, and otherwise manage that data.
While the APIs grant you these powerful abilities, you have to remember to use
them responsibly. Since user data is private information, naturally you want to
access it in a secure manner. A key part of this is being able to authenticate
to Google's servers in a secure fashion.</p>
<p class="para">Let's say you have a great new web application that you want to have tied into the data stored in Google web services. Now you want to authenticate in order to access this private data. Why not just use something simple, like <a href="http://code.google.com/apis/accounts/AuthForInstalledApps.html">ClientLogin</a>? Well, that will do the trick, but then you are handling even <i>more</i> private data: the user's login credentials. ClientLogin requires your application to ask for the user's Google username and password. This is okay for a desktop application that is running on the user's personal machine, but is less than ideal for a web-based application. Besides the liability of handling these credentials on your own server, perhaps some of your more cautious users would be afraid that you might store their information. Another common concern from users is if they only wish to grant a program access to one particular service (like the events on their Google Calendar) but not to some other service (like their Google Documents). <a href="http://code.google.com/apis/accounts/AuthForWebApps.html">AuthSub</a> solves both of these problems by letting a user authenticate through Google's servers and allows your program to only request the access that it needs.</p>
<p class="para">Now that you've read enough about the theory behind AuthSub, it's time to move on to some coding! For this article, I chose to keep things simple and do everything inside of a single ASP page, but you should be able to easily integrate the techniques demonstrated here into your own application.</p>
<h3><a name="handlingauth">Handling Authentication</a></h3>
<p class="para">So what is needed to actually use AuthSub in your web application? First, there are some standard imports from the GData client library:</p>
<pre>
<%@ Import Namespace="Google.GData.Client" %>
<%@ Import Namespace="Google.GData.Extensions" %>
<%@ Import Namespace="System.Net" %>
</pre>
<p class="para">Now the first thing you have to do is send the user to a specially-crafted URL. This is what allows Google's servers to handle the authentication and then redirect the user back to your website. Fortunately, you don't have to generate this URL manually, as there are methods to do so for you. Let's look at an example:</p>
<pre>
authSubUrl = AuthSubUtil.getRequestUrl(target, scope, secure, session);
</pre>
<ul>
<li><strong>target</strong> This is a string containing the URL to your web application. This is where the user will be redirected to after authenticating.</li>
<li><strong>scope</strong> This string is determined by what API you are using. It corresponds to one of the feeds in a GData API. For example, the feed containing all the calendar information for a user is "http://www.google.com/calendar/feeds/default/private/full".</li>
<li><strong>secure</strong> This is a boolean that tells the server you have <a href="http://code.google.com/apis/accounts/RegistrationForWebApps.html">registered with Google</a> and will cryptographically sign your requests to the server. This argument is usually false by default, especially when working in a test environment.</li> <li><strong>session</strong> This is another boolean that indicates that you would like a "session token" rather than a "one-time use token". The role of this argument will become more clear in a moment.</li>
</ul>
<p class="para">After the user clicks in the generated URL, they will be taken to a Google Accounts page which allows them to sign in to their Google account. They will then be redirected back to the web page you specified in the "target" variable, but with a query parameter "token" which contains a one-time use token. Normally, this token can be used exactly once. That is to say, it can be used to perform one action on a given feed. However, if you specified the "session" parameter as true, it can be exchanged for a "session token" that can be reused until the user ends the session. You can do this in the following manner:</p>
<pre>
String token = Request.QueryString["token"];
Session["token"] = AuthSubUtil.exchangeForSessionToken(token, null).ToString();
</pre>
<p class="para">Here you extract the token from the query parameter and exchange it for a "session token". Then, so that it could be saved for later use, you can chose to store it in the automatic <code>Session</code> array of .NET. Naturally, you could also choose to store the token within a database. The next step is to use this token to make an authenticated request:</p>
<pre>
GAuthSubRequestFactory authFactory = new GAuthSubRequestFactory("cl", "My-Cool-Application");
authFactory.Token = (String) Session["token"];
CalendarService service = new CalendarService(authFactory.ApplicationName);
service.RequestFactory = authFactory;
</pre>
<p class="para">Here you set up a CalendarService object to interact with the Google Calendar API using AuthSub for authentication. Note the "cl" used in the constructor for <code>GAuthSubRequestFactory</code> is the service name for Calendar. You can consult <a href="http://code.google.com/support/bin/answer.py?answer=62712&topic=10364">the documentation</a> for other service names.</p>
<h3><a name="secureauthsub">Secure (Registered) AuthSub</a></h3>
<p class="para">If you choose to <a href="http://code.google.com/apis/accounts/RegistrationForWebApps.html">register your web application</a>, then you can enable an additional level of security while using AuthSub. This allows you to digitally sign all requests made by your code, making it so someone can't use AuthSub tokens issued to you unless they have your private key. The first step is making sure you are generating the correct AuthSub link when calling <code>AuthSubUtil.getRequestUrl</code> by setting the "secure" argument to true. There are two other code changes you will need to make:</p>
<pre>
String token = Request.QueryString["token"];
Session["token"] = AuthSubUtil.exchangeForSessionToken(token, rsaKey).ToString();
...
authFactory.PrivateKey = rsaKey;
</pre>
<p class="para">First, notice instead of <code>null</code>, you now pass the variable "rsaKey" to the <code>exchangeForSessionToken</code> method. This same variable is also used to set a property of our <code>GAuthSubRequestFactory</code> when setting up the connection to the service. The "rsaKey" variable is an <code>RSACryptoServiceProvider</code> corresponding to the private key component of the x509 certificate that you registered with Google.</p>
<p class="para">Generating an RSA private key and self-signed certificate can be a little confusing, especially since the .NET framework doesn't understand keys or certificates stored in the PEM format. The following commands show how to generate a private key and public certificate using the <a href="http://www.openssl.org/">OpenSSL</a> suite of tools:</p>
<pre>
openssl req -x509 -nodes -days 365 -newkey rsa:1024 -sha1 -subj \
'/C=US/ST=CA/L=Mountain View/CN=www.example.com' -keyout \
test_key.pem -out test_cert.pem
openssl pkcs12 -export -in test_cert.pem -inkey test_key.pem \
-out test_cert.pfx -name "Testing Certificate"
</pre>
<p class="para">The first step generates a private key and a public X509 certificate both in PEM format called "test_key.pem" and "test_cert.pem", respectively. Note the certificate is set to be registered to "www.example.com" based in Mountain View, CA, US. Substitute the proper values for your company here. The "test_cert.pem" file contains the information you need to submit on the <a href="http://code.google.com/apis/accounts/RegistrationForWebApps.html">AuthSub registration page</a>.</p>
<p class="para">The second step generates a PFX file from your private key and certificate. This file can be imported into the .NET client library to digitally sign requests made to the GData APIs. The following code shows how you can import the private key from the PFX file into a web application:</p>
<pre>
protected AsymmetricAlgorithm getRsaKey()
{
X509Certificate2 cert = new X509Certificate2("C:/MyAspSite/test_cert.pfx","");
RSACryptoServiceProvider privateKey = cert.PrivateKey as RSACryptoServiceProvider;
return privateKey;
}
</pre>
<p class="para">The <code>getRsaKey()</code> function defined by this snippet can be used in place of the "rsaKey" variable shown above when used to authenticate to the APIs. Naturally, the file path should be replaced with the appropriate location of the PFX file you generated.</p>
<h3><a name="completecode">Complete Code Listing</a></h3>
<p class="para">The easiest way to show how to use the methods demonstrated in the previous section is with a live example. The following sample code is a simple ASP page that uses AuthSub to authenticate the user, then prints out the events of their Google Calendar.</p>
<pre>
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<%@ Import Namespace="Google.GData.Client" %>
<%@ Import Namespace="Google.GData.Extensions" %>
<%@ Import Namespace="Google.GData.Calendar" %>
<%@ Import Namespace="System.Net" %>
<script runat="server">
void PrintCalendar() {
GAuthSubRequestFactory authFactory = new GAuthSubRequestFactory("cl", "TesterApp");
authFactory.Token = (String) Session["token"];
CalendarService service = new CalendarService(authFactory.ApplicationName);
service.RequestFactory = authFactory;
EventQuery query = new EventQuery();
query.Uri = new Uri("http://www.google.com/calendar/feeds/default/private/full");
try
{
EventFeed calFeed = service.Query(query);
foreach (Google.GData.Calendar.EventEntry entry in calFeed.Entries)
{
Response.Write("Event: " + entry.Title.Text + "<br/>");
}
}
catch (GDataRequestException gdre)
{
HttpWebResponse response = (HttpWebResponse)gdre.Response;
//bad auth token, clear session and refresh the page
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
Session.Clear();
Response.Redirect(Request.Url.AbsolutePath, true);
}
else
{
Response.Write("Error processing request: " + gdre.ToString());
}
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Test Site</title>
</head>
<body>
<form id="form1" runat="server">
<h1>AuthSub Sample Page</h1>
<div>
<%
GotoAuthSubLink.Visible = false;
if (Session["token"] != null)
{
PrintCalendar();
}
else if (Request.QueryString["token"] != null)
{
String token = Request.QueryString["token"];
Session["token"] = AuthSubUtil.exchangeForSessionToken(token, null).ToString();
Response.Redirect(Request.Url.AbsolutePath, true);
}
else //no auth data, print link
{
GotoAuthSubLink.Text = "Login to your Google Account";
GotoAuthSubLink.Visible = true;
GotoAuthSubLink.NavigateUrl = AuthSubUtil.getRequestUrl(Request.Url.ToString(),
"http://www.google.com/calendar/feeds/",false,true);
}
%>
<asp:HyperLink ID="GotoAuthSubLink" runat="server"/>
</div>
</form>
</body>
</html>
</pre>
<h3><a name="conclusion">Conclusion</a></h3>
<p class="para">AuthSub allows your web application to access data stored
in a user's Google account in a secure and controlled manner. Using the .NET
client library makes it easy to integrate your ASP-based website with Google
services. This article is meant to get you started, but there are additional
resources that you are encouraged to consult: </p>
<ul>
<li>
<a href="http://code.google.com/apis/accounts/AuthForWebApps.html">AuthSub documentation</a></li>
<li>
<a href="http://code.google.com/apis/gdata/authsub.html">AuthSub with
GData Client Libraries Guide</a></li>
<li>
<a href="http://groups.google.com/group/Google-Accounts-API">Accounts API
developer forum</a></li>
</ul>
<!-- Article Ends -->
</body>
</html>
|