Module: SinatraOmniAuth

Defined in:
lib/sinatra/omniauth.rb

Defined Under Namespace

Modules: Helpers

Class Method Summary collapse

Class Method Details

.registered(app) ⇒ Object



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
# File 'lib/sinatra/omniauth.rb', line 125

def self.registered app
  app.class_eval do
    # Register OmniAuth Strategies and keys for all providers:
    use ::OmniAuth::Builder do
      app.settings.omniauth.each do |a|
        provider = a['provider']
        client_options = a[:client_options]
        client_options = client_options ? {:client_options => client_options} : {}
        if key = a['key']
          provider provider, key, a['secret'], client_options
        else
          name = a['name'].downcase.gsub(/ /,' ')
          store = OpenID::Store::Filesystem.new(a['store']||'./tmp')
          provider provider, store, :name => name, :identifier => a['identifier']
        end
      end
    end

    # Make _method=delete work in POST requests:
    enable :method_override

    # Create a flash, so we can display a message after a redirect
    use Rack::Flash, :accessorize => [:notice, :error]
    send(:define_method, :flash) do
      env['x-rack.flash']
    end

    # A little help from our friends...
    include Helpers

    # Display the authentication in use, registered for the current user, and available
    get '/auth' do
      @authentications_possible = settings.omniauth

      if current_user and @authentication_current = current_auth
        @authentications_available = current_user.authentications.all(:order => [ :provider.desc ])
        @authentications_unused = @authentications_available.
          reject do|a|
            a.provider == @authentication_current.provider
          end
        @authentications_possible = @authentications_possible.dup.
          reject do |a|
            @authentications_available.detect{|p| p.provider.gsub(/[ _]/,'') == a['name'].downcase.gsub(/[ _]/,'') }
          end
      end

      haml :auth
    end

    get '/auth/:authentication/callback' do
      callback
    end

    post '/auth/:authentication/callback' do
      callback
    end

    send(:define_method, :callback) do
      # callback: success
      # This handles signing in and adding an authentication authentication to existing accounts itself

      # get the authentication parameter from the Rails router
      authentication_route = params[:authentication] ? params[:authentication] : 'No authentication recognized (invalid callback)'

      # get the full hash from omniauth
      omniauth = request.env['omniauth.auth']

      # continue only if hash and parameter exist
      unless omniauth and params[:authentication]
        flash.error = 'Error while authenticating via ' + authentication_route.capitalize + '. The authentication did not return valid data.'
        redirect to('/signin')
      end

      # create a new regularised authentication hash
      @authhash = Hash.new
      oaeuh = omniauth['extra'] && omniauth['extra']['user_hash']
      oaui = omniauth['user_info']
      if authentication_route == 'facebook'
        @authhash[:email] = oaeuh['email'] || ''
        @authhash[:name] = oaeuh['name'] || ''
        @authhash[:uid] = oaeuh['name'] || ''
        @authhash[:provider] = omniauth['provider'] || ''
      elsif authentication_route == 'github'
        @authhash[:email] = oaui['email'] || ''
        @authhash[:name] = oaui['name'] || ''
        @authhash[:uid] = (oaeuh['id'] || '').to_s
        @authhash[:provider] = omniauth['provider'] || ''
      elsif ['google', 'yahoo', 'linked_in', 'twitter', 'myopenid', 'openid', 'open_id'].index(authentication_route) != nil
        @authhash[:email] = oaui['email'] || ''
        @authhash[:name] = oaui['name'] || ''
        @authhash[:uid] = (omniauth['uid'] || '').to_s
        @authhash[:provider] = omniauth['provider'] || ''
      elsif authentication_route == 'aol'
        @authhash[:email] = oaui['email'] || ''
        @authhash[:name] = oaui['name'] || ''
        @authhash[:uid] = (omniauth['uid'] || '').to_s
        @authhash[:provider] = omniauth['provider'] || ''
      else
        # REVISIT: debug to output the hash that has been returned when adding new authentications
        return '<pre>'+omniauth.to_yaml+'</pre>'
      end

      if @authhash[:uid] == '' or @authhash[:provider] == ''
        flash.error = 'Error while authenticating via ' + authentication_route + '/' + @authhash[:provider].capitalize + '. The authentication returned invalid data for the user id.'
        redirect to('/auth')
      end

      auth = Authentication.first(:provider => @authhash[:provider], :uid => @authhash[:uid])

      # if the user is currently signed in, he/she might want to add another account to signin
      if current_user
        if auth
          flash.notice = 'You are now signed in using your' + @authhash[:provider].capitalize + ' account'
          session[:authentication_provider] = auth.provider   # They're now signed in using the new account
          redirect to('/auth/signedin')  # Already signed in, and we already had this authentication
        else
          auth = current_user.authentications.create!(:provider => @authhash[:provider], :uid => @authhash[:uid], :user_name => @authhash[:name], :user_email => @authhash[:email])
          flash.notice = 'Your ' + @authhash[:provider].capitalize + ' account has been added for signing in at this site.'
          session[:authentication_provider] = auth.provider   # They're now signed in using the new account
          session[:user_name] = @authhash[:name] if @authhash[:name] != ''
          redirect to('/auth/signedin')
        end
      else
        if auth
          # Signin existing user
          # in the session his user id and the authentication id used for signing in is stored
          session[:user_id] = auth.user.id
          session[:authentication_provider] = auth.provider   # They're now signed in using the new account
          session[:user_name] = @authhash[:name] if @authhash[:name] != ''

          flash.notice = 'Signed in successfully via ' + @authhash[:provider].capitalize + '.'
          redirect to('/auth/signedin')
        end

        if email = @authhash[:email] and email != '' and
          auth = Authentication.first(:email => email)
          # Would have been seen as a new user, but instead we found that we know their email address already
          provider = @authhash[:provider]
          auth = auth.user.authentications.create!(
              :provider => provider,
              :uid => @authhash[:uid],
              :user_name => @authhash[:name],
              :user_email => @authhash[:email]
            )
          flash.notice = 'Your ' + provider.capitalize + ' account has been added for signing in at this site.'
          session[:user_id] = auth.user.id
          session[:authentication_provider] = auth.provider   # They're now signed in using the new account
          session[:user_name] = @authhash[:name] if @authhash[:name] != ''
          redirect to('/auth/signedin')
        end

        # this is a new user; add them
        @current_user = User.create()
        session[:user_id] = @current_user.id
        session[:user_name] = @authhash[:name] if @authhash[:name] != ''
        auth = current_user.authentications.create!(:provider => @authhash[:provider], :uid => @authhash[:uid], :user_name => @authhash[:name], :user_email => @authhash[:email])
        session[:authentication_provider] = auth.provider
        redirect to('/auth/welcome')
      end
    end

    get '/auth/failure' do
      flash.error = 'There was an error at the remote authentication authentication. You have not been signed in.'
      redirect to('/')
    end

    get '/auth/signout' do
      authenticate_user!

      session.delete :user_id
      session.delete :user_name
      session.delete :authentication_provider
      flash.notice = 'You have been signed out'
      redirect to('/')
    end

    # authentication
    delete '/auth/:provider' do
      authenticate_user!

      # remove an authentication authentication linked to the current user
      provider = params[:provider]
      @authentication = current_user.authentications.first(:provider => provider)

      if !@authentication
        pass
      elsif session[:authentication_provider] == @authentication.provider
        flash.error = 'You can\'t delete your authorization through #{provider.capitalize} because you are currently signed in with it!'
      else
        @authentication.destroy
      end

      redirect to('/auth')
    end
  end
end