/usr/lib/ruby/1.8/openid/consumer.rb is in libopenid-ruby1.8 2.1.8debian-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 | require "openid/consumer/idres.rb"
require "openid/consumer/checkid_request.rb"
require "openid/consumer/associationmanager.rb"
require "openid/consumer/responses.rb"
require "openid/consumer/discovery_manager"
require "openid/consumer/discovery"
require "openid/message"
require "openid/yadis/discovery"
require "openid/store/nonce"
module OpenID
# OpenID support for Relying Parties (aka Consumers).
#
# This module documents the main interface with the OpenID consumer
# library. The only part of the library which has to be used and
# isn't documented in full here is the store required to create an
# Consumer instance.
#
# = OVERVIEW
#
# The OpenID identity verification process most commonly uses the
# following steps, as visible to the user of this library:
#
# 1. The user enters their OpenID into a field on the consumer's
# site, and hits a login button.
#
# 2. The consumer site discovers the user's OpenID provider using
# the Yadis protocol.
#
# 3. The consumer site sends the browser a redirect to the OpenID
# provider. This is the authentication request as described in
# the OpenID specification.
#
# 4. The OpenID provider's site sends the browser a redirect back to
# the consumer site. This redirect contains the provider's
# response to the authentication request.
#
# The most important part of the flow to note is the consumer's site
# must handle two separate HTTP requests in order to perform the
# full identity check.
#
# = LIBRARY DESIGN
#
# This consumer library is designed with that flow in mind. The
# goal is to make it as easy as possible to perform the above steps
# securely.
#
# At a high level, there are two important parts in the consumer
# library. The first important part is this module, which contains
# the interface to actually use this library. The second is
# openid/store/interface.rb, which describes the interface to use if
# you need to create a custom method for storing the state this
# library needs to maintain between requests.
#
# In general, the second part is less important for users of the
# library to know about, as several implementations are provided
# which cover a wide variety of situations in which consumers may
# use the library.
#
# The Consumer class has methods corresponding to the actions
# necessary in each of steps 2, 3, and 4 described in the overview.
# Use of this library should be as easy as creating an Consumer
# instance and calling the methods appropriate for the action the
# site wants to take.
#
# This library automatically detects which version of the OpenID
# protocol should be used for a transaction and constructs the
# proper requests and responses. Users of this library do not need
# to worry about supporting multiple protocol versions; the library
# supports them implicitly. Depending on the version of the
# protocol in use, the OpenID transaction may be more secure. See
# the OpenID specifications for more information.
#
# = SESSIONS, STORES, AND STATELESS MODE
#
# The Consumer object keeps track of two types of state:
#
# 1. State of the user's current authentication attempt. Things
# like the identity URL, the list of endpoints discovered for
# that URL, and in case where some endpoints are unreachable, the
# list of endpoints already tried. This state needs to be held
# from Consumer.begin() to Consumer.complete(), but it is only
# applicable to a single session with a single user agent, and at
# the end of the authentication process (i.e. when an OP replies
# with either <tt>id_res</tt>. or <tt>cancel</tt> it may be
# discarded.
#
# 2. State of relationships with servers, i.e. shared secrets
# (associations) with servers and nonces seen on signed messages.
# This information should persist from one session to the next
# and should not be bound to a particular user-agent.
#
# These two types of storage are reflected in the first two
# arguments of Consumer's constructor, <tt>session</tt> and
# <tt>store</tt>. <tt>session</tt> is a dict-like object and we
# hope your web framework provides you with one of these bound to
# the user agent. <tt>store</tt> is an instance of Store.
#
# Since the store does hold secrets shared between your application
# and the OpenID provider, you should be careful about how you use
# it in a shared hosting environment. If the filesystem or database
# permissions of your web host allow strangers to read from them, do
# not store your data there! If you have no safe place to store
# your data, construct your consumer with nil for the store, and it
# will operate only in stateless mode. Stateless mode may be
# slower, put more load on the OpenID provider, and trusts the
# provider to keep you safe from replay attacks.
#
# Several store implementation are provided, and the interface is
# fully documented so that custom stores can be used as well. See
# the documentation for the Consumer class for more information on
# the interface for stores. The implementations that are provided
# allow the consumer site to store the necessary data in several
# different ways, including several SQL databases and normal files
# on disk.
#
# = IMMEDIATE MODE
#
# In the flow described above, the user may need to confirm to the
# OpenID provider that it's ok to disclose his or her identity. The
# provider may draw pages asking for information from the user
# before it redirects the browser back to the consumer's site. This
# is generally transparent to the consumer site, so it is typically
# ignored as an implementation detail.
#
# There can be times, however, where the consumer site wants to get
# a response immediately. When this is the case, the consumer can
# put the library in immediate mode. In immediate mode, there is an
# extra response possible from the server, which is essentially the
# server reporting that it doesn't have enough information to answer
# the question yet.
#
# = USING THIS LIBRARY
#
# Integrating this library into an application is usually a
# relatively straightforward process. The process should basically
# follow this plan:
#
# Add an OpenID login field somewhere on your site. When an OpenID
# is entered in that field and the form is submitted, it should make
# a request to the your site which includes that OpenID URL.
#
# First, the application should instantiate a Consumer with a
# session for per-user state and store for shared state using the
# store of choice.
#
# Next, the application should call the <tt>begin</tt> method of
# Consumer instance. This method takes the OpenID URL as entered by
# the user. The <tt>begin</tt> method returns a CheckIDRequest
# object.
#
# Next, the application should call the redirect_url method on the
# CheckIDRequest object. The parameter <tt>return_to</tt> is the
# URL that the OpenID server will send the user back to after
# attempting to verify his or her identity. The <tt>realm</tt>
# parameter is the URL (or URL pattern) that identifies your web
# site to the user when he or she is authorizing it. Send a
# redirect to the resulting URL to the user's browser.
#
# That's the first half of the authentication process. The second
# half of the process is done after the user's OpenID Provider sends
# the user's browser a redirect back to your site to complete their
# login.
#
# When that happens, the user will contact your site at the URL
# given as the <tt>return_to</tt> URL to the redirect_url call made
# above. The request will have several query parameters added to
# the URL by the OpenID provider as the information necessary to
# finish the request.
#
# Get a Consumer instance with the same session and store as before
# and call its complete() method, passing in all the received query
# arguments and URL currently being handled.
#
# There are multiple possible return types possible from that
# method. These indicate the whether or not the login was
# successful, and include any additional information appropriate for
# their type.
class Consumer
attr_accessor :session_key_prefix
# Initialize a Consumer instance.
#
# You should create a new instance of the Consumer object with
# every HTTP request that handles OpenID transactions.
#
# session: the session object to use to store request information.
# The session should behave like a hash.
#
# store: an object that implements the interface in Store.
def initialize(session, store)
@session = session
@store = store
@session_key_prefix = 'OpenID::Consumer::'
end
# Start the OpenID authentication process. See steps 1-2 in the
# overview for the Consumer class.
#
# user_url: Identity URL given by the user. This method performs a
# textual transformation of the URL to try and make sure it is
# normalized. For example, a user_url of example.com will be
# normalized to http://example.com/ normalizing and resolving any
# redirects the server might issue.
#
# anonymous: A boolean value. Whether to make an anonymous
# request of the OpenID provider. Such a request does not ask for
# an authorization assertion for an OpenID identifier, but may be
# used with extensions to pass other data. e.g. "I don't care who
# you are, but I'd like to know your time zone."
#
# Returns a CheckIDRequest object containing the discovered
# information, with a method for building a redirect URL to the
# server, as described in step 3 of the overview. This object may
# also be used to add extension arguments to the request, using
# its add_extension_arg method.
#
# Raises DiscoveryFailure when no OpenID server can be found for
# this URL.
def begin(openid_identifier, anonymous=false)
manager = discovery_manager(openid_identifier)
service = manager.get_next_service(&method(:discover))
if service.nil?
raise DiscoveryFailure.new("No usable OpenID services were found "\
"for #{openid_identifier.inspect}", nil)
else
begin_without_discovery(service, anonymous)
end
end
# Start OpenID verification without doing OpenID server
# discovery. This method is used internally by Consumer.begin()
# after discovery is performed, and exists to provide an interface
# for library users needing to perform their own discovery.
#
# service: an OpenID service endpoint descriptor. This object and
# factories for it are found in the openid/consumer/discovery.rb
# module.
#
# Returns an OpenID authentication request object.
def begin_without_discovery(service, anonymous)
assoc = association_manager(service).get_association
checkid_request = CheckIDRequest.new(assoc, service)
checkid_request.anonymous = anonymous
if service.compatibility_mode
rt_args = checkid_request.return_to_args
rt_args[Consumer.openid1_return_to_nonce_name] = Nonce.mk_nonce
rt_args[Consumer.openid1_return_to_claimed_id_name] =
service.claimed_id
end
self.last_requested_endpoint = service
return checkid_request
end
# Called to interpret the server's response to an OpenID
# request. It is called in step 4 of the flow described in the
# Consumer overview.
#
# query: A hash of the query parameters for this HTTP request.
# Note that in rails, this is <b>not</b> <tt>params</tt> but
# <tt>params.reject{|k,v|request.path_parameters[k]}</tt>
# because <tt>controller</tt> and <tt>action</tt> and other
# "path parameters" are included in params.
#
# current_url: Extract the URL of the current request from your
# application's web request framework and specify it here to have it
# checked against the openid.return_to value in the response. Do not
# just pass <tt>args['openid.return_to']</tt> here; that will defeat the
# purpose of this check. (See OpenID Authentication 2.0 section 11.1.)
#
# If the return_to URL check fails, the status of the completion will be
# FAILURE.
#
# Returns a subclass of Response. The type of response is
# indicated by the status attribute, which will be one of
# SUCCESS, CANCEL, FAILURE, or SETUP_NEEDED.
def complete(query, current_url)
message = Message.from_post_args(query)
mode = message.get_arg(OPENID_NS, 'mode', 'invalid')
begin
meth = method('complete_' + mode)
rescue NameError
meth = method(:complete_invalid)
end
response = meth.call(message, current_url)
cleanup_last_requested_endpoint
if [SUCCESS, CANCEL].member?(response.status)
cleanup_session
end
return response
end
protected
def session_get(name)
@session[session_key(name)]
end
def session_set(name, val)
@session[session_key(name)] = val
end
def session_key(suffix)
@session_key_prefix + suffix
end
def last_requested_endpoint
session_get('last_requested_endpoint')
end
def last_requested_endpoint=(endpoint)
session_set('last_requested_endpoint', endpoint)
end
def cleanup_last_requested_endpoint
@session[session_key('last_requested_endpoint')] = nil
end
def discovery_manager(openid_identifier)
DiscoveryManager.new(@session, openid_identifier, @session_key_prefix)
end
def cleanup_session
discovery_manager(nil).cleanup(true)
end
def discover(identifier)
OpenID.discover(identifier)
end
def negotiator
DefaultNegotiator
end
def association_manager(service)
AssociationManager.new(@store, service.server_url,
service.compatibility_mode, negotiator)
end
def handle_idres(message, current_url)
IdResHandler.new(message, current_url, @store, last_requested_endpoint)
end
def complete_invalid(message, unused_return_to)
mode = message.get_arg(OPENID_NS, 'mode', '<No mode set>')
return FailureResponse.new(last_requested_endpoint,
"Invalid openid.mode: #{mode}")
end
def complete_cancel(unused_message, unused_return_to)
return CancelResponse.new(last_requested_endpoint)
end
def complete_error(message, unused_return_to)
error = message.get_arg(OPENID_NS, 'error')
contact = message.get_arg(OPENID_NS, 'contact')
reference = message.get_arg(OPENID_NS, 'reference')
return FailureResponse.new(last_requested_endpoint,
error, contact, reference)
end
def complete_setup_needed(message, unused_return_to)
if message.is_openid1
return complete_invalid(message, nil)
else
setup_url = message.get_arg(OPENID2_NS, 'user_setup_url')
return SetupNeededResponse.new(last_requested_endpoint, setup_url)
end
end
def complete_id_res(message, current_url)
if message.is_openid1
setup_url = message.get_arg(OPENID_NS, 'user_setup_url')
if !setup_url.nil?
return SetupNeededResponse.new(last_requested_endpoint, setup_url)
end
end
begin
idres = handle_idres(message, current_url)
rescue OpenIDError => why
return FailureResponse.new(last_requested_endpoint, why.message)
else
return SuccessResponse.new(idres.endpoint, message,
idres.signed_fields)
end
end
end
end
|