To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / .svn / pristine / 47 / 478eea0d533e8053ee16800d8a6228965a404db6.svn-base @ 1298:4f746d8966dd

History | View | Annotate | Download (4.34 KB)

1
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