//----------------------------------------------------------------------- // // Copyright (c) Andrew Arnott. All rights reserved. // //----------------------------------------------------------------------- namespace WebFormsRelyingParty.Code { using System; using System.Collections.Generic; using System.Linq; using System.Web; using DotNetOpenAuth.OAuth.ChannelElements; using DotNetOpenAuth.OAuth.Messages; using System.Security.Cryptography.X509Certificates; using DotNetOpenAuth.OAuth; /// /// The token manager this web site uses in its roles both as /// a consumer and as a service provider. /// public class OAuthTokenManager : IConsumerTokenManager, IServiceProviderTokenManager { /// /// Initializes a new instance of the class /// for use as a Consumer. /// /// The consumer key. /// The consumer secret. private OAuthTokenManager(string consumerKey, string consumerSecret) { if (String.IsNullOrEmpty(consumerKey)) { throw new ArgumentNullException("consumerKey"); } if (consumerSecret == null) { throw new ArgumentNullException("consumerSecret"); } this.ConsumerKey = consumerKey; this.ConsumerSecret = consumerSecret; } /// /// Initializes a new instance of the class. /// private OAuthTokenManager() { } #region IConsumerTokenManager Members /// /// Gets the consumer key. /// /// The consumer key. public string ConsumerKey { get; private set; } /// /// Gets the consumer secret. /// /// The consumer secret. public string ConsumerSecret { get; private set; } #endregion #region IServiceProviderTokenManager Members /// /// Gets the Consumer description for a given a Consumer Key. /// /// The Consumer Key. /// /// A description of the consumer. Never null. /// /// Thrown if the consumer key cannot be found. public IConsumerDescription GetConsumer(string consumerKey) { try { return Global.DataContext.Consumer.First(c => c.ConsumerKey == consumerKey); } catch (InvalidOperationException) { throw new KeyNotFoundException(); } } /// /// Checks whether a given request token has already been authorized /// by some user for use by the Consumer that requested it. /// /// The Consumer's request token. /// /// True if the request token has already been fully authorized by the user /// who owns the relevant protected resources. False if the token has not yet /// been authorized, has expired or does not exist. /// public bool IsRequestTokenAuthorized(string requestToken) { return Global.DataContext.IssuedToken.Any( t => t.Token == requestToken && !t.IsAccessToken && t.User != null); } /// /// Gets details on the named request token. /// /// The request token. /// A description of the token. Never null. /// Thrown if the token cannot be found. /// /// It is acceptable for implementations to find the token, see that it has expired, /// delete it from the database and then throw , /// or alternatively it can return the expired token anyway and the OAuth channel will /// log and throw the appropriate error. /// public IServiceProviderRequestToken GetRequestToken(string token) { try { return Global.DataContext.IssuedToken.First(tok => !tok.IsAccessToken && tok.Token == token); } catch (InvalidOperationException) { throw new KeyNotFoundException(); } } /// /// Gets details on the named access token. /// /// The access token. /// A description of the token. Never null. /// Thrown if the token cannot be found. /// /// It is acceptable for implementations to find the token, see that it has expired, /// delete it from the database and then throw , /// or alternatively it can return the expired token anyway and the OAuth channel will /// log and throw the appropriate error. /// public IServiceProviderAccessToken GetAccessToken(string token) { try { return Global.DataContext.IssuedToken.First(tok => tok.IsAccessToken && tok.Token == token); } catch (InvalidOperationException) { throw new KeyNotFoundException(); } } /// /// Persists any changes made to the token. /// /// The token whose properties have been changed. /// /// This library will invoke this method after making a set /// of changes to the token as part of a web request to give the host /// the opportunity to persist those changes to a database. /// Depending on the object persistence framework the host site uses, /// this method MAY not need to do anything (if changes made to the token /// will automatically be saved without any extra handling). /// public void UpdateToken(IServiceProviderRequestToken token) { Global.DataContext.SaveChanges(); } #endregion #region ITokenManager Members /// /// Gets the Token Secret given a request or access token. /// /// The request or access token. /// /// The secret associated with the given token. /// /// Thrown if the secret cannot be found for the given token. public string GetTokenSecret(string token) { try { return Global.DataContext.IssuedToken.First(t => t.Token == token).TokenSecret; } catch (InvalidOperationException) { throw new ArgumentOutOfRangeException(); } } /// /// Stores a newly generated unauthorized request token, secret, and optional /// application-specific parameters for later recall. /// /// The request message that resulted in the generation of a new unauthorized request token. /// The response message that includes the unauthorized request token. /// Thrown if the consumer key is not registered, or a required parameter was not found in the parameters collection. /// /// Request tokens stored by this method SHOULD NOT associate any user account with this token. /// It usually opens up security holes in your application to do so. Instead, you associate a user /// account with access tokens (not request tokens) in the /// method. /// public void StoreNewRequestToken(UnauthorizedTokenRequest request, ITokenSecretContainingMessage response) { Consumer consumer; try { consumer = Global.DataContext.Consumer.First(c => c.ConsumerKey == request.ConsumerKey); } catch (InvalidOperationException) { throw new ArgumentOutOfRangeException(); } var token = new IssuedToken { Callback = request.Callback, Consumer = consumer, CreatedOn = DateTime.Now, ExpirationDate = DateTime.Now.AddHours(1), Token = response.Token, TokenSecret = response.TokenSecret, }; Global.DataContext.AddToIssuedToken(token); Global.DataContext.SaveChanges(); } public void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret) { var token = Global.DataContext.IssuedToken.First( t => t.Consumer.ConsumerKey == consumerKey && !t.IsAccessToken && t.Token == requestToken); // Repurpose this request token to be our access token. token.Token = accessToken; token.TokenSecret = accessTokenSecret; token.ExpirationDate = null; // currently, our access tokens don't expire token.IsAccessToken = true; token.VerificationCode = null; token.CreatedOn = DateTime.Now; Global.DataContext.SaveChanges(); } /// /// Classifies a token as a request token or an access token. /// /// The token to classify. /// /// Request or Access token, or invalid if the token is not recognized. /// public TokenType GetTokenType(string token) { IssuedToken tok = Global.DataContext.IssuedToken.FirstOrDefault(t => t.Token == token); if (tok == null) { return TokenType.InvalidToken; } else { return tok.IsAccessToken ? TokenType.AccessToken : TokenType.RequestToken; } } #endregion /// /// Creates a token manager for use when this web site acts as a consumer of /// another OAuth service provider. /// /// The consumer key. /// The consumer secret. /// The token manager. internal static IConsumerTokenManager CreateConsumer(string consumerKey, string consumerSecret) { if (String.IsNullOrEmpty(consumerKey)) { throw new ArgumentNullException("consumerKey"); } if (consumerSecret == null) { throw new ArgumentNullException("consumerSecret"); } return new OAuthTokenManager(consumerKey, consumerSecret); } /// /// Creates a token manager suitable for this web site acting as an OAuth service provider. /// /// The token manager. internal static IServiceProviderTokenManager CreateServiceProvider() { return new OAuthTokenManager(); } } }