ruby-openid-apps-discovery 1.01 → 1.2.0
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/lib/gapps_openid.rb +71 -36
- metadata +21 -10
data/lib/gapps_openid.rb
CHANGED
@@ -29,10 +29,17 @@ require 'base64'
|
|
29
29
|
# Caching of discovery information is enabled when used with rails. In other environments,
|
30
30
|
# a cache can be set via:
|
31
31
|
#
|
32
|
-
# OpenID
|
32
|
+
# OpenID.cache = ...
|
33
33
|
#
|
34
34
|
# The cache must implement methods read(key) and write(key,value)
|
35
35
|
#
|
36
|
+
# Similarly, logging will attempt to use the default Rail's logger, but can be overriden
|
37
|
+
# by calling
|
38
|
+
#
|
39
|
+
# OpenID.logger = ...
|
40
|
+
#
|
41
|
+
# The logger must respond to warn, debug, and info methods
|
42
|
+
#
|
36
43
|
# In some cases additional setup is required, particularly to set the location of trusted
|
37
44
|
# root certificates for validating XRDS signatures. If standard locations don't work, additional
|
38
45
|
# files and directories can be added via:
|
@@ -81,11 +88,13 @@ module OpenID
|
|
81
88
|
def perform_discovery(uri)
|
82
89
|
OpenID.logger.debug("Performing discovery for #{uri}") unless OpenID.logger.nil?
|
83
90
|
begin
|
91
|
+
domain = uri
|
84
92
|
parsed_uri = URI::parse(uri)
|
85
|
-
|
86
|
-
|
93
|
+
domain = parsed_uri.host unless parsed_uri.host.nil?
|
94
|
+
if site_identifier?(parsed_uri)
|
95
|
+
return discover_site(domain)
|
87
96
|
end
|
88
|
-
return discover_user(
|
97
|
+
return discover_user(domain, uri)
|
89
98
|
rescue Exception => e
|
90
99
|
# If we fail, just return nothing and fallback on default discovery mechanisms
|
91
100
|
OpenID.logger.warn("Unexpected exception performing discovery for id #{uri}: #{e}") unless OpenID.logger.nil?
|
@@ -93,6 +102,10 @@ module OpenID
|
|
93
102
|
end
|
94
103
|
end
|
95
104
|
|
105
|
+
def site_identifier?(parsed_uri)
|
106
|
+
return parsed_uri.scheme.nil? || parsed_uri.path.nil? || parsed_uri.path.strip.empty?
|
107
|
+
end
|
108
|
+
|
96
109
|
# Handles discovery for a user's claimed ID.
|
97
110
|
def discover_user(domain, claimed_id)
|
98
111
|
OpenID.logger.debug("Discovering user identity #{claimed_id} for domain #{domain}") unless OpenID.logger.nil?
|
@@ -101,13 +114,23 @@ module OpenID
|
|
101
114
|
OpenID.logger.debug("#{domain} is not a Google Apps domain, aborting") unless OpenID.logger.nil?
|
102
115
|
return nil # Not a Google Apps domain
|
103
116
|
end
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
117
|
+
|
118
|
+
xrds, signed = fetch_secure_xrds(domain, url)
|
119
|
+
|
120
|
+
unless xrds.nil?
|
121
|
+
# TODO - Need to propogate secure discovery info up through stack
|
122
|
+
user_url, authority = get_user_xrds_url(xrds, claimed_id)
|
123
|
+
user_xrds, signed = fetch_secure_xrds(domain, user_url, false)
|
124
|
+
|
125
|
+
# No user xrds -- likely that identifier was just OP identifier
|
126
|
+
if user_xrds.nil?
|
127
|
+
endpoints = OpenID::OpenIDServiceEndpoint.from_xrds(domain, xrds)
|
128
|
+
return [claimed_id, OpenID.get_op_or_user_services(endpoints)]
|
129
|
+
end
|
108
130
|
|
109
|
-
|
110
|
-
|
131
|
+
endpoints = OpenID::OpenIDServiceEndpoint.from_xrds(claimed_id, user_xrds)
|
132
|
+
return [claimed_id, OpenID.get_op_or_user_services(endpoints)]
|
133
|
+
end
|
111
134
|
end
|
112
135
|
|
113
136
|
# Handles discovery for a domain
|
@@ -118,10 +141,12 @@ module OpenID
|
|
118
141
|
OpenID.logger.debug("#{domain} is not a Google Apps domain, aborting") unless OpenID.logger.nil?
|
119
142
|
return nil # Not a Google Apps domain
|
120
143
|
end
|
121
|
-
xrds =
|
144
|
+
xrds, secure = fetch_secure_xrds(domain, url)
|
145
|
+
|
122
146
|
unless xrds.nil?
|
123
|
-
|
124
|
-
|
147
|
+
# TODO - Need to propogate secure discovery info up through stack
|
148
|
+
endpoints = OpenID::OpenIDServiceEndpoint.from_xrds(domain, xrds)
|
149
|
+
return [domain, OpenID.get_op_or_user_services(endpoints)]
|
125
150
|
end
|
126
151
|
return nil
|
127
152
|
end
|
@@ -133,11 +158,9 @@ module OpenID
|
|
133
158
|
return cached_value unless cached_value.nil?
|
134
159
|
|
135
160
|
host_meta_url = "https://www.google.com/accounts/o8/.well-known/host-meta?hd=#{CGI::escape(domain)}"
|
136
|
-
http_resp =
|
137
|
-
|
138
|
-
|
139
|
-
return nil
|
140
|
-
end
|
161
|
+
http_resp = fetch_url(host_meta_url)
|
162
|
+
return nil if http_resp.nil?
|
163
|
+
|
141
164
|
matches = /Link: <(.*)>/.match( http_resp.body )
|
142
165
|
if matches.nil?
|
143
166
|
OpenID.logger.debug("No link tag found at #{host_meta_url}") unless OpenID.logger.nil?
|
@@ -147,34 +170,43 @@ module OpenID
|
|
147
170
|
return matches[1]
|
148
171
|
end
|
149
172
|
|
173
|
+
def fetch_url(url)
|
174
|
+
http_resp = OpenID.fetch(url)
|
175
|
+
if http_resp.code != "200" and http_resp.code != "206"
|
176
|
+
OpenID.logger.debug("Received #{http_resp.code} when fetching #{url}") unless OpenID.logger.nil?
|
177
|
+
return nil
|
178
|
+
end
|
179
|
+
return http_resp
|
180
|
+
end
|
181
|
+
|
150
182
|
# Fetches the XRDS and verifies the signature and authority for the doc
|
151
|
-
def
|
183
|
+
def fetch_secure_xrds(authority, url, cache=true)
|
152
184
|
return if url.nil?
|
153
185
|
|
154
186
|
OpenID.logger.debug("Retrieving XRDS from #{url}") unless OpenID.logger.nil?
|
155
187
|
|
156
|
-
cached_xrds = get_cache(url)
|
188
|
+
cached_xrds = get_cache("XRDS_#{url}")
|
157
189
|
return cached_xrds unless cached_xrds.nil?
|
158
190
|
|
159
|
-
http_resp =
|
160
|
-
|
161
|
-
OpenID.logger.debug("Received #{http_resp.code} when fetching #{url}") unless OpenID.logger.nil?
|
162
|
-
return nil
|
163
|
-
end
|
191
|
+
http_resp = fetch_url(url)
|
192
|
+
return nil if http_resp.nil?
|
164
193
|
|
165
194
|
body = http_resp.body
|
195
|
+
put_cache("XRDS_#{url}", body)
|
196
|
+
|
166
197
|
signature = http_resp["Signature"]
|
167
198
|
signed_by = SimpleSign.verify(body, signature)
|
168
|
-
|
199
|
+
|
200
|
+
if signed_by.nil?
|
201
|
+
put_cache("XRDS_#{url}", body) if cache
|
202
|
+
return [body, false]
|
203
|
+
elsif signed_by.casecmp(authority) || signed_by.casecmp('hosted-id.google.com')
|
204
|
+
put_cache("XRDS_#{url}", body) if cache
|
205
|
+
return [body, true]
|
206
|
+
else
|
169
207
|
OpenID.logger.warn("Expected signature from #{authority} but found #{signed_by}") unless OpenID.logger.nil?
|
170
|
-
return
|
208
|
+
return nil # Signed, but not by the right domain.
|
171
209
|
end
|
172
|
-
|
173
|
-
# Everything is OK
|
174
|
-
if cache
|
175
|
-
put_cache(url, body)
|
176
|
-
end
|
177
|
-
return body
|
178
210
|
end
|
179
211
|
|
180
212
|
# Process the URITemplate in the XRDS to derive the location of the claimed id's XRDS
|
@@ -257,12 +289,15 @@ module OpenID
|
|
257
289
|
|
258
290
|
# Verifies the signature of the doc, returning the CN of the signer if valid
|
259
291
|
def self.verify(xml, signature_value)
|
260
|
-
raise "Missing signature value" if signature_value.nil?
|
261
|
-
decoded_sig = Base64.decode64(signature_value)
|
262
|
-
|
263
292
|
doc = REXML::Document.new(xml)
|
293
|
+
|
294
|
+
return nil if REXML::XPath.first(doc, "//ds:Signature").nil? and signature_value.nil?
|
295
|
+
|
296
|
+
decoded_sig = Base64.decode64(signature_value)
|
264
297
|
certs = self.parse_certificates(doc)
|
265
298
|
raise "No signature in document" if certs.nil? or certs.empty?
|
299
|
+
raise "Missing signature value" if signature_value.nil?
|
300
|
+
|
266
301
|
|
267
302
|
signing_certificate = certs.first
|
268
303
|
raise "Invalid signature" if !signing_certificate.public_key.verify(OpenSSL::Digest::SHA1.new, decoded_sig, xml)
|
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-openid-apps-discovery
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
version: 1.2.0
|
5
10
|
platform: ruby
|
6
11
|
authors: []
|
7
12
|
|
@@ -9,19 +14,23 @@ autorequire:
|
|
9
14
|
bindir: bin
|
10
15
|
cert_chain: []
|
11
16
|
|
12
|
-
date: 2010-
|
17
|
+
date: 2010-05-17 00:00:00 -07:00
|
13
18
|
default_executable:
|
14
19
|
dependencies:
|
15
20
|
- !ruby/object:Gem::Dependency
|
16
21
|
name: ruby-openid
|
17
|
-
|
18
|
-
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
24
|
requirements:
|
21
25
|
- - ">="
|
22
26
|
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 2
|
29
|
+
- 1
|
30
|
+
- 7
|
23
31
|
version: 2.1.7
|
24
|
-
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
25
34
|
description: |
|
26
35
|
Extension to ruby-openid that enables discovery for Google Apps domains
|
27
36
|
|
@@ -36,7 +45,7 @@ files:
|
|
36
45
|
- lib/gapps_openid.rb
|
37
46
|
- lib/ca-bundle.crt
|
38
47
|
has_rdoc: true
|
39
|
-
homepage:
|
48
|
+
homepage: http://code.google.com/p/ruby-openid-apps-discovery
|
40
49
|
licenses: []
|
41
50
|
|
42
51
|
post_install_message:
|
@@ -48,18 +57,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
48
57
|
requirements:
|
49
58
|
- - ">="
|
50
59
|
- !ruby/object:Gem::Version
|
60
|
+
segments:
|
61
|
+
- 0
|
51
62
|
version: "0"
|
52
|
-
version:
|
53
63
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
64
|
requirements:
|
55
65
|
- - ">="
|
56
66
|
- !ruby/object:Gem::Version
|
67
|
+
segments:
|
68
|
+
- 0
|
57
69
|
version: "0"
|
58
|
-
version:
|
59
70
|
requirements: []
|
60
71
|
|
61
72
|
rubyforge_project:
|
62
|
-
rubygems_version: 1.3.
|
73
|
+
rubygems_version: 1.3.6
|
63
74
|
signing_key:
|
64
75
|
specification_version: 3
|
65
76
|
summary: Google Apps support for ruby-openid
|