google-authsub 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. data/.gitignore +1 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README +98 -0
  4. data/Rakefile +19 -0
  5. data/VERSION +1 -0
  6. data/coverage/-Library-Ruby-Gems-1_8-gems-FakeWeb-1_1_2-lib-fake_net_http_rb.html +679 -0
  7. data/coverage/-Library-Ruby-Gems-1_8-gems-FakeWeb-1_1_2-lib-fake_web_rb.html +843 -0
  8. data/coverage/-Library-Ruby-Gems-1_8-gems-rcov-0_8_1_2_0-lib-rcov_rb.html +1598 -0
  9. data/coverage/index.html +360 -0
  10. data/coverage/lib-googleauthsub_rb.html +877 -0
  11. data/coverage/spec-googleauthsub_spec_rb.html +950 -0
  12. data/coverage/spec-spec_helper_rb.html +640 -0
  13. data/doc/classes/AuthEchoServlet.html +152 -0
  14. data/doc/classes/AuthEchoServlet.src/M000001.html +20 -0
  15. data/doc/classes/AuthEchoServlet.src/M000002.html +18 -0
  16. data/doc/classes/GData/AuthSubError.html +139 -0
  17. data/doc/classes/GData/AuthSubError.src/M000019.html +18 -0
  18. data/doc/classes/GData/Error.html +111 -0
  19. data/doc/classes/GData/GoogleAuthSub.html +521 -0
  20. data/doc/classes/GData/GoogleAuthSub.src/M000001.html +29 -0
  21. data/doc/classes/GData/GoogleAuthSub.src/M000002.html +22 -0
  22. data/doc/classes/GData/GoogleAuthSub.src/M000003.html +29 -0
  23. data/doc/classes/GData/GoogleAuthSub.src/M000004.html +22 -0
  24. data/doc/classes/GData/GoogleAuthSub.src/M000005.html +24 -0
  25. data/doc/classes/GData/GoogleAuthSub.src/M000006.html +19 -0
  26. data/doc/classes/GData/GoogleAuthSub.src/M000007.html +18 -0
  27. data/doc/classes/GData/GoogleAuthSub.src/M000008.html +18 -0
  28. data/doc/classes/GData/GoogleAuthSub.src/M000009.html +24 -0
  29. data/doc/classes/GData/GoogleAuthSub.src/M000010.html +25 -0
  30. data/doc/classes/GData/GoogleAuthSub.src/M000011.html +30 -0
  31. data/doc/classes/GData/GoogleAuthSub.src/M000012.html +18 -0
  32. data/doc/classes/GData/GoogleAuthSub.src/M000013.html +18 -0
  33. data/doc/classes/GData/GoogleAuthSub.src/M000014.html +18 -0
  34. data/doc/classes/GData/GoogleAuthSub.src/M000015.html +18 -0
  35. data/doc/classes/GData/GoogleAuthSub.src/M000016.html +20 -0
  36. data/doc/classes/GData/GoogleAuthSub.src/M000017.html +20 -0
  37. data/doc/classes/GData/GoogleAuthSub.src/M000018.html +19 -0
  38. data/doc/classes/GData.html +162 -0
  39. data/doc/created.rid +1 -0
  40. data/doc/files/googleauthsub_rb.html +140 -0
  41. data/doc/files/lib/googleauthsub_rb.html +140 -0
  42. data/doc/files/spec/googleauthsub_spec_rb.html +146 -0
  43. data/doc/files/spec/googleresponder_rb.html +121 -0
  44. data/doc/files/spec/spec_helper_rb.html +149 -0
  45. data/doc/fr_class_index.html +31 -0
  46. data/doc/fr_file_index.html +30 -0
  47. data/doc/fr_method_index.html +45 -0
  48. data/doc/index.html +24 -0
  49. data/doc/rdoc-style.css +208 -0
  50. data/google-authsub-0.0.2.gem +0 -0
  51. data/google-authsub-0.0.3.gem +0 -0
  52. data/google-authsub.gemspec +109 -0
  53. data/lib/googleauthsub.rb +271 -0
  54. data/live test/authsub_test.html +40 -0
  55. data/live test/gastest.rb +90 -0
  56. data/spec/googleauthsub_spec.rb +350 -0
  57. data/spec/googleresponder.rb +26 -0
  58. data/spec/mock responses/bad_token_info.txt +11 -0
  59. data/spec/mock responses/calendar.txt +11 -0
  60. data/spec/mock responses/revoke_token.txt +7 -0
  61. data/spec/mock responses/revoked_token.txt +17 -0
  62. data/spec/mock responses/session_token.txt +9 -0
  63. data/spec/mock responses/token_info.txt +11 -0
  64. data/spec/mock responses/unauthorized.txt +18 -0
  65. data/spec/mock_certs/test_private_key.pem +15 -0
  66. data/spec/mock_certs/test_public_key.pem +6 -0
  67. data/spec/spec_helper.rb +30 -0
  68. data/spec/spec_opts +7 -0
  69. metadata +125 -0
