svenfuchs-devise_oauth2_authenticatable 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +145 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/devise_oauth2_authenticatable.gemspec +74 -0
- data/lib/devise_oauth2_authenticatable.rb +65 -0
- data/lib/devise_oauth2_authenticatable/locales/en.yml +9 -0
- data/lib/devise_oauth2_authenticatable/model.rb +196 -0
- data/lib/devise_oauth2_authenticatable/rails.rb +24 -0
- data/lib/devise_oauth2_authenticatable/routes.rb +7 -0
- data/lib/devise_oauth2_authenticatable/schema.rb +22 -0
- data/lib/devise_oauth2_authenticatable/strategy.rb +100 -0
- data/lib/devise_oauth2_authenticatable/view_helpers.rb +29 -0
- data/lib/generators/devise/oauth2_authenticatable/USAGE +8 -0
- data/lib/generators/devise/oauth2_authenticatable/oauth2_authenticatable_generator.rb +17 -0
- data/lib/generators/devise/oauth2_authenticatable/templates/oauth2.yml +24 -0
- data/spec/devise_oauth2_authenticatable_spec.rb +7 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +9 -0
- metadata +148 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 bhbryant
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
= devise_oauth2_authenticatable
|
2
|
+
|
3
|
+
== This fork works with Devise 1.1 + Rails 3
|
4
|
+
|
5
|
+
|
6
|
+
==Quick tutorial for Devise 1.1 + Rails 3 + devise_oauth2_authenticatable
|
7
|
+
|
8
|
+
Set up your Facebook app at http://developers.facebook.com/setup/
|
9
|
+
|
10
|
+
Create the Rails app:
|
11
|
+
rails new YOUR_APP
|
12
|
+
cd YOUR_APP
|
13
|
+
|
14
|
+
Add the following lines to your Gemfile:
|
15
|
+
gem "oauth2"
|
16
|
+
gem "devise", :git => "git://github.com/plataformatec/devise.git"
|
17
|
+
gem "devise_oauth2_authenticatable", :git => "git://github.com/jerryluk/devise_oauth2_authenticatable.git"
|
18
|
+
|
19
|
+
Run the following commands:
|
20
|
+
bundle install
|
21
|
+
rails g devise:install
|
22
|
+
rails g devise User
|
23
|
+
rails g devise:oauth2_authenticatable APP_ID SECRET
|
24
|
+
|
25
|
+
Your DeviseCreateUsers migration should look like this:
|
26
|
+
class DeviseCreateUsers < ActiveRecord::Migration
|
27
|
+
def self.up
|
28
|
+
create_table(:users) do |t|
|
29
|
+
t.database_authenticatable
|
30
|
+
t.rememberable
|
31
|
+
t.trackable
|
32
|
+
t.oauth2_authenticatable
|
33
|
+
t.string :email
|
34
|
+
|
35
|
+
t.timestamps
|
36
|
+
end
|
37
|
+
|
38
|
+
add_index :users, :oauth2_uid, :unique => true
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.down
|
42
|
+
drop_table :users
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Make sure user.rb has the following line:
|
47
|
+
devise :oauth2_authenticatable, ...
|
48
|
+
|
49
|
+
Add this to your application_controller.rb:
|
50
|
+
before_filter :authenticate_user!
|
51
|
+
|
52
|
+
Add the sign in/sign out links to your applications.html.erb:
|
53
|
+
<% if user_signed_in? %>
|
54
|
+
<%= link_to "Sign out", destroy_user_session_path %>
|
55
|
+
<% else %>
|
56
|
+
<%= link_to_oauth2 "Sign In with Facebook" %>
|
57
|
+
<% end %>
|
58
|
+
|
59
|
+
The usual stuffs:
|
60
|
+
rm public/index.html
|
61
|
+
rake db:create
|
62
|
+
rake db:migrate
|
63
|
+
rails s
|
64
|
+
|
65
|
+
Navigate your browser to http://localhost:3000, there are many things to fix but you are mostly there!
|
66
|
+
|
67
|
+
==
|
68
|
+
This is the basic framework for an OAuth2 gem for Devise.
|
69
|
+
|
70
|
+
It currently works with FacebookGraph, to get started begin by registering a new application at
|
71
|
+
|
72
|
+
http://developers.facebook.com/setup/
|
73
|
+
|
74
|
+
|
75
|
+
A generator is provided for creating your oauth yml file
|
76
|
+
|
77
|
+
rails g devise:oauth2_authenticatable
|
78
|
+
|
79
|
+
Ex:
|
80
|
+
|
81
|
+
rails g devise:oauth2_authenticatable APP_ID SECRET 'email,offline_access,publish_stream'
|
82
|
+
|
83
|
+
|
84
|
+
for more details
|
85
|
+
|
86
|
+
http://developers.facebook.com/docs/authentication/
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
It's based on the devise facebook gem provided by grimen
|
91
|
+
|
92
|
+
http://github.com/grimen/devise_facebook_connectable
|
93
|
+
|
94
|
+
|
95
|
+
|
96
|
+
And uses the example provided in OAuth2 library provided by mbleigh
|
97
|
+
|
98
|
+
http://github.com/intridea/oauth2
|
99
|
+
|
100
|
+
|
101
|
+
DB Migration :
|
102
|
+
|
103
|
+
add_column :users, :oauth2_uid, :integer, :limit => 8 # BIGINT unsigned / 64-bit int
|
104
|
+
add_column :users, :oauth2_token, :string, :limit => 149 # [128][1][20] chars
|
105
|
+
add_index :users, :oauth2_uid, :unique => true
|
106
|
+
|
107
|
+
|
108
|
+
|
109
|
+
Note:
|
110
|
+
|
111
|
+
A little souce of confusion when working with Facebook Graph
|
112
|
+
|
113
|
+
The api key and secret key are no the same a Facebook Connect/the old API.
|
114
|
+
|
115
|
+
The client id should be your application id and the client_key, should be your API key (not secret key)
|
116
|
+
|
117
|
+
|
118
|
+
== TODO
|
119
|
+
|
120
|
+
Write tests :
|
121
|
+
Currently no tests have been written. My bad.
|
122
|
+
|
123
|
+
Add Javascript / token based auth :
|
124
|
+
Facebook graph offes a complete authorization solution using javascript and a returned authentication token. Adding optional support for this would complete the Facebook Graph authentication interface.
|
125
|
+
|
126
|
+
Generalize for OAuth2:
|
127
|
+
Add support for other OAuth2 services. Wrote this specifically for facebook graph, althought configuration arugments should be generalized to support other interfaces.
|
128
|
+
|
129
|
+
|
130
|
+
|
131
|
+
Description goes here.
|
132
|
+
|
133
|
+
== Note on Patches/Pull Requests
|
134
|
+
|
135
|
+
* Fork the project.
|
136
|
+
* Make your feature addition or bug fix.
|
137
|
+
* Add tests for it. This is important so I don't break it in a
|
138
|
+
future version unintentionally.
|
139
|
+
* Commit, do not mess with rakefile, version, or history.
|
140
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
141
|
+
* Send me a pull request. Bonus points for topic branches.
|
142
|
+
|
143
|
+
== Copyright
|
144
|
+
|
145
|
+
Copyright (c) 2010 bhbryant. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "devise_oauth2_authenticatable"
|
8
|
+
gem.summary = %Q{Implements OAuth2 for Devise }
|
9
|
+
gem.description = %Q{Implements OAuth2 for Devise, specifically integrating with facebook Graph}
|
10
|
+
gem.email = "benjamin@bryantmarkowsky.com"
|
11
|
+
gem.homepage = "http://github.com/bhbryant/devise_oauth2_authenticatable"
|
12
|
+
gem.authors = ["bhbryant"]
|
13
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
14
|
+
|
15
|
+
gem.add_dependency'devise', '>= 1.0.0'
|
16
|
+
gem.add_dependency "oauth2"
|
17
|
+
gem.add_dependency "json"
|
18
|
+
|
19
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
20
|
+
end
|
21
|
+
Jeweler::GemcutterTasks.new
|
22
|
+
rescue LoadError
|
23
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'spec/rake/spectask'
|
27
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
28
|
+
spec.libs << 'lib' << 'spec'
|
29
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
30
|
+
end
|
31
|
+
|
32
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
33
|
+
spec.libs << 'lib' << 'spec'
|
34
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
35
|
+
spec.rcov = true
|
36
|
+
end
|
37
|
+
|
38
|
+
task :spec => :check_dependencies
|
39
|
+
|
40
|
+
task :default => :spec
|
41
|
+
|
42
|
+
require 'rake/rdoctask'
|
43
|
+
Rake::RDocTask.new do |rdoc|
|
44
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
45
|
+
|
46
|
+
rdoc.rdoc_dir = 'rdoc'
|
47
|
+
rdoc.title = "devise_oauth2_authenticatable #{version}"
|
48
|
+
rdoc.rdoc_files.include('README*')
|
49
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
50
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{svenfuchs-devise_oauth2_authenticatable}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["bhbryant"]
|
12
|
+
s.date = %q{2010-06-13}
|
13
|
+
s.description = %q{Implements OAuth2 for Devise}
|
14
|
+
s.email = %q{benjamin@bryantmarkowsky.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"devise_oauth2_authenticatable.gemspec",
|
27
|
+
"lib/devise_oauth2_authenticatable.rb",
|
28
|
+
"lib/devise_oauth2_authenticatable/locales/en.yml",
|
29
|
+
"lib/devise_oauth2_authenticatable/rails.rb",
|
30
|
+
"lib/devise_oauth2_authenticatable/model.rb",
|
31
|
+
"lib/devise_oauth2_authenticatable/routes.rb",
|
32
|
+
"lib/devise_oauth2_authenticatable/schema.rb",
|
33
|
+
"lib/devise_oauth2_authenticatable/strategy.rb",
|
34
|
+
"lib/devise_oauth2_authenticatable/view_helpers.rb",
|
35
|
+
"lib/generators/devise/oauth2_authenticatable/oauth2_authenticatable_generator.rb",
|
36
|
+
"lib/generators/devise/oauth2_authenticatable/templates/oauth2.yml",
|
37
|
+
"lib/generators/devise/oauth2_authenticatable/USAGE",
|
38
|
+
"spec/devise_oauth2_authenticatable_spec.rb",
|
39
|
+
"spec/spec.opts",
|
40
|
+
"spec/spec_helper.rb"
|
41
|
+
]
|
42
|
+
s.homepage = %q{http://github.com/bhbryant/devise_oauth2_authenticatable}
|
43
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
44
|
+
s.require_paths = ["lib"]
|
45
|
+
s.rubygems_version = %q{1.3.6}
|
46
|
+
s.summary = %q{Implements OAuth2 for Devise}
|
47
|
+
s.test_files = [
|
48
|
+
"spec/devise_oauth2_authenticatable_spec.rb",
|
49
|
+
"spec/spec_helper.rb"
|
50
|
+
]
|
51
|
+
|
52
|
+
if s.respond_to? :specification_version then
|
53
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
54
|
+
s.specification_version = 3
|
55
|
+
|
56
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
57
|
+
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
58
|
+
s.add_runtime_dependency(%q<devise>, [">= 1.0.0"])
|
59
|
+
s.add_runtime_dependency(%q<oauth2>, [">= 0"])
|
60
|
+
s.add_runtime_dependency(%q<json>, [">= 0"])
|
61
|
+
else
|
62
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
63
|
+
s.add_dependency(%q<devise>, [">= 1.0.0"])
|
64
|
+
s.add_dependency(%q<oauth2>, [">= 0"])
|
65
|
+
s.add_dependency(%q<json>, [">= 0"])
|
66
|
+
end
|
67
|
+
else
|
68
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
69
|
+
s.add_dependency(%q<devise>, [">= 1.0.0"])
|
70
|
+
s.add_dependency(%q<oauth2>, [">= 0"])
|
71
|
+
s.add_dependency(%q<json>, [">= 0"])
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'devise'
|
3
|
+
require 'oauth2'
|
4
|
+
|
5
|
+
require 'devise_oauth2_authenticatable/model'
|
6
|
+
require 'devise_oauth2_authenticatable/strategy'
|
7
|
+
require 'devise_oauth2_authenticatable/schema'
|
8
|
+
require 'devise_oauth2_authenticatable/routes'
|
9
|
+
#require 'devise_oauth2_authenticatable/controller_filters'
|
10
|
+
require 'devise_oauth2_authenticatable/view_helpers'
|
11
|
+
require 'devise_oauth2_authenticatable/rails'
|
12
|
+
|
13
|
+
module Devise
|
14
|
+
# Specifies the name of the database column name used for storing
|
15
|
+
# the oauth UID. Useful if this info should be saved in a
|
16
|
+
# generic column if different authentication solutions are used.
|
17
|
+
mattr_accessor :oauth2_uid_field
|
18
|
+
@@oauth2_uid_field = :oauth2_uid
|
19
|
+
|
20
|
+
# Specifies the name of the database column name used for storing
|
21
|
+
# the user Facebook session key. Useful if this info should be saved in a
|
22
|
+
# generic column if different authentication solutions are used.
|
23
|
+
mattr_accessor :oauth2_token_field
|
24
|
+
@@oauth2_token_field = :oauth2_token
|
25
|
+
|
26
|
+
# Specifies if account should be created if no account exists for
|
27
|
+
# a specified Facebook UID or not.
|
28
|
+
mattr_accessor :oauth2_auto_create_account
|
29
|
+
@@oauth2_auto_create_account = true
|
30
|
+
|
31
|
+
def self.oauth2_client
|
32
|
+
@@oauth2_client ||= OAuth2::Client.new(
|
33
|
+
OAUTH2_CONFIG['client_id'],
|
34
|
+
OAUTH2_CONFIG['client_secret'],
|
35
|
+
:site => OAUTH2_CONFIG['authorization_server'],
|
36
|
+
:authorize_path => OAUTH2_CONFIG['authorize_path'],
|
37
|
+
:access_token_path => OAUTH2_CONFIG['access_token_path'])
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def self.session_sign_in_url(request, mapping)
|
42
|
+
url = URI.parse(request.url)
|
43
|
+
# url.path = "#{mapping.parsed_path}/#{mapping.path_names[:sign_in]}"
|
44
|
+
url.path = "/#{mapping.path}/#{mapping.path_names[:oauth2]}"
|
45
|
+
url.query = nil
|
46
|
+
url.to_s
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.requested_scope
|
50
|
+
@@requested_scope ||= OAUTH2_CONFIG['requested_scope']
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
# Load core I18n locales: en
|
56
|
+
#
|
57
|
+
I18n.load_path.unshift File.join(File.dirname(__FILE__), *%w[devise_oauth2_authenticatable locales en.yml])
|
58
|
+
|
59
|
+
# Add +:facebook_connectable+ strategies to defaults.
|
60
|
+
#
|
61
|
+
Devise.add_module(:oauth2_authenticatable,
|
62
|
+
:strategy => true,
|
63
|
+
:controller => :sessions,
|
64
|
+
:route => :oauth2,
|
65
|
+
:model => 'devise_oauth2_authenticatable/model')
|
@@ -0,0 +1,9 @@
|
|
1
|
+
en:
|
2
|
+
devise:
|
3
|
+
sessions:
|
4
|
+
oauth2_invalid: "Could not login. Invalid account."
|
5
|
+
oauth2_timeout: "OAuth2 session expired., please sign in again to continue."
|
6
|
+
oauth2_authenticity_token: "Something went wrong. For security reasons, please sign in again." # Revise this message =)
|
7
|
+
oauth2_actions:
|
8
|
+
sign_in: "Sign in" # NOTE: Not used for the default Facebook Connect button.
|
9
|
+
sign_out: "Sign out"
|
@@ -0,0 +1,196 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'devise/models'
|
3
|
+
|
4
|
+
|
5
|
+
module Devise #:nodoc:
|
6
|
+
# module OAuth2Authenticatable #:nodoc:
|
7
|
+
module Models #:nodoc:
|
8
|
+
|
9
|
+
# OAuth2 Connectable Module, responsible for validating authenticity of a
|
10
|
+
# user and storing credentials while signing in using their OAuth2 account.
|
11
|
+
#
|
12
|
+
# == Configuration:
|
13
|
+
#
|
14
|
+
# You can overwrite configuration values by setting in globally in Devise (+Devise.setup+),
|
15
|
+
# using devise method, or overwriting the respective instance method.
|
16
|
+
#
|
17
|
+
# +oauth2_uid_field+ - Defines the name of the OAuth2 user UID database attribute/column.
|
18
|
+
#
|
19
|
+
# +oauth2_token_field+ - Defines the name of the OAuth2 session key database attribute/column.
|
20
|
+
#
|
21
|
+
# +oauth2_auto_create_account+ - Speifies if account should automatically be created upon connect
|
22
|
+
# if not already exists.
|
23
|
+
#
|
24
|
+
# == Examples:
|
25
|
+
#
|
26
|
+
# User.oauth2_connect(:uid => '123456789') # returns authenticated user or nil
|
27
|
+
# User.find(1).oauth2_connected? # returns true/false
|
28
|
+
#
|
29
|
+
module Oauth2Authenticatable
|
30
|
+
|
31
|
+
def self.included(base) #:nodoc:
|
32
|
+
base.class_eval do
|
33
|
+
extend ClassMethods
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Store OAuth2 Connect account/session credentials.
|
38
|
+
#
|
39
|
+
def store_oauth2_credentials!(attributes = {})
|
40
|
+
self.send(:"#{self.class.oauth2_uid_field}=", attributes[:uid])
|
41
|
+
self.send(:"#{self.class.oauth2_token_field}=", attributes[:token])
|
42
|
+
|
43
|
+
# Confirm without e-mail - if confirmable module is loaded.
|
44
|
+
self.skip_confirmation! if self.respond_to?(:skip_confirmation!)
|
45
|
+
|
46
|
+
# Only populate +email+ field if it's available (e.g. if +authenticable+ module is used).
|
47
|
+
self.email = attributes[:email] || '' if self.respond_to?(:email)
|
48
|
+
|
49
|
+
# Lazy hack: These database fields are required if +authenticable+/+confirmable+
|
50
|
+
# module(s) is used. Could be avoided with :null => true for authenticatable
|
51
|
+
# migration, but keeping this to avoid unnecessary problems.
|
52
|
+
self.password_salt = '' if self.respond_to?(:password_salt)
|
53
|
+
self.encrypted_password = '' if self.respond_to?(:encrypted_password)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Checks if OAuth2 Connected.
|
57
|
+
#
|
58
|
+
def oauth2_connected?
|
59
|
+
self.send(:"#{self.class.oauth2_uid_field}").present?
|
60
|
+
end
|
61
|
+
alias :is_oauth2_connected? :oauth2_connected?
|
62
|
+
|
63
|
+
# Hook that gets called *before* connect (only at creation). Useful for
|
64
|
+
# specifiying additional user info (etc.) from OAuth2.
|
65
|
+
#
|
66
|
+
# Default: Do nothing.
|
67
|
+
#
|
68
|
+
# == Examples:
|
69
|
+
#
|
70
|
+
# # Overridden in OAuth2 Connect:able model, e.g. "User".
|
71
|
+
# #
|
72
|
+
# def before_oauth2_auto_create(oauth2_user_attributes)
|
73
|
+
|
74
|
+
# self.profile.first_name = oauth2_user_attributes.first_name
|
75
|
+
|
76
|
+
#
|
77
|
+
# end
|
78
|
+
#
|
79
|
+
# == For more info:
|
80
|
+
#
|
81
|
+
# * http://oauth2er.pjkh.com/user/populate
|
82
|
+
#
|
83
|
+
def on_before_oauth2_auto_create(oauth2_user_attributes)
|
84
|
+
|
85
|
+
if self.respond_to?(:before_oauth2_auto_create)
|
86
|
+
self.send(:before_oauth2_auto_create, oauth2_user_attributes) rescue nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Hook that gets called *after* a connection (each time). Useful for
|
91
|
+
# fetching additional user info (etc.) from OAuth2.
|
92
|
+
#
|
93
|
+
# Default: Do nothing.
|
94
|
+
#
|
95
|
+
# == Example:
|
96
|
+
#
|
97
|
+
# # Overridden in OAuth2 Connect:able model, e.g. "User".
|
98
|
+
# #
|
99
|
+
# def after_oauth2_connect(oauth2_user_attributes)
|
100
|
+
# # See "on_before_oauth2_connect" example.
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
def on_after_oauth2_connect(oauth2_user_attributes)
|
104
|
+
|
105
|
+
if self.respond_to?(:after_oauth2_connect)
|
106
|
+
self.send(:after_oauth2_connect, oauth2_user_attributes) rescue nil
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Optional: Store session key.
|
111
|
+
#
|
112
|
+
def store_session(using_token)
|
113
|
+
if self.token != using_token
|
114
|
+
self.update_attribute(self.send(:"#{self.class.oauth2_token_field}"), using_token)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
protected
|
119
|
+
|
120
|
+
# Passwords are always required if it's a new rechord and no oauth_id exists, or if the password
|
121
|
+
# or confirmation are being set somewhere.
|
122
|
+
def password_required?
|
123
|
+
|
124
|
+
( new_record? && self.send(:"#{self.class.oauth2_uid_field}").nil? ) || !password.nil? || !password_confirmation.nil?
|
125
|
+
end
|
126
|
+
|
127
|
+
module ClassMethods
|
128
|
+
|
129
|
+
# Configuration params accessible within +Devise.setup+ procedure (in initalizer).
|
130
|
+
#
|
131
|
+
# == Example:
|
132
|
+
#
|
133
|
+
# Devise.setup do |config|
|
134
|
+
# config.oauth2_uid_field = :oauth2_uid
|
135
|
+
# config.oauth2_token_field = :oauth2_token
|
136
|
+
# config.oauth2_auto_create_account = true
|
137
|
+
# end
|
138
|
+
#
|
139
|
+
::Devise::Models.config(self,
|
140
|
+
:oauth2_uid_field,
|
141
|
+
:oauth2_token_field,
|
142
|
+
:oauth2_auto_create_account
|
143
|
+
)
|
144
|
+
|
145
|
+
# Alias don't work for some reason, so...a more Ruby-ish alias
|
146
|
+
# for +oauth2_auto_create_account+.
|
147
|
+
#
|
148
|
+
def oauth2_auto_create_account?
|
149
|
+
self.oauth2_auto_create_account
|
150
|
+
end
|
151
|
+
|
152
|
+
# Authenticate a user based on OAuth2 UID.
|
153
|
+
#
|
154
|
+
def authenticate_with_oauth2(oauth2_id, oauth2_token)
|
155
|
+
|
156
|
+
# find user and update access token
|
157
|
+
returning(self.find_for_oauth2(oauth2_id)) do |user|
|
158
|
+
user.update_attributes(:"#{self.oauth2_token_field}" => oauth2_token) unless user.nil?
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
protected
|
164
|
+
|
165
|
+
|
166
|
+
|
167
|
+
# Find first record based on conditions given (OAuth2 UID).
|
168
|
+
# Overwrite to add customized conditions, create a join, or maybe use a
|
169
|
+
# namedscope to filter records while authenticating.
|
170
|
+
#
|
171
|
+
# == Example:
|
172
|
+
#
|
173
|
+
# def self.find_for_oauth2(uid, conditions = {})
|
174
|
+
# conditions[:active] = true
|
175
|
+
# self.find_by_oauth2_uid(uid, :conditions => conditions)
|
176
|
+
# end
|
177
|
+
#
|
178
|
+
def find_for_oauth2(uid, conditions = {})
|
179
|
+
self.send(:"find_by_#{self.oauth2_uid_field}",uid, :conditions => conditions)
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
|
184
|
+
# Contains the logic used in authentication. Overwritten by other devise modules.
|
185
|
+
# In the OAuth2 Connect case; nothing fancy required.
|
186
|
+
#
|
187
|
+
def valid_for_oauth2(resource, attributes)
|
188
|
+
true
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
end
|
195
|
+
# end
|
196
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Devise
|
2
|
+
class Engine
|
3
|
+
config.after_initialize do
|
4
|
+
begin
|
5
|
+
config_file = Rails.root.join('config', 'oauth2.yml')
|
6
|
+
unless File.exists?(config_file)
|
7
|
+
config_file = Rails.root.join('config', 'oauth2_config.yml')
|
8
|
+
if File.exists?(config_file)
|
9
|
+
puts "Deprecated OAuth2 config file config/oauth2_config.yml. Please use config/oauth.yml instead."
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
Devise::OAUTH2_CONFIG = YAML.load_file(config_file)[Rails.env]
|
14
|
+
|
15
|
+
unless Devise::OAUTH2_CONFIG['user_attributes_path']
|
16
|
+
puts "Your config/oauth2.yml does not seem to contain a user_attributes_path setting. Assuming '/me' for FacebookConnect."
|
17
|
+
Devise::OAUTH2_CONFIG['user_attributes_path'] = '/me'
|
18
|
+
end
|
19
|
+
rescue
|
20
|
+
puts "Can't load oauth2.yml. You can generate with rails g devise:oauth2_authenticatable"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'devise/schema'
|
3
|
+
|
4
|
+
module Devise #:nodoc:
|
5
|
+
module Oauth2Authenticatable #:nodoc:
|
6
|
+
|
7
|
+
module Schema
|
8
|
+
|
9
|
+
# Database migration schema for Facebook Connect.
|
10
|
+
#
|
11
|
+
def oauth2_authenticatable
|
12
|
+
apply_devise_schema ::Devise.oauth2_uid_field, Integer, :limit => 8 # BIGINT unsigned / 64-bit int
|
13
|
+
apply_devise_schema ::Devise.oauth2_token_field, String, :limit => 149 # [128][1][20] chars
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
Devise::Schema.module_eval do
|
21
|
+
include ::Devise::Oauth2Authenticatable::Schema
|
22
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'devise/strategies/base'
|
3
|
+
|
4
|
+
|
5
|
+
module Devise #:nodoc:
|
6
|
+
module Oauth2Authenticatable #:nodoc:
|
7
|
+
module Strategies #:nodoc:
|
8
|
+
|
9
|
+
# Default strategy for signing in a user using Facebook Connect (a Facebook account).
|
10
|
+
# Redirects to sign_in page if it's not authenticated
|
11
|
+
#
|
12
|
+
class Oauth2Authenticatable < ::Devise::Strategies::Base
|
13
|
+
|
14
|
+
|
15
|
+
|
16
|
+
# Without a oauth session authentication cannot proceed.
|
17
|
+
#
|
18
|
+
def valid?
|
19
|
+
|
20
|
+
valid_controller? && valid_params? && mapping.to.respond_to?('authenticate_with_oauth2')
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
# Authenticate user with OAuth2
|
25
|
+
#
|
26
|
+
def authenticate!
|
27
|
+
klass = mapping.to
|
28
|
+
begin
|
29
|
+
|
30
|
+
|
31
|
+
# Verify User Auth code and get access token from auth server: will error on failue
|
32
|
+
access_token = Devise::oauth2_client.web_server.get_access_token(
|
33
|
+
params[:code], :redirect_uri => Devise::session_sign_in_url(request,mapping)
|
34
|
+
)
|
35
|
+
|
36
|
+
# retrieve user attributes
|
37
|
+
|
38
|
+
# Get user details from OAuth2 Service
|
39
|
+
oauth2_user_attributes = JSON.parse(access_token.get(OAUTH2_CONFIG['user_attributes_path']))
|
40
|
+
|
41
|
+
user = klass.authenticate_with_oauth2(oauth2_user_attributes['id'], access_token.token)
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
if user.present?
|
46
|
+
user.on_after_oauth2_connect(oauth2_user_attributes)
|
47
|
+
success!(user)
|
48
|
+
else
|
49
|
+
if klass.oauth2_auto_create_account?
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
user = returning(klass.new) do |u|
|
54
|
+
u.store_oauth2_credentials!(
|
55
|
+
:token => access_token.token,
|
56
|
+
:uid => oauth2_user_attributes['id']
|
57
|
+
)
|
58
|
+
u.on_before_oauth2_auto_create(oauth2_user_attributes)
|
59
|
+
end
|
60
|
+
|
61
|
+
begin
|
62
|
+
|
63
|
+
|
64
|
+
user.save(true)
|
65
|
+
user.on_after_oauth2_connect(oauth2_user_attributes)
|
66
|
+
|
67
|
+
|
68
|
+
success!(user)
|
69
|
+
rescue
|
70
|
+
fail!(:oauth2_invalid)
|
71
|
+
end
|
72
|
+
else
|
73
|
+
fail!(:oauth2_invalid)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
rescue => e
|
78
|
+
fail!(e.message)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
protected
|
86
|
+
def valid_controller?
|
87
|
+
# params[:controller] == 'sessions'
|
88
|
+
mapping.controllers[:sessions] == params[:controller]
|
89
|
+
end
|
90
|
+
|
91
|
+
def valid_params?
|
92
|
+
params[:code].present?
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
Warden::Strategies.add(:oauth2_authenticatable, Devise::Oauth2Authenticatable::Strategies::Oauth2Authenticatable)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'devise/mapping'
|
3
|
+
|
4
|
+
module Devise #:nodoc:
|
5
|
+
module Oauth2Authenticatable #:nodoc:
|
6
|
+
|
7
|
+
# OAuth2 view helpers to easily add the link to the OAuth2 connection popup and also the necessary JS code.
|
8
|
+
#
|
9
|
+
module Helpers
|
10
|
+
|
11
|
+
# Creates the link to
|
12
|
+
def link_to_oauth2(link_text, options={})
|
13
|
+
|
14
|
+
|
15
|
+
session_sign_in_url = Devise::session_sign_in_url(request,::Devise.mappings[:user])
|
16
|
+
|
17
|
+
link_to link_text, Devise::oauth2_client.web_server.authorize_url(
|
18
|
+
:redirect_uri => session_sign_in_url,
|
19
|
+
:scope => Devise::requested_scope
|
20
|
+
), options
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
::ActionView::Base.send :include, Devise::Oauth2Authenticatable::Helpers
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Devise
|
2
|
+
class Oauth2AuthenticatableGenerator < Rails::Generators::Base
|
3
|
+
source_root File.expand_path('../templates', __FILE__)
|
4
|
+
argument :client_id, :type => :string, :default => "YOUR_APP_API_ID"
|
5
|
+
argument :client_key, :type => :string, :default => "YOUR_APP_SECRET_KEY"
|
6
|
+
argument :requested_scope, :type => :string, :default => "email,offline_access,publish_stream"
|
7
|
+
argument :auth_server, :type => :string, :default => "https://graph.facebook.com"
|
8
|
+
argument :authorize_path, :type => :string, :default => "/oauth/authorize"
|
9
|
+
argument :access_token_path, :type => :string, :default => "/oauth/access_token"
|
10
|
+
argument :user_attributes_path, :type => :string, :default => "/me"
|
11
|
+
desc "Generates a OAuth2 config file for your application. All the parameters are optional."
|
12
|
+
|
13
|
+
def generate_oauth2_config
|
14
|
+
template 'oauth2_config.yml', File.join(*%w[config oauth2.yml])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
defaults: &defaults
|
2
|
+
# Required.
|
3
|
+
client_id: <%= client_id %>
|
4
|
+
client_secret: <%= client_key %>
|
5
|
+
authorization_server: <%= auth_server %>
|
6
|
+
requested_scope: <%= requested_scope %>
|
7
|
+
authorize_path: <%= authorize_path %>
|
8
|
+
access_token_path: <%= access_token_path %>
|
9
|
+
user_attributes_path: <%= user_attributes_path %>
|
10
|
+
|
11
|
+
development:
|
12
|
+
<<: *defaults
|
13
|
+
|
14
|
+
test: &test
|
15
|
+
<<: *defaults
|
16
|
+
|
17
|
+
production: &production
|
18
|
+
<<: *defaults
|
19
|
+
|
20
|
+
# staging:
|
21
|
+
# <<: *production
|
22
|
+
#
|
23
|
+
# cucumber:
|
24
|
+
# <<: *test
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: svenfuchs-devise_oauth2_authenticatable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- bhbryant
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-06-13 00:00:00 +02:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rspec
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 13
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 2
|
33
|
+
- 9
|
34
|
+
version: 1.2.9
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: devise
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 23
|
46
|
+
segments:
|
47
|
+
- 1
|
48
|
+
- 0
|
49
|
+
- 0
|
50
|
+
version: 1.0.0
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: oauth2
|
55
|
+
prerelease: false
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 3
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
type: :runtime
|
66
|
+
version_requirements: *id003
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: json
|
69
|
+
prerelease: false
|
70
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
hash: 3
|
76
|
+
segments:
|
77
|
+
- 0
|
78
|
+
version: "0"
|
79
|
+
type: :runtime
|
80
|
+
version_requirements: *id004
|
81
|
+
description: Implements OAuth2 for Devise
|
82
|
+
email: benjamin@bryantmarkowsky.com
|
83
|
+
executables: []
|
84
|
+
|
85
|
+
extensions: []
|
86
|
+
|
87
|
+
extra_rdoc_files:
|
88
|
+
- LICENSE
|
89
|
+
- README.rdoc
|
90
|
+
files:
|
91
|
+
- .document
|
92
|
+
- .gitignore
|
93
|
+
- LICENSE
|
94
|
+
- README.rdoc
|
95
|
+
- Rakefile
|
96
|
+
- VERSION
|
97
|
+
- devise_oauth2_authenticatable.gemspec
|
98
|
+
- lib/devise_oauth2_authenticatable.rb
|
99
|
+
- lib/devise_oauth2_authenticatable/locales/en.yml
|
100
|
+
- lib/devise_oauth2_authenticatable/rails.rb
|
101
|
+
- lib/devise_oauth2_authenticatable/model.rb
|
102
|
+
- lib/devise_oauth2_authenticatable/routes.rb
|
103
|
+
- lib/devise_oauth2_authenticatable/schema.rb
|
104
|
+
- lib/devise_oauth2_authenticatable/strategy.rb
|
105
|
+
- lib/devise_oauth2_authenticatable/view_helpers.rb
|
106
|
+
- lib/generators/devise/oauth2_authenticatable/oauth2_authenticatable_generator.rb
|
107
|
+
- lib/generators/devise/oauth2_authenticatable/templates/oauth2.yml
|
108
|
+
- lib/generators/devise/oauth2_authenticatable/USAGE
|
109
|
+
- spec/devise_oauth2_authenticatable_spec.rb
|
110
|
+
- spec/spec.opts
|
111
|
+
- spec/spec_helper.rb
|
112
|
+
has_rdoc: true
|
113
|
+
homepage: http://github.com/bhbryant/devise_oauth2_authenticatable
|
114
|
+
licenses: []
|
115
|
+
|
116
|
+
post_install_message:
|
117
|
+
rdoc_options:
|
118
|
+
- --charset=UTF-8
|
119
|
+
require_paths:
|
120
|
+
- lib
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
hash: 3
|
127
|
+
segments:
|
128
|
+
- 0
|
129
|
+
version: "0"
|
130
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
|
+
none: false
|
132
|
+
requirements:
|
133
|
+
- - ">="
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
hash: 3
|
136
|
+
segments:
|
137
|
+
- 0
|
138
|
+
version: "0"
|
139
|
+
requirements: []
|
140
|
+
|
141
|
+
rubyforge_project:
|
142
|
+
rubygems_version: 1.3.7
|
143
|
+
signing_key:
|
144
|
+
specification_version: 3
|
145
|
+
summary: Implements OAuth2 for Devise
|
146
|
+
test_files:
|
147
|
+
- spec/devise_oauth2_authenticatable_spec.rb
|
148
|
+
- spec/spec_helper.rb
|