devise_oauth2_authenticatable 0.0.1
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 +82 -0
- data/Rakefile +52 -0
- data/devise_oauth2_authenticatable.gemspec +73 -0
- data/generators/devise_oauth2_authenticatable/devise_oauth2_authenticatable_generator.rb +44 -0
- data/generators/devise_oauth2_authenticatable/templates/oauth2_config.yml +23 -0
- data/lib/devise_oauth2_authenticatable.rb +59 -0
- data/lib/devise_oauth2_authenticatable/locales/en.yml +9 -0
- data/lib/devise_oauth2_authenticatable/model.rb +197 -0
- data/lib/devise_oauth2_authenticatable/routes.rb +11 -0
- data/lib/devise_oauth2_authenticatable/schema.rb +22 -0
- data/lib/devise_oauth2_authenticatable/strategy.rb +102 -0
- data/lib/devise_oauth2_authenticatable/version.rb +5 -0
- data/lib/devise_oauth2_authenticatable/view_helpers.rb +29 -0
- data/rails/init.rb +4 -0
- data/spec/devise_oauth2_authenticatable_spec.rb +7 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +9 -0
- metadata +134 -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,82 @@
|
|
1
|
+
= devise_oauth2_authenticatable
|
2
|
+
|
3
|
+
This is the basic framework for an OAuth2 gem for Devise.
|
4
|
+
|
5
|
+
It currently works with FacebookGraph, to get started begin by registering a new application at
|
6
|
+
|
7
|
+
http://developers.facebook.com/setup/
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
A generator is provided for creating your oauth yml file
|
12
|
+
|
13
|
+
script/generate devise_oauth2_authenticatable
|
14
|
+
|
15
|
+
Ex:
|
16
|
+
|
17
|
+
script/generate devise_oauth2_authenticatable --id API_ID --key SECRET --server https://graph.facebook.com --scope 'email,offline_access,publish_stream'
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
for more details
|
26
|
+
|
27
|
+
http://developers.facebook.com/docs/authentication/
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
It's based on the devise facebook gem provided by grimen
|
32
|
+
|
33
|
+
http://github.com/grimen/devise_facebook_connectable
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
And uses the example provided in OAuth2 library provided by mbleigh
|
39
|
+
|
40
|
+
http://github.com/intridea/oauth2
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
DB Migration :
|
48
|
+
|
49
|
+
add_column :users, :oauth2_uid, :integer, :limit => 8 # BIGINT unsigned / 64-bit int
|
50
|
+
add_column :users, :oauth2_token, :string, :limit => 149 # [128][1][20] chars
|
51
|
+
add_index :users, :oauth2_uid, :unique => true
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
Note:
|
56
|
+
|
57
|
+
A little souce of confusion when working with Facebook Graph
|
58
|
+
|
59
|
+
The api key and secret key are no the same a Facebook Connect/the old API.
|
60
|
+
|
61
|
+
The client id should be your application id and the client_key, should be your API key (not secret key)
|
62
|
+
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
Description goes here.
|
69
|
+
|
70
|
+
== Note on Patches/Pull Requests
|
71
|
+
|
72
|
+
* Fork the project.
|
73
|
+
* Make your feature addition or bug fix.
|
74
|
+
* Add tests for it. This is important so I don't break it in a
|
75
|
+
future version unintentionally.
|
76
|
+
* Commit, do not mess with rakefile, version, or history.
|
77
|
+
(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)
|
78
|
+
* Send me a pull request. Bonus points for topic branches.
|
79
|
+
|
80
|
+
== Copyright
|
81
|
+
|
82
|
+
Copyright (c) 2010 bhbryant. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require File.join(File.dirname(__FILE__), 'lib', 'devise_oauth2_authenticatable', 'version')
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'jeweler'
|
7
|
+
Jeweler::Tasks.new do |gem|
|
8
|
+
gem.name = "devise_oauth2_authenticatable"
|
9
|
+
gem.version = ::Devise::Oauth2Authenticatable::VERSION
|
10
|
+
gem.summary = %{Devise << OAuth2}
|
11
|
+
gem.description = %{Implements OAuth2 for devises, specifically integrating with facebook Graph}
|
12
|
+
gem.email = "benjamin@bryantmarkowsky.com"
|
13
|
+
gem.homepage = "http://github.com/bhbryant/devise_oauth2_authenticatable"
|
14
|
+
gem.authors = ["bhbryant"]
|
15
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
16
|
+
|
17
|
+
gem.add_dependency'devise', '>= 1.0.0'
|
18
|
+
gem.add_dependency "oauth2"
|
19
|
+
gem.add_dependency "json"
|
20
|
+
|
21
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
22
|
+
end
|
23
|
+
Jeweler::GemcutterTasks.new
|
24
|
+
rescue LoadError
|
25
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
26
|
+
end
|
27
|
+
|
28
|
+
require 'spec/rake/spectask'
|
29
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
30
|
+
spec.libs << 'lib' << 'spec'
|
31
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
35
|
+
spec.libs << 'lib' << 'spec'
|
36
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
37
|
+
spec.rcov = true
|
38
|
+
end
|
39
|
+
|
40
|
+
task :spec => :check_dependencies
|
41
|
+
|
42
|
+
task :default => :spec
|
43
|
+
|
44
|
+
require 'rake/rdoctask'
|
45
|
+
Rake::RDocTask.new do |rdoc|
|
46
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
47
|
+
|
48
|
+
rdoc.rdoc_dir = 'rdoc'
|
49
|
+
rdoc.title = "devise_oauth2_authenticatable #{version}"
|
50
|
+
rdoc.rdoc_files.include('README*')
|
51
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
52
|
+
end
|
@@ -0,0 +1,73 @@
|
|
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{devise_oauth2_authenticatable}
|
8
|
+
s.version = "0.0.1"
|
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-05-18}
|
13
|
+
s.description = %q{Implements OAuth2 for devises, specifically integrating with facebook Graph}
|
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
|
+
"devise_oauth2_authenticatable.gemspec",
|
26
|
+
"generators/devise_oauth2_authenticatable/devise_oauth2_authenticatable_generator.rb",
|
27
|
+
"generators/devise_oauth2_authenticatable/templates/oauth2_config.yml",
|
28
|
+
"lib/devise_oauth2_authenticatable.rb",
|
29
|
+
"lib/devise_oauth2_authenticatable/locales/en.yml",
|
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/version.rb",
|
35
|
+
"lib/devise_oauth2_authenticatable/view_helpers.rb",
|
36
|
+
"rails/init.rb",
|
37
|
+
"spec/devise_oauth2_authenticatable_spec.rb",
|
38
|
+
"spec/spec.opts",
|
39
|
+
"spec/spec_helper.rb"
|
40
|
+
]
|
41
|
+
s.homepage = %q{http://github.com/bhbryant/devise_oauth2_authenticatable}
|
42
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
43
|
+
s.require_paths = ["lib"]
|
44
|
+
s.rubygems_version = %q{1.3.6}
|
45
|
+
s.summary = %q{Devise << OAuth2}
|
46
|
+
s.test_files = [
|
47
|
+
"spec/devise_oauth2_authenticatable_spec.rb",
|
48
|
+
"spec/spec_helper.rb"
|
49
|
+
]
|
50
|
+
|
51
|
+
if s.respond_to? :specification_version then
|
52
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
53
|
+
s.specification_version = 3
|
54
|
+
|
55
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
56
|
+
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
57
|
+
s.add_runtime_dependency(%q<devise>, [">= 1.0.0"])
|
58
|
+
s.add_runtime_dependency(%q<oauth2>, [">= 0"])
|
59
|
+
s.add_runtime_dependency(%q<json>, [">= 0"])
|
60
|
+
else
|
61
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
62
|
+
s.add_dependency(%q<devise>, [">= 1.0.0"])
|
63
|
+
s.add_dependency(%q<oauth2>, [">= 0"])
|
64
|
+
s.add_dependency(%q<json>, [">= 0"])
|
65
|
+
end
|
66
|
+
else
|
67
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
68
|
+
s.add_dependency(%q<devise>, [">= 1.0.0"])
|
69
|
+
s.add_dependency(%q<oauth2>, [">= 0"])
|
70
|
+
s.add_dependency(%q<json>, [">= 0"])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class DeviseOauth2AuthenticatableGenerator < Rails::Generator::Base #:nodoc:
|
4
|
+
|
5
|
+
default_options :client_id => "YOUR_APP_API_ID",
|
6
|
+
:client_key => "YOUR_APP_SECRET_KEY",
|
7
|
+
:auth_server => "https://graph.facebook.com",
|
8
|
+
:requested_scope => "email,offline_access,publish_stream"
|
9
|
+
|
10
|
+
def manifest
|
11
|
+
record do |m|
|
12
|
+
# m.dependency 'xd_receiver', [], options.merge(:collision => :skip)
|
13
|
+
m.template 'oauth2_config.yml', File.join(*%w[config oauth2_config.yml])
|
14
|
+
# m.template 'devise.facebook_connectable.js', File.join(*%w[public javascripts devise.facebook_connectable.js])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
def add_options!(opt)
|
21
|
+
opt.separator ''
|
22
|
+
opt.separator 'Options:'
|
23
|
+
|
24
|
+
opt.on('--id CLIENT_ID', "Application API ID.") do |v|
|
25
|
+
options[:client_id] = v if v.present?
|
26
|
+
end
|
27
|
+
|
28
|
+
opt.on('--key SECRET_KEY', "Application Secret key.") do |v|
|
29
|
+
options[:client_key] = v if v.present?
|
30
|
+
end
|
31
|
+
opt.on('--server AUTH_SERVER', "Authentication Server.") do |v|
|
32
|
+
options[:auth_server] = v if v.present?
|
33
|
+
end
|
34
|
+
opt.on('--resources REQUESTED_RESOURCES', "Requested Resources.") do |v|
|
35
|
+
options[:requested_scope] = v if v.present?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def banner
|
41
|
+
"Usage: #{$0} devise_oauth2_authenticatable [--id API_ID] [--key SECRET_KEY] [--server AUTH_SERVER] [--scope REQUESTED RESOURCES]"
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
defaults: &defaults
|
2
|
+
# Required.
|
3
|
+
client_id: <%= options[:client_id] %>
|
4
|
+
client_secret: <%= options[:client_key] %>
|
5
|
+
authorization_server: <%= options[:auth_server] %>
|
6
|
+
requested_scope: <%= options[:requested_scope] %>
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
development:
|
11
|
+
<<: *defaults
|
12
|
+
|
13
|
+
test: &test
|
14
|
+
<<: *defaults
|
15
|
+
|
16
|
+
production: &production
|
17
|
+
<<: *defaults
|
18
|
+
|
19
|
+
# staging:
|
20
|
+
# <<: *production
|
21
|
+
#
|
22
|
+
# cucumber:
|
23
|
+
# <<: *test
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'devise'
|
3
|
+
require 'oauth2'
|
4
|
+
|
5
|
+
|
6
|
+
require 'devise_oauth2_authenticatable/model'
|
7
|
+
require 'devise_oauth2_authenticatable/strategy'
|
8
|
+
require 'devise_oauth2_authenticatable/schema'
|
9
|
+
require 'devise_oauth2_authenticatable/routes'
|
10
|
+
#require 'devise_oauth2_authenticatable/controller_filters'
|
11
|
+
require 'devise_oauth2_authenticatable/view_helpers'
|
12
|
+
|
13
|
+
|
14
|
+
module Devise
|
15
|
+
# Specifies the name of the database column name used for storing
|
16
|
+
# the oauth UID. Useful if this info should be saved in a
|
17
|
+
# generic column if different authentication solutions are used.
|
18
|
+
mattr_accessor :oauth2_uid_field
|
19
|
+
@@oauth2_uid_field = :oauth2_uid
|
20
|
+
|
21
|
+
# Specifies the name of the database column name used for storing
|
22
|
+
# the user Facebook session key. Useful if this info should be saved in a
|
23
|
+
# generic column if different authentication solutions are used.
|
24
|
+
mattr_accessor :oauth2_token_field
|
25
|
+
@@oauth2_token_field = :oauth2_token
|
26
|
+
|
27
|
+
# Specifies if account should be created if no account exists for
|
28
|
+
# a specified Facebook UID or not.
|
29
|
+
mattr_accessor :oauth2_auto_create_account
|
30
|
+
@@oauth2_auto_create_account = true
|
31
|
+
|
32
|
+
def self.oauth2_client
|
33
|
+
@@oauth2_client ||= OAuth2::Client.new(OAUTH2_CONFIG['client_id'], OAUTH2_CONFIG['client_secret'], :site => OAUTH2_CONFIG['authorization_server'])
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def self.session_sign_in_url(request, mapping)
|
38
|
+
url = URI.parse(request.url)
|
39
|
+
url.path = "#{mapping.parsed_path}/#{mapping.path_names[:sign_in]}"
|
40
|
+
url.query = nil
|
41
|
+
url.to_s
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.requested_scope
|
45
|
+
@@requested_scope ||= OAUTH2_CONFIG['requested_scope']
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
# Load core I18n locales: en
|
51
|
+
#
|
52
|
+
I18n.load_path.unshift File.join(File.dirname(__FILE__), *%w[devise_oauth2_authenticatable locales en.yml])
|
53
|
+
|
54
|
+
# Add +:facebook_connectable+ strategies to defaults.
|
55
|
+
#
|
56
|
+
Devise.add_module(:oauth2_authenticatable,
|
57
|
+
:strategy => true,
|
58
|
+
:controller => :sessions,
|
59
|
+
: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,197 @@
|
|
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_auto_create)
|
106
|
+
self.send(:after_oauth2_auto_create, 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? && oauth2_uid.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(:oauth2_token => 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
|
+
|
180
|
+
self.find_by_oauth2_uid(uid, :conditions => conditions)
|
181
|
+
end
|
182
|
+
|
183
|
+
|
184
|
+
|
185
|
+
# Contains the logic used in authentication. Overwritten by other devise modules.
|
186
|
+
# In the OAuth2 Connect case; nothing fancy required.
|
187
|
+
#
|
188
|
+
def valid_for_oauth2(resource, attributes)
|
189
|
+
true
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
195
|
+
end
|
196
|
+
# end
|
197
|
+
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_schema ::Devise.oauth2_uid_field, Integer, :limit => 8 # BIGINT unsigned / 64-bit int
|
13
|
+
apply_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,102 @@
|
|
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
|
+
# NOTE: Facebook Graph Specific
|
40
|
+
# TODO: break this out into separate model or class to handle
|
41
|
+
# different oauth2 providers
|
42
|
+
oauth2_user_attributes = JSON.parse(access_token.get('/me'))
|
43
|
+
|
44
|
+
user = klass.authenticate_with_oauth2(oauth2_user_attributes['id'], access_token.token)
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
if user.present?
|
49
|
+
user.on_after_oauth2_connect(oauth2_user_attributes)
|
50
|
+
success!(user)
|
51
|
+
else
|
52
|
+
if klass.oauth2_auto_create_account?
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
user = returning(klass.new) do |u|
|
57
|
+
u.store_oauth2_credentials!(
|
58
|
+
:token => access_token.token,
|
59
|
+
:uid => oauth2_user_attributes['id']
|
60
|
+
)
|
61
|
+
u.on_before_oauth2_auto_create(oauth2_user_attributes)
|
62
|
+
end
|
63
|
+
|
64
|
+
begin
|
65
|
+
|
66
|
+
|
67
|
+
user.save(true)
|
68
|
+
user.on_after_oauth2_connect(oauth2_user_attributes)
|
69
|
+
|
70
|
+
|
71
|
+
success!(user)
|
72
|
+
rescue
|
73
|
+
fail!(:oauth2_invalid)
|
74
|
+
end
|
75
|
+
else
|
76
|
+
fail!(:oauth2_invalid)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
rescue => e
|
81
|
+
fail!(e.message)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
|
87
|
+
|
88
|
+
protected
|
89
|
+
def valid_controller?
|
90
|
+
params[:controller] == 'sessions'
|
91
|
+
end
|
92
|
+
|
93
|
+
def valid_params?
|
94
|
+
params[:code].present?
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
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
|
data/rails/init.rb
ADDED
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: devise_oauth2_authenticatable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- bhbryant
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-05-18 00:00:00 -07:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rspec
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 1
|
29
|
+
- 2
|
30
|
+
- 9
|
31
|
+
version: 1.2.9
|
32
|
+
type: :development
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: devise
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 1
|
43
|
+
- 0
|
44
|
+
- 0
|
45
|
+
version: 1.0.0
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id002
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: oauth2
|
50
|
+
prerelease: false
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
segments:
|
56
|
+
- 0
|
57
|
+
version: "0"
|
58
|
+
type: :runtime
|
59
|
+
version_requirements: *id003
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: json
|
62
|
+
prerelease: false
|
63
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
segments:
|
68
|
+
- 0
|
69
|
+
version: "0"
|
70
|
+
type: :runtime
|
71
|
+
version_requirements: *id004
|
72
|
+
description: Implements OAuth2 for devises, specifically integrating with facebook Graph
|
73
|
+
email: benjamin@bryantmarkowsky.com
|
74
|
+
executables: []
|
75
|
+
|
76
|
+
extensions: []
|
77
|
+
|
78
|
+
extra_rdoc_files:
|
79
|
+
- LICENSE
|
80
|
+
- README.rdoc
|
81
|
+
files:
|
82
|
+
- .document
|
83
|
+
- .gitignore
|
84
|
+
- LICENSE
|
85
|
+
- README.rdoc
|
86
|
+
- Rakefile
|
87
|
+
- devise_oauth2_authenticatable.gemspec
|
88
|
+
- generators/devise_oauth2_authenticatable/devise_oauth2_authenticatable_generator.rb
|
89
|
+
- generators/devise_oauth2_authenticatable/templates/oauth2_config.yml
|
90
|
+
- lib/devise_oauth2_authenticatable.rb
|
91
|
+
- lib/devise_oauth2_authenticatable/locales/en.yml
|
92
|
+
- lib/devise_oauth2_authenticatable/model.rb
|
93
|
+
- lib/devise_oauth2_authenticatable/routes.rb
|
94
|
+
- lib/devise_oauth2_authenticatable/schema.rb
|
95
|
+
- lib/devise_oauth2_authenticatable/strategy.rb
|
96
|
+
- lib/devise_oauth2_authenticatable/version.rb
|
97
|
+
- lib/devise_oauth2_authenticatable/view_helpers.rb
|
98
|
+
- rails/init.rb
|
99
|
+
- spec/devise_oauth2_authenticatable_spec.rb
|
100
|
+
- spec/spec.opts
|
101
|
+
- spec/spec_helper.rb
|
102
|
+
has_rdoc: true
|
103
|
+
homepage: http://github.com/bhbryant/devise_oauth2_authenticatable
|
104
|
+
licenses: []
|
105
|
+
|
106
|
+
post_install_message:
|
107
|
+
rdoc_options:
|
108
|
+
- --charset=UTF-8
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
segments:
|
116
|
+
- 0
|
117
|
+
version: "0"
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
segments:
|
123
|
+
- 0
|
124
|
+
version: "0"
|
125
|
+
requirements: []
|
126
|
+
|
127
|
+
rubyforge_project:
|
128
|
+
rubygems_version: 1.3.6
|
129
|
+
signing_key:
|
130
|
+
specification_version: 3
|
131
|
+
summary: Devise << OAuth2
|
132
|
+
test_files:
|
133
|
+
- spec/devise_oauth2_authenticatable_spec.rb
|
134
|
+
- spec/spec_helper.rb
|