google_client_login 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +24 -0
- data/LICENSE +24 -0
- data/README.textile +139 -0
- data/Rakefile +9 -0
- data/google_client_login.gemspec +22 -0
- data/lib/google_client_login.rb +137 -0
- data/lib/google_client_login/version.rb +3 -0
- data/spec/login_spec.rb +18 -0
- data/spec/spec_helper.rb +8 -0
- metadata +94 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
google_client_login (0.3.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.1.2)
|
10
|
+
rspec (2.4.0)
|
11
|
+
rspec-core (~> 2.4.0)
|
12
|
+
rspec-expectations (~> 2.4.0)
|
13
|
+
rspec-mocks (~> 2.4.0)
|
14
|
+
rspec-core (2.4.0)
|
15
|
+
rspec-expectations (2.4.0)
|
16
|
+
diff-lcs (~> 1.1.2)
|
17
|
+
rspec-mocks (2.4.0)
|
18
|
+
|
19
|
+
PLATFORMS
|
20
|
+
ruby
|
21
|
+
|
22
|
+
DEPENDENCIES
|
23
|
+
google_client_login!
|
24
|
+
rspec (>= 2.0.0)
|
data/LICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2010 Toon Willems
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person
|
6
|
+
obtaining a copy of this software and associated documentation
|
7
|
+
files (the "Software"), to deal in the Software without
|
8
|
+
restriction, including without limitation the rights to use,
|
9
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the
|
11
|
+
Software is furnished to do so, subject to the following
|
12
|
+
conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be
|
15
|
+
included in all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
19
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
21
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
22
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
23
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
24
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
h1. Google_Client_Login Gem
|
2
|
+
|
3
|
+
This gem provides authorization for access to Google API-based services using Google's ClientLogin scheme. Add this gem to a Rails application to gain access to Google services that require login to a user's Google account.
|
4
|
+
|
5
|
+
The Google ClientLogin scheme is described in this document: "http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html":http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html
|
6
|
+
|
7
|
+
h2. Similar Gems
|
8
|
+
|
9
|
+
For an alternative implementation, see Jason L. Perry's "https://github.com/ambethia/google-client_login":https://github.com/ambethia/google-client_login. Note the similarity in gem names. Jason L. Perry's gem is "google-client_login" (with one hyphen and one underscore). This gem is "google_client_login" (with two underscores).
|
10
|
+
|
11
|
+
h2. Implementation
|
12
|
+
|
13
|
+
h3. What Is Implemented
|
14
|
+
|
15
|
+
Given an email address and a password, this gem will request an authorization token from Google. The gem accommodates all error conditions with robust exception handling, including conditions where Google presents a CAPTCHA challenge.
|
16
|
+
|
17
|
+
h3. What Is Not Implemented
|
18
|
+
|
19
|
+
By itself, this gem is not sufficient to implement access to any Google API. It only provides an authorization token. Access to most Google APIs requires additional code to provide details such as a developer identity token in addition to the authorization token.
|
20
|
+
|
21
|
+
h3. An Example: Accessing the Google AdWords API
|
22
|
+
|
23
|
+
Using the Google AdWords API, you can control most aspects of an AdWords campaign programmatically. A developer applies for AdWords API access from within an AdWords "My Client Center" (MCC) account. The developer is assigned a "developer token" once the application is approved. This unique text string of letters, numbers and symbols must be included in every API request to the servers. In addition to supplying the developer token in every API request, the application also must provide an "authorization token". The authorization token is sent as part of the API request as a form of proof that you are who you claim to be, and that you are allowed access to the API. Your application obtains authorization separately from API requests, making it a two step process: first retrieve a token, and then include it with your requests. You obtain an authorization token by sending a login request to Google's servers, providing an email address and password that matches your Google account. This gem provides the library that allows you to obtain the authorization token.
|
24
|
+
|
25
|
+
Here is Google's documentation about how ClientLogin works with the AdWords API: "http://adwordsapi.blogspot.com/2010/07/discover-v2009-working-with-authtokens.html":http://adwordsapi.blogspot.com/2010/07/discover-v2009-working-with-authtokens.html
|
26
|
+
|
27
|
+
h2. Dependencies
|
28
|
+
|
29
|
+
This app is based on the Ruby language version 1.8.7 or 1.9.2 and has been tested with Rails 3.0.3.
|
30
|
+
|
31
|
+
Check that appropriate versions of Ruby and Rails are installed in your development environment:
|
32
|
+
|
33
|
+
<pre>
|
34
|
+
$ ruby -v
|
35
|
+
$ rails -v
|
36
|
+
</pre>
|
37
|
+
|
38
|
+
h2. Usage
|
39
|
+
|
40
|
+
h3. Basic Usage
|
41
|
+
|
42
|
+
Include this gem in your Gemfile:
|
43
|
+
|
44
|
+
@gem "google_client_login"@
|
45
|
+
|
46
|
+
Be sure to run @bundle install@.
|
47
|
+
|
48
|
+
Create a method for authentication in a Rails model or controller. This example would be suitable for access to the AdWords API:
|
49
|
+
|
50
|
+
<pre>
|
51
|
+
def authenticate(email, password)
|
52
|
+
login_service = GoogleClientLogin::GoogleAuth.new(:accountType => 'GOOGLE',
|
53
|
+
:service => 'adwords',
|
54
|
+
:source => 'companyName-applicationName-versionID')
|
55
|
+
login_service.authenticate(email, password)
|
56
|
+
auth_token = login_service.auth
|
57
|
+
end
|
58
|
+
</pre>
|
59
|
+
|
60
|
+
Three parameters are supplied to the initialization method: service, source and (optionally) accountType.
|
61
|
+
|
62
|
+
* :service - the service identifier (see your Google API documentation)
|
63
|
+
* :source - the name of your application, like "companyName-applicationName-versionID"
|
64
|
+
* :accountType - "GOOGLE", "HOSTED", "HOSTED_OR_GOOGLE" (default)
|
65
|
+
|
66
|
+
After initializing an instance of GoogleAuth and calling the @authenticate@ method, if there is no exception thrown, you can obtain the authentication token by calling the @auth@ method.
|
67
|
+
|
68
|
+
In the response, Google provides additional values, labeled "SID" and "LSID", which are not useful (Google says they "are not currently active and should not be used"). You could use the @sid@ and @lsid@ methods to obtain these values.
|
69
|
+
|
70
|
+
h3. Advanced Usage (Handling CAPTCHA)
|
71
|
+
|
72
|
+
To block automated attempts to obtain user passwords, Google may add a visual CAPTCHA™ to the authentication process; this usually happens when the server suspects an illegal intrusion, such as after too many incorrect login attempts. A CAPTCHA ensures that a real person is trying to log in. When this happens the @authenticate@ method will raise an exception (@CaptchaRequired@).
|
73
|
+
|
74
|
+
The URL to the CAPTCHA is accesible via the @captcha_url@ method. Extending the example given above:
|
75
|
+
|
76
|
+
<pre>
|
77
|
+
login_service.captcha_url
|
78
|
+
=> http://www.google.com/accounts/Captcha?ctoken=HiteT4b0Bk5Xg18_AcVoP6-yFkHPibe7O9EqxeiI7lUSN
|
79
|
+
</pre>
|
80
|
+
|
81
|
+
You can write code to catch the @CaptchaRequired@ exception and display the CAPTCHA image. After the user has interpreted the CAPTCHA, you can resubmit the authentication request including the user's CAPTCHA response.
|
82
|
+
|
83
|
+
@login_service.authenticate email, password, captcha_response@
|
84
|
+
|
85
|
+
You can use a convenient block construct. If you give a block to the @authenticate@ method, the block will be called with the CAPTCHA URL. The return value from the block should be the CAPTCHA answer. And it will attempt to authenticate again automatically.
|
86
|
+
|
87
|
+
h2. Testing
|
88
|
+
|
89
|
+
The gem includes tests created with RSpec. If you've obtained the source code for the gem, you can run the tests:
|
90
|
+
|
91
|
+
@rake spec@
|
92
|
+
|
93
|
+
h2. Documentation and Support
|
94
|
+
|
95
|
+
This application is provided without additional documentation or support.
|
96
|
+
|
97
|
+
Any issues? Please create an "Issue":http://github.com/fortuity/google_client_login/issues on GitHub.
|
98
|
+
|
99
|
+
h2. Contributing
|
100
|
+
|
101
|
+
If you make improvements to this application, please share with others.
|
102
|
+
|
103
|
+
* Fork the project on GitHub.
|
104
|
+
* Make your feature addition or bug fix.
|
105
|
+
* Commit with Git.
|
106
|
+
* Send the author a pull request.
|
107
|
+
|
108
|
+
If you add functionality to this application, create an alternative implementation, or build an application that shows how this gem can be used, please contact me and I'll add a note to the README so that others can find your work.
|
109
|
+
|
110
|
+
h2. Credits
|
111
|
+
|
112
|
+
Toon Willems ("http://twitter.com/nudded":http://twitter.com/nudded) created the Ruby library.
|
113
|
+
|
114
|
+
Daniel Kehoe ("http://twitter.com/yaxdotcom":http://twitter.com/yaxdotcom) created the gem.
|
115
|
+
|
116
|
+
h2. MIT License
|
117
|
+
|
118
|
+
Copyright (c) 2010 Toon Willems
|
119
|
+
|
120
|
+
Permission is hereby granted, free of charge, to any person
|
121
|
+
obtaining a copy of this software and associated documentation
|
122
|
+
files (the "Software"), to deal in the Software without
|
123
|
+
restriction, including without limitation the rights to use,
|
124
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
125
|
+
copies of the Software, and to permit persons to whom the
|
126
|
+
Software is furnished to do so, subject to the following
|
127
|
+
conditions:
|
128
|
+
|
129
|
+
The above copyright notice and this permission notice shall be
|
130
|
+
included in all copies or substantial portions of the Software.
|
131
|
+
|
132
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
133
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
134
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
135
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
136
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
137
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
138
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
139
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "google_client_login/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "google_client_login"
|
7
|
+
s.version = GoogleClientLogin::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Daniel Kehoe"]
|
10
|
+
s.email = ["kehoe@fortuity.com"]
|
11
|
+
s.homepage = "http://github.com/fortuity/google_client_login"
|
12
|
+
s.summary = %q{Authentication for Google APIs using the Google ClientLogin.}
|
13
|
+
s.description = %q{Use this gem for access to Google services protected by a user's Google or Google Apps account.}
|
14
|
+
|
15
|
+
s.rubyforge_project = "google_client_login"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
s.add_development_dependency "rspec", ">= 2.0.0"
|
22
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require "net/https"
|
2
|
+
require "uri"
|
3
|
+
|
4
|
+
module GoogleClientLogin
|
5
|
+
|
6
|
+
# Use this Class to get an auth-token
|
7
|
+
class GoogleAuth
|
8
|
+
|
9
|
+
# Base Exception class
|
10
|
+
LoginError = Class.new Exception
|
11
|
+
|
12
|
+
# All the possible exceptions
|
13
|
+
[
|
14
|
+
"BadAuthentication",
|
15
|
+
"NotVerified",
|
16
|
+
"TermsNotAgreed",
|
17
|
+
"CaptchaRequired",
|
18
|
+
"Unknown",
|
19
|
+
"AccountDeleted",
|
20
|
+
"AccountDisabled",
|
21
|
+
"ServiceDisabled",
|
22
|
+
"ServiceUnavailable",
|
23
|
+
].each do |const|
|
24
|
+
const_set const, Class.new(LoginError)
|
25
|
+
end
|
26
|
+
|
27
|
+
DEFAULTS = {
|
28
|
+
:accountType => 'HOSTED_OR_GOOGLE' ,
|
29
|
+
:source => 'companyName-applicationName-versionID',
|
30
|
+
:service => 'service-identifier'
|
31
|
+
}
|
32
|
+
|
33
|
+
attr_reader :auth, :sid, :lsid, :captcha_url
|
34
|
+
|
35
|
+
# specify the :service, :source and optionally :accountType
|
36
|
+
#
|
37
|
+
# [:service] the service identifier, check the google api documentation.
|
38
|
+
#
|
39
|
+
# [:source] the name of your application. String should be in the form
|
40
|
+
# "companyName-applicationName-versionID".
|
41
|
+
#
|
42
|
+
# [:accountType] one of the following values:
|
43
|
+
# "GOOGLE", "HOSTED", "HOSTED_OR_GOOGLE" (default if none
|
44
|
+
# given)
|
45
|
+
def initialize(arghash = {})
|
46
|
+
@options = DEFAULTS.merge arghash
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
# authenticate a user, which sets the auth, sid and lsid instance_variables
|
51
|
+
# if you provide a block, it will be called with a captcha url if google
|
52
|
+
# forces you to answer the captcha. Make sure you return the answer in the block.
|
53
|
+
#
|
54
|
+
# if no block is given, this will raise a CaptchaRequired error.
|
55
|
+
# you can rescue them and show the url via the captcha_url method.
|
56
|
+
#
|
57
|
+
# you can then call authenticate and as 3rd parameter you provide the
|
58
|
+
# captcha answer.
|
59
|
+
#
|
60
|
+
# all Exceptions this raises are subclasses of ClientLogin::LoginError.
|
61
|
+
# so make sure you handle them.
|
62
|
+
#
|
63
|
+
# This is a list of all the possible errors and their meaning
|
64
|
+
# Error code:: Description
|
65
|
+
# BadAuthentication:: The login request used a username or password that is not recognized.
|
66
|
+
# NotVerified:: The account email address has not been verified. The user will need to access their Google account directly to resolve the issue before logging in using a non-Google application.
|
67
|
+
# TermsNotAgreed:: The user has not agreed to terms. The user will need to access their Google account directly to resolve the issue before logging in using a non-Google application.
|
68
|
+
# CaptchaRequired:: A CAPTCHA is required. (A response with this error code will also contain an image URL and a CAPTCHA token.)
|
69
|
+
# Unknown:: The error is unknown or unspecified; the request contained invalid input or was malformed.
|
70
|
+
# AccountDeleted:: The user account has been deleted.
|
71
|
+
# AccountDisabled:: The user account has been disabled.
|
72
|
+
# ServiceDisabled:: The user's access to the specified service has been disabled. (The user account may still be valid.)
|
73
|
+
# ServiceUnavailable:: The service is not available; try again later.
|
74
|
+
def authenticate(username, password, captcha_response = nil)
|
75
|
+
@options[:Email], @options[:Passwd] = username, password
|
76
|
+
# set logincaptcha, captchatoken will already be set
|
77
|
+
@options[:logincaptcha] = captcha_response if captcha_response
|
78
|
+
|
79
|
+
parse_response perform_request
|
80
|
+
|
81
|
+
rescue CaptchaRequired
|
82
|
+
if block_given?
|
83
|
+
@options[:logincaptcha] = yield captcha_url
|
84
|
+
retry
|
85
|
+
else
|
86
|
+
raise CaptchaRequired
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def perform_request
|
93
|
+
request = Net::HTTP::Post.new '/accounts/ClientLogin'
|
94
|
+
request.form_data = @options
|
95
|
+
|
96
|
+
https = Net::HTTP.new 'www.google.com', 443
|
97
|
+
https.use_ssl = true
|
98
|
+
|
99
|
+
https.request request
|
100
|
+
end
|
101
|
+
|
102
|
+
def parse_body(response_body)
|
103
|
+
response_body.scan(/(\w+)=(.+)\n/).each do |key, value|
|
104
|
+
instance_variable_set "@#{key.downcase}" , value
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def parse_response(response)
|
109
|
+
if response.code_type == Net::HTTPOK
|
110
|
+
parse_body response.body
|
111
|
+
else
|
112
|
+
handle_error response.body
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
def handle_error(response_body)
|
118
|
+
error_message = response_body.match(/Error=(\w+)\n/)[1].strip
|
119
|
+
|
120
|
+
if error_message == "CaptchaRequired"
|
121
|
+
@options[:logintoken] = response_body.match(/CaptchaToken=(.+)\n/)[1]
|
122
|
+
self.captcha_url = response_body.match(/CaptchaUrl=(.+)\n/)[1]
|
123
|
+
end
|
124
|
+
|
125
|
+
raise_error_class error_message
|
126
|
+
end
|
127
|
+
|
128
|
+
def raise_error_class(error_message)
|
129
|
+
raise self.class.const_get error_message
|
130
|
+
end
|
131
|
+
|
132
|
+
def captcha_url=(url)
|
133
|
+
@captcha_url = "http://www.google.com/accounts/" << url
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
data/spec/login_spec.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "login attempt" do
|
4
|
+
|
5
|
+
context "successful login" do
|
6
|
+
|
7
|
+
it "should have an authentication token"
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
context "failed login" do
|
12
|
+
|
13
|
+
it "should not have an authentication token"
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: google_client_login
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 17
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 3
|
9
|
+
- 1
|
10
|
+
version: 0.3.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Daniel Kehoe
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-01-13 00:00:00 -08:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rspec
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 15
|
30
|
+
segments:
|
31
|
+
- 2
|
32
|
+
- 0
|
33
|
+
- 0
|
34
|
+
version: 2.0.0
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id001
|
37
|
+
description: Use this gem for access to Google services protected by a user's Google or Google Apps account.
|
38
|
+
email:
|
39
|
+
- kehoe@fortuity.com
|
40
|
+
executables: []
|
41
|
+
|
42
|
+
extensions: []
|
43
|
+
|
44
|
+
extra_rdoc_files: []
|
45
|
+
|
46
|
+
files:
|
47
|
+
- .gitignore
|
48
|
+
- Gemfile
|
49
|
+
- Gemfile.lock
|
50
|
+
- LICENSE
|
51
|
+
- README.textile
|
52
|
+
- Rakefile
|
53
|
+
- google_client_login.gemspec
|
54
|
+
- lib/google_client_login.rb
|
55
|
+
- lib/google_client_login/version.rb
|
56
|
+
- spec/login_spec.rb
|
57
|
+
- spec/spec_helper.rb
|
58
|
+
has_rdoc: true
|
59
|
+
homepage: http://github.com/fortuity/google_client_login
|
60
|
+
licenses: []
|
61
|
+
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options: []
|
64
|
+
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
hash: 3
|
73
|
+
segments:
|
74
|
+
- 0
|
75
|
+
version: "0"
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
hash: 3
|
82
|
+
segments:
|
83
|
+
- 0
|
84
|
+
version: "0"
|
85
|
+
requirements: []
|
86
|
+
|
87
|
+
rubyforge_project: google_client_login
|
88
|
+
rubygems_version: 1.3.7
|
89
|
+
signing_key:
|
90
|
+
specification_version: 3
|
91
|
+
summary: Authentication for Google APIs using the Google ClientLogin.
|
92
|
+
test_files:
|
93
|
+
- spec/login_spec.rb
|
94
|
+
- spec/spec_helper.rb
|