Added code to determine the location of the discovery document.
[arvados.git] / lib / google / api_client / auth / oauth_1.rb
1 # Copyright 2010 Google Inc.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 require "addressable/uri"
16 require "oauth"
17
18 module Google #:nodoc:
19   class APIClient #:nodoc:
20     class OAuth1
21       ##
22       # The default OAuth 1.0a configuration values.  These may be overrided
23       # simply by passing in the same key to the constructor.
24       DEFAULTS = {
25         :request_token_uri =>
26           'https://www.google.com/accounts/OAuthGetRequestToken',
27         :authorization_uri =>
28           'https://www.google.com/accounts/OAuthAuthorizeToken',
29         :access_token_uri =>
30           'https://www.google.com/accounts/OAuthGetAccessToken',
31         :scopes => [],
32         :callback => OAuth::OUT_OF_BAND,
33         :display_name => nil,
34         :consumer_key => "anonymous",
35         :consumer_secret => "anonymous"
36       }
37       
38       ##
39       # A set of default configuration values specific to each service.  These
40       # may be overrided simply by passing in the same key to the constructor.
41       SERVICE_DEFAULTS = {
42         :buzz => {
43           :authorization_uri =>
44             'https://www.google.com/buzz/api/auth/OAuthAuthorizeToken',
45           :scopes => ["https://www.googleapis.com/auth/buzz"]
46         }
47       }
48
49       ##
50       # Creates a new OAuth 1.0a handler.  This object obtains the tokens from
51       # the provider and handles signing any requests to the API.
52       #
53       # @param [Hash] options
54       #   The configuration options.
55       #   <code>:service</code>::
56       #     The name of the service.
57       #   <code>:request_token_uri</code>::
58       #     The OAuth endpoint for obtaining a request token.
59       #   <code>:authorization_uri</code>::
60       #     The OAuth endpoint for obtaining user permission.
61       #   <code>:access_token_uri</code>::
62       #     The OAuth endpoint for obtaining an access token.
63       #   <code>:scopes</code>::
64       #     An <code>Array</code> of scopes that define the access being
65       #     requested to the API.
66       #   <code>:callback</code>::
67       #     The URI the user will be redirected to if access is granted to the
68       #     API.  For development purposes, the special value
69       #     <code>OAuth::OUT_OF_BAND</code> may also be used.
70       #   <code>:display_name</code>::
71       #     A human-readable service name to present to the user when they
72       #     visit the <code>:authorization_uri</code>.
73       #   <code>:consumer_key</code>::
74       #     The consumer key you registered with the Google Accounts API.
75       #   <code>:consumer_secret</code>::
76       #     The consumer secret issued to you when you registered with the
77       #     Google Accounts API.
78       #
79       # @return [Google::APIClient::OAuth1] The OAuth 1.0a handler.
80       def initialize(options={})
81         if options[:service] && SERVICE_DEFAULTS[options[:service]]
82           @options = DEFAULTS.merge(SERVICE_DEFAULTS[options[:service]])
83         else
84           @options = DEFAULTS.clone
85         end
86         @options.merge!(options)
87         @options[:request_token_uri] =
88           Addressable::URI.parse(@options[:request_token_uri])
89         @options[:authorization_uri] =
90           Addressable::URI.parse(@options[:authorization_uri])
91         @options[:access_token_uri] =
92           Addressable::URI.parse(@options[:access_token_uri])
93         if (@options[:request_token_uri].site !=
94             @options[:authorization_uri].site) ||
95             (@options[:request_token_uri].site !=
96             @options[:authorization_uri].site)
97           raise ArgumentError, "All OAuth endpoints must be on the same site."
98         end
99         @oauth_consumer = ::OAuth::Consumer.new(
100           @options[:consumer_key], @options[:consumer_secret], {
101             # This is an extremely unfortunate way to configure the consumer,
102             # but not worth forking or patching to resolve.  Yet.
103             :site               => @options[:request_token_uri].site,
104             :scheme             => :header,
105             :http_method        => :post,
106             :request_token_path => @options[:request_token_uri].request_uri,
107             :access_token_path  => @options[:access_token_uri].request_uri,
108             :authorize_path     => @options[:authorization_uri].request_uri
109           }
110         )
111       end
112       
113       ##
114       # Returns the configuration of the handler.  Configuration options that
115       # are not recognized by the handler are ignored.
116       #
117       # @return [Hash] The configuration options.
118       def options
119         return @options
120       end
121
122       ##
123       # Returns the current request token.  Obtains a new request token if
124       # one hasn't already been obtained.
125       #
126       # @return [OAuth::RequestToken] The request token.
127       def request_token
128         oauth_parameters = {
129           :oauth_callback => @options[:callback]
130         }
131         app_parameters = {
132           :scope => @options[:scopes].join(" ")
133         }
134         if @options[:display_name]
135           app_parameters[:xoauth_displayname] = @options[:display_name]
136         end
137         return @request_token ||= @oauth_consumer.get_request_token(
138           oauth_parameters,
139           app_parameters
140         )
141       end
142
143       ##
144       # Sets the request token for the handler.
145       #
146       # @param [OAuth::RequestToken] new_request_token The request token.
147       def request_token=(new_request_token)
148         if new_request_token.kind_of?(OAuth::RequestToken)
149           @request_token = new_request_token
150         else
151           raise TypeError,
152             "Expected OAuth::RequestToken, got #{new_request_token.class}."
153         end
154       end
155
156       ##
157       # Returns the current access token.  Obtains a new access token if
158       # one hasn't already been obtained.  An request token must have already
159       # been obtained and authorized or this method will fail.
160       #
161       # @return [OAuth::AccessToken] The access token.
162       def access_token
163         return @access_token ||=
164           @oauth_consumer.get_access_token(self.request_token)
165       end
166
167       ##
168       # Sets the access token for the handler.
169       #
170       # @param [OAuth::AccessToken] new_access_token The access token.
171       def access_token=(new_access_token)
172         if new_access_token.kind_of?(OAuth::AccessToken)
173           @access_token = new_access_token
174         else
175           raise TypeError,
176             "Expected OAuth::AccessToken, got #{new_access_token.class}."
177         end
178       end
179
180       ##
181       # Returns the list of scopes for the handler.
182       #
183       # @return [Array] An <code>Array</code> of access scopes.
184       def scopes
185         return @options[:scopes]
186       end
187
188       ##
189       # Returns the callback for the handler.
190       #
191       # @return [String] The OAuth 1.0a callback for the consumer.
192       def callback
193         return @options[:callback]
194       end
195
196       ##
197       # Returns a human-readable service name to present to the user when they
198       # visit the <code>:authorization_uri</code>.
199       #
200       # @return [String] The display name for the consumer.
201       def display_name
202         return @options[:display_name]
203       end
204
205       ##
206       # Returns the consumer key.
207       #
208       # @return [String]
209       #   The consumer key you registered with the Google Accounts API.
210       def consumer_key
211         return @oauth_consumer.key
212       end
213
214       ##
215       # Returns the consumer key.
216       #
217       # @return [String]
218       #   The consumer secret issued to you when you registered with the
219       #   Google Accounts API.
220       def consumer_secret
221         return @oauth_consumer.secret
222       end
223
224       ##
225       # Returns the request token URI.
226       #
227       # @return [String]
228       #   The OAuth endpoint for obtaining a request token.
229       def request_token_uri
230         return @oauth_consumer.request_token_url
231       end
232
233       ##
234       # Returns the authorization endpoint URI.  This URI is used to construct
235       # the {#authorization_uri}.
236       #
237       # @return [String]
238       #   The OAuth endpoint for obtaining user permission.
239       def authorization_endpoint_uri
240         return @oauth_consumer.authorize_url
241       end
242
243       ##
244       # Builds the authorization URI that the user will be redirected to. 
245       # Note that this value is derived from the
246       # {#authorization_endpoint_uri}.
247       #
248       # @param [Hash] parameters
249       #   The extra URI query parameters appended to the
250       #   {#authorization_endpoint_uri}.
251       #
252       # @return [String]
253       #   The URI to redirect the user to to obtain permission.
254       def authorization_uri(parameters={})
255         return self.request_token.authorize_url(parameters)
256       end
257
258       ##
259       # Returns the access token URI.
260       #
261       # @return [String]
262       #   The OAuth endpoint for obtaining an access token.
263       def access_token_uri
264         return @oauth_consumer.access_token_url
265       end
266     end
267   end
268 end