4. Create another class named as "OAuthBase.cs"
using System;
using System.Security.Cryptography;
using System.Collections.Generic;
using System.Text;
using System.Web;
namespace OAuth {
public class OAuthBase {
/// <summary>
/// Provides a predefined set of algorithms that are supported officially by the protocol
/// </summary>
public enum SignatureTypes {
HMACSHA1,
PLAINTEXT,
RSASHA1
}
/// <summary>
/// Provides an internal structure to sort the query parameter
/// </summary>
protected class QueryParameter {
private string name = null;
private string value = null;
public QueryParameter(string name, string value) {
this.name = name;
this.value = value;
}
public string Name {
get { return name; }
}
public string Value {
get { return value; }
}
}
/// <summary>
/// Comparer class used to perform the sorting of the query parameters
/// </summary>
protected class QueryParameterComparer : IComparer<QueryParameter> {
#region IComparer<QueryParameter> Members
public int Compare(QueryParameter x, QueryParameter y) {
if (x.Name == y.Name) {
return string.Compare(x.Value, y.Value);
} else {
return string.Compare(x.Name, y.Name);
}
}
#endregion
}
protected const string OAuthVersion = "1.0";
protected const string OAuthParameterPrefix = "oauth_";
//
// List of know and used oauth parameters' names
//
protected const string OAuthConsumerKeyKey = "oauth_consumer_key";
protected const string OAuthCallbackKey = "oauth_callback";
protected const string OAuthVersionKey = "oauth_version";
protected const string OAuthSignatureMethodKey = "oauth_signature_method";
protected const string OAuthSignatureKey = "oauth_signature";
protected const string OAuthTimestampKey = "oauth_timestamp";
protected const string OAuthNonceKey = "oauth_nonce";
protected const string OAuthTokenKey = "oauth_token";
protected const string OAuthTokenSecretKey = "oauth_token_secret";
protected const string HMACSHA1SignatureType = "HMAC-SHA1";
protected const string PlainTextSignatureType = "PLAINTEXT";
protected const string RSASHA1SignatureType = "RSA-SHA1";
protected Random random = new Random();
protected string unreservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
/// <summary>
/// Helper function to compute a hash value
/// </summary>
/// <param name="hashAlgorithm">The hashing algoirhtm used. If that algorithm needs some initialization, like HMAC and its derivatives, they should be initialized prior to passing it to this function</param>
/// <param name="data">The data to hash</param>
/// <returns>a Base64 string of the hash value</returns>
private string ComputeHash(HashAlgorithm hashAlgorithm, string data) {
if (hashAlgorithm == null) {
throw new ArgumentNullException("hashAlgorithm");
}
if (string.IsNullOrEmpty(data)) {
throw new ArgumentNullException("data");
}
byte[] dataBuffer = System.Text.Encoding.ASCII.GetBytes(data);
byte[] hashBytes = hashAlgorithm.ComputeHash(dataBuffer);
return Convert.ToBase64String(hashBytes);
}
/// <summary>
/// Internal function to cut out all non oauth query string parameters (all parameters not begining with "oauth_")
/// </summary>
/// <param name="parameters">The query string part of the Url</param>
/// <returns>A list of QueryParameter each containing the parameter name and value</returns>
private List<QueryParameter> GetQueryParameters(string parameters) {
if (parameters.StartsWith("?")) {
parameters = parameters.Remove(0, 1);
}
List<QueryParameter> result = new List<QueryParameter>();
if (!string.IsNullOrEmpty(parameters)) {
string[] p = parameters.Split('&');
foreach (string s in p) {
if (!string.IsNullOrEmpty(s) && !s.StartsWith(OAuthParameterPrefix)) {
if (s.IndexOf('=') > -1) {
string[] temp = s.Split('=');
result.Add(new QueryParameter(temp[0], temp[1]));
} else {
result.Add(new QueryParameter(s, string.Empty));
}
}
}
}
return result;
}
/// <summary>
/// This is a different Url Encode implementation since the default .NET one outputs the percent encoding in lower case.
/// While this is not a problem with the percent encoding spec, it is used in upper case throughout OAuth
/// </summary>
/// <param name="value">The value to Url encode</param>
/// <returns>Returns a Url encoded string</returns>
protected string UrlEncode(string value) {
StringBuilder result = new StringBuilder();
foreach (char symbol in value) {
if (unreservedChars.IndexOf(symbol) != -1) {
result.Append(symbol);
} else {
result.Append('%' + String.Format("{0:X2}", (int)symbol));
}
}
return result.ToString();
}
/// <summary>
/// Normalizes the request parameters according to the spec
/// </summary>
/// <param name="parameters">The list of parameters already sorted</param>
/// <returns>a string representing the normalized parameters</returns>
protected string NormalizeRequestParameters(IList<QueryParameter> parameters) {
StringBuilder sb = new StringBuilder();
QueryParameter p = null;
for (int i = 0; i < parameters.Count; i++) {
p = parameters[i];
sb.AppendFormat("{0}={1}", p.Name, p.Value);
if (i < parameters.Count - 1) {
sb.Append("&");
}
}
return sb.ToString();
}
/// <summary>
/// Generate the signature base that is used to produce the signature
/// </summary>
/// <param name="url">The full url that needs to be signed including its non OAuth url parameters</param>
/// <param name="consumerKey">The consumer key</param>
/// <param name="token">The token, if available. If not available pass null or an empty string</param>
/// <param name="tokenSecret">The token secret, if available. If not available pass null or an empty string</param>
/// <param name="httpMethod">The http method used. Must be a valid HTTP method verb (POST,GET,PUT, etc)</param>
/// <param name="signatureType">The signature type. To use the default values use <see cref="OAuthBase.SignatureTypes">OAuthBase.SignatureTypes</see>.</param>
/// <returns>The signature base</returns>
public string GenerateSignatureBase(Uri url, string consumerKey, string token, string tokenSecret, string httpMethod, string timeStamp, string nonce, string signatureType, out string normalizedUrl, out string normalizedRequestParameters) {
if (token == null) {
token = string.Empty;
}
if (tokenSecret == null) {
tokenSecret = string.Empty;
}
if (string.IsNullOrEmpty(consumerKey)) {
throw new ArgumentNullException("consumerKey");
}
if (string.IsNullOrEmpty(httpMethod)) {
throw new ArgumentNullException("httpMethod");
}
if (string.IsNullOrEmpty(signatureType)) {
throw new ArgumentNullException("signatureType");
}
normalizedUrl = null;
normalizedRequestParameters = null;
List<QueryParameter> parameters = GetQueryParameters(url.Query);
parameters.Add(new QueryParameter(OAuthVersionKey, OAuthVersion));
parameters.Add(new QueryParameter(OAuthNonceKey, nonce));
parameters.Add(new QueryParameter(OAuthTimestampKey, timeStamp));
parameters.Add(new QueryParameter(OAuthSignatureMethodKey, signatureType));
parameters.Add(new QueryParameter(OAuthConsumerKeyKey, consumerKey));
if (!string.IsNullOrEmpty(token)) {
parameters.Add(new QueryParameter(OAuthTokenKey, token));
}
parameters.Sort(new QueryParameterComparer());
normalizedUrl = string.Format("{0}://{1}", url.Scheme, url.Host);
if (!((url.Scheme == "http" && url.Port == 80) || (url.Scheme == "https" && url.Port == 443)))
{
normalizedUrl += ":" + url.Port;
}
normalizedUrl += url.AbsolutePath;
normalizedRequestParameters = NormalizeRequestParameters(parameters);
StringBuilder signatureBase = new StringBuilder();
signatureBase.AppendFormat("{0}&", httpMethod.ToUpper());
signatureBase.AppendFormat("{0}&", UrlEncode(normalizedUrl));
signatureBase.AppendFormat("{0}", UrlEncode(normalizedRequestParameters));
return signatureBase.ToString();
}
/// <summary>
/// Generate the signature value based on the given signature base and hash algorithm
/// </summary>
/// <param name="signatureBase">The signature based as produced by the GenerateSignatureBase method or by any other means</param>
/// <param name="hash">The hash algorithm used to perform the hashing. If the hashing algorithm requires initialization or a key it should be set prior to calling this method</param>
/// <returns>A base64 string of the hash value</returns>
public string GenerateSignatureUsingHash(string signatureBase, HashAlgorithm hash) {
return ComputeHash(hash, signatureBase);
}
/// <summary>
/// Generates a signature using the HMAC-SHA1 algorithm
/// </summary>
/// <param name="url">The full url that needs to be signed including its non OAuth url parameters</param>
/// <param name="consumerKey">The consumer key</param>
/// <param name="consumerSecret">The consumer seceret</param>
/// <param name="token">The token, if available. If not available pass null or an empty string</param>
/// <param name="tokenSecret">The token secret, if available. If not available pass null or an empty string</param>
/// <param name="httpMethod">The http method used. Must be a valid HTTP method verb (POST,GET,PUT, etc)</param>
/// <returns>A base64 string of the hash value</returns>
public string GenerateSignature(Uri url, string consumerKey, string consumerSecret, string token, string tokenSecret, string httpMethod, string timeStamp, string nonce, out string normalizedUrl, out string normalizedRequestParameters) {
return GenerateSignature(url, consumerKey, consumerSecret, token, tokenSecret, httpMethod, timeStamp, nonce, SignatureTypes.HMACSHA1, out normalizedUrl, out normalizedRequestParameters);
}
/// <summary>
/// Generates a signature using the specified signatureType
/// </summary>
/// <param name="url">The full url that needs to be signed including its non OAuth url parameters</param>
/// <param name="consumerKey">The consumer key</param>
/// <param name="consumerSecret">The consumer seceret</param>
/// <param name="token">The token, if available. If not available pass null or an empty string</param>
/// <param name="tokenSecret">The token secret, if available. If not available pass null or an empty string</param>
/// <param name="httpMethod">The http method used. Must be a valid HTTP method verb (POST,GET,PUT, etc)</param>
/// <param name="signatureType">The type of signature to use</param>
/// <returns>A base64 string of the hash value</returns>
public string GenerateSignature(Uri url, string consumerKey, string consumerSecret, string token, string tokenSecret, string httpMethod, string timeStamp, string nonce, SignatureTypes signatureType, out string normalizedUrl, out string normalizedRequestParameters) {
normalizedUrl = null;
normalizedRequestParameters = null;
switch (signatureType) {
case SignatureTypes.PLAINTEXT:
return HttpUtility.UrlEncode(string.Format("{0}&{1}", consumerSecret, tokenSecret));
case SignatureTypes.HMACSHA1:
string signatureBase = GenerateSignatureBase(url, consumerKey, token, tokenSecret, httpMethod, timeStamp, nonce, HMACSHA1SignatureType, out normalizedUrl, out normalizedRequestParameters);
HMACSHA1 hmacsha1 = new HMACSHA1();
hmacsha1.Key = Encoding.ASCII.GetBytes(string.Format("{0}&{1}", UrlEncode(consumerSecret), string.IsNullOrEmpty(tokenSecret) ? "" : UrlEncode(tokenSecret)));
return GenerateSignatureUsingHash(signatureBase, hmacsha1);
case SignatureTypes.RSASHA1:
throw new NotImplementedException();
default:
throw new ArgumentException("Unknown signature type", "signatureType");
}
}
/// <summary>
/// Generate the timestamp for the signature
/// </summary>
/// <returns></returns>
public virtual string GenerateTimeStamp() {
// Default implementation of UNIX time of the current UTC time
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
return Convert.ToInt64(ts.TotalSeconds).ToString();
}
/// <summary>
/// Generate a nonce
/// </summary>
/// <returns></returns>
public virtual string GenerateNonce() {
// Just a simple implementation of a random number between 123400 and 9999999
return random.Next(123400, 9999999).ToString();
}
}
}
5. create another class named "WindowsLiveLogin.cs"
its code is :
/*
* FILE: WindowsLiveLogin.cs
*
* DESCRIPTION: Sample implementation of Web Authentication and Delegated
* Authentication protocol in C#. Also includes trusted
* sign-in and application verification sample
* implementations.
*
* VERSION: 1.1
*
* Copyright (c) 2008 Microsoft Corporation. All Rights Reserved.
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Specialized;
using System.Collections;
using System.Web;
using System.Web.Configuration;
using System.Security.Cryptography;
using System.IO;
using System.Net;
using System.Reflection;
using System.Xml;
namespace WindowsLive
{
/// <summary>
/// Sample implementation of Web Authentication and Delegated Authentication
/// protocol. Also includes trusted sign-in and application
/// verification sample implementations.
/// </summary>
public class WindowsLiveLogin
{
/// <summary>
/// Stub implementation for logging debug output. You can run
/// a tool such as 'dbmon' to see the output.
/// </summary>
static void debug(string msg)
{
System.Diagnostics.Debug.WriteLine(msg);
System.Diagnostics.Debug.Flush();
}
/// <summary>
/// Initialize the WindowsLiveLogin module with the
/// application ID and secret key.
///
/// We recommend that you employ strong measures to protect
/// the secret key. The secret key should never be
/// exposed to the Web or other users.
/// </summary>
public WindowsLiveLogin(string appId, string secret) :
this(appId, secret, null){}
/// <summary>
/// Initialize the WindowsLiveLogin module with the
/// application ID, secret key, and security algorithm.
///
/// We recommend that you employ strong measures to protect
/// the secret key. The secret key should never be
/// exposed to the Web or other users.
/// </summary>
public WindowsLiveLogin(string appId, string secret, string securityAlgorithm) :
this(appId, secret, securityAlgorithm, false){}
/// <summary>
/// Initialize the WindowsLiveLogin module with the
/// forceDelAuthNonProvisioned flag, policy URL, and return URL.
///
/// The 'force_delauth_nonprovisioned' flag indicates whether
/// your application is registered for Delegated Authentication
/// (that is, whether it uses an application ID and secret key). We
/// recommend that your Delegated Authentication application always
/// be registered for enhanced security and functionality.
/// </summary>
public WindowsLiveLogin(bool forceDelAuthNonProvisioned, string policyUrl, string returnUrl)
{
ForceDelAuthNonProvisioned = forceDelAuthNonProvisioned;
PolicyUrl = policyUrl;
ReturnUrl = returnUrl;
}
/// <summary>
/// Initialize the WindowsLiveLogin module with the
/// application ID, secret key, security algorithm and
/// forceDelAuthNonProvisioned flag.
///
/// We recommend that you employ strong measures to protect
/// the secret key. The secret key should never be
/// exposed to the Web or other users.
///
/// The 'force_delauth_nonprovisioned' flag indicates whether
/// your application is registered for Delegated Authentication
/// (that is, whether it uses an application ID and secret key). We
/// recommend that your Delegated Authentication application always
/// be registered for enhanced security and functionality.
/// </summary>
public WindowsLiveLogin(string appId, string secret, string securityAlgorithm, bool forceDelAuthNonProvisioned) :
this(appId, secret, securityAlgorithm, forceDelAuthNonProvisioned, null){}
/// <summary>
/// Initialize the WindowsLiveLogin module with the
/// application ID, secret key, security algorithm,
/// forceDelAuthNonProvisioned and policy URL use.
///
/// We recommend that you employ strong measures to protect
/// the secret key. The secret key should never be
/// exposed to the Web or other users.
///
/// The 'force_delauth_nonprovisioned' flag indicates whether
/// your application is registered for Delegated Authentication
/// (that is, whether it uses an application ID and secret key). We
/// recommend that your Delegated Authentication application always
/// be registered for enhanced security and functionality.
/// </summary>
public WindowsLiveLogin(string appId, string secret, string securityAlgorithm, bool forceDelAuthNonProvisioned, string policyUrl) :
this(appId, secret, securityAlgorithm, forceDelAuthNonProvisioned, policyUrl, null){}
/// <summary>
/// Initialize the WindowsLiveLogin module with the
/// application ID, secret key, security algorithm,
/// forceDelAuthNonProvisioned, policy URL and return URL.
///
/// We recommend that you employ strong measures to protect
/// the secret key. The secret key should never be
/// exposed to the Web or other users.
///
/// The 'force_delauth_nonprovisioned' flag indicates whether
/// your application is registered for Delegated Authentication
/// (that is, whether it uses an application ID and secret key). We
/// recommend that your Delegated Authentication application always
/// be registered for enhanced security and functionality.
public WindowsLiveLogin(string appId, string secret, string securityAlgorithm, bool forceDelAuthNonProvisioned, string policyUrl, string returnUrl)
{
ForceDelAuthNonProvisioned = forceDelAuthNonProvisioned;
AppId = appId;
Secret = secret;
SecurityAlgorithm = securityAlgorithm;
PolicyUrl = policyUrl;
ReturnUrl = returnUrl;
}
/// <summary>
/// Initialize the WindowsLiveLogin module from the
/// web.config file if loadAppSettings is true. Otherwise,
/// you will have to manually set the AppId, Secret and
/// SecurityAlgorithm properties.
///
/// In a Delegated Authentication scenario, you may also specify
/// the return and privacy policy URLs to use, as shown in the
/// Delegated Authentication samples.
/// </summary>
public WindowsLiveLogin(bool loadAppSettings)
{
if (!loadAppSettings) { return; }
NameValueCollection appSettings = WebConfigurationManager.AppSettings;
if (appSettings == null)
{
throw new IOException("Error: WindowsLiveLogin: Failed to load the Web application settings.");
}
string forceDelAuthNonProvisioned = appSettings["wll_force_delauth_nonprovisioned"];
if (!string.IsNullOrEmpty(forceDelAuthNonProvisioned) &&
(forceDelAuthNonProvisioned.ToLower() == "true"))
{
ForceDelAuthNonProvisioned = true;
}
else
{
ForceDelAuthNonProvisioned = false;
}
AppId = appSettings["wll_appid"];
Secret = appSettings["wll_secret"];
OldSecret = appSettings["wll_oldsecret"];
OldSecretExpiry = appSettings["wll_oldsecretexpiry"];
SecurityAlgorithm = appSettings["wll_securityalgorithm"];
PolicyUrl = appSettings["wll_policyurl"];
ReturnUrl = appSettings["wll_returnurl"];
BaseUrl = appSettings["wll_baseurl"];
SecureUrl = appSettings["wll_secureurl"];
ConsentUrl = appSettings["wll_consenturl"];
}
/// <summary><![CDATA[
/// Initialize the WindowsLiveLogin module from a settings file.
///
/// 'settingsFile' specifies the location of the XML settings
/// file containing the application ID, secret key, an optional
/// security algorithm and a privacy policy URL (required for
/// Delegated Auth). The file is of the following format:
///
/// <windowslivelogin>
/// <appid>APPID</appid>
/// <secret>SECRET</secret>
/// <securityalgorithm>wsignin1.0</securityalgorithm>
/// <policyurl>http://[your domain]/[your privacy policy]</policyurl>
/// <returnurl>http://[your domain]/[your return url]</policyurl>
/// </windowslivelogin>
///
/// In a Delegated Authentication scenario, you may also specify
/// 'returnurl' and 'policyurl' in the settings file.
///
/// We recommend that you store the Windows Live Login settings file
/// in an area on your server that cannot be accessed through
/// the Internet. This file contains important confidential
/// information.
/// ]]></summary>
public WindowsLiveLogin(string settingsFile)
{
NameValueCollection settings = parseSettings(settingsFile);
string forceDelAuthNonProvisioned = settings["force_delauth_nonprovisioned"];
if (!string.IsNullOrEmpty(forceDelAuthNonProvisioned) &&
(forceDelAuthNonProvisioned.ToLower() == "true"))
{
ForceDelAuthNonProvisioned = true;
}
else
{
ForceDelAuthNonProvisioned = false;
}
AppId = settings["appid"];
Secret = settings["secret"];
OldSecret = settings["oldsecret"];
OldSecretExpiry = settings["oldsecretexpiry"];
SecurityAlgorithm = settings["securityalgorithm"];
PolicyUrl = settings["policyurl"];
ReturnUrl = settings["returnurl"];
BaseUrl = settings["baseurl"];
SecureUrl = settings["secureurl"];
ConsentUrl = settings["consenturl"];
}
string appId;
/// <summary>
/// Gets or sets the application ID.
/// </summary>
public string AppId
{
set
{
if (string.IsNullOrEmpty(value))
{
if (ForceDelAuthNonProvisioned)
{
return;
}
throw new ArgumentNullException("value");
}
Regex re = new Regex(@"^\w+$");
if (!re.IsMatch(value))
{
throw new ArgumentException("Error: AppId: Application ID must be alphanumeric: " + value);
}
appId = value;
}
get
{
if (string.IsNullOrEmpty(appId))
{
throw new InvalidOperationException("Error: AppId: Application ID was not set. Aborting.");
}
return appId;
}
}
byte[] cryptKey;
byte[] signKey;
/// <summary>
/// Sets your secret key. Use this method if you did not specify
/// a secret key at initialization.
/// </summary>
public string Secret
{
set
{
if (string.IsNullOrEmpty(value))
{
if (ForceDelAuthNonProvisioned)
{
return;
}
throw new ArgumentNullException("value");
}
if (value.Length < 16)
{
throw new ArgumentException("Error: Secret: Secret key is expected to be longer than 16 characters: " + value.Length);
}
cryptKey = derive(value, "ENCRYPTION");
signKey = derive(value, "SIGNATURE");
}
get { return null; }
}
byte[] oldCryptKey;
byte[] oldSignKey;
/// <summary>
/// Sets your old secret key.
///
/// Use this property to set your old secret key if you are in the
/// process of transitioning to a new secret key. You may need this
/// property because the Windows Live ID servers can take up to
/// 24 hours to propagate a new secret key after you have updated
/// your application settings.
///
/// If an old secret key is specified here and has not expired
/// (as determined by the OldSecretExpiry setting), it will be used
/// as a fallback if token decryption fails with the new secret
/// key.
/// </summary>
public string OldSecret
{
set
{
if (string.IsNullOrEmpty(value))
{
return;
}
if (value.Length < 16)
{
throw new ArgumentException("Error: OldSecret: Secret key is expected to be longer than 16 characters: " + value.Length);
}
oldCryptKey = derive(value, "ENCRYPTION");
oldSignKey = derive(value, "SIGNATURE");
}
get { return null; }
}
string oldSecretExpiryString;
DateTime oldSecretExpiry;
/// <summary>
/// Sets or gets the expiry time for your old secret key.
///
/// After this time has passed, the old secret key will no longer be
/// used even if token decryption fails with the new secret key.
///
/// The old secret expiry time is represented as the number of seconds
/// elapsed since January 1, 1970.
/// </summary>
public string OldSecretExpiry
{
set
{
if (string.IsNullOrEmpty(value))
{
return;
}
oldSecretExpiryString = value;
int timestampInt;
try
{
timestampInt = Convert.ToInt32(value);
}
catch (Exception)
{
throw new ArgumentException("Error: OldSecretExpiry: Invalid timestamp: "
+ value);
}
DateTime refTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
oldSecretExpiry = refTime.AddSeconds(timestampInt);
}
get { return oldSecretExpiryString; }
}
string securityAlgorithm;
/// <summary>
/// Sets or gets the version of the security algorithm being used.
/// </summary>
public string SecurityAlgorithm
{
set { securityAlgorithm = value; }
get
{
if (string.IsNullOrEmpty(securityAlgorithm))
{
return "wsignin1.0";
}
return securityAlgorithm;
}
}
bool forceDelAuthNonProvisioned = false;
/// <summary>
/// Sets or gets a flag that indicates whether Delegated Authentication
/// is non-provisioned (i.e. does not use an application ID or secret
/// key).
/// </summary>
public bool ForceDelAuthNonProvisioned
{
set { forceDelAuthNonProvisioned = value; }
get { return forceDelAuthNonProvisioned; }
}
string policyUrl;
/// <summary>
/// Sets or gets the privacy policy URL.
///
/// Set the property for Delegated Authentication, if you did
/// not provide one at initialization time.
/// </summary>
public string PolicyUrl
{
set
{
if (string.IsNullOrEmpty(value) && ForceDelAuthNonProvisioned)
{
throw new ArgumentNullException("value");
}
policyUrl = value;
}
get
{
if (string.IsNullOrEmpty(policyUrl))
{
debug("Warning: In the initial release of Delegated Auth, a Policy URL must be configured in the SDK for both provisioned and non-provisioned scenarios.");
if (ForceDelAuthNonProvisioned)
{
throw new InvalidOperationException("Error: PolicyUrl: Policy URL must be set in a Delegated Auth non-provisioned scenario. Aborting.");
}
}
return policyUrl;
}
}
string returnUrl;
/// <summary>
/// Sets or gets the return URL--the URL on your site to which the consent
/// service redirects users (along with the action, consent token,
/// and application context) after they have successfully provided
/// consent information for Delegated Authentication.
///
/// This value will override the return URL specified during
/// registration.
/// </summary>
public string ReturnUrl
{
set
{
if (string.IsNullOrEmpty(value) && ForceDelAuthNonProvisioned)
{
throw new ArgumentNullException("value");
}
returnUrl = value;
}
get
{
if (string.IsNullOrEmpty(returnUrl) && ForceDelAuthNonProvisioned)
{
throw new InvalidOperationException("Error: ReturnUrl: Return URL must be specified in a delegated auth non-provisioned scenario. Aborting.");
}
return returnUrl;
}
}
string baseUrl;
/// <summary>
/// Sets or gets the URL to use for the Windows Live Login server.
/// You should not have to use or change this. Furthermore, we
/// recommend that you use the Sign In control instead of
/// the URL methods provided here.
/// </summary>
public string BaseUrl
{
set { baseUrl = value; }
get
{
if (string.IsNullOrEmpty(baseUrl))
{
return "http://login.live.com/";
}
return baseUrl;
}
}
string secureUrl;
/// <summary>
/// Sets or gets the secure (HTTPS) URL to use for the Windows Live
/// Login server. You should not have to use or change this
/// directly.
// </summary>
public string SecureUrl
{
set { secureUrl = value; }
get
{
if (string.IsNullOrEmpty(secureUrl))
{
return "https://login.live.com/";
}
return secureUrl;
}
}
string consentUrl;
/// <summary>
/// Sets or gets the URL to use for the Windows Live Consent server. You
/// should not have to use or change this directly.
/// </summary>
public string ConsentUrl
{
set { consentUrl = value; }
get
{
if (string.IsNullOrEmpty(consentUrl))
{
return "https://consent.live.com/";
}
return consentUrl;
}
}
/* Methods for Web Authentication support. */
/// <summary>
/// Returns the sign-in URL to use for the Windows Live Login server.
/// We recommend that you use the Sign In control instead.
/// </summary>
/// <returns>Sign-in URL</returns>
public string GetLoginUrl()
{
return GetLoginUrl(null);
}
/// <summary>
/// Returns the sign-in URL to use for the Windows Live Login server.
/// We recommend that you use the Sign In control instead.
/// </summary>
/// <param name="context">If you specify it, <paramref
/// name="context"/> will be returned as-is in the sign-in
/// response for site-specific use.</param>
/// <returns>Sign-in URL</returns>
public string GetLoginUrl(string context)
{
return GetLoginUrl(context, null);
}
/// <summary>
/// Returns the sign-in URL to use for the Windows Live Login server.
/// We recommend that you use the Sign In control instead.
/// </summary>
/// <param name="context">If you specify it, <paramref
/// name="context"/> will be returned as-is in the sign-in
/// response for site-specific use.</param>
/// <param name="market">The language in which the sign-in page is
/// displayed is configured by culture ID (For example, 'fr-fr' or
/// 'en-us') specified in the 'market' parameter.</param>
/// <returns>Sign-in URL</returns>
public string GetLoginUrl(string context, string market)
{
string alg = "&alg=" + SecurityAlgorithm;
context = string.IsNullOrEmpty(context) ?
string.Empty : "&appctx=" + HttpUtility.UrlEncode(context);
market = string.IsNullOrEmpty(market) ?
string.Empty : "&mkt=" + HttpUtility.UrlEncode(market);
return BaseUrl + "wlogin.srf?appid=" + AppId +
alg + context + market;
}
/// <summary>
/// Returns the sign-out URL to use for the Windows Live Login server.
/// We recommend that you use the Sign In control instead.
/// </summary>
/// <returns>Sign-out URL</returns>
public string GetLogoutUrl()
{
return GetLogoutUrl(null);
}
/// <summary>
/// Returns the sign-out URL to use for the Windows Live Login server.
/// We recommend that you use the Sign In control instead.
/// </summary>
/// <param name="market">The language in which the sign-in page is
/// displayed is configured by culture ID (For example, 'fr-fr' or
/// 'en-us') specified in the 'market' parameter.</param>
/// <returns>Sign-out URL</returns>
public string GetLogoutUrl(string market)
{
market = string.IsNullOrEmpty(market) ?
string.Empty : "&mkt=" + HttpUtility.UrlEncode(market);
return BaseUrl + "logout.srf?appid=" + AppId + market;
}
/// <summary>
/// Holds the user information after a successful sign-in.
/// </summary>
public class User
{
public User(string timestamp, string id, string flags, string context, string token)
{
setTimestamp(timestamp);
setId(id);
setFlags(flags);
setContext(context);
setToken(token);
}
DateTime timestamp;
/// <summary>
/// Returns the timestamp as obtained from the SSO token.
/// </summary>
public DateTime Timestamp { get { return timestamp; } }
/// <summary>
/// Sets the Unix timestamp.
/// </summary>
/// <param name="timestamp"></param>
private void setTimestamp(string timestamp)
{
if (string.IsNullOrEmpty(timestamp))
{
throw new ArgumentException("Error: User: Null timestamp in token.");
}
int timestampInt;
try
{
timestampInt = Convert.ToInt32(timestamp);
}
catch (Exception)
{
throw new ArgumentException("Error: User: Invalid timestamp: "
+ timestamp);
}
DateTime refTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
this.timestamp = refTime.AddSeconds(timestampInt);
}
string id;
/// <summary>
/// Returns the pairwise unique ID for the user.
/// </summary>
public string Id { get { return id; } }
/// <summary>
/// Sets the pairwise unique ID for the user.
/// </summary>
/// <param name="id">User id</param>
private void setId(string id)
{
if (string.IsNullOrEmpty(id))
{
throw new ArgumentException("Error: User: Null id in token.");
}
Regex re = new Regex(@"^\w+$");
if (!re.IsMatch(id))
{
throw new ArgumentException("Error: User: Invalid id: " + id);
}
this.id = id;
}
bool usePersistentCookie;
/// <summary>
/// Indicates whether the application
/// is expected to store the user token in a session or
/// persistent cookie.
/// </summary>
public bool UsePersistentCookie { get { return usePersistentCookie; } }
/// <summary>
/// Sets the usePersistentCookie flag for the user.
/// </summary>
/// <param name="flags"></param>
private void setFlags(string flags)
{
this.usePersistentCookie = false;
if (!string.IsNullOrEmpty(flags))
{
try
{
int flagsInt = Convert.ToInt32(flags);
this.usePersistentCookie = ((flagsInt % 2) == 1);
}
catch (Exception)
{
throw new ArgumentException("Error: User: Invalid flags: "
+ flags);
}
}
}
string context;
/// <summary>
/// Returns the application context that was originally passed
/// to the sign-in request, if any.
/// </summary>
public string Context { get { return context; } }
/// <summary>
/// Sets the the Application context.
/// </summary>
/// <param name="context"></param>
private void setContext(string context)
{
this.context = context;
}
string token;
/// <summary>
/// Returns the encrypted Web Authentication token containing
/// the UID. This can be cached in a cookie and the UID can be
/// retrieved by calling the ProcessToken method.
/// </summary>
public string Token { get { return token; } }
/// <summary>
/// Sets the the User token.
/// </summary>
/// <param name="token"></param>
private void setToken(string token)
{
this.token = token;
}
}
/// <summary>
/// Processes the sign-in response from the Windows Live Login server.
/// </summary>
///
/// <param name="query">Contains the preprocessed POST query
/// such as that returned by HttpRequest.Form</param>
///
/// <returns>The method returns a User object on successful
/// sign-in; otherwise null.</returns>
public User ProcessLogin(NameValueCollection query)
{
if (query == null)
{
debug("Error: ProcessLogin: Invalid query.");
return null;
}
string action = query["action"];
if (action != "login")
{
debug("Warning: ProcessLogin: query action ignored: " + action);
return null;
}
string token = query["stoken"];
string context = query["appctx"];
if (context != null)
{
context = HttpUtility.UrlDecode(context);
}
return ProcessToken(token, context);
}
/// <summary>
/// Decodes and validates a Web Authentication token. Returns a User
/// object on success.
/// </summary>
public User ProcessToken(string token)
{
return ProcessToken(token, null);
}
/// <summary>
/// Decodes and validates a Web Authentication token. Returns a User
/// object on success. If a context is passed in, it will be
/// returned as the context field in the User object.
/// </summary>
/// <param name="token">Web Authentication token</param>
/// <param name="context">If you specify it, <paramref
/// name="context"/> will be returned as-is in the sign-in
/// response for site-specific use.</param>
/// <returns>User object</returns>
public User ProcessToken(string token, string context)
{
if (string.IsNullOrEmpty(token))
{
debug("Error: ProcessToken: Invalid token.");
return null;
}
string stoken = DecodeAndValidateToken(token);
if (string.IsNullOrEmpty(stoken))
{
debug("Error: ProcessToken: Failed to decode/validate token: " +
token);
return null;
}
NameValueCollection parsedToken = parse(stoken);
if (parsedToken == null || parsedToken.Count < 3)
{
debug("Error: ProcessToken: Failed to parse token after decoding: " +
token);
return null;
}
string appId = parsedToken["appid"];
if (appId != AppId)
{
debug("Error: ProcessToken: Application ID in token did not match ours: " +
appId + ", " + AppId);
return null;
}
User user = null;
try
{
user = new User(parsedToken["ts"],
parsedToken["uid"],
parsedToken["flags"],
context, token);
}
catch (Exception e)
{
debug("Error: ProcessToken: Contents of token considered invalid: " + e);
}
return user;
}
/// <summary>
/// Returns an appropriate content type and body
/// response that the application handler can return to
/// signify a successful sign-out from the application.
///
/// When a user signs out of Windows Live or a Windows Live
/// application, a best-effort attempt is made to sign the user out
/// from all other Windows Live applications the user might be signed
/// in to. This is done by calling the handler page for each
/// application with 'action' parameter set to 'clearcookie' in the query
/// string. The application handler is then responsible for clearing
/// any cookies or data associated with the sign-in. After successfully
/// signing the user out, the handler should return a GIF (any
/// GIF) as response to the action=clearcookie query.
/// </summary>
public void GetClearCookieResponse(out string type, out byte[] content)
{
const string gif =
"R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAEALAAAAAABAAEAAAIBTAA7";
type = "image/gif";
content = Convert.FromBase64String(gif);
}
/* Methods for Delegated Authentication support. */
/// <summary>
/// Returns the consent URL to use for Delegated Authentication for
/// the given comma-delimited list of offers.
/// </summary>
/// <param name="offers">Comma-delimited list of offers.</param>
/// <returns>Consent URL</returns>
public string GetConsentUrl(string offers)
{
return GetConsentUrl(offers, null);
}
/// <summary>
/// Returns the consent URL to use for Delegated Authentication for
/// the given comma-delimited list of offers.
/// </summary>
/// <param name="offers">Comma-delimited list of offers.</param>
/// <param name="context">If you specify it, <paramref
/// name="context"/> will be returned as-is in the consent
/// response for site-specific use.</param>
/// <returns>Consent URL</returns>
public string GetConsentUrl(string offers, string context)
{
return GetConsentUrl(offers, context, null);
}
/// <summary>
/// Returns the consent URL to use for Delegated Authentication for
/// the given comma-delimited list of offers.
/// </summary>
/// <param name="offers">Comma-delimited list of offers.</param>
/// <param name="context">If you specify it, <paramref
/// name="context"/> will be returned as-is in the consent
/// response for site-specific use.</param>
/// <param name="ru">The registered/configured return URL will be
/// overridden by 'ru' specified here.</param>
/// <returns>Consent URL</returns>
public string GetConsentUrl(string offers, string context, string ru)
{
return GetConsentUrl(offers, context, ru, null);
}
/// <summary>
/// Returns the consent URL to use for Delegated Authentication for
/// the given comma-delimited list of offers.
/// </summary>
/// <param name="offers">Comma-delimited list of offers.</param>
/// <param name="context">If you specify it, <paramref
/// name="context"/> will be returned as-is in the sign-in
/// response for site-specific use.</param>
/// <param name="ru">The registered/configured return URL will be
/// overridden by 'ru' specified here.</param>
/// <param name="market">The language in which the consent page is
/// displayed is configured by culture ID (For example, 'fr-fr' or
/// 'en-us') specified in the 'market' parameter.</param>
/// <returns>Consent URL</returns>
public string GetConsentUrl(string offers, string context, string ru, string market)
{
if (string.IsNullOrEmpty(offers))
{
throw new ArgumentException("Error: GetConsentUrl: Invalid offers list.");
}
offers = "?ps=" + HttpUtility.UrlEncode(offers);
context = string.IsNullOrEmpty(context) ?
string.Empty : "&appctx=" + HttpUtility.UrlEncode(context);
if (string.IsNullOrEmpty(ru))
{
ru = ReturnUrl;
}
ru = string.IsNullOrEmpty(ru) ?
string.Empty : "&ru=" + HttpUtility.UrlEncode(ru);
market = string.IsNullOrEmpty(market) ?
string.Empty : "&mkt=" + HttpUtility.UrlEncode(market);
string pu = string.Empty;
if (!string.IsNullOrEmpty(PolicyUrl))
{
pu = "&pl=" + HttpUtility.UrlEncode(PolicyUrl);
}
string app = string.Empty;
if (!ForceDelAuthNonProvisioned)
{
app = "&app=" + GetAppVerifier();
}
return (ConsentUrl + "Delegation.aspx" + offers + context + ru + pu + market + app);
}
/// <summary>
/// Returns the URL to use to download a new consent token, given the
/// offers and refresh token.
/// </summary>
/// <param name="offers">Comma-delimited list of offers.</param>
/// <param name="refreshToken">Refresh token.</param>
/// <returns>Refresh consent token URL</returns>
public string GetRefreshConsentTokenUrl(string offers, string refreshToken)
{
return GetRefreshConsentTokenUrl(offers, refreshToken, null);
}
/// <summary>
/// Returns the URL to use to download a new consent token, given the
/// offers and refresh token.
/// </summary>
/// <param name="offers">Comma-delimited list of offers.</param>
/// <param name="refreshToken">Refresh token.</param>
/// <returns>Refresh consent token URL</returns>
/// <param name="ru">The registered/configured return URL will be
/// overridden by 'ru' specified here.</param>
/// <returns>Refresh consent token URL</returns>
public string GetRefreshConsentTokenUrl(string offers, string refreshToken, string ru)
{
if (string.IsNullOrEmpty(offers))
{
throw new ArgumentException("Error: GetRefreshConsentTokenUrl: Invalid offers list.");
}
offers = "?ps=" + HttpUtility.UrlEncode(offers);
if (string.IsNullOrEmpty(refreshToken))
{
throw new ArgumentException("Error: GetRefreshConsentTokenUrl: Invalid refresh token.");
}
refreshToken = "&reft=" + refreshToken;
if (string.IsNullOrEmpty(ru))
{
ru = ReturnUrl;
}
ru = string.IsNullOrEmpty(ru) ?
string.Empty : "&ru=" + HttpUtility.UrlEncode(ru);
string app = string.Empty;
if (!ForceDelAuthNonProvisioned)
{
app = "&app=" + GetAppVerifier();
}
return ConsentUrl + "RefreshToken.aspx" + offers + refreshToken + ru + app;
}
/// <summary>
/// Returns the URL for the consent-management user interface.
/// </summary>
/// <returns>Manage consent URL</returns>
public string GetManageConsentUrl()
{
return GetManageConsentUrl(null);
}
/// <summary>
/// Returns the URL for the consent-management user interface.
/// </summary>
/// <param name="market">The language in which the consent page is
/// displayed is configured by culture ID (For example, 'fr-fr' or
/// 'en-us') specified in the 'market' parameter.</param>
/// <returns>Manage consent URL</returns>
public string GetManageConsentUrl(string market)
{
market = string.IsNullOrEmpty(market) ?
string.Empty : "?mkt=" + HttpUtility.UrlEncode(market);
return ConsentUrl + "ManageConsent.aspx" + market;
}
/// <summary>
/// Holds the Consent Token object corresponding to consent granted.
/// </summary>
public class ConsentToken
{
WindowsLiveLogin wll;
/// <summary>
/// Initialize the ConsentToken.
/// </summary>
/// <param name="wll">WindowsLiveLogin</param>
/// <param name="delegationToken">Delegation token</param>
/// <param name="refreshToken">Refresh token</param>
/// <param name="sessionKey">Session key</param>
/// <param name="expiry">Expiry</param>
/// <param name="offers">Offers</param>
/// <param name="locationID">Location ID</param>
/// <param name="context">Application context</param>
/// <param name="decodedToken">Decoded token</param>
/// <param name="token">Raw token</param>
public ConsentToken(WindowsLiveLogin wll, string delegationToken, string refreshToken, string sessionKey, string expiry, string offers, string locationID, string context, string decodedToken, string token)
{
this.wll = wll;
setDelegationToken(delegationToken);
setRefreshToken(refreshToken);
setSessionKey(sessionKey);
setExpiry(expiry);
setOffers(offers);
setLocationID(locationID);
setContext(context);
setDecodedToken(decodedToken);
setToken(token);
}
string delegationToken;
/// <summary>
/// Gets the Delegation token.
/// </summary>
public string DelegationToken { get { return delegationToken; } }
/// <summary>
/// Sets the Delegation token.
/// </summary>
/// <param name="delegationToken">Delegation token</param>
private void setDelegationToken(string delegationToken)
{
if (string.IsNullOrEmpty(delegationToken))
{
throw new ArgumentException("Error: ConsentToken: Null delegation token.");
}
this.delegationToken = delegationToken;
}
string refreshToken;
/// <summary>
/// Gets the refresh token.
/// </summary>
public string RefreshToken { get { return refreshToken; } }
/// <summary>
/// Sets the refresh token.
/// </summary>
/// <param name="refreshToken">Refresh token</param>
private void setRefreshToken(string refreshToken)
{
this.refreshToken = refreshToken;
}
byte[] sessionKey;
/// <summary>
/// Gets the session key.
/// </summary>
public byte[] SessionKey { get { return sessionKey; } }
/// <summary>
/// Sets the session key.
/// </summary>
/// <param name="sessionKey">Session key</param>
private void setSessionKey(string sessionKey)
{
if (string.IsNullOrEmpty(sessionKey))
{
throw new ArgumentException("Error: ConsentToken: Null session key.");
}
this.sessionKey = WindowsLiveLogin.u64(sessionKey);
}
DateTime expiry;
/// <summary>
/// Gets the expiry time of delegation token.
/// </summary>
public DateTime Expiry { get { return expiry; } }
/// <summary>
/// Sets the expiry time of delegation token.
/// </summary>
/// <param name="expiry">Expiry time</param>
private void setExpiry(string expiry)
{
if (string.IsNullOrEmpty(expiry))
{
throw new ArgumentException("Error: ConsentToken: Null expiry time.");
}
int expiryInt;
try
{
expiryInt = Convert.ToInt32(expiry);
}
catch (Exception)
{
throw new ArgumentException("Error: Consent: Invalid expiry time: "
+ expiry);
}
DateTime refTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
this.expiry = refTime.AddSeconds(expiryInt);
}
IList offers;
/// <summary>
/// Gets the list of offers/actions for which the user granted consent.
/// </summary>
public IList Offers { get { return offers; } }
string offersString;
/// <summary>
/// Gets the string representation of all the offers/actions for which
/// the user granted consent.
/// </summary>
public String OffersString { get { return offersString; } }
/// <summary>
/// Sets the offers/actions for which user granted consent.
/// </summary>
/// <param name="offers">Comma-delimited list of offers</param>
private void setOffers(string offers)
{
if (string.IsNullOrEmpty(offers))
{
throw new ArgumentException("Error: ConsentToken: Null offers.");
}
offers = HttpUtility.UrlDecode(offers);
this.offersString = string.Empty;
this.offers = new ArrayList();
string[] offersList = offers.Split(new Char[]{';'});
foreach (string offer in offersList)
{
if (!(this.offersString == string.Empty))
{
this.offersString += ",";
}
int separator = offer.IndexOf(':');
if (separator == -1)
{
debug("Warning: ConsentToken: offer may be invalid: " + offer);
this.offers.Add(offer);
this.offersString += offer;
}
else
{
string o = offer.Substring(0, separator);
this.offers.Add(o);
this.offersString += o;
}
}
}
string locationID;
/// <summary>
/// Gets the location ID.
/// </summary>
public string LocationID { get { return locationID; } }
/// <summary>
/// Sets the location ID.
/// </summary>
/// <param name="locationID">Location ID</param>
private void setLocationID(string locationID)
{
this.locationID = locationID;
}
string context;
/// <summary>
/// Returns the application context that was originally passed
/// to the consent request, if any.
/// </summary>
public string Context { get { return context; } }
/// <summary>
/// Sets the application context.
/// </summary>
/// <param name="context">Application context</param>
private void setContext(string context)
{
this.context = context;
}
string decodedToken;
/// <summary>
/// Gets the decoded token.
/// </summary>
public string DecodedToken { get { return decodedToken; } }
/// <summary>
/// Sets the decoded token.
/// </summary>
/// <param name="decodedToken">Decoded token</param>
private void setDecodedToken(string decodedToken)
{
this.decodedToken = decodedToken;
}
string token;
/// <summary>
/// Gets the raw token.
/// </summary>
public string Token { get { return token; } }
/// <summary>
/// Sets the raw token.
/// </summary>
/// <param name="token">Raw token</param>
private void setToken(string token)
{
this.token = token;
}
/// <summary>
/// Indicates whether the delegation token is set and has not expired.
/// </summary>
/// <returns></returns>
public bool IsValid()
{
if (string.IsNullOrEmpty(DelegationToken))
{
return false;
}
if (DateTime.UtcNow.AddSeconds(-300) > Expiry)
{
return false;
}
return true;
}
/// <summary>
/// Attempt to refresh the current token and replace it. If operation succeeds
/// true is returned to signify success.
/// </summary>
/// <returns></returns>
public bool Refresh()
{
ConsentToken ct = wll.RefreshConsentToken(this);
if (ct == null)
{
return false;
}
copy(ct);
return true;
}
/// <summary>
/// Makes a copy of the ConsentToken object.
/// </summary>
/// <param name="consentToken"></param>
void copy(ConsentToken consentToken)
{
this.delegationToken = consentToken.delegationToken;
this.refreshToken = consentToken.refreshToken;
this.sessionKey = consentToken.sessionKey;
this.expiry = consentToken.expiry;
this.offers = consentToken.offers;
this.locationID = consentToken.locationID;
this.offersString = consentToken.offersString;
this.decodedToken = consentToken.decodedToken;
this.token = consentToken.token;
}
}
/// <summary>
/// Processes the POST response from the Delegated Authentication
/// service after a user has granted consent. The processConsent
/// function extracts the consent token string and returns the result
/// of invoking the processConsentToken method.
/// </summary>
/// <param name="query">Response from the Delegated Authentication service.</param>
/// <returns>ConsentToken</returns>
public ConsentToken ProcessConsent(NameValueCollection query)
{
if (query == null)
{
debug("Error: ProcessConsent: Invalid query.");
return null;
}
string action = query["action"];
if (action != "delauth")
{
debug("Warning: ProcessConsent: query action ignored: " + action);
return null;
}
if (query["ResponseCode"] != "RequestApproved")
{
debug("Error: ProcessConsent: Consent was not successfully granted: "
+ query["ResponseCode"]);
return null;
}
string token = query["ConsentToken"];
string context = query["appctx"];
if (!string.IsNullOrEmpty(context))
{
context = HttpUtility.UrlDecode(context);
}
return ProcessConsentToken(token, context);
}
/// <summary>
/// Processes the consent token string that is returned in the POST
/// response by the Delegated Authentication service after a
/// user has granted consent.
/// </summary>
/// <param name="token">Raw token.</param>
/// <returns>ConsentToken</returns>
public ConsentToken ProcessConsentToken(string token)
{
return ProcessConsentToken(token, null);
}
/// <summary>
/// Processes the consent token string that is returned in the POST
/// response by the Delegated Authentication service after a
/// user has granted consent.
/// </summary>
/// <param name="token">Raw token.</param>
/// <param name="context">If you specify it, <paramref
/// name="context"/> will be returned as-is in the sign-in
/// response for site-specific use.</param>
/// <returns></returns>
public ConsentToken ProcessConsentToken(string token, string context)
{
string decodedToken = token;
if (string.IsNullOrEmpty(token))
{
debug("Error: ProcessConsentToken: Null token.");
return null;
}
NameValueCollection parsedToken =
parse(HttpUtility.UrlDecode(token));
if (!string.IsNullOrEmpty(parsedToken["eact"]))
{
decodedToken = DecodeAndValidateToken(parsedToken["eact"]);
if (string.IsNullOrEmpty(decodedToken))
{
debug("Error: ProcessConsentToken: Failed to decode/validate token: " +
token);
return null;
}
parsedToken = parse(decodedToken);
decodedToken = HttpUtility.UrlEncode(decodedToken);
}
ConsentToken consentToken = null;
try
{
consentToken = new ConsentToken(this,
parsedToken["delt"],
parsedToken["reft"],
parsedToken["skey"],
parsedToken["exp"],
parsedToken["offer"],
parsedToken["lid"],
context, decodedToken,
token);
}
catch (Exception e)
{
debug("Error: ProcessConsentToken: Contents of token considered invalid: " + e);
}
return consentToken;
}
/// <summary>
/// Attempts to obtain a new, refreshed token and return it. The
/// original token is not modified.
/// </summary>
/// <param name="token">ConsentToken object.</param>
/// <returns>Refreshed ConsentToken object.</returns>
public ConsentToken RefreshConsentToken(ConsentToken token)
{
return RefreshConsentToken(token, null);
}
/// <summary>
/// Attempts to obtain a new, refreshed token and return it. The
/// original token is not modified.
/// </summary>
/// <param name="token">ConsentToken object.</param>
/// <param name="ru">The registered/configured return URL will be
/// overridden by 'ru' specified here.</param>
/// <returns>Refreshed ConsentToken object.</returns>
public ConsentToken RefreshConsentToken(ConsentToken token, string ru)
{
if (token == null)
{
debug("Error: RefreshConsentToken: Null consent token.");
return null;
}
return RefreshConsentToken(token.OffersString, token.RefreshToken, ru);
}
/// <summary>
/// Attempts to obtain a new, refreshed token and return it using
/// the offers and refresh token. The original token is not modified.
/// </summary>
/// <param name="offers">Comma-delimited list of offers.</param>
/// <param name="refreshToken">Refresh token.</param>
/// <returns>Refreshed ConsentToken object.</returns>
public ConsentToken RefreshConsentToken(string offers, string refreshToken)
{
return RefreshConsentToken(offers, refreshToken, null);
}
/// <summary>
/// Attempts to obtain a new, refreshed token and return it using
/// the offers and refresh token. The original token is not modified.
/// </summary>
/// <param name="offers">Comma-delimited list of offers.</param>
/// <param name="refreshToken">Refresh token.</param>
/// <param name="ru">The registered/configured return URL will be
/// overridden by 'ru' specified here.</param>
/// <returns>Refreshed ConsentToken object.</returns>
public ConsentToken RefreshConsentToken(string offers, string refreshToken, string ru)
{
string url = null;
try
{
url = GetRefreshConsentTokenUrl(offers, refreshToken, ru);
}
catch (Exception e)
{
debug("Error: Failed to construct refresh consent token URL: " + e);
return null;
}
if (string.IsNullOrEmpty(url))
{
debug("Error: Failed to construct refresh consent token URL.");
return null;
}
string body = fetch(url);
if (string.IsNullOrEmpty(body))
{
debug("Error: RefreshConsentToken: Failed to download token.");
return null;
}
Regex re = new Regex("{\"ConsentToken\":\"(.*)\"}");
GroupCollection gc = re.Match(body).Groups;
if (gc.Count != 2)
{
debug("Error: RefreshConsentToken: Failed to extract token: " + body);
return null;
}
CaptureCollection cc = gc[1].Captures;
if (cc.Count != 1)
{
debug("Error: RefreshConsentToken: Failed to extract token: " + body);
return null;
}
return ProcessConsentToken(cc[0].ToString());
}
/* Common methods. */
/// <summary>
/// Decodes and validates the raw token.
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
public string DecodeAndValidateToken(string token)
{
bool haveOldSecret = false;
if ((oldSecretExpiry != null) && (DateTime.UtcNow < oldSecretExpiry))
{
if ((oldCryptKey != null) && (oldSignKey != null))
{
haveOldSecret = true;
}
}
string stoken = DecodeAndValidateToken(token, cryptKey, signKey);
if (string.IsNullOrEmpty(stoken))
{
if (haveOldSecret)
{
debug("Warning: Failed to validate token with current secret, attempting old secret.");
return DecodeAndValidateToken(token, oldCryptKey, oldSignKey);
}
}
return stoken;
}
/// <summary>
/// Decodes and validates the raw token with appropriate crypt key
/// and sign key.
/// </summary>
/// <param name="token">Raw token.</param>
/// <param name="cryptKey">Crypt key.</param>
/// <param name="signKey">Sign key.</param>
/// <returns></returns>
public string DecodeAndValidateToken(string token, byte[] cryptKey, byte[] signKey)
{
string stoken = DecodeToken(token, cryptKey);
if (!string.IsNullOrEmpty(stoken))
{
stoken = ValidateToken(stoken, signKey);
}
return stoken;
}
/// <summary>
/// Decode the given token. Returns null on failure.
/// </summary>
///
/// <list type="number">
/// <item>First, the string is URL unescaped and base64
/// decoded.</item>
/// <item>Second, the IV is extracted from the first 16 bytes
/// of the string.</item>
/// <item>Finally, the string is decrypted by using the
/// encryption key.</item>
/// </list>
/// <param name="token">Raw token.</param>
/// <returns>Decoded token.</returns>
public string DecodeToken(string token)
{
return DecodeToken(token, cryptKey);
}
/// <summary>
/// Decode the given token. Returns null on failure.
/// </summary>
///
/// <list type="number">
/// <item>First, the string is URL unescaped and base64
/// decoded.</item>
/// <item>Second, the IV is extracted from the first 16 bytes
/// of the string.</item>
/// <item>Finally, the string is decrypted by using the
/// encryption key.</item>
/// </list>
/// <param name="token">Raw token.</param>
/// <param name="cryptKey">Crypt key.</param>
/// <returns>Decoded token.</returns>
public string DecodeToken(string token, byte[] cryptKey)
{
if (cryptKey == null || cryptKey.Length == 0)
{
throw new InvalidOperationException("Error: DecodeToken: Secret key was not set. Aborting.");
}
if (string.IsNullOrEmpty(token))
{
debug("Error: DecodeToken: Null token input.");
return null;
}
const int ivLength = 16;
byte[] ivAndEncryptedValue = u64(token);
if ((ivAndEncryptedValue == null) ||
(ivAndEncryptedValue.Length <= ivLength) ||
((ivAndEncryptedValue.Length % ivLength) != 0))
{
debug("Error: DecodeToken: Attempted to decode invalid token.");
return null;
}
Rijndael aesAlg = null;
MemoryStream memStream = null;
CryptoStream cStream = null;
StreamReader sReader = null;
string decodedValue = null;
try
{
aesAlg = new RijndaelManaged();
aesAlg.KeySize = 128;
aesAlg.Key = cryptKey;
aesAlg.Padding = PaddingMode.PKCS7;
memStream = new MemoryStream(ivAndEncryptedValue);
byte[] iv = new byte[ivLength];
memStream.Read(iv, 0, ivLength);
aesAlg.IV = iv;
cStream = new CryptoStream(memStream, aesAlg.CreateDecryptor(), CryptoStreamMode.Read);
sReader = new StreamReader(cStream, Encoding.ASCII);
decodedValue = sReader.ReadToEnd();
}
catch (Exception e)
{
debug("Error: DecodeToken: Decryption failed: " + e);
return null;
}
finally
{
try
{
if (sReader != null) { sReader.Close(); }
if (cStream != null) { cStream.Close(); }
if (memStream != null) { memStream.Close(); }
if (aesAlg != null) { aesAlg.Clear(); }
}
catch (Exception e)
{
debug("Error: DecodeToken: Failure during resource cleanup: " + e);
}
}
return decodedValue;
}
/// <summary>
/// Creates a signature for the given string.
/// </summary>
public byte[] SignToken(string token)
{
return SignToken(token, signKey);
}
/// <summary>
/// Creates a signature for the given string by using the
/// signature key.
/// </summary>
public byte[] SignToken(string token, byte[] signKey)
{
if (signKey == null || signKey.Length == 0)
{
throw new InvalidOperationException("Error: SignToken: Secret key was not set. Aborting.");
}
if (string.IsNullOrEmpty(token))
{
debug("Attempted to sign null token.");
return null;
}
using (HashAlgorithm hashAlg = new HMACSHA256(signKey))
{
byte[] data = Encoding.Default.GetBytes(token);
byte[] hash = hashAlg.ComputeHash(data);
return hash;
}
}
/// <summary>
/// Extracts the signature from the token and validates it.
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
public string ValidateToken(string token)
{
return ValidateToken(token, signKey);
}
/// <summary>
/// Extracts the signature from the token and validates it by using the
/// signature key.
/// </summary>
public string ValidateToken(string token, byte[] signKey)
{
if (string.IsNullOrEmpty(token))
{
debug("Error: ValidateToken: Null token.");
return null;
}
string[] s = { "&sig=" };
string[] bodyAndSig = token.Split(s, StringSplitOptions.None);
if (bodyAndSig.Length != 2)
{
debug("Error: ValidateToken: Invalid token: " + token);
return null;
}
byte[] sig = u64(bodyAndSig[1]);
if (sig == null)
{
debug("Error: ValidateToken: Could not extract the signature from the token.");
return null;
}
byte[] sig2 = SignToken(bodyAndSig[0], signKey);
if (sig2 == null)
{
debug("Error: ValidateToken: Could not generate a signature for the token.");
return null;
}
if (sig.Length == sig2.Length)
{
for (int i = 0; i < sig.Length; i++)
{
if (sig[i] != sig2[i]) { goto badSig; }
}
return token;
}
badSig:
debug("Error: ValidateToken: Signature did not match.");
return null;
}
/* Implementation of the methods needed to perform Windows Live
application verification as well as trusted sign-in. */
/// <summary>
/// Generates an Application Verifier token.
/// </summary>
public string GetAppVerifier()
{
return GetAppVerifier(null);
}
/// <summary>
/// Generates an Application Verifier token. An IP address
/// can be included in the token.
/// </summary>
public string GetAppVerifier(string ip)
{
ip = string.IsNullOrEmpty(ip) ? string.Empty : ("&ip=" + ip);
string token = "appid=" + AppId + "&ts=" + getTimestamp() + ip;
string sig = e64(SignToken(token));
if (string.IsNullOrEmpty(sig))
{
debug("Error: GetAppVerifier: Failed to sign the token.");
return null;
}
token += "&sig=" + sig;
return HttpUtility.UrlEncode(token);
}
/// <summary>
/// Returns the URL needed to retrieve the application
/// security token. The application security token
/// will be generated for the Windows Live site.
///
/// JavaScript Output Notation (JSON) output is returned:
///
/// {"token":"<value>"}
/// </summary>
public string GetAppLoginUrl()
{
return GetAppLoginUrl(null, null, false);
}
/// <summary>
/// Returns the URL needed to retrieve the application
/// security token.
///
/// By default, the application security token will be
/// generated for the Windows Live site; a specific Site ID
/// can optionally be specified in 'siteId'.
///
/// JSON output is returned:
///
/// {"token":"<value>"}
/// </summary>
public string GetAppLoginUrl(string siteId)
{
return GetAppLoginUrl(siteId, null, false);
}
/// <summary>
/// Returns the URL needed to retrieve the application
/// security token.
///
/// By default, the application security token will be
/// generated for the Windows Live site; a specific Site ID
/// can optionally be specified in 'siteId'. The IP address
/// can also optionally be included in 'ip'.
///
/// JSON output is returned:
///
/// {"token":"<value>"}
/// </summary>
public string GetAppLoginUrl(string siteId, string ip)
{
return GetAppLoginUrl(siteId, ip, false);
}
/// <summary>
/// Returns the URL needed to retrieve the application
/// security token.
///
/// By default, the application security token will be
/// generated for the Windows Live site; a specific Site ID
/// can optionally be specified in 'siteId'. The IP address
/// can also optionally be included in 'ip'.
///
/// If 'js' is false, then JSON output is returned:
///
/// {"token":"<value>"}
///
/// Otherwise, a JavaScript response is returned. It is assumed
/// that WLIDResultCallback is a custom function implemented to
/// handle the token value:
///
/// WLIDResultCallback("<tokenvalue>");
/// </summary>
public string GetAppLoginUrl(string siteId, string ip, bool js)
{
string algPart = "&alg=" + SecurityAlgorithm;
string sitePart = string.IsNullOrEmpty(siteId) ?
string.Empty : "&id=" + siteId;
string jsPart = (!js) ? string.Empty : "&js=1";
string url = SecureUrl + "wapplogin.srf?app=" +
GetAppVerifier(ip) + algPart + sitePart + jsPart;
return url;
}
/// <summary>
/// Retrieves the application security token for application
/// verification from the application sign-in URL. The
/// application security token will be generated for the
/// Windows Live site.
/// </summary>
public string GetAppSecurityToken()
{
return GetAppSecurityToken(null, null);
}
/// <summary>
/// Retrieves the application security token for application
/// verification from the application sign-in URL.
///
/// By default, the application security token will be
/// generated for the Windows Live site; a specific Site ID
/// can optionally be specified in 'siteId'.
/// </summary>
public string GetAppSecurityToken(string siteId)
{
return GetAppSecurityToken(siteId, null);
}
/// <summary>
/// Retrieves the application security token for application
/// verification from the application sign-in URL.
///
/// By default, the application security token will be
/// generated for the Windows Live site; a specific Site ID
/// can optionally be specified in 'siteId'. The IP address
/// can also optionally be included in 'ip'.
///
/// Implementation note: The application security token is
/// downloaded from the application sign-in URL in JSON format
/// {"token":"<value>"}, so we need to extract
/// <value> from the string and return it as seen here.
/// </summary>
public string GetAppSecurityToken(string siteId, string ip)
{
string url = GetAppLoginUrl(siteId, ip);
string body = fetch(url);
if (string.IsNullOrEmpty(body))
{
debug("Error: GetAppSecurityToken: Failed to download token.");
return null;
}
Regex re = new Regex("{\"token\":\"(.*)\"}");
GroupCollection gc = re.Match(body).Groups;
if (gc.Count != 2)
{
debug("Error: GetAppSecurityToken: Failed to extract token: " + body);
return null;
}
CaptureCollection cc = gc[1].Captures;
if (cc.Count != 1)
{
debug("Error: GetAppSecurityToken: Failed to extract token: " + body);
return null;
}
return cc[0].ToString();
}
/// <summary>
/// Returns a string that can be passed to the GetTrustedParams
/// function as the 'retcode' parameter. If this is specified as
/// the 'retcode', then the app will be used as return URL
/// after it finishes trusted sign-in.
/// </summary>
public string GetAppRetCode()
{
return "appid=" + AppId;
}
/// <summary>
/// Returns a table of key-value pairs that must be posted to
/// the sign-in URL for trusted sign-in. Use HTTP POST to do
/// this. Be aware that the values in the table are neither
/// URL nor HTML escaped and may have to be escaped if you are
/// inserting them in code such as an HTML form.
///
/// The user to be trusted on the local site is passed in as
/// string 'user'.
/// </summary>
public NameValueCollection GetTrustedParams(string user)
{
return GetTrustedParams(user, null);
}
/// <summary>
/// Returns a table of key-value pairs that must be posted to
/// the sign-in URL for trusted sign-in. Use HTTP POST to do
/// this. Be aware that the values in the table are neither
/// URL nor HTML escaped and may have to be escaped if you are
/// inserting them in code such as an HTML form.
///
/// The user to be trusted on the local site is passed in as
/// string 'user'.
///
/// Optionally, 'retcode' specifies the resource to which
/// successful sign-in is redirected, such as Windows Live Mail,
/// and is typically a string in the format 'id=2000'. If you
/// pass in the value from GetAppRetCode instead, sign-in will
/// be redirected to the application. Otherwise, an HTTP 200
/// response is returned.
/// </summary>
public NameValueCollection GetTrustedParams(string user, string retcode)
{
string token = GetTrustedToken(user);
if (string.IsNullOrEmpty(token)) { return null; }
token = "<wst:RequestSecurityTokenResponse xmlns:wst=\"http://schemas.xmlsoap.org/ws/2005/02/trust\"><wst:RequestedSecurityToken><wsse:BinarySecurityToken xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">" + token + "</wsse:BinarySecurityToken></wst:RequestedSecurityToken><wsp:AppliesTo xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2004/09/policy\"><wsa:EndpointReference xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\"><wsa:Address>uri:WindowsLiveID</wsa:Address></wsa:EndpointReference></wsp:AppliesTo></wst:RequestSecurityTokenResponse>";
NameValueCollection nvc = new NameValueCollection(3);
nvc["wa"] = SecurityAlgorithm;
nvc["wresult"] = token;
if (retcode != null)
{
nvc["wctx"] = retcode;
}
return nvc;
}
/// <summary>
/// Returns the trusted sign-in token in the format needed by the
/// trusted sign-in gadget.
///
/// User to be trusted on the local site is passed in as string
/// 'user'.
/// </summary>
public string GetTrustedToken(string user)
{
if (string.IsNullOrEmpty(user))
{
debug("Error: GetTrustedToken: Invalid user specified.");
return null;
}
string token = "appid=" + AppId + "&uid=" +
HttpUtility.UrlEncode(user) + "&ts=" + getTimestamp();
string sig = e64(SignToken(token));
if (string.IsNullOrEmpty(sig))
{
debug("Error: GetTrustedToken: Failed to sign the token.");
return null;
}
token += "&sig=" + sig;
return HttpUtility.UrlEncode(token);
}
/// <summary>
/// Returns the trusted sign-in URL to use for the Windows Live
/// Login server.
/// </summary>
public string GetTrustedLoginUrl()
{
return SecureUrl + "wlogin.srf";
}
/// <summary>
/// Returns the trusted sign-out URL to use for the Windows Live
/// Login server.
/// </summary>
public string GetTrustedLogoutUrl()
{
return SecureUrl + "logout.srf?appid=" + AppId;
}
/* Helper methods */
/// <summary>
/// Function to parse the settings file.
/// </summary>
/// <param name="settingsFile"></param>
/// <returns></returns>
static NameValueCollection parseSettings(string settingsFile)
{
if (string.IsNullOrEmpty(settingsFile))
{
throw new ArgumentNullException("settingsFile");
}
// Throws an exception on any failure.
XmlDocument xd = new XmlDocument();
xd.Load(settingsFile);
XmlNode topNode = xd.SelectSingleNode("//windowslivelogin");
if (topNode == null)
{
throw new XmlException("Error: parseSettings: Failed to parse settings file: " + settingsFile);
}
NameValueCollection settings = new NameValueCollection();
IEnumerator children = topNode.GetEnumerator();
while (children.MoveNext())
{
XmlNode child = (XmlNode) children.Current;
settings[child.Name] = child.InnerText;
}
return settings;
}
/// <summary>
/// Derives the key, given the secret key and prefix as described in the
/// Web Authentication SDK documentation.
/// </summary>
static byte[] derive(string secret, string prefix)
{
using (HashAlgorithm hashAlg = HashAlgorithm.Create("SHA256"))
{
const int keyLength = 16;
byte[] data = Encoding.Default.GetBytes(prefix+secret);
byte[] hashOutput = hashAlg.ComputeHash(data);
byte[] byteKey = new byte[keyLength];
Array.Copy(hashOutput, byteKey, keyLength);
return byteKey;
}
}
/// <summary>
/// Parses query string and return a table representation of
/// the key and value pairs. Similar to
/// HttpUtility.ParseQueryString, except that no URL decoding
/// is done and only the last value is considered in the case
/// of multiple values with one key.
/// </summary>
static NameValueCollection parse(string input)
{
if (string.IsNullOrEmpty(input))
{
debug("Error: parse: Null input.");
return null;
}
NameValueCollection pairs = new NameValueCollection();
string[] kvs = input.Split(new Char[]{'&'});
foreach (string kv in kvs)
{
int separator = kv.IndexOf('=');
if ((separator == -1) || (separator == kv.Length))
{
debug("Warning: parse: Ignoring pair: " + kv);
continue;
}
pairs[kv.Substring(0, separator)] = kv.Substring(separator+1);
}
return pairs;
}
/// <summary>
/// Generates a timestamp suitable for the application
/// verifier token.
/// </summary>
static string getTimestamp()
{
DateTime refTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
TimeSpan ts = DateTime.UtcNow - refTime;
return ((uint)ts.TotalSeconds).ToString();
}
/// <summary>
/// Base64-encodes and URL-escapes a byte array.
/// </summary>
static string e64(byte[] b)
{
string s = null;
if (b == null) { return s; }
try
{
s = Convert.ToBase64String(b);
s = HttpUtility.UrlEncode(s);
}
catch(Exception e)
{
debug("Error: e64: Base64 conversion error: " + e);
}
return s;
}
/// <summary>
/// URL-unescapes and Base64-decodes a string.
/// </summary>
static byte[] u64(string s)
{
byte[] b = null;
if (s == null) { return b; }
s = HttpUtility.UrlDecode(s);
try
{
b = Convert.FromBase64String(s);
}
catch (Exception e)
{
debug("Error: u64: Base64 conversion error: " + s + ", " + e);
}
return b;
}
/// <summary>
/// Fetches the contents given a URL.
/// </summary>
static string fetch(string url)
{
string body = null;
try
{
WebRequest req = HttpWebRequest.Create(url);
req.Method = "GET";
WebResponse res = req.GetResponse();
using (StreamReader sr = new StreamReader(res.GetResponseStream(), Encoding.UTF8))
{
body = sr.ReadToEnd();
}
}
catch (Exception e)
{
debug("Error: fetch: Failed to get the document: " + url +
", " + e);
}
return body;
}
}
}
6. Add a web page to website.
HTML code is :
Preview (hint: you can copy and paste the preview into Microsoft Word):
<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
CodeBehind="Default.aspx.cs" Inherits="ImportContacts._Default" %>
<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
<script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script>
<script type="text/javascript">
function GetGmailContacts() {
window.location = 'https://accounts.google.com/o/oauth2/auth?client_id=569316988455.apps.googleusercontent.com&redirect_uri=http://test.ie&scope=https://www.google.com/m8/feeds/&response_type=code'
}
function yahooclick() {
$.ajax({
type: "POST",
url: "Default.aspx/GetYahooContacts",
contentType: "application/json",
success: function (data) {
// Replace the div's content with the page method's return.
window.location = data.d;
}
});
}
function hotmailclick() {
$.ajax({
type: "POST",
url: "Default.aspx/GetHotmailContacts",
contentType: "application/json",
success: function (data) {
// Replace the div's content with the page method's return.
window.location = data.d;
}
});
}
</script>
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
<img src="Images/yahoo_mail_icon.png" alt="" onclick="yahooclick();" />
<img src="Images/wave4hotmail.png" alt="" onclick="hotmailclick();" />
<img src="Images/Gmail_logo.png" alt="" onclick="GetGmailContacts();" />
<div>
<h2>Emails:</h2>
<asp:ListView runat="server" ID="listView" >
<ItemTemplate>
<span><%# Container.DataItem %></span><br />
</ItemTemplate>
</asp:ListView>
</div>
</asp:Content>
|
and code behind code is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Services;
using System.Configuration;
using WindowsLive;
using System.Net;
using System.Xml;
using System.IO;
using Google.GData.Client;
using Google.Contacts;
using System.Web.Script.Serialization;
namespace ImportContacts
{
public partial class _Default : System.Web.UI.Page
{
const string Offers = "Contacts.View";
const string AuthCookie = "delauthtoken";
static WindowsLiveLogin wll = new WindowsLiveLogin(true);
protected WindowsLiveLogin.ConsentToken Token;
protected string ConsentUrl;
protected void Page_Load(object sender, EventArgs e)
{
ConsentUrl = wll.GetConsentUrl(Offers);
Session["wll"] = wll;
if (Session["HotmailToken"] != null)
{
WindowsLiveLogin.ConsentToken token = wll.ProcessConsent(Request.Form);
Token = wll.ProcessConsentToken((string)Session["HotmailToken"]);
if (Token != null)
{
string lid = Token.LocationID;
long llid = Int64.Parse(lid, System.Globalization.NumberStyles.HexNumber);
string delegatedToken = Token.DelegationToken;
string uri = "https://livecontacts.services.live.com/@L@" + lid + "/rest/LiveContacts/Contacts/";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.UserAgent = "Windows Live Data Interactive SDK";
request.ContentType = "application/xml; charset=utf-8";
request.Method = "GET";
request.Headers.Add("Authorization", "DelegatedToken dt=\"" + delegatedToken + "\"");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
XmlDocument contacts = new XmlDocument();
contacts.LoadXml(new StreamReader(response.GetResponseStream()).ReadToEnd());
List<string> emails = new List<string>();
XmlNodeList nodeList = contacts.SelectNodes("//Email/Address");
foreach (XmlNode node in nodeList)
{
if (!String.IsNullOrEmpty(node.InnerText))
{
emails.Add(node.InnerText);
}
}
listView.DataSource = emails;
listView.DataBind();
}
}
if (Request["code"] != null)
{
List<string> emails = GetGmailContacts((string)Request["code"]);
listView.DataSource = emails;
listView.DataBind();
}
//yahoo
if (Request["oauth_token"] != null)
{
Yahoo.GetYahooContacts yahoo = (Yahoo.GetYahooContacts)HttpContext.Current.Session["yahoo"];
yahoo.OauthToken = Request["oauth_token"];
yahoo.OauthVerifier = Request["oauth_verifier"];
List<string> emails = yahoo.GetContacts();
listView.DataSource = emails;
listView.DataBind();
}
}
[WebMethod]
public static string GetYahooContacts()
{
Yahoo.GetYahooContacts yahoo = new Yahoo.GetYahooContacts();
HttpContext.Current.Session["yahoo"] = yahoo;
return yahoo.authorization(ConfigurationManager.AppSettings["ReturnUrl"]);
}
[WebMethod]
public static string GetHotmailContacts()
{
return wll.GetConsentUrl(Offers);
}
public List<string> GetGmailContacts(string code)
{
List<string> emails = new List<string>();
try
{
string postcontents = string.Format("code={0}&client_id={1}&client_secret={2}&redirect_uri={3}&grant_type=authorization_code"
, System.Web.HttpUtility.UrlEncode(code)
, System.Web.HttpUtility.UrlEncode(ConfigurationManager.AppSettings["gmailclientid"])
, System.Web.HttpUtility.UrlEncode(ConfigurationManager.AppSettings["gmailsecret"])
, System.Web.HttpUtility.UrlEncode(ConfigurationManager.AppSettings["gmailreturnurl"]));
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("https://accounts.google.com/o/oauth2/token");
request.Method = "POST";
byte[] postcontentsArray = System.Text.Encoding.UTF8.GetBytes(postcontents);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postcontentsArray.Length;
GoogleOAuthToken token;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(postcontentsArray, 0, postcontentsArray.Length);
requestStream.Close();
WebResponse response = request.GetResponse();
using (Stream responseStream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(responseStream))
{
string responseFromServer = reader.ReadToEnd();
reader.Close();
responseStream.Close();
response.Close();
// return SerializeToken(responseFromServer);
JavaScriptSerializer ser = new JavaScriptSerializer();
token = ser.Deserialize<GoogleOAuthToken>(responseFromServer);
}
}
RequestSettings contactrequest = new RequestSettings("import contact", token.access_token);
contactrequest.AutoPaging = true;
ContactsRequest req = new ContactsRequest(contactrequest);
foreach (Contact contact in req.GetContacts().Entries)
{
emails.Add(contact.PrimaryEmail.Address);
}
return emails;
}
catch (Exception ex)
{
return emails;
}
}
public class GoogleOAuthToken
{
public string access_token;
public string expires_in;
public string token_type;
public string refresh_token;
}
}
}
And there will be some settings in web.config also :
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0"/>
</system.web>
<system.web.extensions>
<scripting>
<scriptResourceHandler enableCompression="true" enableCaching="true" />
</scripting>
</system.web.extensions>
<appSettings>
<add key="wll_appid" value="******" />
<add key="wll_secret" value="******************" />
<add key="wll_securityalgorithm" value="wsignin1.0" />
<add key="wll_returnurl" value="http://localhost:4730/default.aspx" />
<add key="wll_policyurl" value="http://test.ie/policy.html" />
<add key="ReturnUrl" value="http://localhost:4730/" />
<add key="gmailclientid" value="************************" />
<add key="gmailsecret" value="************************" />
<add key="gmailreturnurl" value="http://localhost:4730" />
</appSettings>
</configuration>
thats all