To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.
root / .svn / pristine / 47 / 478eea0d533e8053ee16800d8a6228965a404db6.svn-base @ 1297:0a574315af3e
History | View | Annotate | Download (4.34 KB)
| 1 | 1296:038ba2d95de8 | Chris | require 'uri' |
|---|---|---|---|
| 2 | require 'openid' |
||
| 3 | require 'rack/openid' |
||
| 4 | |||
| 5 | module OpenIdAuthentication |
||
| 6 | def self.new(app) |
||
| 7 | store = OpenIdAuthentication.store |
||
| 8 | if store.nil? |
||
| 9 | Rails.logger.warn "OpenIdAuthentication.store is nil. Using in-memory store." |
||
| 10 | end |
||
| 11 | |||
| 12 | ::Rack::OpenID.new(app, OpenIdAuthentication.store) |
||
| 13 | end |
||
| 14 | |||
| 15 | def self.store |
||
| 16 | @@store |
||
| 17 | end |
||
| 18 | |||
| 19 | def self.store=(*store_option) |
||
| 20 | store, *parameters = *([ store_option ].flatten) |
||
| 21 | |||
| 22 | @@store = case store |
||
| 23 | when :memory |
||
| 24 | require 'openid/store/memory' |
||
| 25 | OpenID::Store::Memory.new |
||
| 26 | when :file |
||
| 27 | require 'openid/store/filesystem' |
||
| 28 | OpenID::Store::Filesystem.new(Rails.root.join('tmp/openids'))
|
||
| 29 | when :memcache |
||
| 30 | require 'memcache' |
||
| 31 | require 'openid/store/memcache' |
||
| 32 | OpenID::Store::Memcache.new(MemCache.new(parameters)) |
||
| 33 | else |
||
| 34 | store |
||
| 35 | end |
||
| 36 | end |
||
| 37 | |||
| 38 | self.store = nil |
||
| 39 | |||
| 40 | class InvalidOpenId < StandardError |
||
| 41 | end |
||
| 42 | |||
| 43 | class Result |
||
| 44 | ERROR_MESSAGES = {
|
||
| 45 | :missing => "Sorry, the OpenID server couldn't be found", |
||
| 46 | :invalid => "Sorry, but this does not appear to be a valid OpenID", |
||
| 47 | :canceled => "OpenID verification was canceled", |
||
| 48 | :failed => "OpenID verification failed", |
||
| 49 | :setup_needed => "OpenID verification needs setup" |
||
| 50 | } |
||
| 51 | |||
| 52 | def self.[](code) |
||
| 53 | new(code) |
||
| 54 | end |
||
| 55 | |||
| 56 | def initialize(code) |
||
| 57 | @code = code |
||
| 58 | end |
||
| 59 | |||
| 60 | def status |
||
| 61 | @code |
||
| 62 | end |
||
| 63 | |||
| 64 | ERROR_MESSAGES.keys.each { |state| define_method("#{state}?") { @code == state } }
|
||
| 65 | |||
| 66 | def successful? |
||
| 67 | @code == :successful |
||
| 68 | end |
||
| 69 | |||
| 70 | def unsuccessful? |
||
| 71 | ERROR_MESSAGES.keys.include?(@code) |
||
| 72 | end |
||
| 73 | |||
| 74 | def message |
||
| 75 | ERROR_MESSAGES[@code] |
||
| 76 | end |
||
| 77 | end |
||
| 78 | |||
| 79 | # normalizes an OpenID according to http://openid.net/specs/openid-authentication-2_0.html#normalization |
||
| 80 | def self.normalize_identifier(identifier) |
||
| 81 | # clean up whitespace |
||
| 82 | identifier = identifier.to_s.strip |
||
| 83 | |||
| 84 | # if an XRI has a prefix, strip it. |
||
| 85 | identifier.gsub!(/xri:\/\//i, '') |
||
| 86 | |||
| 87 | # dodge XRIs -- TODO: validate, don't just skip. |
||
| 88 | unless ['=', '@', '+', '$', '!', '('].include?(identifier.at(0))
|
||
| 89 | # does it begin with http? if not, add it. |
||
| 90 | identifier = "http://#{identifier}" unless identifier =~ /^http/i
|
||
| 91 | |||
| 92 | # strip any fragments |
||
| 93 | identifier.gsub!(/\#(.*)$/, '') |
||
| 94 | |||
| 95 | begin |
||
| 96 | uri = URI.parse(identifier) |
||
| 97 | uri.scheme = uri.scheme.downcase if uri.scheme # URI should do this |
||
| 98 | identifier = uri.normalize.to_s |
||
| 99 | rescue URI::InvalidURIError |
||
| 100 | raise InvalidOpenId.new("#{identifier} is not an OpenID identifier")
|
||
| 101 | end |
||
| 102 | end |
||
| 103 | |||
| 104 | return identifier |
||
| 105 | end |
||
| 106 | |||
| 107 | protected |
||
| 108 | # The parameter name of "openid_identifier" is used rather than |
||
| 109 | # the Rails convention "open_id_identifier" because that's what |
||
| 110 | # the specification dictates in order to get browser auto-complete |
||
| 111 | # working across sites |
||
| 112 | def using_open_id?(identifier = nil) #:doc: |
||
| 113 | identifier ||= open_id_identifier |
||
| 114 | !identifier.blank? || request.env[Rack::OpenID::RESPONSE] |
||
| 115 | end |
||
| 116 | |||
| 117 | def authenticate_with_open_id(identifier = nil, options = {}, &block) #:doc:
|
||
| 118 | identifier ||= open_id_identifier |
||
| 119 | |||
| 120 | if request.env[Rack::OpenID::RESPONSE] |
||
| 121 | complete_open_id_authentication(&block) |
||
| 122 | else |
||
| 123 | begin_open_id_authentication(identifier, options, &block) |
||
| 124 | end |
||
| 125 | end |
||
| 126 | |||
| 127 | private |
||
| 128 | def open_id_identifier |
||
| 129 | params[:openid_identifier] || params[:openid_url] |
||
| 130 | end |
||
| 131 | |||
| 132 | def begin_open_id_authentication(identifier, options = {})
|
||
| 133 | options[:identifier] = identifier |
||
| 134 | value = Rack::OpenID.build_header(options) |
||
| 135 | response.headers[Rack::OpenID::AUTHENTICATE_HEADER] = value |
||
| 136 | head :unauthorized |
||
| 137 | end |
||
| 138 | |||
| 139 | def complete_open_id_authentication |
||
| 140 | response = request.env[Rack::OpenID::RESPONSE] |
||
| 141 | identifier = response.display_identifier |
||
| 142 | |||
| 143 | case response.status |
||
| 144 | when OpenID::Consumer::SUCCESS |
||
| 145 | yield Result[:successful], identifier, |
||
| 146 | OpenID::SReg::Response.from_success_response(response) |
||
| 147 | when :missing |
||
| 148 | yield Result[:missing], identifier, nil |
||
| 149 | when :invalid |
||
| 150 | yield Result[:invalid], identifier, nil |
||
| 151 | when OpenID::Consumer::CANCEL |
||
| 152 | yield Result[:canceled], identifier, nil |
||
| 153 | when OpenID::Consumer::FAILURE |
||
| 154 | yield Result[:failed], identifier, nil |
||
| 155 | when OpenID::Consumer::SETUP_NEEDED |
||
| 156 | yield Result[:setup_needed], response.setup_url, nil |
||
| 157 | end |
||
| 158 | end |
||
| 159 | end |