More public API work.
[dotnetoauth.git] / src / DotNetOAuth / Consumer.cs
blobaad9300f54b120aab22311a1448df5ff60bd1b1b
1 //-----------------------------------------------------------------------
2 // <copyright file="Consumer.cs" company="Andrew Arnott">
3 // Copyright (c) Andrew Arnott. All rights reserved.
4 // </copyright>
5 //-----------------------------------------------------------------------
7 namespace DotNetOAuth {
8 using System;
9 using System.Collections.Generic;
10 using System.Net;
11 using System.Web;
12 using DotNetOAuth.ChannelElements;
13 using DotNetOAuth.Messages;
14 using DotNetOAuth.Messaging;
15 using DotNetOAuth.Messaging.Bindings;
17 /// <summary>
18 /// A website or application that uses OAuth to access the Service Provider on behalf of the User.
19 /// </summary>
20 /// <remarks>
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.
23 /// </remarks>
24 public class Consumer {
25 /// <summary>
26 /// Initializes a new instance of the <see cref="Consumer"/> class.
27 /// </summary>
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;
46 /// <summary>
47 /// Gets or sets the Consumer Key used to communicate with the Service Provider.
48 /// </summary>
49 public string ConsumerKey { get; set; }
51 /// <summary>
52 /// Gets or sets the Consumer Secret used to communicate with the Service Provider.
53 /// </summary>
54 public string ConsumerSecret { get; set; }
56 /// <summary>
57 /// Gets the Service Provider that will be accessed.
58 /// </summary>
59 public ServiceProviderDescription ServiceProvider { get; private set; }
61 /// <summary>
62 /// Gets the persistence store for tokens and secrets.
63 /// </summary>
64 public ITokenManager TokenManager { get; private set; }
66 /// <summary>
67 /// Gets or sets the object that processes <see cref="HttpWebRequest"/>s.
68 /// </summary>
69 /// <remarks>
70 /// This defaults to a straightforward implementation, but can be set
71 /// to a mock object for testing purposes.
72 /// </remarks>
73 internal IWebRequestHandler WebRequestHandler { get; set; }
75 /// <summary>
76 /// Gets or sets the channel to use for sending/receiving messages.
77 /// </summary>
78 internal OAuthChannel Channel { get; set; }
80 /// <summary>
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.
84 /// </summary>
85 /// <returns>The pending user agent redirect based message to be sent as an HttpResponse.</returns>
86 /// <remarks>
87 /// Requires HttpContext.Current.
88 /// </remarks>
89 public Response RequestUserAuthorization() {
90 return this.RequestUserAuthorization(MessagingUtilities.GetRequestUrlFromContext(), null, null);
93 /// <summary>
94 /// Begins an OAuth authorization request and redirects the user to the Service Provider
95 /// to provide that authorization.
96 /// </summary>
97 /// <param name="callback">
98 /// An optional Consumer URL that the Service Provider should redirect the
99 /// User Agent to upon successful authorization.
100 /// </param>
101 /// <param name="requestParameters">Extra parameters to add to the request token message. Optional.</param>
102 /// <param name="redirectParameters">Extra parameters to add to the redirect to Service Provider message. Optional.</param>
103 /// <returns>The pending user agent redirect based message to be sent as an HttpResponse.</returns>
104 public Response RequestUserAuthorization(Uri callback, IDictionary<string, string> requestParameters, IDictionary<string, string> redirectParameters) {
105 // Obtain an unauthorized request token.
106 var requestToken = new RequestTokenMessage(this.ServiceProvider.RequestTokenEndpoint) {
107 ConsumerKey = this.ConsumerKey,
108 ConsumerSecret = this.ConsumerSecret,
110 requestToken.AddNonOAuthParameters(requestParameters);
111 var requestTokenResponse = this.Channel.Request<UnauthorizedRequestTokenMessage>(requestToken);
112 this.TokenManager.StoreNewRequestToken(this.ConsumerKey, requestTokenResponse.RequestToken, requestTokenResponse.TokenSecret, null/*TODO*/);
114 // Request user authorization.
115 var requestAuthorization = new DirectUserToServiceProviderMessage(this.ServiceProvider.UserAuthorizationEndpoint) {
116 Callback = callback,
117 RequestToken = requestTokenResponse.RequestToken,
119 requestAuthorization.AddNonOAuthParameters(redirectParameters);
120 return this.Channel.Send(requestAuthorization);
123 /// <summary>
124 /// Processes an incoming authorization-granted message from an SP and obtains an access token.
125 /// </summary>
126 /// <returns>The access token, or null if no incoming authorization message was recognized.</returns>
127 /// <remarks>
128 /// Requires HttpContext.Current.
129 /// </remarks>
130 public GrantAccessTokenMessage ProcessUserAuthorization() {
131 return this.ProcessUserAuthorization(this.Channel.GetRequestFromContext());
134 /// <summary>
135 /// Processes an incoming authorization-granted message from an SP and obtains an access token.
136 /// </summary>
137 /// <param name="request">The incoming HTTP request.</param>
138 /// <returns>The access token, or null if no incoming authorization message was recognized.</returns>
139 public GrantAccessTokenMessage ProcessUserAuthorization(HttpRequest request) {
140 return this.ProcessUserAuthorization(new HttpRequestInfo(request));
143 /// <summary>
144 /// Creates a web request prepared with OAuth authorization
145 /// that may be further tailored by adding parameters by the caller.
146 /// </summary>
147 /// <param name="endpoint">The URL and method on the Service Provider to send the request to.</param>
148 /// <param name="accessToken">The access token that permits access to the protected resource.</param>
149 /// <returns>The initialized WebRequest object.</returns>
150 public WebRequest CreateAuthorizedRequest(MessageReceivingEndpoint endpoint, string accessToken) {
151 IDirectedProtocolMessage message = this.CreateAuthorizedRequestInternal(endpoint, accessToken);
152 HttpWebRequest wr = this.Channel.InitializeRequest(message);
153 return wr;
156 /// <summary>
157 /// Creates a web request prepared with OAuth authorization
158 /// that may be further tailored by adding parameters by the caller.
159 /// </summary>
160 /// <param name="endpoint">The URL and method on the Service Provider to send the request to.</param>
161 /// <param name="accessToken">The access token that permits access to the protected resource.</param>
162 /// <returns>The initialized WebRequest object.</returns>
163 /// <exception cref="WebException">Thrown if the request fails for any reason after it is sent to the Service Provider.</exception>
164 public Response SendAuthorizedRequest(MessageReceivingEndpoint endpoint, string accessToken) {
165 IDirectedProtocolMessage message = this.CreateAuthorizedRequestInternal(endpoint, accessToken);
166 HttpWebRequest wr = this.Channel.InitializeRequest(message);
167 return this.WebRequestHandler.GetResponse(wr);
170 /// <summary>
171 /// Processes an incoming authorization-granted message from an SP and obtains an access token.
172 /// </summary>
173 /// <param name="request">The incoming HTTP request.</param>
174 /// <returns>The access token, or null if no incoming authorization message was recognized.</returns>
175 internal GrantAccessTokenMessage ProcessUserAuthorization(HttpRequestInfo request) {
176 DirectUserToConsumerMessage authorizationMessage;
177 if (this.Channel.TryReadFromRequest<DirectUserToConsumerMessage>(request, out authorizationMessage)) {
178 // Exchange request token for access token.
179 string requestTokenSecret = this.TokenManager.GetTokenSecret(authorizationMessage.RequestToken);
180 var requestAccess = new RequestAccessTokenMessage(this.ServiceProvider.AccessTokenEndpoint) {
181 RequestToken = authorizationMessage.RequestToken,
182 TokenSecret = requestTokenSecret,
183 ConsumerKey = this.ConsumerKey,
184 ConsumerSecret = this.ConsumerSecret,
186 var grantAccess = this.Channel.Request<GrantAccessTokenMessage>(requestAccess);
187 this.TokenManager.ExpireRequestTokenAndStoreNewAccessToken(this.ConsumerKey, authorizationMessage.RequestToken, grantAccess.AccessToken, grantAccess.TokenSecret);
188 return grantAccess;
189 } else {
190 return null;
194 /// <summary>
195 /// Creates a web request prepared with OAuth authorization
196 /// that may be further tailored by adding parameters by the caller.
197 /// </summary>
198 /// <param name="endpoint">The URL and method on the Service Provider to send the request to.</param>
199 /// <param name="accessToken">The access token that permits access to the protected resource.</param>
200 /// <returns>The initialized WebRequest object.</returns>
201 internal AccessProtectedResourcesMessage CreateAuthorizedRequestInternal(MessageReceivingEndpoint endpoint, string accessToken) {
202 if (endpoint == null) {
203 throw new ArgumentNullException("endpoint");
205 if (String.IsNullOrEmpty(accessToken)) {
206 throw new ArgumentNullException("accessToken");
209 AccessProtectedResourcesMessage message = new AccessProtectedResourcesMessage(endpoint) {
210 AccessToken = accessToken,
211 TokenSecret = this.TokenManager.GetTokenSecret(accessToken),
212 ConsumerKey = this.ConsumerKey,
213 ConsumerSecret = this.ConsumerSecret,
216 return message;