1
//-----------------------------------------------------------------------
2 // <copyright file="Consumer.cs" company="Andrew Arnott">
3 // Copyright (c) Andrew Arnott. All rights reserved.
5 //-----------------------------------------------------------------------
7 namespace DotNetOAuth
{
9 using System
.Collections
.Generic
;
12 using DotNetOAuth
.ChannelElements
;
13 using DotNetOAuth
.Messages
;
14 using DotNetOAuth
.Messaging
;
15 using DotNetOAuth
.Messaging
.Bindings
;
18 /// A website or application that uses OAuth to access the Service Provider on behalf of the User.
21 /// The methods on this class are thread-safe. Provided the properties are set and not changed
22 /// afterward, a single instance of this class may be used by an entire web application safely.
24 public class Consumer
{
26 /// Initializes a new instance of the <see cref="Consumer"/> class.
28 /// <param name="serviceDescription">The endpoints and behavior of the Service Provider.</param>
29 /// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param>
30 public Consumer(ServiceProviderDescription serviceDescription
, ITokenManager tokenManager
) {
31 if (serviceDescription
== null) {
32 throw new ArgumentNullException("serviceDescription");
34 if (tokenManager
== null) {
35 throw new ArgumentNullException("tokenManager");
38 this.WebRequestHandler
= new StandardWebRequestHandler();
39 ITamperProtectionChannelBindingElement signingElement
= serviceDescription
.CreateTamperProtectionElement();
40 INonceStore store
= new NonceMemoryStore(StandardExpirationBindingElement
.DefaultMaximumMessageAge
);
41 this.Channel
= new OAuthChannel(signingElement
, store
, new OAuthConsumerMessageTypeProvider(tokenManager
), this.WebRequestHandler
);
42 this.ServiceProvider
= serviceDescription
;
43 this.TokenManager
= tokenManager
;
47 /// Gets or sets the Consumer Key used to communicate with the Service Provider.
49 public string ConsumerKey { get; set; }
52 /// Gets or sets the Consumer Secret used to communicate with the Service Provider.
54 public string ConsumerSecret { get; set; }
57 /// Gets the Service Provider that will be accessed.
59 public ServiceProviderDescription ServiceProvider { get; private set; }
62 /// Gets the persistence store for tokens and secrets.
64 public ITokenManager TokenManager { get; private set; }
67 /// Gets or sets the object that processes <see cref="HttpWebRequest"/>s.
70 /// This defaults to a straightforward implementation, but can be set
71 /// to a mock object for testing purposes.
73 internal IWebRequestHandler WebRequestHandler { get; set; }
76 /// Gets or sets the channel to use for sending/receiving messages.
78 internal OAuthChannel Channel { get; set; }
81 /// Begins an OAuth authorization request and redirects the user to the Service Provider
82 /// to provide that authorization. Upon successful authorization, the user is redirected
83 /// back to the current page.
85 /// <returns>The pending user agent redirect based message to be sent as an HttpResponse.</returns>
87 /// Requires HttpContext.Current.
89 public Response
RequestUserAuthorization() {
90 Uri callback
= MessagingUtilities
.GetRequestUrlFromContext().StripQueryArgumentsWithPrefix(Protocol
.Default
.ParameterPrefix
);
91 return this.RequestUserAuthorization(callback
, null, null);
95 /// Begins an OAuth authorization request and redirects the user to the Service Provider
96 /// to provide that authorization.
98 /// <param name="callback">
99 /// An optional Consumer URL that the Service Provider should redirect the
100 /// User Agent to upon successful authorization.
102 /// <param name="requestParameters">Extra parameters to add to the request token message. Optional.</param>
103 /// <param name="redirectParameters">Extra parameters to add to the redirect to Service Provider message. Optional.</param>
104 /// <returns>The pending user agent redirect based message to be sent as an HttpResponse.</returns>
105 public Response
RequestUserAuthorization(Uri callback
, IDictionary
<string, string> requestParameters
, IDictionary
<string, string> redirectParameters
) {
107 return this.RequestUserAuthorization(callback
, requestParameters
, redirectParameters
, out token
);
111 /// Begins an OAuth authorization request from a desktop client app.
113 /// <param name="requestParameters">Extra parameters to add to the request token message. Optional.</param>
114 /// <param name="redirectParameters">Extra parameters to add to the redirect to Service Provider message. Optional.</param>
115 /// <param name="requestToken">The request token that must be exchanged for an access token after the user has provided authorization.</param>
116 /// <returns>The URL to open a browser window to allow the user to provide authorization.</returns>
117 public Uri
RequestUserAuthorization(IDictionary
<string, string> requestParameters
, IDictionary
<string, string> redirectParameters
, out string requestToken
) {
118 return this.RequestUserAuthorization(null, requestParameters
, redirectParameters
, out requestToken
).DirectUriRequest
;
122 /// Processes an incoming authorization-granted message from an SP and obtains an access token.
124 /// <returns>The access token, or null if no incoming authorization message was recognized.</returns>
126 /// Requires HttpContext.Current.
128 public GrantAccessTokenMessage
ProcessUserAuthorization() {
129 return this.ProcessUserAuthorization(this.Channel
.GetRequestFromContext());
133 /// Processes an incoming authorization-granted message from an SP and obtains an access token.
135 /// <param name="request">The incoming HTTP request.</param>
136 /// <returns>The access token, or null if no incoming authorization message was recognized.</returns>
137 public GrantAccessTokenMessage
ProcessUserAuthorization(HttpRequest request
) {
138 return this.ProcessUserAuthorization(new HttpRequestInfo(request
));
142 /// Exchanges a given request token for access token.
144 /// <param name="requestToken">The request token that the user has authorized.</param>
145 /// <returns>The access token assigned by the Service Provider.</returns>
146 public GrantAccessTokenMessage
ProcessUserAuthorization(string requestToken
) {
147 string requestTokenSecret
= this.TokenManager
.GetTokenSecret(requestToken
);
148 var requestAccess
= new RequestAccessTokenMessage(this.ServiceProvider
.AccessTokenEndpoint
) {
149 RequestToken
= requestToken
,
150 TokenSecret
= requestTokenSecret
,
151 ConsumerKey
= this.ConsumerKey
,
152 ConsumerSecret
= this.ConsumerSecret
,
154 var grantAccess
= this.Channel
.Request
<GrantAccessTokenMessage
>(requestAccess
);
155 this.TokenManager
.ExpireRequestTokenAndStoreNewAccessToken(this.ConsumerKey
, requestToken
, grantAccess
.AccessToken
, grantAccess
.TokenSecret
);
160 /// Creates a web request prepared with OAuth authorization
161 /// that may be further tailored by adding parameters by the caller.
163 /// <param name="endpoint">The URL and method on the Service Provider to send the request to.</param>
164 /// <param name="accessToken">The access token that permits access to the protected resource.</param>
165 /// <returns>The initialized WebRequest object.</returns>
166 public WebRequest
CreateAuthorizedRequest(MessageReceivingEndpoint endpoint
, string accessToken
) {
167 IDirectedProtocolMessage message
= this.CreateAuthorizedRequestInternal(endpoint
, accessToken
);
168 HttpWebRequest wr
= this.Channel
.InitializeRequest(message
);
173 /// Creates a web request prepared with OAuth authorization
174 /// that may be further tailored by adding parameters by the caller.
176 /// <param name="endpoint">The URL and method on the Service Provider to send the request to.</param>
177 /// <param name="accessToken">The access token that permits access to the protected resource.</param>
178 /// <returns>The initialized WebRequest object.</returns>
179 /// <exception cref="WebException">Thrown if the request fails for any reason after it is sent to the Service Provider.</exception>
180 public Response
SendAuthorizedRequest(MessageReceivingEndpoint endpoint
, string accessToken
) {
181 IDirectedProtocolMessage message
= this.CreateAuthorizedRequestInternal(endpoint
, accessToken
);
182 HttpWebRequest wr
= this.Channel
.InitializeRequest(message
);
183 return this.WebRequestHandler
.GetResponse(wr
);
187 /// Begins an OAuth authorization request and redirects the user to the Service Provider
188 /// to provide that authorization.
190 /// <param name="callback">
191 /// An optional Consumer URL that the Service Provider should redirect the
192 /// User Agent to upon successful authorization.
194 /// <param name="requestParameters">Extra parameters to add to the request token message. Optional.</param>
195 /// <param name="redirectParameters">Extra parameters to add to the redirect to Service Provider message. Optional.</param>
196 /// <param name="token">The request token that must be exchanged for an access token after the user has provided authorization.</param>
197 /// <returns>The pending user agent redirect based message to be sent as an HttpResponse.</returns>
198 internal Response
RequestUserAuthorization(Uri callback
, IDictionary
<string, string> requestParameters
, IDictionary
<string, string> redirectParameters
, out string token
) {
199 // Obtain an unauthorized request token.
200 var requestToken
= new RequestTokenMessage(this.ServiceProvider
.RequestTokenEndpoint
) {
201 ConsumerKey
= this.ConsumerKey
,
202 ConsumerSecret
= this.ConsumerSecret
,
204 requestToken
.AddNonOAuthParameters(requestParameters
);
205 var requestTokenResponse
= this.Channel
.Request
<UnauthorizedRequestTokenMessage
>(requestToken
);
206 this.TokenManager
.StoreNewRequestToken(requestToken
, requestTokenResponse
);
208 // Request user authorization.
209 var requestAuthorization
= new DirectUserToServiceProviderMessage(this.ServiceProvider
.UserAuthorizationEndpoint
) {
211 RequestToken
= requestTokenResponse
.RequestToken
,
213 requestAuthorization
.AddNonOAuthParameters(redirectParameters
);
214 token
= requestAuthorization
.RequestToken
;
215 return this.Channel
.Send(requestAuthorization
);
219 /// Processes an incoming authorization-granted message from an SP and obtains an access token.
221 /// <param name="request">The incoming HTTP request.</param>
222 /// <returns>The access token, or null if no incoming authorization message was recognized.</returns>
223 internal GrantAccessTokenMessage
ProcessUserAuthorization(HttpRequestInfo request
) {
224 DirectUserToConsumerMessage authorizationMessage
;
225 if (this.Channel
.TryReadFromRequest
<DirectUserToConsumerMessage
>(request
, out authorizationMessage
)) {
226 string requestToken
= authorizationMessage
.RequestToken
;
227 return this.ProcessUserAuthorization(requestToken
);
234 /// Creates a web request prepared with OAuth authorization
235 /// that may be further tailored by adding parameters by the caller.
237 /// <param name="endpoint">The URL and method on the Service Provider to send the request to.</param>
238 /// <param name="accessToken">The access token that permits access to the protected resource.</param>
239 /// <returns>The initialized WebRequest object.</returns>
240 internal AccessProtectedResourcesMessage
CreateAuthorizedRequestInternal(MessageReceivingEndpoint endpoint
, string accessToken
) {
241 if (endpoint
== null) {
242 throw new ArgumentNullException("endpoint");
244 if (String
.IsNullOrEmpty(accessToken
)) {
245 throw new ArgumentNullException("accessToken");
248 AccessProtectedResourcesMessage message
= new AccessProtectedResourcesMessage(endpoint
) {
249 AccessToken
= accessToken
,
250 TokenSecret
= this.TokenManager
.GetTokenSecret(accessToken
),
251 ConsumerKey
= this.ConsumerKey
,
252 ConsumerSecret
= this.ConsumerSecret
,