summaryrefslogtreecommitdiffstats
path: root/src/OAuth/OAuthServiceProvider/Code/DatabaseTokenManager.cs
blob: 49da45de4bec839a7cc6a3937a27e584024af996 (plain)
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
//-----------------------------------------------------------------------
// <copyright file="DatabaseTokenManager.cs" company="Outercurve Foundation">
//     Copyright (c) Outercurve Foundation. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

namespace OAuthServiceProvider.Code {
	using System;
	using System.Collections.Generic;
	using System.Diagnostics;
	using System.Linq;
	using DotNetOpenAuth.OAuth.ChannelElements;
	using DotNetOpenAuth.OAuth.Messages;

	public class DatabaseTokenManager : IServiceProviderTokenManager {
		#region IServiceProviderTokenManager

		public IConsumerDescription GetConsumer(string consumerKey) {
			var consumerRow = Global.DataContext.OAuthConsumers.SingleOrDefault(
				consumerCandidate => consumerCandidate.ConsumerKey == consumerKey);
			if (consumerRow == null) {
				throw new KeyNotFoundException();
			}

			return consumerRow;
		}

		public IServiceProviderRequestToken GetRequestToken(string token) {
			try {
				return Global.DataContext.OAuthTokens.First(t => t.Token == token && t.State != TokenAuthorizationState.AccessToken);
			} catch (InvalidOperationException ex) {
				throw new KeyNotFoundException("Unrecognized token", ex);
			}
		}

		public IServiceProviderAccessToken GetAccessToken(string token) {
			try {
				return Global.DataContext.OAuthTokens.First(t => t.Token == token && t.State == TokenAuthorizationState.AccessToken);
			} catch (InvalidOperationException ex) {
				throw new KeyNotFoundException("Unrecognized token", ex);
			}
		}

		public void UpdateToken(IServiceProviderRequestToken token) {
			// Nothing to do here, since we're using Linq To SQL, and
			// We call LinqToSql's SubmitChanges method via our Global.Application_EndRequest method.
			// This is a good pattern because we only save changes if the request didn't end up somehow failing.
			// But if you DO want to save changes at this point, you could do it like so:
			////Global.DataContext.SubmitChanges();
		}

		#endregion

		#region ITokenManager Members

		public string GetTokenSecret(string token) {
			var tokenRow = Global.DataContext.OAuthTokens.SingleOrDefault(
				tokenCandidate => tokenCandidate.Token == token);
			if (tokenRow == null) {
				throw new ArgumentException();
			}

			return tokenRow.TokenSecret;
		}

		public void StoreNewRequestToken(UnauthorizedTokenRequest request, ITokenSecretContainingMessage response) {
			RequestScopedTokenMessage scopedRequest = (RequestScopedTokenMessage)request;
			var consumer = Global.DataContext.OAuthConsumers.Single(consumerRow => consumerRow.ConsumerKey == request.ConsumerKey);
			string scope = scopedRequest.Scope;
			OAuthToken newToken = new OAuthToken {
				OAuthConsumer = consumer,
				Token = response.Token,
				TokenSecret = response.TokenSecret,
				IssueDate = DateTime.UtcNow,
				Scope = scope,
			};

			Global.DataContext.OAuthTokens.InsertOnSubmit(newToken);
			Global.DataContext.SubmitChanges();
		}

		/// <summary>
		/// Checks whether a given request token has already been authorized
		/// by some user for use by the Consumer that requested it.
		/// </summary>
		/// <param name="requestToken">The Consumer's request token.</param>
		/// <returns>
		/// 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.
		/// </returns>
		public bool IsRequestTokenAuthorized(string requestToken) {
			var tokenFound = Global.DataContext.OAuthTokens.SingleOrDefault(
				token => token.Token == requestToken &&
				token.State == TokenAuthorizationState.AuthorizedRequestToken);
			return tokenFound != null;
		}

		public void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret) {
			var data = Global.DataContext;
			var consumerRow = data.OAuthConsumers.Single(consumer => consumer.ConsumerKey == consumerKey);
			var tokenRow = data.OAuthTokens.Single(token => token.Token == requestToken && token.OAuthConsumer == consumerRow);
			Debug.Assert(tokenRow.State == TokenAuthorizationState.AuthorizedRequestToken, "The token should be authorized already!");

			// Update the existing row to be an access token.
			tokenRow.IssueDate = DateTime.UtcNow;
			tokenRow.State = TokenAuthorizationState.AccessToken;
			tokenRow.Token = accessToken;
			tokenRow.TokenSecret = accessTokenSecret;
		}

		/// <summary>
		/// Classifies a token as a request token or an access token.
		/// </summary>
		/// <param name="token">The token to classify.</param>
		/// <returns>Request or Access token, or invalid if the token is not recognized.</returns>
		public TokenType GetTokenType(string token) {
			var tokenRow = Global.DataContext.OAuthTokens.SingleOrDefault(tokenCandidate => tokenCandidate.Token == token);
			if (tokenRow == null) {
				return TokenType.InvalidToken;
			} else if (tokenRow.State == TokenAuthorizationState.AccessToken) {
				return TokenType.AccessToken;
			} else {
				return TokenType.RequestToken;
			}
		}

		#endregion

		public void AuthorizeRequestToken(string requestToken, User user) {
			if (requestToken == null) {
				throw new ArgumentNullException("requestToken");
			}
			if (user == null) {
				throw new ArgumentNullException("user");
			}

			var tokenRow = Global.DataContext.OAuthTokens.SingleOrDefault(
				tokenCandidate => tokenCandidate.Token == requestToken &&
				tokenCandidate.State == TokenAuthorizationState.UnauthorizedRequestToken);
			if (tokenRow == null) {
				throw new ArgumentException();
			}

			tokenRow.State = TokenAuthorizationState.AuthorizedRequestToken;
			tokenRow.User = user;
		}

		public OAuthConsumer GetConsumerForToken(string token) {
			if (string.IsNullOrEmpty(token)) {
				throw new ArgumentNullException("requestToken");
			}

			var tokenRow = Global.DataContext.OAuthTokens.SingleOrDefault(
				tokenCandidate => tokenCandidate.Token == token);
			if (tokenRow == null) {
				throw new ArgumentException();
			}

			return tokenRow.OAuthConsumer;
		}
	}
}