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.
- data/.gitignore +1 -0
- data/MIT-LICENSE +20 -0
- data/README +98 -0
- data/Rakefile +19 -0
- data/VERSION +1 -0
- data/coverage/-Library-Ruby-Gems-1_8-gems-FakeWeb-1_1_2-lib-fake_net_http_rb.html +679 -0
- data/coverage/-Library-Ruby-Gems-1_8-gems-FakeWeb-1_1_2-lib-fake_web_rb.html +843 -0
- data/coverage/-Library-Ruby-Gems-1_8-gems-rcov-0_8_1_2_0-lib-rcov_rb.html +1598 -0
- data/coverage/index.html +360 -0
- data/coverage/lib-googleauthsub_rb.html +877 -0
- data/coverage/spec-googleauthsub_spec_rb.html +950 -0
- data/coverage/spec-spec_helper_rb.html +640 -0
- data/doc/classes/AuthEchoServlet.html +152 -0
- data/doc/classes/AuthEchoServlet.src/M000001.html +20 -0
- data/doc/classes/AuthEchoServlet.src/M000002.html +18 -0
- data/doc/classes/GData/AuthSubError.html +139 -0
- data/doc/classes/GData/AuthSubError.src/M000019.html +18 -0
- data/doc/classes/GData/Error.html +111 -0
- data/doc/classes/GData/GoogleAuthSub.html +521 -0
- data/doc/classes/GData/GoogleAuthSub.src/M000001.html +29 -0
- data/doc/classes/GData/GoogleAuthSub.src/M000002.html +22 -0
- data/doc/classes/GData/GoogleAuthSub.src/M000003.html +29 -0
- data/doc/classes/GData/GoogleAuthSub.src/M000004.html +22 -0
- data/doc/classes/GData/GoogleAuthSub.src/M000005.html +24 -0
- data/doc/classes/GData/GoogleAuthSub.src/M000006.html +19 -0
- data/doc/classes/GData/GoogleAuthSub.src/M000007.html +18 -0
- data/doc/classes/GData/GoogleAuthSub.src/M000008.html +18 -0
- data/doc/classes/GData/GoogleAuthSub.src/M000009.html +24 -0
- data/doc/classes/GData/GoogleAuthSub.src/M000010.html +25 -0
- data/doc/classes/GData/GoogleAuthSub.src/M000011.html +30 -0
- data/doc/classes/GData/GoogleAuthSub.src/M000012.html +18 -0
- data/doc/classes/GData/GoogleAuthSub.src/M000013.html +18 -0
- data/doc/classes/GData/GoogleAuthSub.src/M000014.html +18 -0
- data/doc/classes/GData/GoogleAuthSub.src/M000015.html +18 -0
- data/doc/classes/GData/GoogleAuthSub.src/M000016.html +20 -0
- data/doc/classes/GData/GoogleAuthSub.src/M000017.html +20 -0
- data/doc/classes/GData/GoogleAuthSub.src/M000018.html +19 -0
- data/doc/classes/GData.html +162 -0
- data/doc/created.rid +1 -0
- data/doc/files/googleauthsub_rb.html +140 -0
- data/doc/files/lib/googleauthsub_rb.html +140 -0
- data/doc/files/spec/googleauthsub_spec_rb.html +146 -0
- data/doc/files/spec/googleresponder_rb.html +121 -0
- data/doc/files/spec/spec_helper_rb.html +149 -0
- data/doc/fr_class_index.html +31 -0
- data/doc/fr_file_index.html +30 -0
- data/doc/fr_method_index.html +45 -0
- data/doc/index.html +24 -0
- data/doc/rdoc-style.css +208 -0
- data/google-authsub-0.0.2.gem +0 -0
- data/google-authsub-0.0.3.gem +0 -0
- data/google-authsub.gemspec +109 -0
- data/lib/googleauthsub.rb +271 -0
- data/live test/authsub_test.html +40 -0
- data/live test/gastest.rb +90 -0
- data/spec/googleauthsub_spec.rb +350 -0
- data/spec/googleresponder.rb +26 -0
- data/spec/mock responses/bad_token_info.txt +11 -0
- data/spec/mock responses/calendar.txt +11 -0
- data/spec/mock responses/revoke_token.txt +7 -0
- data/spec/mock responses/revoked_token.txt +17 -0
- data/spec/mock responses/session_token.txt +9 -0
- data/spec/mock responses/token_info.txt +11 -0
- data/spec/mock responses/unauthorized.txt +18 -0
- data/spec/mock_certs/test_private_key.pem +15 -0
- data/spec/mock_certs/test_public_key.pem +6 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/spec_opts +7 -0
- metadata +125 -0
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Generated by jeweler
|
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
|
4
|
+
# -*- encoding: utf-8 -*-
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |s|
|
|
7
|
+
s.name = %q{google-authsub}
|
|
8
|
+
s.version = "0.0.4"
|
|
9
|
+
|
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
11
|
+
s.authors = ["Stuart Coyle", "Jesse Storimer"]
|
|
12
|
+
s.date = %q{2010-01-22}
|
|
13
|
+
s.description = %q{GoogleAuthSub provides the Google Authentications for Web Applications API.}
|
|
14
|
+
s.email = %q{stuart.coyle@gmail.com}
|
|
15
|
+
s.extra_rdoc_files = [
|
|
16
|
+
"README"
|
|
17
|
+
]
|
|
18
|
+
s.files = [
|
|
19
|
+
".gitignore",
|
|
20
|
+
"MIT-LICENSE",
|
|
21
|
+
"README",
|
|
22
|
+
"Rakefile",
|
|
23
|
+
"VERSION",
|
|
24
|
+
"coverage/-Library-Ruby-Gems-1_8-gems-FakeWeb-1_1_2-lib-fake_net_http_rb.html",
|
|
25
|
+
"coverage/-Library-Ruby-Gems-1_8-gems-FakeWeb-1_1_2-lib-fake_web_rb.html",
|
|
26
|
+
"coverage/-Library-Ruby-Gems-1_8-gems-rcov-0_8_1_2_0-lib-rcov_rb.html",
|
|
27
|
+
"coverage/index.html",
|
|
28
|
+
"coverage/lib-googleauthsub_rb.html",
|
|
29
|
+
"coverage/spec-googleauthsub_spec_rb.html",
|
|
30
|
+
"coverage/spec-spec_helper_rb.html",
|
|
31
|
+
"doc/classes/AuthEchoServlet.html",
|
|
32
|
+
"doc/classes/AuthEchoServlet.src/M000001.html",
|
|
33
|
+
"doc/classes/AuthEchoServlet.src/M000002.html",
|
|
34
|
+
"doc/classes/GData.html",
|
|
35
|
+
"doc/classes/GData/AuthSubError.html",
|
|
36
|
+
"doc/classes/GData/AuthSubError.src/M000019.html",
|
|
37
|
+
"doc/classes/GData/Error.html",
|
|
38
|
+
"doc/classes/GData/GoogleAuthSub.html",
|
|
39
|
+
"doc/classes/GData/GoogleAuthSub.src/M000001.html",
|
|
40
|
+
"doc/classes/GData/GoogleAuthSub.src/M000002.html",
|
|
41
|
+
"doc/classes/GData/GoogleAuthSub.src/M000003.html",
|
|
42
|
+
"doc/classes/GData/GoogleAuthSub.src/M000004.html",
|
|
43
|
+
"doc/classes/GData/GoogleAuthSub.src/M000005.html",
|
|
44
|
+
"doc/classes/GData/GoogleAuthSub.src/M000006.html",
|
|
45
|
+
"doc/classes/GData/GoogleAuthSub.src/M000007.html",
|
|
46
|
+
"doc/classes/GData/GoogleAuthSub.src/M000008.html",
|
|
47
|
+
"doc/classes/GData/GoogleAuthSub.src/M000009.html",
|
|
48
|
+
"doc/classes/GData/GoogleAuthSub.src/M000010.html",
|
|
49
|
+
"doc/classes/GData/GoogleAuthSub.src/M000011.html",
|
|
50
|
+
"doc/classes/GData/GoogleAuthSub.src/M000012.html",
|
|
51
|
+
"doc/classes/GData/GoogleAuthSub.src/M000013.html",
|
|
52
|
+
"doc/classes/GData/GoogleAuthSub.src/M000014.html",
|
|
53
|
+
"doc/classes/GData/GoogleAuthSub.src/M000015.html",
|
|
54
|
+
"doc/classes/GData/GoogleAuthSub.src/M000016.html",
|
|
55
|
+
"doc/classes/GData/GoogleAuthSub.src/M000017.html",
|
|
56
|
+
"doc/classes/GData/GoogleAuthSub.src/M000018.html",
|
|
57
|
+
"doc/created.rid",
|
|
58
|
+
"doc/files/googleauthsub_rb.html",
|
|
59
|
+
"doc/files/lib/googleauthsub_rb.html",
|
|
60
|
+
"doc/files/spec/googleauthsub_spec_rb.html",
|
|
61
|
+
"doc/files/spec/googleresponder_rb.html",
|
|
62
|
+
"doc/files/spec/spec_helper_rb.html",
|
|
63
|
+
"doc/fr_class_index.html",
|
|
64
|
+
"doc/fr_file_index.html",
|
|
65
|
+
"doc/fr_method_index.html",
|
|
66
|
+
"doc/index.html",
|
|
67
|
+
"doc/rdoc-style.css",
|
|
68
|
+
"google-authsub-0.0.2.gem",
|
|
69
|
+
"google-authsub-0.0.3.gem",
|
|
70
|
+
"google-authsub.gemspec",
|
|
71
|
+
"lib/googleauthsub.rb",
|
|
72
|
+
"live test/authsub_test.html",
|
|
73
|
+
"live test/gastest.rb",
|
|
74
|
+
"spec/googleauthsub_spec.rb",
|
|
75
|
+
"spec/googleresponder.rb",
|
|
76
|
+
"spec/mock responses/bad_token_info.txt",
|
|
77
|
+
"spec/mock responses/calendar.txt",
|
|
78
|
+
"spec/mock responses/revoke_token.txt",
|
|
79
|
+
"spec/mock responses/revoked_token.txt",
|
|
80
|
+
"spec/mock responses/session_token.txt",
|
|
81
|
+
"spec/mock responses/token_info.txt",
|
|
82
|
+
"spec/mock responses/unauthorized.txt",
|
|
83
|
+
"spec/mock_certs/test_private_key.pem",
|
|
84
|
+
"spec/mock_certs/test_public_key.pem",
|
|
85
|
+
"spec/spec_helper.rb",
|
|
86
|
+
"spec/spec_opts"
|
|
87
|
+
]
|
|
88
|
+
s.homepage = %q{http://github.com/stuart/google-authsub/tree/master}
|
|
89
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
|
90
|
+
s.require_paths = ["lib"]
|
|
91
|
+
s.rubygems_version = %q{1.3.5}
|
|
92
|
+
s.summary = %q{A ruby implementation of Google Authentication for Web Applications API}
|
|
93
|
+
s.test_files = [
|
|
94
|
+
"spec/googleauthsub_spec.rb",
|
|
95
|
+
"spec/googleresponder.rb",
|
|
96
|
+
"spec/spec_helper.rb"
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
if s.respond_to? :specification_version then
|
|
100
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
|
101
|
+
s.specification_version = 3
|
|
102
|
+
|
|
103
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
|
104
|
+
else
|
|
105
|
+
end
|
|
106
|
+
else
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# AuthSub - Ruby library for Google Authorization
|
|
2
|
+
# # Copyright 2008-2009 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
|
+
require 'uri'
|
|
24
|
+
require 'net/https'
|
|
25
|
+
require 'openssl'
|
|
26
|
+
require 'base64'
|
|
27
|
+
require 'cgi'
|
|
28
|
+
|
|
29
|
+
# Note: The module declared here may change depending on what other developers are using.
|
|
30
|
+
#
|
|
31
|
+
module GData
|
|
32
|
+
|
|
33
|
+
GOOGLE_HOST_URL = "www.google.com"
|
|
34
|
+
GOOGLE_AUTHSUB_BASE_PATH = "/accounts"
|
|
35
|
+
GOOGLE_AUTHSUB_REQUEST_PATH = GOOGLE_AUTHSUB_BASE_PATH + "/AuthSubRequest"
|
|
36
|
+
GOOGLE_AUTHSUB_SESSION_TOKEN_PATH = GOOGLE_AUTHSUB_BASE_PATH + "/AuthSubSessionToken"
|
|
37
|
+
GOOGLE_AUTHSUB_REVOKE_PATH = GOOGLE_AUTHSUB_BASE_PATH + "/AuthSubRevokeToken"
|
|
38
|
+
GOOGLE_AUTHSUB_TOKEN_INFO_PATH = GOOGLE_AUTHSUB_BASE_PATH + "/AuthSubTokenInfo"
|
|
39
|
+
|
|
40
|
+
class Error < Exception
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
class AuthSubError < Error
|
|
44
|
+
def message
|
|
45
|
+
"Google Authentication Error" << " : #{@message}" if @message
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# GoogleAuthSub
|
|
51
|
+
# This class handles the Google Authentication for Web Applications API
|
|
52
|
+
#
|
|
53
|
+
class GoogleAuthSub
|
|
54
|
+
|
|
55
|
+
attr_accessor :target, :scope, :session, :secure, :next_url, :token, :sigalg
|
|
56
|
+
|
|
57
|
+
# +key+ can be a File, String or OpenSSL::Pkey::RSA
|
|
58
|
+
# Sets the private key to use for secure sessions.
|
|
59
|
+
# This should correspond to the public key sent to Google in
|
|
60
|
+
# the registration process.
|
|
61
|
+
# For registration details see:
|
|
62
|
+
# http://code.google.com/apis/accounts/docs/RegistrationForWebAppsAuto.html
|
|
63
|
+
#
|
|
64
|
+
# This sets the class variable @@pkey to an OpenSSL::Pkey::RSA object
|
|
65
|
+
#
|
|
66
|
+
def self.set_private_key(key)
|
|
67
|
+
case key
|
|
68
|
+
when OpenSSL::PKey::RSA
|
|
69
|
+
@@pkey = key
|
|
70
|
+
when File
|
|
71
|
+
# Read key from a PEM file.
|
|
72
|
+
@@pkey = OpenSSL::PKey::RSA.new(key.read)
|
|
73
|
+
when String
|
|
74
|
+
# Get key from a PEM in the form of a string.
|
|
75
|
+
@@pkey = OpenSSL::PKey::RSA.new(key)
|
|
76
|
+
else
|
|
77
|
+
raise AuthSubError, "Private Key in wrong format. Require IO, String or OpenSSL::Pkey::RSA, you gave me #{key.class}"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Create a new GoogleAuthsub object
|
|
82
|
+
# Options specified in +opts+ consist of:
|
|
83
|
+
#
|
|
84
|
+
# * :next_url - (String) The url to redirect back to once the user has signed in to Google.
|
|
85
|
+
# * :scope_url - (String) The service from Google that you wish to receive data from with this token.
|
|
86
|
+
# * :session - (boolean) Whether the token is able to be used to get a session token or is just one use.
|
|
87
|
+
# * :secure - (boolean) Whether the token can be used for sessions.
|
|
88
|
+
# * :sigalg - (String) Currently not needed, as the Authsub specification only has rsa-sha1.
|
|
89
|
+
def initialize(opts = {})
|
|
90
|
+
self.next_url = opts[:next_url] || ''
|
|
91
|
+
self.scope = opts[:scope_url] || ''
|
|
92
|
+
self.session = opts[:session] || false
|
|
93
|
+
self.secure = opts[:secure] || false
|
|
94
|
+
self.sigalg = opts[:sigalg] || "rsa-sha1"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# This returns a URI::HTTPS object which contains the Google url to request a token from.
|
|
98
|
+
def request_url
|
|
99
|
+
raise AuthSubError, "Invalid next URL: #{@next_url}" if !full_url?(@next_url)
|
|
100
|
+
raise AuthSubError, "Invalid scope URL: #{@scope}" if !full_url?(@scope)
|
|
101
|
+
query = "next=" << @next_url << "&scope=" << @scope << "&session="<<
|
|
102
|
+
(session_token? ? '1' : '0')<< "&secure="<< (secure_token? ? '1' : '0')
|
|
103
|
+
query = URI.encode(query)
|
|
104
|
+
URI::HTTPS.build({:host => GOOGLE_HOST_URL, :path => GOOGLE_AUTHSUB_REQUEST_PATH, :query => query })
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# +url+ :the URL received from Google once the user has signed in.
|
|
108
|
+
#
|
|
109
|
+
# This method extracts the token from the request url that Google
|
|
110
|
+
# sends the user back to.
|
|
111
|
+
# This url will be like: http://www.example.com/next?Token=CMDshfjfkeodf
|
|
112
|
+
# In Rails applications you don't need this method, just use
|
|
113
|
+
# +GoogleAuthsub#token=params[:token]+
|
|
114
|
+
#
|
|
115
|
+
def receive_token(url)
|
|
116
|
+
raise AuthSubError, "receive_token() was not passed a url, #{@url.class} received instead." if !url.class == URI::HTTP
|
|
117
|
+
q = url.query.match( /.*token=(.*)/i) if !url.query.nil?
|
|
118
|
+
@token = q[1] if !q.nil?
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Returns true if this token can be exchanged for a session token
|
|
122
|
+
def session_token?
|
|
123
|
+
session == true
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Returns true if the token is used for secure sessions
|
|
127
|
+
def secure_token?
|
|
128
|
+
secure == true
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# request_session_token
|
|
132
|
+
# This method exchanges a previously received single use token with a session token.
|
|
133
|
+
# Raises error if an invalid response is received.
|
|
134
|
+
def request_session_token
|
|
135
|
+
url = URI::HTTPS.build({:host => GOOGLE_HOST_URL,
|
|
136
|
+
:path => GOOGLE_AUTHSUB_SESSION_TOKEN_PATH})
|
|
137
|
+
begin
|
|
138
|
+
response = get(url)
|
|
139
|
+
rescue
|
|
140
|
+
raise AuthSubError, "Invalid session token response."
|
|
141
|
+
end
|
|
142
|
+
@token = response.body.match(/^Token=(.*)$/)[1]
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# revoke_token
|
|
146
|
+
# This revokes either a single use or session token
|
|
147
|
+
# The token will not be able to be used again if this call is successful.
|
|
148
|
+
# It returns true on sucess, false on failure.
|
|
149
|
+
def revoke_token
|
|
150
|
+
url = URI::HTTPS.build({:host=>GOOGLE_HOST_URL,
|
|
151
|
+
:path => GOOGLE_AUTHSUB_REVOKE_PATH})
|
|
152
|
+
begin
|
|
153
|
+
response = get(url)
|
|
154
|
+
true
|
|
155
|
+
rescue
|
|
156
|
+
false
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# token_info
|
|
161
|
+
# Returns the information for the session token from Google.
|
|
162
|
+
# Returns a map {:target, :scope, :secure}
|
|
163
|
+
def token_info
|
|
164
|
+
url = URI::HTTPS.build({:host=>GOOGLE_HOST_URL,
|
|
165
|
+
:path => GOOGLE_AUTHSUB_TOKEN_INFO_PATH})
|
|
166
|
+
response = get(url)
|
|
167
|
+
info = Hash.new
|
|
168
|
+
begin
|
|
169
|
+
info[:target] = response.body.match(/^Target=(.*)$/)[1]
|
|
170
|
+
info[:scope] = response.body.match(/^Scope=(.*)$/)[1]
|
|
171
|
+
info[:secure] = (response.body.match(/^Secure=(.*)$/)[1].downcase == 'true')
|
|
172
|
+
rescue
|
|
173
|
+
raise AuthSubError, "Google Authsub Error: invalid token info packet received."
|
|
174
|
+
end
|
|
175
|
+
return info
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# get +url+s
|
|
179
|
+
# Does a HTTP GET request to Google using the AuthSub token.
|
|
180
|
+
# This returns a Net::HTTPResponse object.
|
|
181
|
+
def get(url)
|
|
182
|
+
authsub_http_request(Net::HTTP::Get,url)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# post +url+
|
|
186
|
+
# Does a HTTP POST request to Google using the AuthSub token.
|
|
187
|
+
# This returns a Net::HTTPResponse object.
|
|
188
|
+
def post(url)
|
|
189
|
+
authsub_http_request(Net::HTTP::Post,url)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# put +url+
|
|
193
|
+
# Does a HTTP PUT request to Google using the AuthSub token.
|
|
194
|
+
# This returns a Net::HTTPResponse object.
|
|
195
|
+
def put(url)
|
|
196
|
+
authsub_http_request(Net::HTTP::Put,url)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# delete +url+
|
|
200
|
+
# Does a HTTP DELETE request to Google using the AuthSub token.
|
|
201
|
+
# This returns a Net::HTTPResponse object.
|
|
202
|
+
def delete(url)
|
|
203
|
+
authsub_http_request(Net::HTTP::Delete,url)
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
private
|
|
207
|
+
|
|
208
|
+
def authsub_http_request(method, u) #:nodoc:
|
|
209
|
+
case u
|
|
210
|
+
when String
|
|
211
|
+
# Add scope
|
|
212
|
+
u = (@scope << u) if @scope && !u.include?(@scope)
|
|
213
|
+
begin
|
|
214
|
+
url = URI.parse(u)
|
|
215
|
+
rescue URI::InvalidURIError
|
|
216
|
+
raise URI::InvalidURIError
|
|
217
|
+
end
|
|
218
|
+
when URI
|
|
219
|
+
url = u
|
|
220
|
+
else
|
|
221
|
+
raise AuthSubError, "url must be String or URI, #{url.class} received."
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
if method.superclass != Net::HTTPRequest
|
|
225
|
+
raise AuthSubError, "method must be a Net::HTTPRequest subclass (GET POST PUT DELETE). #{method} received."
|
|
226
|
+
end
|
|
227
|
+
request = method.new(url.path)
|
|
228
|
+
request['Authorization'] = authorization_header(request, url)
|
|
229
|
+
connection = Net::HTTP.new(url.host, url.port)
|
|
230
|
+
connection.use_ssl= (url.scheme == 'https')
|
|
231
|
+
response = connection.start{ |http| http.request(request) }
|
|
232
|
+
case response
|
|
233
|
+
when Net::HTTPSuccess
|
|
234
|
+
#OK
|
|
235
|
+
else
|
|
236
|
+
response.error!
|
|
237
|
+
end
|
|
238
|
+
response
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# Construct the authorization header for a request
|
|
242
|
+
def authorization_header(request, url)
|
|
243
|
+
case secure_token?
|
|
244
|
+
when false
|
|
245
|
+
return "AuthSub token=\"#{@token}\""
|
|
246
|
+
when true
|
|
247
|
+
timestamp = Time.now.to_i
|
|
248
|
+
nonce = OpenSSL::BN.rand_range(2**64)
|
|
249
|
+
data = request.method + ' ' + url.to_s + ' ' + timestamp.to_s + ' ' + nonce.to_s
|
|
250
|
+
digest = OpenSSL::Digest::SHA1.new(data).hexdigest
|
|
251
|
+
sig = [@@pkey.private_encrypt(digest)].pack("m") #Base64 encode
|
|
252
|
+
return "AuthSub token=\"#{@token}\" data=\"#{data}\" sig=\"#{sig}\" sigalg=\"#{@sigalg}\""
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# Checks whether a URL is a full url, i.e. has all of scheme, host and path.
|
|
257
|
+
def full_url?(url)
|
|
258
|
+
# First check if it is a bad uri
|
|
259
|
+
begin
|
|
260
|
+
u = URI.parse(url)
|
|
261
|
+
rescue URI.InvalidURIError
|
|
262
|
+
return false
|
|
263
|
+
end
|
|
264
|
+
return false if u.scheme.nil? || u.host.nil? || u.path.nil?
|
|
265
|
+
true
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
end
|
|
271
|
+
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
|
2
|
+
"http://www.w3.org/TR/html4/strict.dtd">
|
|
3
|
+
|
|
4
|
+
<html lang="en">
|
|
5
|
+
<head>
|
|
6
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
7
|
+
<title>authsub_test</title>
|
|
8
|
+
<meta name="generator" content="TextMate http://macromates.com/">
|
|
9
|
+
<meta name="author" content="stuart">
|
|
10
|
+
<!-- Date: 2008-08-20 -->
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<h2>Google Authsub Test</h2>
|
|
14
|
+
<p>These pages test the Ruby google-authsub library and explain how to use it.</p>
|
|
15
|
+
<h3>STEP 1: <i>Request a token from Google</i></h3>
|
|
16
|
+
<p>For a web app to access Google's services. We need to get an authorization token from Google.</p>
|
|
17
|
+
|
|
18
|
+
<p>We will create our GoogleAuthSub object something like this:</p>
|
|
19
|
+
<p> <code>auth = GoogleAuthSub.new(:next_url=>"http://www.schedy.com/test2.html, :session=>false, :secure=>false, :scope=>"http://google.com/calendar/feeds")</code>
|
|
20
|
+
</p>
|
|
21
|
+
<p>The url to redirect to is found from <code>auth.request_url</code>. It is then up to the application to perform this redirect.
|
|
22
|
+
</p>
|
|
23
|
+
<p>If the request is successful and the user logs in correctly, the user will be redirected back to the <code>auth.next_url</code>
|
|
24
|
+
</p>
|
|
25
|
+
<p>To try it, use the form below and press 'Continue'</p>
|
|
26
|
+
<form action="authsub_test_2" method="get" accept-charset="utf-8">
|
|
27
|
+
<h3>Google Authsub Token Attributes</h3>
|
|
28
|
+
<b>Token Type</b><p>If session is selected, the token will be able to be exchanged for a session (i.e. multiple use) token.</p><nbsp>
|
|
29
|
+
Session:<input type="radio" name="session" value="true" id="session">
|
|
30
|
+
Single Use:<input type="radio" name="session" value="false" id="session" checked="true"><br/><br/>
|
|
31
|
+
<b>Secure (use https)</b><p>If secure=true, this token will be used for secure exchanges using https. The web application site must be registered with Google and have the correct certificate for this to work.</p><nbsp>
|
|
32
|
+
True<input type="radio" name="secure" value="true" id="session">
|
|
33
|
+
False<input type="radio" name="secure" value="false" id="session" checked="true"><br/><br/>
|
|
34
|
+
<b>Scope:</b>
|
|
35
|
+
<input type="text" name="scope" value="http://google.com/calendar/feeds" id="scope" size="60">
|
|
36
|
+
<p><input type="submit" value="Continue →"></p>
|
|
37
|
+
</form>
|
|
38
|
+
<div id=request_url></div>
|
|
39
|
+
</body>
|
|
40
|
+
</html>
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
#require 'rubygems'
|
|
4
|
+
require '../lib/googleauthsub'
|
|
5
|
+
require 'webrick'
|
|
6
|
+
include WEBrick
|
|
7
|
+
include GData
|
|
8
|
+
|
|
9
|
+
s = HTTPServer.new( :Port => 2000,
|
|
10
|
+
:SSLEnable => true
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
class SimpleAuthServlet < HTTPServlet::AbstractServlet
|
|
14
|
+
def do_GET(req, res)
|
|
15
|
+
@@auth.next_url="http://schedy.com:2000/simpletest"
|
|
16
|
+
@@auth.receive_token(req.request_uri);
|
|
17
|
+
url = @@auth.request_url.to_s
|
|
18
|
+
res.body = << END_RESPONSE
|
|
19
|
+
<html><head></head><body><h2>Google-Authsub Test</h2>
|
|
20
|
+
<p>TOKEN: #{req.query_string.to_s}</p>
|
|
21
|
+
<p><a href= #{url}>Request GoogleAuthsub Token</a></p>
|
|
22
|
+
<p><a href=/tokeninfo>Token Information</a></body></html>
|
|
23
|
+
END_RESPONSE
|
|
24
|
+
res['Content-Type'] = "text/html"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class SessionAuthServlet < HTTPServlet::AbstractServlet
|
|
30
|
+
def do_GET(req, res)
|
|
31
|
+
@@auth.session = true
|
|
32
|
+
@@auth.receive_token(req.request_uri)
|
|
33
|
+
@@auth.request_session_token if !@@auth.token.nil?
|
|
34
|
+
url = @@auth.request_url.to_s
|
|
35
|
+
res.body = "<html><head></head><body><h2>Google-Authsub Test</h2><p>Session Token</p><p>TOKEN: "+req.query_string.to_s+
|
|
36
|
+
"</p><p><a href="+ url +
|
|
37
|
+
">Request GoogleAuthsub Token</a></p><p><a href=/tokeninfo>Token Information</a></body></html>"
|
|
38
|
+
res['Content-Type'] = "text/html"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
class SecureAuthServlet < HTTPServlet::AbstractServlet
|
|
43
|
+
def do_GET(req, res)
|
|
44
|
+
@@auth.next_url="http://schedy.com:2000/sessiontest"
|
|
45
|
+
@@auth.session = true
|
|
46
|
+
@@auth.secure = true
|
|
47
|
+
@@auth.receive_token(req.request_uri);
|
|
48
|
+
url = @@auth.request_url.to_s
|
|
49
|
+
res.body = "<html><head></head><body><h2>Google-Authsub Test</h2><p>Secure Token</p><p>TOKEN: "+req.query_string.to_s+
|
|
50
|
+
"</p><p><a href="+ url +
|
|
51
|
+
">Request GoogleAuthsub Token</a></p><p>INFO:<a href=/tokeninfo>Token Information</a>"
|
|
52
|
+
"</body></html>"
|
|
53
|
+
res['Content-Type'] = "text/html"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
class TokenInfoServlet < HTTPServlet::AbstractServlet
|
|
58
|
+
def do_GET(req, res)
|
|
59
|
+
info = @@auth.token_info
|
|
60
|
+
res.body = "<html><head></head><body><h2>Google-Authsub Test</h2><p>TOKEN INFORMATION<ul>" +
|
|
61
|
+
"<li>Target: "+ info[:target] + "</li>" +
|
|
62
|
+
"<li>Secure: "+ info[:secure].to_s + "</li>" +
|
|
63
|
+
"<li>Scope: "+ info[:scope] + "</li>" +
|
|
64
|
+
"</ul></ul></p></body></html>"
|
|
65
|
+
res['Content-Type'] = "text/html"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
class CalendarServlet < HTTPServlet::AbstractServlet
|
|
69
|
+
def do_GET(req, res)
|
|
70
|
+
res = @@auth.get("http://www.google.com/calendar/feeds/default/owncalendars/full")
|
|
71
|
+
res['Content-Type'] = "text/html"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
@@auth = GoogleAuthSub.new(:scope_url=>"http://www.google.com/calendar/feeds");
|
|
77
|
+
#s.mount("/authsub_test",AuthSub1Servlet)
|
|
78
|
+
#s.mount("/authsub_test_2",AuthSub2Servlet)
|
|
79
|
+
|
|
80
|
+
# Assume we have the private key in the file google.key
|
|
81
|
+
GoogleAuthSub.set_private_key("google.key")
|
|
82
|
+
|
|
83
|
+
s.mount("/simpletest", SimpleAuthServlet)
|
|
84
|
+
s.mount("/tokeninfo",TokenInfoServlet)
|
|
85
|
+
s.mount("/sessiontest", SessionAuthServlet)
|
|
86
|
+
s.mount("/securetest", SecureAuthServlet)
|
|
87
|
+
s.mount("/mycalendars", CalendarServlet)
|
|
88
|
+
|
|
89
|
+
trap("INT"){ s.shutdown }
|
|
90
|
+
s.start
|