sinatra_omniauth 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +108 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +111 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/config.ru +25 -0
- data/css/auth.css +47 -0
- data/lib/models/authorization.rb +16 -0
- data/lib/models/user.rb +14 -0
- data/lib/sinatra/omniauth.rb +273 -0
- data/models/authentication.rb +12 -0
- data/models/user.rb +12 -0
- data/omniauth.yml +71 -0
- data/public/css/omniauth.css +34 -0
- data/public/images/authbuttons/aol_128.png +0 -0
- data/public/images/authbuttons/aol_256.png +0 -0
- data/public/images/authbuttons/aol_32.png +0 -0
- data/public/images/authbuttons/aol_64.png +0 -0
- data/public/images/authbuttons/basecamp_128.png +0 -0
- data/public/images/authbuttons/basecamp_256.png +0 -0
- data/public/images/authbuttons/basecamp_32.png +0 -0
- data/public/images/authbuttons/basecamp_64.png +0 -0
- data/public/images/authbuttons/campfire_128.png +0 -0
- data/public/images/authbuttons/campfire_256.png +0 -0
- data/public/images/authbuttons/campfire_32.png +0 -0
- data/public/images/authbuttons/campfire_64.png +0 -0
- data/public/images/authbuttons/facebook_128.png +0 -0
- data/public/images/authbuttons/facebook_256.png +0 -0
- data/public/images/authbuttons/facebook_32.png +0 -0
- data/public/images/authbuttons/facebook_64.png +0 -0
- data/public/images/authbuttons/github_128.png +0 -0
- data/public/images/authbuttons/github_256.png +0 -0
- data/public/images/authbuttons/github_32.png +0 -0
- data/public/images/authbuttons/github_64.png +0 -0
- data/public/images/authbuttons/google_128.png +0 -0
- data/public/images/authbuttons/google_256.png +0 -0
- data/public/images/authbuttons/google_32.png +0 -0
- data/public/images/authbuttons/google_64.png +0 -0
- data/public/images/authbuttons/linkedin_128.png +0 -0
- data/public/images/authbuttons/linkedin_256.png +0 -0
- data/public/images/authbuttons/linkedin_32.png +0 -0
- data/public/images/authbuttons/linkedin_64.png +0 -0
- data/public/images/authbuttons/myspace_128.png +0 -0
- data/public/images/authbuttons/myspace_256.png +0 -0
- data/public/images/authbuttons/myspace_32.png +0 -0
- data/public/images/authbuttons/myspace_64.png +0 -0
- data/public/images/authbuttons/openid_128.png +0 -0
- data/public/images/authbuttons/openid_256.png +0 -0
- data/public/images/authbuttons/openid_32.png +0 -0
- data/public/images/authbuttons/openid_64.png +0 -0
- data/public/images/authbuttons/presently_128.png +0 -0
- data/public/images/authbuttons/presently_256.png +0 -0
- data/public/images/authbuttons/presently_32.png +0 -0
- data/public/images/authbuttons/presently_64.png +0 -0
- data/public/images/authbuttons/twitter_128.png +0 -0
- data/public/images/authbuttons/twitter_256.png +0 -0
- data/public/images/authbuttons/twitter_32.png +0 -0
- data/public/images/authbuttons/twitter_64.png +0 -0
- data/public/images/authbuttons/yahoo_128.png +0 -0
- data/public/images/authbuttons/yahoo_256.png +0 -0
- data/public/images/authbuttons/yahoo_32.png +0 -0
- data/public/images/authbuttons/yahoo_64.png +0 -0
- data/sinatra_omniauth.gemspec +137 -0
- data/test/helper.rb +18 -0
- data/test/test_sinatra_omniauth.rb +7 -0
- data/views/auth.haml +62 -0
- metadata +292 -0
data/.document
ADDED
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
|
data/Gemfile.lock
ADDED
@@ -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
|
data/LICENSE.txt
ADDED
@@ -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.
|
data/README.rdoc
ADDED
@@ -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
|
+
|
data/Rakefile
ADDED
@@ -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
|
data/config.ru
ADDED
@@ -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
|
data/css/auth.css
ADDED
@@ -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
|
data/lib/models/user.rb
ADDED
@@ -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
|