@@ -0,0 +1,350 @@
1
+ # GoogleAuthSub - Ruby on Rails plugin for Google Authorization
2
+ # # Copyright 2008 Stuart Coyle <stuart.coyle@gmail.com>
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+
24
+ require File.dirname(__FILE__) + '/spec_helper'
25
+ require 'fake_web'
26
+ require 'net/http'
27
+ require 'openssl'
28
+
29
+ include GData
30
+
31
+ describe GoogleAuthSub do
32
+
33
+ before do
34
+
35
+ @test_next_url = "http://www.example.com/next"
36
+ @test_scope_url = "http://www.google.com/calendar/feeds"
37
+
38
+ # Valid test token
39
+ @token = TOKEN
40
+
41
+ # Invalid test token
42
+ @invalid_token = INVALID_TOKEN
43
+ @session_token = SESSION_TOKEN
44
+
45
+ # Various URLs we expect to call
46
+ @valid_request_url = AUTHSUB_REQUEST_URL + "?next=http://www.example.com/next&scope=http://www.google.com/calendar/feeds&session=0&secure=0"
47
+ @valid_session_request_url = AUTHSUB_REQUEST_URL + "?next=http://www.example.com/next&scope=http://www.google.com/calendar/feeds&session=1&secure=0"
48
+ @valid_secure_session_url = AUTHSUB_REQUEST_URL + "?next=http://www.example.com/next&scope=http://www.google.com/calendar/feeds&session=1&secure=1"
49
+ @session_token_request_url = AUTHSUB_SESSION_TOKEN_URL
50
+ @token_revoke_url = AUTHSUB_REVOKE_TOKEN_URL
51
+ @token_info_url = AUTHSUB_TOKEN_INFO_URL
52
+ @data_request_url = @test_scope_url + "/default/private/full"
53
+
54
+ @authsub = GoogleAuthSub.new({:next_url => @test_next_url, :scope_url => @test_scope_url})
55
+
56
+ # Disable real network access
57
+ FakeWeb.allow_net_connect = false
58
+ end
59
+
60
+ describe "Methods GoogleAuthsubToken should have" do
61
+
62
+ it "should have a request_url method" do
63
+ @authsub.should respond_to(:request_url)
64
+ end
65
+
66
+ it "should have a request_session_token method" do
67
+ @authsub.should respond_to(:request_session_token)
68
+ end
69
+
70
+ it "should have an revoke_token method" do
71
+ @authsub.should respond_to(:revoke_token)
72
+ end
73
+
74
+ it "should have a token_info method" do
75
+ @authsub.should respond_to(:token_info)
76
+ end
77
+
78
+ it "should have a get method" do
79
+ @authsub.should respond_to(:get)
80
+ end
81
+
82
+ it "should have a post method" do
83
+ @authsub.should respond_to(:post)
84
+ end
85
+
86
+ it "should have a put method" do
87
+ @authsub.should respond_to(:put)
88
+ end
89
+
90
+ it "should have a delete method" do
91
+ @authsub.should respond_to(:delete)
92
+ end
93
+ end
94
+
95
+ describe "Request method - getting a single use token from Google" do
96
+
97
+ it "should redirect to request url" do
98
+ @authsub.request_url.to_s.should == @valid_request_url
99
+ end
100
+
101
+ it "should redirect to request url with session = true" do
102
+ @authsub.session = true
103
+ @authsub.request_url.to_s.should == @valid_session_request_url
104
+ end
105
+
106
+ it "should redirect to request url with secure = true" do
107
+ @authsub.session = true
108
+ @authsub.secure = true
109
+ @authsub.request_url.to_s.should == @valid_secure_session_url
110
+ end
111
+
112
+ it 'should raise an error if the scope URL is not a full path' do
113
+ @authsub.scope = "www.google.com/calendar/feeds"
114
+ lambda { @authsub.request_url }.should raise_error(AuthSubError)
115
+ end
116
+
117
+ it "should raise an error if the next_url is not a full path" do
118
+ @authsub.next_url = "www.schedy.com"
119
+ lambda { @authsub.request_url }.should raise_error(AuthSubError)
120
+ end
121
+ end
122
+
123
+ describe "Token Signatures" do
124
+ before(:all) do
125
+ # Private key for signing
126
+ f = File.open(File.dirname(__FILE__)+"/mock_certs/test_private_key.pem")
127
+ @private_key = OpenSSL::PKey::RSA.new(f.read)
128
+ @public_key = @private_key.public_key
129
+ GoogleAuthSub.set_private_key(@private_key)
130
+ end
131
+
132
+ before do
133
+ Time.stub!(:now).and_return(Time.local(2008,"mar",8,12,15,1)) # == 1204942501
134
+ OpenSSL::BN.stub!(:rand_range).and_return(100000000000000) # set our nonce to known value
135
+ FakeWeb.register_uri(:any, @data_request_url, :response => File.dirname(__FILE__)+"/mock responses/calendar.txt")
136
+ @authsub.secure = true
137
+ @authsub.token = @token
138
+ end
139
+
140
+ it "should have a signing algorithm" do
141
+ @authsub.should respond_to(:sigalg)
142
+ end
143
+
144
+ it "should have rsa-sha1 as the sigalg" do
145
+ @authsub.sigalg.should == 'rsa-sha1'
146
+ end
147
+
148
+ it "should generate a correct authorization header when not secure" do
149
+ @authsub.secure = false
150
+ @authsub.auth_header(Net::HTTP::Get.new(@data_request_url), @data_request_url).should == "AuthSub token=\"#{@token}\""
151
+ end
152
+
153
+
154
+ it "should have a correct token when secure" do
155
+ @authsub.auth_header(Net::HTTP::Get.new(@data_request_url), @data_request_url).should include("token=\"#{@token}\"")
156
+ end
157
+
158
+ # data = http-method SP http-request-URL SP timestamp SP nonce
159
+ it "should have a proper data parameter" do
160
+ @authsub.auth_header(Net::HTTP::Get.new(@data_request_url), @data_request_url).should include("data=\"GET #{@data_request_url} 1204942501 100000000000000\"")
161
+ end
162
+
163
+ it "should generate the correct signature" do
164
+ expected_sig = "GET #{@data_request_url} 1204942501 100000000000000"
165
+ sig = @authsub.auth_header(Net::HTTP::Get.new(@data_request_url), @data_request_url).match(/sig=\"([^\"]*)$/)[1]
166
+ @public_key.public_decrypt(sig.unpack("m").join).should == OpenSSL::Digest::SHA1.new(expected_sig).hexdigest
167
+ end
168
+
169
+ it "should generate a correct authorization header when secure" do
170
+ @authsub.auth_header(Net::HTTP::Get.new(@data_request_url), @data_request_url).should ==
171
+ "AuthSub token=\"CMScoaHmDxC80Y2pAg\" data=\"GET http://www.google.com/calendar/feeds/default/private/full 1204942501 100000000000000\" sig=\"5H44KRwb+B9dMraK0mxsVv3aSF+gCz1hz7FEMViYdl89rC/BXQkmW7Xb9/Xf\n226E5Q+RPtFd+DaK/mXFxtoOJBqlz7mZgV+QOrr/dxCM6HpjIpxF9Qxo9zCT\nKvz0IS4gxXCVMgEgJOdF3YjqZo2bMgiG/Wjm/774Yitkc2tKhL8=\n\" sigalg=\"rsa-sha1\""
172
+ end
173
+
174
+ end
175
+
176
+ describe "setting the private key" do
177
+ it "should take private key as a file" do
178
+ f = File.open(File.dirname(__FILE__)+"/mock_certs/test_private_key.pem")
179
+ GoogleAuthSub.set_private_key(f)
180
+ end
181
+
182
+ it "should take private key as a string" do
183
+ s = File.open(File.dirname(__FILE__)+"/mock_certs/test_private_key.pem").read
184
+ GoogleAuthSub.set_private_key(s)
185
+ end
186
+ end
187
+
188
+ describe "Token received from Google in response url. Note: in Rails this is simply params[:token]" do
189
+ before do
190
+ url = URI::HTTP.build({:host => "www.example.com", :path => "/next", :query => "token=#{@token}"})
191
+ @authsub.receive_token(url)
192
+ end
193
+
194
+ it "should find the token in the headers and save it" do
195
+ @authsub.token.should == @token
196
+ end
197
+
198
+ it "should retain current token value if no token is found" do
199
+ url = URI::HTTP.build({:host => "www.example.com", :path => "/next", :query => ""})
200
+ @authsub.receive_token(url)
201
+ @authsub.token.should == @token
202
+ end
203
+
204
+ end
205
+
206
+ describe "Getting a session token from google" do
207
+ before do
208
+ FakeWeb.register_uri(:get, @session_token_request_url, :response => File.dirname(__FILE__)+"/mock responses/session_token.txt")
209
+ end
210
+
211
+ it "should make request to correct url" do
212
+ @authsub.request_session_token.should be true
213
+ end
214
+
215
+ end
216
+
217
+ describe "Succesful receipt of a session token" do
218
+ before do
219
+ FakeWeb.register_uri(:any,@session_token_request_url, :response => File.dirname(__FILE__)+"/mock responses/session_token.txt")
220
+ end
221
+
222
+ it "should set session_token in session to correct value" do
223
+ @authsub.request_session_token
224
+ @authsub.token.should == @session_token
225
+ end
226
+ end
227
+
228
+ describe "Unsuccessful request for session token - revoked token" do
229
+ it "should raise a server exception error" do
230
+ FakeWeb.register_uri(:get,@session_token_request_url, :response => File.dirname(__FILE__)+"/mock responses/revoked_token.txt")
231
+ lambda {
232
+ @authsub.request_session_token
233
+ }.should raise_error(AuthSubError)
234
+ end
235
+ end
236
+
237
+ describe "Revoking a session token" do
238
+ before do
239
+ FakeWeb.register_uri(:get, @token_revoke_url, :response => File.dirname(__FILE__)+"/mock responses/revoke_token.txt")
240
+ @authsub.token = @token
241
+ end
242
+
243
+ it "should make request to correct url" do
244
+ @authsub.revoke_token.should be_true
245
+ end
246
+
247
+ it "should return false on an error" do
248
+ FakeWeb.register_uri(:get, @token_revoke_url, :response => File.dirname(__FILE__)+"/mock responses/unauthorized.txt")
249
+ @authsub.revoke_token.should be_false
250
+ end
251
+ end
252
+
253
+ describe "Getting token info from google" do
254
+ before do
255
+ FakeWeb.register_uri(:get,@token_info_url, :response => File.dirname(__FILE__)+"/mock responses/token_info.txt")
256
+ @authsub.token = @token
257
+ end
258
+
259
+ it "should make request to correct url" do
260
+ @authsub.token_info.should be_true
261
+ end
262
+
263
+ it "should return the info as [:target => target, :scope=> scope, :secure=> secure]" do
264
+ @authsub.token_info.should == {:target=>'http://www.example.com',
265
+ :scope=>'http://www.google.com/calendar/feeds/',
266
+ :secure=>true}
267
+ end
268
+
269
+ it "should throw an error on an incorrect response from Google" do
270
+ FakeWeb.register_uri(:get,@token_info_url, :response => File.dirname(__FILE__)+"/mock responses/bad_token_info.txt")
271
+ lambda{
272
+ @authsub.token_info
273
+ }.should raise_error(AuthSubError)
274
+ end
275
+ end
276
+
277
+
278
+ describe "GET data from google using the token" do
279
+ before do
280
+ FakeWeb.register_uri(:get, @data_request_url, :response => File.dirname(__FILE__)+"/mock responses/calendar.txt")
281
+ end
282
+
283
+ it "should append the scope to the url when it does not start with http://" do
284
+ lambda do
285
+ @authsub.get("/default/private/full")
286
+ end.should_not raise_error
287
+ end
288
+
289
+ it "should raise errors if there is an error in the response" do
290
+ FakeWeb.register_uri(:get,@data_request_url, :response => File.dirname(__FILE__)+"/mock responses/unauthorized.txt")
291
+ lambda{@authsub.get(@data_request_url)}.should raise_error(Net::HTTPServerException)
292
+ end
293
+
294
+ it "should pass the entire response as a Net::HTTPResponse object" do
295
+ @authsub.get(@data_request_url).should be_a_kind_of(Net::HTTPResponse)
296
+ end
297
+
298
+ it "should have the correct body" do
299
+ @authsub.get(@data_request_url).body.should == "This is my wonderful calendar!\nEmpty as usual.\nHire me!!"
300
+ end
301
+ end
302
+
303
+ describe "POST Data to Google using the token" do
304
+ before do
305
+ FakeWeb.register_uri(:post ,@data_request_url, :response => File.dirname(__FILE__)+"/mock responses/calendar.txt")
306
+ end
307
+
308
+ it "should append the scope to the url when it does not start with http://" do
309
+ lambda do
310
+ @authsub.post("/default/private/full")
311
+ end.should_not raise_error
312
+ end
313
+
314
+ it "should raise errors if there is an error in the response" do
315
+ FakeWeb.register_uri(:post, @data_request_url, :response => File.dirname(__FILE__)+"/mock responses/unauthorized.txt")
316
+ lambda{@authsub.post(@data_request_url)}.should raise_error(Net::HTTPServerException)
317
+ end
318
+
319
+ it "should pass the entire response as a Net::HTTPResponse object" do
320
+ @authsub.post(@data_request_url).should be_a_kind_of(Net::HTTPResponse)
321
+ end
322
+
323
+ it "should have the correct body" do
324
+ @authsub.post(@data_request_url).body.should == "This is my wonderful calendar!\nEmpty as usual.\nHire me!!"
325
+ end
326
+ end
327
+
328
+ describe "PUT to Google using the token" do
329
+ before do
330
+ FakeWeb.register_uri(:put,@data_request_url, :response => File.dirname(__FILE__)+"/mock responses/calendar.txt")
331
+ end
332
+
333
+ it "should recieve a PUT" do
334
+ lambda do
335
+ @authsub.put(@data_request_url)
336
+ end.should_not raise_error
337
+ end
338
+ end
339
+
340
+ describe "DELETE request to Google using the token" do
341
+ before do
342
+ FakeWeb.register_uri(:delete ,@data_request_url, :response => File.dirname(__FILE__)+"/mock responses/calendar.txt")
343
+ end
344
+ it "should recieve a DELETE" do
345
+ lambda do
346
+ @authsub.delete(@data_request_url)
347
+ end.should_not raise_error
348
+ end
349
+ end
350
+ end
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Currently unused...
4
+ require 'webrick'
5
+ include WEBrick
6
+
7
+ s = HTTPServer.new( :Port => 2000,
8
+ :SSLEnable => true
9
+ )
10
+
11
+ class AuthEchoServlet < HTTPServlet::AbstractServlet
12
+ def do_GET(req, res)
13
+ res.body = req[Authorization]
14
+ res['Content-Type'] = "text/html"
15
+
16
+ end
17
+
18
+ def do_PUT(req,res)
19
+
20
+ end
21
+ end
22
+ s.mount("/accounts", AuthEchoServlet)
23
+
24
+
25
+ trap("INT"){ s.shutdown }
26
+ s.start
@@ -0,0 +1,11 @@
1
+ HTTP/1.1 200 OK
2
+ Content-Type: text/plain; charset=UTF-8
3
+ Expires: Fri, 14 Mar 2008 10:56:31 GMT
4
+ Cache-Control: private, max-age=0
5
+ Content-Length: 85
6
+ Date: Fri, 14 Mar 2008 10:56:31 GMT
7
+ Server: GFE/1.3
8
+
9
+
10
+ Scope=http://www.google.com/calendar/feeds/
11
+ Secure=true
@@ -0,0 +1,11 @@
1
+ HTTP/1.1 200 OK
2
+ Content-Type: text/plain; charset=UTF-8
3
+ Expires: Fri, 14 Mar 2008 10:56:31 GMT
4
+ Cache-Control: private, max-age=0
5
+ Content-Length: 85
6
+ Date: Fri, 14 Mar 2008 10:56:31 GMT
7
+ Server: GFE/1.3
8
+
9
+ This is my wonderful calendar!
10
+ Empty as usual.
11
+ Hire me!!
@@ -0,0 +1,7 @@
1
+ HTTP/1.1 200 OK
2
+ Content-Type: text/html; charset=UTF-8
3
+ Expires: Sat, 15 Mar 2008 00:37:21 GMT
4
+ Cache-Control: private, max-age=0
5
+ Content-Length: 0
6
+ Date: Sat, 15 Mar 2008 00:37:21 GMT
7
+ Server: GFE/1.3
@@ -0,0 +1,17 @@
1
+ HTTP/1.1 403 Token was revoked
2
+ Content-Type: text/html; charset=UTF-8
3
+ Expires: Fri, 14 Mar 2008 10:54:39 GMT
4
+ Cache-Control: private, max-age=0
5
+ Content-Length: 157
6
+ Date: Fri, 14 Mar 2008 10:54:39 GMT
7
+ Server: GFE/1.3
8
+
9
+ <HTML>
10
+ <HEAD>
11
+ <TITLE>Token was revoked</TITLE>
12
+ </HEAD>
13
+ <BODY BGCOLOR="#FFFFFF" TEXT="#000000">
14
+ <H1>Token was revoked</H1>
15
+ <H2>Error 403</H2>
16
+ </BODY>
17
+ </HTML>
@@ -0,0 +1,9 @@
1
+ HTTP/1.1 200 OK
2
+ Content-Type: text/plain; charset=UTF-8
3
+ Expires: Fri, 14 Mar 2008 10:56:31 GMT
4
+ Cache-Control: private, max-age=0
5
+ Content-Length: 25
6
+ Date: Fri, 14 Mar 2008 10:56:31 GMT
7
+ Server: GFE/1.3
8
+
9
+ Token=CMScoaHmDxDM9dqPBA
@@ -0,0 +1,11 @@
1
+ HTTP/1.1 200 OK
2
+ Content-Type: text/plain; charset=UTF-8
3
+ Expires: Fri, 14 Mar 2008 10:56:31 GMT
4
+ Cache-Control: private, max-age=0
5
+ Content-Length: 85
6
+ Date: Fri, 14 Mar 2008 10:56:31 GMT
7
+ Server: GFE/1.3
8
+
9
+ Target=http://www.example.com
10
+ Scope=http://www.google.com/calendar/feeds/
11
+ Secure=true