sinatra_omniauth 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/.document +5 -0
  2. data/Gemfile +17 -0
  3. data/Gemfile.lock +108 -0
  4. data/LICENSE.txt +20 -0
  5. data/README.rdoc +111 -0
  6. data/Rakefile +53 -0
  7. data/VERSION +1 -0
  8. data/config.ru +25 -0
  9. data/css/auth.css +47 -0
  10. data/lib/models/authorization.rb +16 -0
  11. data/lib/models/user.rb +14 -0
  12. data/lib/sinatra/omniauth.rb +273 -0
  13. data/models/authentication.rb +12 -0
  14. data/models/user.rb +12 -0
  15. data/omniauth.yml +71 -0
  16. data/public/css/omniauth.css +34 -0
  17. data/public/images/authbuttons/aol_128.png +0 -0
  18. data/public/images/authbuttons/aol_256.png +0 -0
  19. data/public/images/authbuttons/aol_32.png +0 -0
  20. data/public/images/authbuttons/aol_64.png +0 -0
  21. data/public/images/authbuttons/basecamp_128.png +0 -0
  22. data/public/images/authbuttons/basecamp_256.png +0 -0
  23. data/public/images/authbuttons/basecamp_32.png +0 -0
  24. data/public/images/authbuttons/basecamp_64.png +0 -0
  25. data/public/images/authbuttons/campfire_128.png +0 -0
  26. data/public/images/authbuttons/campfire_256.png +0 -0
  27. data/public/images/authbuttons/campfire_32.png +0 -0
  28. data/public/images/authbuttons/campfire_64.png +0 -0
  29. data/public/images/authbuttons/facebook_128.png +0 -0
  30. data/public/images/authbuttons/facebook_256.png +0 -0
  31. data/public/images/authbuttons/facebook_32.png +0 -0
  32. data/public/images/authbuttons/facebook_64.png +0 -0
  33. data/public/images/authbuttons/github_128.png +0 -0
  34. data/public/images/authbuttons/github_256.png +0 -0
  35. data/public/images/authbuttons/github_32.png +0 -0
  36. data/public/images/authbuttons/github_64.png +0 -0
  37. data/public/images/authbuttons/google_128.png +0 -0
  38. data/public/images/authbuttons/google_256.png +0 -0
  39. data/public/images/authbuttons/google_32.png +0 -0
  40. data/public/images/authbuttons/google_64.png +0 -0
  41. data/public/images/authbuttons/linkedin_128.png +0 -0
  42. data/public/images/authbuttons/linkedin_256.png +0 -0
  43. data/public/images/authbuttons/linkedin_32.png +0 -0
  44. data/public/images/authbuttons/linkedin_64.png +0 -0
  45. data/public/images/authbuttons/myspace_128.png +0 -0
  46. data/public/images/authbuttons/myspace_256.png +0 -0
  47. data/public/images/authbuttons/myspace_32.png +0 -0
  48. data/public/images/authbuttons/myspace_64.png +0 -0
  49. data/public/images/authbuttons/openid_128.png +0 -0
  50. data/public/images/authbuttons/openid_256.png +0 -0
  51. data/public/images/authbuttons/openid_32.png +0 -0
  52. data/public/images/authbuttons/openid_64.png +0 -0
  53. data/public/images/authbuttons/presently_128.png +0 -0
  54. data/public/images/authbuttons/presently_256.png +0 -0
  55. data/public/images/authbuttons/presently_32.png +0 -0
  56. data/public/images/authbuttons/presently_64.png +0 -0
  57. data/public/images/authbuttons/twitter_128.png +0 -0
  58. data/public/images/authbuttons/twitter_256.png +0 -0
  59. data/public/images/authbuttons/twitter_32.png +0 -0
  60. data/public/images/authbuttons/twitter_64.png +0 -0
  61. data/public/images/authbuttons/yahoo_128.png +0 -0
  62. data/public/images/authbuttons/yahoo_256.png +0 -0
  63. data/public/images/authbuttons/yahoo_32.png +0 -0
  64. data/public/images/authbuttons/yahoo_64.png +0 -0
  65. data/sinatra_omniauth.gemspec +137 -0
  66. data/test/helper.rb +18 -0
  67. data/test/test_sinatra_omniauth.rb +7 -0
  68. data/views/auth.haml +62 -0
  69. metadata +292 -0
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'sinatra'
4
+ gem 'omniauth'
5
+ gem 'dm-core'
6
+ gem 'dm-migrations'
7
+ #gem 'dm-sqlite-adapter'
8
+ gem 'dm-postgres-adapter'
9
+ gem 'sqlite3'
10
+ gem 'rack-flash'
11
+
12
+ group :development do
13
+ gem "bundler", ">= 1.0.0"
14
+ gem "jeweler", "~> 1.6.2"
15
+ gem "rcov", ">= 0"
16
+ gem "rdoc", ">= 2.4.0"
17
+ end
@@ -0,0 +1,108 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ addressable (2.2.6)
5
+ data_objects (0.10.6)
6
+ addressable (~> 2.1)
7
+ dm-core (1.1.0)
8
+ addressable (~> 2.2.4)
9
+ dm-do-adapter (1.1.0)
10
+ data_objects (~> 0.10.2)
11
+ dm-core (~> 1.1.0)
12
+ dm-migrations (1.1.0)
13
+ dm-core (~> 1.1.0)
14
+ dm-postgres-adapter (1.1.0)
15
+ dm-do-adapter (~> 1.1.0)
16
+ do_postgres (~> 0.10.2)
17
+ do_postgres (0.10.6)
18
+ data_objects (= 0.10.6)
19
+ faraday (0.6.1)
20
+ addressable (~> 2.2.4)
21
+ multipart-post (~> 1.1.0)
22
+ rack (>= 1.1.0, < 2)
23
+ git (1.2.5)
24
+ jeweler (1.6.4)
25
+ bundler (~> 1.0)
26
+ git (>= 1.2.5)
27
+ rake
28
+ mime-types (1.16)
29
+ multi_json (0.0.5)
30
+ multipart-post (1.1.3)
31
+ net-ldap (0.1.1)
32
+ nokogiri (1.4.7)
33
+ oa-basic (0.2.3)
34
+ multi_json (~> 0.0.2)
35
+ nokogiri (~> 1.4.2)
36
+ oa-core (= 0.2.3)
37
+ rest-client (~> 1.6.0)
38
+ oa-core (0.2.3)
39
+ rack (~> 1.1)
40
+ oa-enterprise (0.2.3)
41
+ net-ldap (~> 0.1.1)
42
+ nokogiri (~> 1.4.2)
43
+ oa-core (= 0.2.3)
44
+ pyu-ruby-sasl (~> 0.0.3.1)
45
+ rubyntlm (~> 0.1.1)
46
+ oa-more (0.2.3)
47
+ multi_json (~> 0.0.2)
48
+ oa-core (= 0.2.3)
49
+ rest-client (~> 1.6.0)
50
+ oa-oauth (0.2.3)
51
+ faraday (~> 0.6.1)
52
+ multi_json (>= 0.0.5)
53
+ nokogiri (~> 1.4.2)
54
+ oa-core (= 0.2.3)
55
+ oauth (~> 0.4.0)
56
+ oauth2 (~> 0.3.0)
57
+ oa-openid (0.2.3)
58
+ oa-core (= 0.2.3)
59
+ rack-openid (~> 1.2.0)
60
+ ruby-openid-apps-discovery
61
+ oauth (0.4.5)
62
+ oauth2 (0.3.0)
63
+ faraday (~> 0.6.0)
64
+ multi_json (~> 0.0.4)
65
+ omniauth (0.2.3)
66
+ oa-basic (= 0.2.3)
67
+ oa-core (= 0.2.3)
68
+ oa-enterprise (= 0.2.3)
69
+ oa-more (= 0.2.3)
70
+ oa-oauth (= 0.2.3)
71
+ oa-openid (= 0.2.3)
72
+ pyu-ruby-sasl (0.0.3.3)
73
+ rack (1.3.2)
74
+ rack-flash (0.1.2)
75
+ rack
76
+ rack-openid (1.2.0)
77
+ rack (>= 1.1.0)
78
+ ruby-openid (>= 2.1.8)
79
+ rake (0.9.2)
80
+ rcov (0.9.9)
81
+ rdoc (3.9.1)
82
+ rest-client (1.6.3)
83
+ mime-types (>= 1.16)
84
+ ruby-openid (2.1.8)
85
+ ruby-openid-apps-discovery (1.2.0)
86
+ ruby-openid (>= 2.1.7)
87
+ rubyntlm (0.1.1)
88
+ sinatra (1.2.6)
89
+ rack (~> 1.1)
90
+ tilt (< 2.0, >= 1.2.2)
91
+ sqlite3 (1.3.4)
92
+ tilt (1.3.2)
93
+
94
+ PLATFORMS
95
+ ruby
96
+
97
+ DEPENDENCIES
98
+ bundler (>= 1.0.0)
99
+ dm-core
100
+ dm-migrations
101
+ dm-postgres-adapter
102
+ jeweler (~> 1.6.2)
103
+ omniauth
104
+ rack-flash
105
+ rcov
106
+ rdoc (>= 2.4.0)
107
+ sinatra
108
+ sqlite3
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Clifford Heath
2
+ Copyright (c) 2011 Markus Proske
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in
12
+ all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
@@ -0,0 +1,111 @@
1
+ = sinatra_omniauth
2
+
3
+ Sinatra OmniAuth provides a Sinatra extension for adding pure OmniAuth authentication
4
+ to your Sinatra application. "Pure" here means that you don't even need a username
5
+ on the system, let alone a password; you just sign in using one of your existing
6
+ social media accounts.
7
+
8
+ SinatraOmniAuth uses DataMapper and Haml, though you can write your own templates too.
9
+ SinatraOmniAuth uses the wonderful icon set from <https://github.com/intridea/authbuttons>
10
+
11
+ == Description
12
+
13
+ Read Markus Proske's full article "Omniauth pure: Authentication with Facebook, Google, Google Apps, Twitter, Github, AOL, MyOpenID and many other OpenID providers" on CommunityGuides.
14
+ Copyright (c) 2011 Markus Proske
15
+ Copyright (c) 2011 Clifford Heath
16
+
17
+ This article demonstrates how to set up a multi-provider authentication in Rails using the fabulous Omniauth gem. Users can add multiple providers to their account and views for sign-in, sign-up and management of linked accounts are provided. The full source code is available on Github as a basis for your own projects.
18
+
19
+ This gem, sinatra_omniauth, provides a partial clone of the Omniauth_pure functionality, but as a Sinatra extension using DataMapper and various other goodies.
20
+
21
+ == Using sinatra_omniauth
22
+
23
+ In your Gemfile, add:
24
+
25
+ gem 'sinatra_omniauth'
26
+
27
+ In the root directory of your app (same dir as config.ru), add your API keys to "omniauth.yml"
28
+
29
+ In your application:
30
+
31
+ require 'sinatra/omniauth'
32
+
33
+ set :omniauth, YAML.load_file(File.dirname(__FILE__)+"/omniauth.yml")
34
+
35
+ register SinatraOmniAuth
36
+
37
+ Models:
38
+ Copy user.rb and authentication.rb from the models directory, and add any
39
+ other fields and relationships you need.
40
+
41
+ Routes which SinatraOmniAuth will handle (you may override these if needed):
42
+ /auth
43
+ presents a list of configured authentication services, including the
44
+ user's current sign-in account and any other registered accounts.
45
+ This page also includes a signout link and the ability to delete
46
+ secondary authentication methods.
47
+ /auth/signout
48
+ Signs the user out immediately and redirects to '/'
49
+ /auth/<provider>/callback
50
+ This URL is triggered when the authentication service redirects the user's
51
+ browser here, after a successful authentication. The handler signs in the
52
+ user, who may be a new user just joining, an existing user adding a new
53
+ authentication method, or an existing user signing in or changing to a
54
+ different authentication method
55
+ /auth/failure
56
+ Sets a flash saying that the authorization failed before redirecting to .
57
+ /auth/:id
58
+ A POST here with the magic _method=delete will delete this authentication
59
+ method from the current user's account
60
+
61
+ Views:
62
+ Copy views/auth.haml and css/auth.css to wherever they will be found.
63
+
64
+ Note that auth.haml uses assets helpers include_javascripts and include_stylesheets
65
+ to load packed or unpacked JS (jQuery required) and CSS. Youy'll be wanting to
66
+ style it all up yourself anyhow, but when you're there, replace the helpers as needed.
67
+
68
+ Images:
69
+ Use the authbuttons images as noted. auth.haml expects them to be in </images/authbuttons/>
70
+
71
+ Helper methods:
72
+ authenticate_user!
73
+ Redirects to /auth if the user is not already signed in
74
+ current_user
75
+ The User record of the current signed-in user
76
+ current_auth
77
+ The Authentication record with which the user is signed in.
78
+ Note that for most authentication services, this includes the user's name
79
+ and email address.
80
+
81
+ Make sure you add a handler for the following routes:
82
+ get '/auth/welcome' - When a new user first joins
83
+ get '/auth/signedin' - When the user signs in
84
+
85
+ These handlers may simply set a flash and redirect to another place.
86
+
87
+ Oh, did I say flash? SinatraOmniAuth uses the "rack-flash" gem, so you can say:
88
+
89
+ flash.notice = "Welcome back!"; redirect to('/')
90
+ ... and also access flash.error, flash.notice, etc, in your views.
91
+
92
+ == Contributing to sinatra_omniauth
93
+
94
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
95
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
96
+ * Fork the project
97
+ * Start a feature/bugfix branch
98
+ * Commit and push until you are happy with your contribution
99
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
100
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
101
+
102
+ == Credits:
103
+
104
+ Omniauth: http://github.com/intridea/omniauth
105
+ authbuttons: http://github.com/intridea/authbuttons
106
+ Omniauth pure and article: Markus Proske
107
+
108
+ == Copyright
109
+
110
+ Copyright (c) 2011 Clifford Heath. MIT Licensed. See LICENSE.txt for further details.
111
+
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "sinatra_omniauth"
18
+ gem.homepage = "http://github.com/cjheath/sinatra_omniauth"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{A Sinatra extension that provides pure OmniAuth goodness to your application (with DataMapper)}
21
+ gem.description = %Q{This Sinatra extension, derived from omniauth_pure by Marcus Proske, adds OmniAuth authorization to your Sinatra application, so your users can login using FaceBook, Twitter and many other authorization providers, as long as you supply the API keys. It uses DataMapper and HAML.}
22
+ gem.email = "clifford.heath@gmail.com"
23
+ gem.authors = ["Clifford Heath"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ require 'rcov/rcovtask'
36
+ Rcov::RcovTask.new do |test|
37
+ test.libs << 'test'
38
+ test.pattern = 'test/**/test_*.rb'
39
+ test.verbose = true
40
+ test.rcov_opts << '--exclude "gems/*"'
41
+ end
42
+
43
+ task :default => :test
44
+
45
+ require 'rdoc/task'
46
+ RDoc::Task.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "sinatra_omniauth #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.0
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Driver program for Sinatra Omniauth gem.
4
+ # You don't need to use this in your program, it just demonstrates the minimum to get things running
5
+ #
6
+
7
+ require 'sinatra'
8
+ require 'dm-core'
9
+ require 'dm-migrations'
10
+ require 'dm-sqlite-adapter'
11
+
12
+ DataMapper::Logger.new($stdout, :debug)
13
+ DataMapper.setup(:default, "sqlite3://#{Dir.pwd}/omniauth_sinatra.sqlite3")
14
+
15
+ DataMapper.auto_upgrade!
16
+
17
+ app = Sinatra::Omniauth.new
18
+
19
+ # Set up API keys:
20
+ app.settings.set :omniauth, {
21
+ :facebook => []
22
+ # etc...
23
+ }
24
+
25
+ run app
@@ -0,0 +1,47 @@
1
+ /* Authentication "badge" */
2
+ .authentication {
3
+ position: relative;
4
+ display: inline-block;
5
+ padding: 0.1em 0.5em 0.1em 0.5em;
6
+ margin: 0.5em 0.3em;
7
+ Xpadding: 5px;
8
+ min-height: 40px;
9
+ background-color: #EEE;
10
+ border-radius: 0.5em; border: 2px black;
11
+ -webkit-box-shadow: 0 0 5px #000; -moz-box-shadow: 0 0 5px #000; box-shadow: 0 0 5px #000;
12
+ background-repeat: no-repeat;
13
+ background-position: left center;
14
+ cursor: pointer;
15
+ }
16
+ .authentication.available {
17
+ padding-right: 1em;
18
+ }
19
+ .authentication.current {
20
+ padding-right: 0em;
21
+ cursor: default;
22
+ }
23
+ .authentication.available *,
24
+ .authentication.current * {
25
+ margin: 3px 10px 3px 32px;
26
+ }
27
+ .authentication * {
28
+ margin: 12px 8px 12px 32px;
29
+ }
30
+ .authentication .provider {
31
+ font-weight: bold;
32
+ }
33
+ .authentication .remove { /* The X to delete this authentication method */
34
+ position: absolute;
35
+ right: 0px;
36
+ top: 0px;
37
+ }
38
+
39
+ /* Alternate auth providers */
40
+ .auth_provider {
41
+ position: relative;
42
+ display: inline-block;
43
+ text-align: center;
44
+ }
45
+ .auth_provider * {
46
+ display:block;
47
+ }
@@ -0,0 +1,16 @@
1
+ require 'dm-core'
2
+ require 'dm-timestamps'
3
+
4
+ class Authorization
5
+ include DataMapper::Resource
6
+ belongs_to :user
7
+
8
+ property :id, Serial
9
+ property :user_id, Integer
10
+ property :provider, String
11
+ property :uid, String
12
+ property :uname, String
13
+ property :uemail, String
14
+ property :created_at, DateTime
15
+ property :updated_at, DateTime
16
+ end
@@ -0,0 +1,14 @@
1
+ require 'dm-core'
2
+ require 'dm-timestamps'
3
+
4
+ class User
5
+ include DataMapper::Resource
6
+
7
+ property :id, Serial
8
+ property :name, String
9
+ property :email, String
10
+ property :created_at, DateTime
11
+ property :updated_at, DateTime
12
+
13
+ has n, :authorizations
14
+ end
@@ -0,0 +1,273 @@
1
+ #
2
+ # Sinatra OmniAuth
3
+ #
4
+ # Copyright 2011 Clifford Heath.
5
+ # License: MIT
6
+ #
7
+ # Sinatra OmniAuth provides a Sinatra extension for adding pure OmniAuth authentication
8
+ # to your Sinatra application. "Pure" here means that you don't even need a username
9
+ # on the system, let alone a password; you just sign in using one of your existing
10
+ # social media accounts.
11
+ #
12
+ # SinatraOmniAuth uses DataMapper and Haml, though you can write your own templates too.
13
+ # SinatraOmniAuth uses the wonderful icon set from <https://github.com/intridea/authbuttons>
14
+ #
15
+ # Usage:
16
+ # In your Gemfile, add:
17
+ #
18
+ # gem 'sinatra_omniauth'
19
+ #
20
+ # In the root directory of your app (same dir as config.ru), add your API keys to "omniauth.yml"
21
+ #
22
+ # In your application:
23
+ #
24
+ # require 'sinatra/omniauth'
25
+ #
26
+ # set :omniauth, YAML.load_file(File.dirname(__FILE__)+"/omniauth.yml")
27
+ #
28
+ # register SinatraOmniAuth
29
+ #
30
+ # Models:
31
+ # Copy user.rb and authentication.rb from the models directory, and add any
32
+ # other fields and relationships you need.
33
+ #
34
+ # Routes which SinatraOmniAuth will handle (you may override these if needed):
35
+ # /auth
36
+ # presents a list of configured authentication services, including the
37
+ # user's current sign-in account and any other registered accounts.
38
+ # This page also includes a signout link and the ability to delete
39
+ # secondary authentication methods.
40
+ # /auth/signout
41
+ # Signs the user out immediately and redirects to '/'
42
+ # /auth/<provider>/callback
43
+ # This URL is triggered when the authentication service redirects the user's
44
+ # browser here, after a successful authentication. The handler signs in the
45
+ # user, who may be a new user just joining, an existing user adding a new
46
+ # authentication method, or an existing user signing in or changing to a
47
+ # different authentication method
48
+ # /auth/failure
49
+ # Sets a flash saying that the authorization failed before redirecting to .
50
+ # /auth/:id
51
+ # A POST here with the magic _method=delete will delete this authentication
52
+ # method from the current user's account
53
+ #
54
+ # Views:
55
+ # Copy views/auth.haml and css/auth.css to wherever they will be found.
56
+ #
57
+ # Note that auth.haml uses assets helpers include_javascripts and include_stylesheets
58
+ # to load packed or unpacked JS (jQuery required) and CSS. Youy'll be wanting to
59
+ # style it all up yourself anyhow, but when you're there, replace the helpers as needed.
60
+ #
61
+ # Images:
62
+ # Use the authbuttons images as noted. auth.haml expects them to be in </images/authbuttons/>
63
+ #
64
+ # Helper methods:
65
+ # authenticate_user!
66
+ # Redirects to /auth if the user is not already signed in
67
+ # current_user
68
+ # The User record of the current signed-in user
69
+ # current_auth
70
+ # The Authentication record with which the user is signed in.
71
+ # Note that for most authentication services, this includes the user's name
72
+ # and email address.
73
+ #
74
+ # Make sure you add a handler for the following routes:
75
+ # get '/auth/welcome' - When a new user first joins
76
+ # get '/auth/signedin' - When the user signs in
77
+ #
78
+ # These handlers may simply set a flash and redirect to another place.
79
+ #
80
+ # Oh, did I say flash? SinatraOmniAuth uses the "rack-flash" gem, so you can say:
81
+ #
82
+ # flash.notice = "Welcome back!"; redirect to('/')
83
+ # ... and also access flash.error, flash.notice, etc, in your views.
84
+ #
85
+ # You're welcome :)
86
+ #
87
+ require 'omniauth'
88
+ require 'openid/store/filesystem'
89
+ require 'rack-flash'
90
+
91
+ module SinatraOmniAuth
92
+ module Helpers
93
+ def current_user
94
+ @current_user ||= User.get(session[:user_id]) if session[:user_id]
95
+ end
96
+
97
+ def current_auth
98
+ @current_auth ||= Authentication.get(session[:authentication_id]) if session[:authentication_id]
99
+ end
100
+
101
+ def authenticate_user!
102
+ if !current_user
103
+ flash.error = 'You need to sign in before you can access this page!'
104
+ redirect to('/auth')
105
+ end
106
+ end
107
+ end
108
+
109
+ def self.registered app
110
+ # Register OmniAuth Strategies and keys for all providers:
111
+ app.use ::OmniAuth::Builder do
112
+ app.settings.omniauth.each do |a|
113
+ provider = a['provider']
114
+ if key = a['key']
115
+ provider provider, key, a['secret'], (a['client_options'] || {})
116
+ else
117
+ name = a['name'].downcase.gsub(/ /,' ')
118
+ store = OpenID::Store::Filesystem.new(a['store']||'./tmp')
119
+ provider provider, store, :name => name, :identifier => a['identifier']
120
+ end
121
+ end
122
+ end
123
+
124
+ # Make _method=delete work in POST requests:
125
+ app.enable :method_override
126
+
127
+ # Create a flash, so we can display a message after a redirect
128
+ app.use Rack::Flash, :accessorize => [:notice, :error]
129
+ app.send(:define_method, :flash) do
130
+ env['x-rack.flash']
131
+ end
132
+
133
+ # A little help from our friends...
134
+ app.send(:include, Helpers)
135
+
136
+ # Display the authentication in use, registered for the current user, and available
137
+ app.get '/auth' do
138
+ @authentications_possible = settings.omniauth
139
+
140
+ if current_user
141
+ @authentication_current = Authentication.get(session[:authentication_id])
142
+ @authentications_available = current_user.authentications.all(:order => [ :provider.desc ])
143
+ @authentications_unused = @authentications_available.
144
+ reject do|a|
145
+ a.id == @authentication_current.id
146
+ end
147
+ @authentications_possible = @authentications_possible.dup.
148
+ reject do |a|
149
+ @authentications_available.detect{|p| p.provider == a['provider'] }
150
+ end
151
+ end
152
+
153
+ haml :auth
154
+ end
155
+
156
+ app.get '/auth/:authentication/callback' do
157
+ # callback: success
158
+ # This handles signing in and adding an authentication authentication to existing accounts itself
159
+
160
+ # get the authentication parameter from the Rails router
161
+ authentication_route = params[:authentication] ? params[:authentication] : 'No authentication recognized (invalid callback)'
162
+
163
+ # get the full hash from omniauth
164
+ omniauth = request.env['omniauth.auth']
165
+
166
+ # continue only if hash and parameter exist
167
+ unless omniauth and params[:authentication]
168
+ flash.error = 'Error while authenticating via ' + authentication_route.capitalize + '. The authentication did not return valid data.'
169
+ redirect to('/signin')
170
+ end
171
+
172
+ # create a new regularised authentication hash
173
+ @authhash = Hash.new
174
+ oaeuh = omniauth['extra']['user_hash']
175
+ oaui = omniauth['user_info']
176
+ if authentication_route == 'facebook'
177
+ @authhash[:email] = oaeuh['email'] || ''
178
+ @authhash[:name] = oaeuh['name'] || ''
179
+ @authhash[:uid] = oaeuh['name'] || ''
180
+ @authhash[:provider] = omniauth['provider'] || ''
181
+ elsif authentication_route == 'github'
182
+ @authhash[:email] = oaui['email'] || ''
183
+ @authhash[:name] = oaui['name'] || ''
184
+ @authhash[:uid] = (oaeuh['id'] || '').to_s
185
+ @authhash[:provider] = omniauth['provider'] || ''
186
+ elsif ['google', 'yahoo', 'linked_in', 'twitter', 'myopenid', 'openid', 'open_id'].index(authentication_route) != nil
187
+ @authhash[:email] = oaui['email'] || ''
188
+ @authhash[:name] = oaui['name'] || ''
189
+ @authhash[:uid] = (omniauth['uid'] || '').to_s
190
+ @authhash[:provider] = omniauth['provider'] || ''
191
+ else
192
+ # REVISIT: debug to output the hash that has been returned when adding new authentications
193
+ return '<pre>'+omniauth.to_yaml+'</pre>'
194
+ end
195
+
196
+ if @authhash[:uid] == '' or @authhash[:provider] == ''
197
+ flash.error = 'Error while authenticating via ' + authentication_route + '/' + @authhash[:provider].capitalize + '. The authentication returned invalid data for the user id.'
198
+ redirect to('/auth')
199
+ end
200
+
201
+ auth = Authentication.first(:provider => @authhash[:provider], :uid => @authhash[:uid])
202
+
203
+ # if the user is currently signed in, he/she might want to add another account to signin
204
+ if current_user
205
+ if auth
206
+ flash.notice = 'You are now signed in using your' + @authhash[:provider].capitalize + ' account'
207
+ session[:authentication_id] = auth.id # They're now signed in using the new account
208
+ redirect to('/auth/signedin') # Already signed in, and we already had this authentication
209
+ else
210
+ auth = current_user.authentications.create!(:provider => @authhash[:provider], :uid => @authhash[:uid], :user_name => @authhash[:name], :user_email => @authhash[:email])
211
+ flash.notice = 'Your ' + @authhash[:provider].capitalize + ' account has been added for signing in at this site.'
212
+ session[:authentication_id] = auth.id # They're now signed in using the new account
213
+ session[:user_name] = @authhash[:name] if @authhash[:name] != ''
214
+ redirect to('/auth/signedin')
215
+ end
216
+ else
217
+ if auth
218
+ # Signin existing user
219
+ # in the session his user id and the authentication id used for signing in is stored
220
+ session[:user_id] = auth.user.id
221
+ session[:authentication_id] = auth.id
222
+ session[:user_name] = @authhash[:name] if @authhash[:name] != ''
223
+
224
+ flash.notice = 'Signed in successfully via ' + @authhash[:provider].capitalize + '.'
225
+ redirect to('/auth/signedin')
226
+ end
227
+
228
+ # this is a new user; add them
229
+ @current_user = User.create()
230
+ session[:user_id] = @current_user.id
231
+ session[:user_name] = @authhash[:name] if @authhash[:name] != ''
232
+ auth = current_user.authentications.create!(:provider => @authhash[:provider], :uid => @authhash[:uid], :user_name => @authhash[:name], :user_email => @authhash[:email])
233
+ session[:authentication_id] = auth.id
234
+ redirect to('/auth/welcome')
235
+ end
236
+ end
237
+
238
+ app.get '/auth/failure' do
239
+ flash.error = 'There was an error at the remote authentication authentication. You have not been signed in.'
240
+ redirect to('/')
241
+ end
242
+
243
+ app.get '/auth/signout' do
244
+ authenticate_user!
245
+
246
+ session[:user_id] = nil
247
+ session[:user_name] = nil
248
+ session[:authentication_id] = nil
249
+ session.delete :user_id
250
+ session.delete :user_name
251
+ session.delete :authentication_id
252
+ flash.notice = 'You have been signed out'
253
+ redirect to('/')
254
+ end
255
+
256
+ # authentication
257
+ app.delete '/auth/:id' do
258
+ authenticate_user!
259
+
260
+ # remove an authentication authentication linked to the current user
261
+ @authentication = current_user.authentications.get(params[:id])
262
+
263
+ if session[:authentication_id] == @authentication.id
264
+ flash.error = 'You can\'t delete this authorization because you are currently signed in with it!'
265
+ else
266
+ @authentication.destroy
267
+ end
268
+
269
+ redirect to('/auth')
270
+ end
271
+
272
+ end
273
+ end