vidibus-oauth2_server 0.0.2 → 0.0.3
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/README.rdoc +75 -40
- data/Rakefile +18 -0
- data/VERSION +1 -1
- data/app/controllers/oauth2/authentication_controller.rb +84 -86
- data/app/controllers/oauth2/users_controller.rb +12 -14
- data/app/controllers/oauth2_controller.rb +2 -0
- data/vidibus-oauth2_server.gemspec +3 -2
- metadata +5 -4
data/README.rdoc
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
=
|
1
|
+
= Vidibus::Oauth2Server
|
2
2
|
|
3
|
-
Allows OAuth2 authentication based on http://tools.ietf.org/html/draft-ietf-oauth2-v2-00.
|
3
|
+
Allows OAuth2 authentication for Rails applications based on http://tools.ietf.org/html/draft-ietf-oauth2-v2-00.
|
4
4
|
|
5
|
-
This gem is part of the open source SOA framework Vidibus
|
5
|
+
This gem is part of the open source SOA framework {Vidibus}[http://vidibus.org].
|
6
6
|
|
7
7
|
It is far from being complete and stable! But this will change soon.
|
8
8
|
|
@@ -15,44 +15,53 @@ Add the dependency to the Gemfile of your application:
|
|
15
15
|
|
16
16
|
Then call bundle install on your console.
|
17
17
|
|
18
|
+
To get your own OAuth2 server working, some small adjustments will have to be made to your Rails application:
|
18
19
|
|
19
|
-
=== Routes
|
20
|
-
|
21
|
-
Two routes will be added to your application. If you use a catch-all route, you will have to define these routes manually:
|
22
20
|
|
23
|
-
|
24
|
-
post "oauth/access_token" => "oauth2#access_token"
|
21
|
+
=== Client model
|
25
22
|
|
23
|
+
Each remote application that requests authentication has to be authorized to do this. Usually, such an application will have to provide an API key that will be validated against a local repository. For OAuth2 this API key is called "client_id".
|
26
24
|
|
27
|
-
|
25
|
+
Additionally, each client application has to provide a password to make a valid Oauth2 request, the "client_secret".
|
28
26
|
|
29
|
-
|
27
|
+
This gem will validate an incoming OAuth2 request against client_id and client_secret parameters. Thus your client model has to provide both attributes, although they don't have to be named like this.
|
30
28
|
|
31
|
-
|
29
|
+
You'll also have to provide a #domain method on your OAuth client model that returns the domain name of the client, e.g. vidibus.org. This method is used to validate the redirect_url parameter.
|
32
30
|
|
33
|
-
|
34
|
-
def authenticate_user!
|
35
|
-
logged_in? or login_required
|
36
|
-
end
|
31
|
+
Before issuing a token, the Oauth2Controller will ensure that the given client_secret is valid. In order to perform this validation, a method #valid_oauth2_secret? must be given on your client model.
|
37
32
|
|
38
|
-
|
33
|
+
If you use the {Vidibus::Service}[https://github.com/vidibus/vidibus-service] gem, you'll get this method on the service model:
|
39
34
|
|
40
|
-
# Returns
|
41
|
-
|
42
|
-
|
43
|
-
# uuid and realm, concatenated by -
|
44
|
-
def oauth2_client(client_id)
|
45
|
-
Service(*client_id.split("-"))
|
35
|
+
# Returns true if given client_secret matches signature.
|
36
|
+
def valid_oauth2_secret?(client_secret)
|
37
|
+
client_secret == Vidibus::Secure.sign("#{Service.this.url}#{uuid}", secret)
|
46
38
|
end
|
47
39
|
|
48
40
|
|
49
41
|
=== User model
|
50
42
|
|
51
|
-
Your user model has to provide an unique UUID. If you use Mongoid,
|
43
|
+
Your user model has to provide an unique UUID in compact format. If you use Mongoid, you may include the UUID generator provided by the {Vidibus::Uuid}[https://github.com/vidibus/vidibus-uuid] gem:
|
52
44
|
|
53
|
-
|
45
|
+
class User
|
46
|
+
include Mongoid::Document
|
47
|
+
include Vidibus::Uuid::Mongoid
|
48
|
+
...
|
49
|
+
end
|
54
50
|
|
55
|
-
If you have an ActiveRecord model,
|
51
|
+
If you have an ActiveRecord model, implement something like this:
|
52
|
+
|
53
|
+
require "uuid"
|
54
|
+
class User < ActiveRecord::Base
|
55
|
+
before_create :generate_uuid
|
56
|
+
...
|
57
|
+
protected
|
58
|
+
|
59
|
+
def generate_uuid
|
60
|
+
self.uuid ||= UUID.new.generate(:compact)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
And don't forget the migration:
|
56
65
|
|
57
66
|
require "uuid"
|
58
67
|
class AddUuidToUsers < ActiveRecord::Migration
|
@@ -71,9 +80,44 @@ If you have an ActiveRecord model, add a migration like this:
|
|
71
80
|
end
|
72
81
|
|
73
82
|
|
74
|
-
===
|
83
|
+
=== Routes
|
84
|
+
|
85
|
+
Two routes will be added to your Rails application. If you use a catch-all route, you will have to define these routes manually:
|
75
86
|
|
76
|
-
|
87
|
+
get "oauth/authorize" => "oauth2#authorize"
|
88
|
+
post "oauth/access_token" => "oauth2#access_token"
|
89
|
+
|
90
|
+
|
91
|
+
=== ApplicationController
|
92
|
+
|
93
|
+
In the ApplicationController of your OAuth server application you'll have to define two methods in order to perform OAuth authentication.
|
94
|
+
|
95
|
+
The first method performs the sign-in of the current user. If you use Devise for authentication with a "User" model, that method already exists and works. This is an example that works with Authlogic:
|
96
|
+
|
97
|
+
# Calls authentication method.
|
98
|
+
def authenticate_user!
|
99
|
+
logged_in? or login_required
|
100
|
+
end
|
101
|
+
|
102
|
+
The second method returns a service client with given id. This is an example taken from the {Vidibus::Service}[https://github.com/vidibus/vidibus-service] gem:
|
103
|
+
|
104
|
+
# Returns service matching given client_id.
|
105
|
+
# This method is called from Vidibus' Oauth2Server gem.
|
106
|
+
#
|
107
|
+
# In this example from Vidibus the given client_id
|
108
|
+
# comprises the requesting service's uuid and realm,
|
109
|
+
# concatenated by -.
|
110
|
+
#
|
111
|
+
# Adjust this method to your needs.
|
112
|
+
#
|
113
|
+
def oauth2_client(client_id)
|
114
|
+
Service(*client_id.split("-"))
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
=== Oauth2::UsersController
|
119
|
+
|
120
|
+
This gem will also provide an action to obtain data of the user currently logged in. The following route will be added:
|
77
121
|
|
78
122
|
get "/oauth/user" => "oauth2/users#show"
|
79
123
|
|
@@ -86,31 +130,22 @@ For a typical ActiveRecord model this would be:
|
|
86
130
|
User.first(:conditions => {:uuid => uuid})
|
87
131
|
end
|
88
132
|
|
89
|
-
The default #show method delivers a JSON string including name, email and UUID of the current user:
|
133
|
+
The default #show method of this controller delivers a JSON string including name, email and UUID of the current user:
|
90
134
|
|
91
135
|
def show
|
92
136
|
render :json => @user.attributes.only(*%w[name email uuid])
|
93
137
|
end
|
94
138
|
|
139
|
+
== And the client side?
|
95
140
|
|
96
|
-
|
97
|
-
|
98
|
-
Provide a #domain method to your OAuth client model that returns the domain name of the client. This method is used to validate the redirect_url.
|
141
|
+
Well, this is just the server side of the story. To implement OAuth2 on your client applications, there are many solutions available. The basic tools are provided by the excellent {OAuth2}[https://github.com/intridea/oauth2] gem. For a sophisticated example, check out {OmniAuth}[https://github.com/intridea/omniauth].
|
99
142
|
|
100
|
-
|
101
|
-
|
102
|
-
If you use the vidibus-service gem, you'll get this method on the service model:
|
103
|
-
|
104
|
-
# Returns true if given client_secret matches signature.
|
105
|
-
def valid_oauth2_secret?(client_secret)
|
106
|
-
client_secret == Vidibus::Secure.sign("#{Service.this.url}#{uuid}", secret)
|
107
|
-
end
|
143
|
+
In a typical Vidibus service-oriented environment, clients are equipped with the {Vidibus::User}[https://github.com/vidibus/vidibus-user] gem.
|
108
144
|
|
109
145
|
|
110
146
|
== TODO
|
111
147
|
|
112
148
|
* Write specs!
|
113
|
-
* Explain usage and integration
|
114
149
|
* Implement token expiry
|
115
150
|
* Apply changes made in http://tools.ietf.org/html/draft-ietf-oauth2-v2-10?
|
116
151
|
|
data/Rakefile
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require "rubygems"
|
2
2
|
require "rake"
|
3
|
+
require "rake/rdoctask"
|
4
|
+
require "rspec"
|
5
|
+
require "rspec/core/rake_task"
|
3
6
|
|
4
7
|
begin
|
5
8
|
require "jeweler"
|
@@ -16,3 +19,18 @@ begin
|
|
16
19
|
rescue LoadError
|
17
20
|
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
18
21
|
end
|
22
|
+
|
23
|
+
Rspec::Core::RakeTask.new(:rcov) do |t|
|
24
|
+
t.pattern = "spec/**/*_spec.rb"
|
25
|
+
t.rcov = true
|
26
|
+
t.rcov_opts = ["--exclude", "^spec,/gems/"]
|
27
|
+
end
|
28
|
+
|
29
|
+
Rake::RDocTask.new do |rdoc|
|
30
|
+
version = File.exist?("VERSION") ? File.read("VERSION") : ""
|
31
|
+
rdoc.rdoc_dir = "rdoc"
|
32
|
+
rdoc.title = "vidibus-oauth2_server #{version}"
|
33
|
+
rdoc.rdoc_files.include("README*")
|
34
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
35
|
+
rdoc.options << "--charset=utf-8"
|
36
|
+
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.3
|
@@ -1,102 +1,100 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
skip_before_filter :verify_authenticity_token
|
1
|
+
class Oauth2::AuthenticationController < Oauth2Controller
|
2
|
+
skip_before_filter :verify_authenticity_token
|
4
3
|
|
5
|
-
|
4
|
+
around_filter :oauth2_error_handler
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
before_filter :validate_oauth2_type!
|
7
|
+
before_filter :validate_oauth2_client_id!
|
8
|
+
before_filter :validate_oauth2_redirect_url!
|
10
9
|
|
11
|
-
|
12
|
-
|
10
|
+
before_filter :authenticate_user!, :only => :authorize
|
11
|
+
before_filter :validate_oauth2_client_secret!, :only => :access_token
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
13
|
+
def authorize
|
14
|
+
args = params.slice(:client_id, :redirect_url)
|
15
|
+
args[:user_id] = current_user.uuid
|
16
|
+
token = Oauth2Token.create!(args)
|
17
|
+
uri_params = { :code => token.code }
|
18
|
+
uri_params[:state] = params[:state] if params.has_key?(:state)
|
19
|
+
uri = params[:redirect_url].with_params(uri_params)
|
20
|
+
redirect_to(uri)
|
21
|
+
end
|
23
22
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
def access_token
|
24
|
+
token = Oauth2Token.find!(params)
|
25
|
+
render :text => { :access_token => token.token }.to_uri, :type => :url_encoded_form, :status => :ok
|
26
|
+
end
|
28
27
|
|
29
|
-
|
28
|
+
protected
|
30
29
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
30
|
+
# Ensures that the type of flow is supported
|
31
|
+
def validate_oauth2_type!
|
32
|
+
type = params[:type]
|
33
|
+
raise Vidibus::Oauth2Server::MissingTypeError if type.blank?
|
34
|
+
raise Vidibus::Oauth2Server::UnsupportedTypeError unless Vidibus::Oauth2Server::FLOWS.include?(type)
|
35
|
+
end
|
37
36
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
37
|
+
# Ensures that given client id is valid
|
38
|
+
def validate_oauth2_client_id!
|
39
|
+
raise Vidibus::Oauth2Server::MissingClientIdError if params[:client_id].blank?
|
40
|
+
@oauth2_client = oauth2_client(params[:client_id])
|
41
|
+
raise Vidibus::Oauth2Server::InvalidClientIdError unless @oauth2_client
|
42
|
+
end
|
44
43
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
end
|
44
|
+
# Ensures that redirect_url is valid for given client.
|
45
|
+
def validate_oauth2_redirect_url!
|
46
|
+
redirect_url = params[:redirect_url]
|
47
|
+
raise Vidibus::Oauth2Server::MissingRedirectUrlError if redirect_url.blank?
|
48
|
+
raise Vidibus::Oauth2Server::MalformedRedirectUrlError unless valid_uri?(redirect_url)
|
49
|
+
unless redirect_url.match(/^https?:\/\/([a-z0-9]+\.)?#{@oauth2_client.domain}/) # allow subdomains but ensure host of client application
|
50
|
+
raise Vidibus::Oauth2Server::InvalidRedirectUrlError
|
53
51
|
end
|
52
|
+
end
|
54
53
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
54
|
+
# Ensures that given client_secret is valid for given client.
|
55
|
+
def validate_oauth2_client_secret!
|
56
|
+
raise Vidibus::Oauth2Server::InvalidClientSecretError unless @oauth2_client.valid_oauth2_secret?(params[:client_secret])
|
57
|
+
end
|
59
58
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
end
|
59
|
+
# Returns error message for given exception.
|
60
|
+
def oauth2_error_handler
|
61
|
+
begin
|
62
|
+
yield
|
63
|
+
rescue Vidibus::Oauth2Server::MissingTypeError
|
64
|
+
error = "missing_type"
|
65
|
+
rescue Vidibus::Oauth2Server::UnsupportedTypeError
|
66
|
+
error = "unsupported_type"
|
67
|
+
rescue Vidibus::Oauth2Server::MissingClientIdError
|
68
|
+
error = "missing_client_id"
|
69
|
+
rescue Vidibus::Oauth2Server::InvalidClientIdError
|
70
|
+
error = "invalid_client_id"
|
71
|
+
rescue Vidibus::Oauth2Server::InvalidClientSecretError
|
72
|
+
error = "invalid_client_secret"
|
73
|
+
rescue Vidibus::Oauth2Server::MissingRedirectUrlError
|
74
|
+
error = "missing_redirect_url"
|
75
|
+
rescue Vidibus::Oauth2Server::MalformedRedirectUrlError
|
76
|
+
error = "malformed_redirect_url"
|
77
|
+
rescue Vidibus::Oauth2Server::InvalidRedirectUrlError
|
78
|
+
error = "invalid_redirect_url"
|
79
|
+
rescue Vidibus::Oauth2Server::MissingCodeError
|
80
|
+
error = "missing_code"
|
81
|
+
rescue Vidibus::Oauth2Server::InvalidCodeError
|
82
|
+
error = "invalid_code"
|
83
|
+
rescue Vidibus::Oauth2Server::ExpiredCodeError
|
84
|
+
error = "expired_code"
|
85
|
+
rescue Vidibus::Oauth2Server::InvalidTokenError
|
86
|
+
error = "invalid_token"
|
87
|
+
rescue Vidibus::Oauth2Server::ExpiredTokenError
|
88
|
+
error = "expired_token"
|
89
|
+
ensure
|
90
|
+
if error
|
91
|
+
status ||= :bad_request
|
92
|
+
render :text => I18n.t("oauth2_server.errors.#{error}"), :status => status
|
95
93
|
end
|
96
|
-
|
97
|
-
# Autorization error?
|
98
|
-
# :status => :unauthorized # The response MUST include a WWW-Authenticate header field (section 14.47) containing a challenge applicable to the requested resource.
|
99
|
-
# :status => :forbidden # Maybe better?
|
100
94
|
end
|
95
|
+
|
96
|
+
# Autorization error?
|
97
|
+
# :status => :unauthorized # The response MUST include a WWW-Authenticate header field (section 14.47) containing a challenge applicable to the requested resource.
|
98
|
+
# :status => :forbidden # Maybe better?
|
101
99
|
end
|
102
100
|
end
|
@@ -1,20 +1,18 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
before_filter :find_user
|
1
|
+
class Oauth2::UsersController < Oauth2Controller
|
2
|
+
before_filter :ensure_token!
|
3
|
+
before_filter :find_user
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
def show
|
6
|
+
render :json => @user.attributes.only(*%w[name email uuid])
|
7
|
+
end
|
9
8
|
|
10
|
-
|
9
|
+
protected
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
def find_user
|
12
|
+
@user = find_user_by_uuid(@access_token.user_id) or render(:nothing => true, :status => :bad_request)
|
13
|
+
end
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
end
|
15
|
+
def ensure_token!
|
16
|
+
@access_token = Oauth2Token.find!(:token => params[:access_token])
|
19
17
|
end
|
20
18
|
end
|
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{vidibus-oauth2_server}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Andre Pankratz"]
|
12
|
-
s.date = %q{2011-
|
12
|
+
s.date = %q{2011-02-23}
|
13
13
|
s.description = %q{OAuth2 server for Rails 3 with Mongoid.}
|
14
14
|
s.email = %q{andre@vidibus.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -26,6 +26,7 @@ Gem::Specification.new do |s|
|
|
26
26
|
"VERSION",
|
27
27
|
"app/controllers/oauth2/authentication_controller.rb",
|
28
28
|
"app/controllers/oauth2/users_controller.rb",
|
29
|
+
"app/controllers/oauth2_controller.rb",
|
29
30
|
"app/models/oauth2_token.rb",
|
30
31
|
"config/locales/en.yml",
|
31
32
|
"config/routes.rb",
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vidibus-oauth2_server
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 3
|
10
|
+
version: 0.0.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Andre Pankratz
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-02-23 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -189,6 +189,7 @@ files:
|
|
189
189
|
- VERSION
|
190
190
|
- app/controllers/oauth2/authentication_controller.rb
|
191
191
|
- app/controllers/oauth2/users_controller.rb
|
192
|
+
- app/controllers/oauth2_controller.rb
|
192
193
|
- app/models/oauth2_token.rb
|
193
194
|
- config/locales/en.yml
|
194
195
|
- config/routes.rb
|