oauth2-provider 0.0.16
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/.gitignore +8 -0
- data/Gemfile +3 -0
- data/README.md +49 -0
- data/Rakefile +24 -0
- data/examples/client/Gemfile +6 -0
- data/examples/client/Gemfile.lock +20 -0
- data/examples/client/README +8 -0
- data/examples/client/app.rb +59 -0
- data/examples/client/config.ru +3 -0
- data/examples/client/views/home.haml +3 -0
- data/examples/client/views/response.haml +11 -0
- data/examples/rails3-example/.gitignore +4 -0
- data/examples/rails3-example/Gemfile +10 -0
- data/examples/rails3-example/Gemfile.lock +82 -0
- data/examples/rails3-example/README +9 -0
- data/examples/rails3-example/Rakefile +7 -0
- data/examples/rails3-example/app/controllers/account_controller.rb +14 -0
- data/examples/rails3-example/app/controllers/application_controller.rb +18 -0
- data/examples/rails3-example/app/controllers/authorization_controller.rb +18 -0
- data/examples/rails3-example/app/controllers/home_controller.rb +4 -0
- data/examples/rails3-example/app/controllers/session_controller.rb +24 -0
- data/examples/rails3-example/app/helpers/application_helper.rb +2 -0
- data/examples/rails3-example/app/models/account.rb +6 -0
- data/examples/rails3-example/app/views/authorization/new.html.erb +5 -0
- data/examples/rails3-example/app/views/home/show.html.erb +1 -0
- data/examples/rails3-example/app/views/layouts/application.html.erb +16 -0
- data/examples/rails3-example/app/views/session/new.html.erb +7 -0
- data/examples/rails3-example/config.ru +4 -0
- data/examples/rails3-example/config/application.rb +42 -0
- data/examples/rails3-example/config/boot.rb +6 -0
- data/examples/rails3-example/config/database.yml +22 -0
- data/examples/rails3-example/config/environment.rb +5 -0
- data/examples/rails3-example/config/environments/development.rb +26 -0
- data/examples/rails3-example/config/environments/production.rb +49 -0
- data/examples/rails3-example/config/environments/test.rb +35 -0
- data/examples/rails3-example/config/initializers/backtrace_silencers.rb +7 -0
- data/examples/rails3-example/config/initializers/inflections.rb +10 -0
- data/examples/rails3-example/config/initializers/mime_types.rb +5 -0
- data/examples/rails3-example/config/initializers/secret_token.rb +7 -0
- data/examples/rails3-example/config/initializers/session_store.rb +8 -0
- data/examples/rails3-example/config/locales/en.yml +5 -0
- data/examples/rails3-example/config/routes.rb +9 -0
- data/examples/rails3-example/db/migrate/20110508151935_add_account_table.rb +12 -0
- data/examples/rails3-example/db/migrate/20110508151948_add_oauth2_tables.rb +43 -0
- data/examples/rails3-example/db/schema.rb +52 -0
- data/examples/rails3-example/db/seeds.rb +11 -0
- data/examples/rails3-example/doc/README_FOR_APP +2 -0
- data/examples/rails3-example/lib/tasks/.gitkeep +0 -0
- data/examples/rails3-example/public/404.html +26 -0
- data/examples/rails3-example/public/422.html +26 -0
- data/examples/rails3-example/public/500.html +26 -0
- data/examples/rails3-example/public/favicon.ico +0 -0
- data/examples/rails3-example/public/images/rails.png +0 -0
- data/examples/rails3-example/public/robots.txt +5 -0
- data/examples/rails3-example/public/stylesheets/.gitkeep +0 -0
- data/examples/rails3-example/script/rails +6 -0
- data/lib/oauth2-provider.rb +3 -0
- data/lib/oauth2/provider.rb +39 -0
- data/lib/oauth2/provider/models.rb +40 -0
- data/lib/oauth2/provider/models/access_token.rb +54 -0
- data/lib/oauth2/provider/models/active_record.rb +30 -0
- data/lib/oauth2/provider/models/active_record/access_token.rb +13 -0
- data/lib/oauth2/provider/models/active_record/authorization.rb +16 -0
- data/lib/oauth2/provider/models/active_record/authorization_code.rb +13 -0
- data/lib/oauth2/provider/models/active_record/client.rb +15 -0
- data/lib/oauth2/provider/models/authorization.rb +40 -0
- data/lib/oauth2/provider/models/authorization_code.rb +27 -0
- data/lib/oauth2/provider/models/client.rb +28 -0
- data/lib/oauth2/provider/models/mongoid.rb +30 -0
- data/lib/oauth2/provider/models/mongoid/access_token.rb +40 -0
- data/lib/oauth2/provider/models/mongoid/authorization.rb +32 -0
- data/lib/oauth2/provider/models/mongoid/authorization_code.rb +43 -0
- data/lib/oauth2/provider/models/mongoid/client.rb +40 -0
- data/lib/oauth2/provider/rack.rb +11 -0
- data/lib/oauth2/provider/rack/access_token_handler.rb +103 -0
- data/lib/oauth2/provider/rack/authorization_code_request.rb +74 -0
- data/lib/oauth2/provider/rack/authorization_codes_support.rb +25 -0
- data/lib/oauth2/provider/rack/middleware.rb +28 -0
- data/lib/oauth2/provider/rack/resource_request.rb +91 -0
- data/lib/oauth2/provider/rack/responses.rb +34 -0
- data/lib/oauth2/provider/rails.rb +37 -0
- data/lib/oauth2/provider/rails/controller_authentication.rb +21 -0
- data/lib/oauth2/provider/random.rb +30 -0
- data/lib/oauth2/provider/version.rb +5 -0
- data/oauth2-provider.gemspec +35 -0
- data/spec/models/access_token_spec.rb +123 -0
- data/spec/models/authorization_code_spec.rb +115 -0
- data/spec/models/authorization_spec.rb +110 -0
- data/spec/models/client_spec.rb +75 -0
- data/spec/requests/access_tokens_controller_spec.rb +360 -0
- data/spec/requests/authentication_spec.rb +150 -0
- data/spec/requests/authorization_codes_support_spec.rb +157 -0
- data/spec/schema.rb +38 -0
- data/spec/set_backend_env_to_mongoid.rb +1 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/support/activerecord_backend.rb +18 -0
- data/spec/support/factories.rb +56 -0
- data/spec/support/macros.rb +46 -0
- data/spec/support/mongoid_backend.rb +34 -0
- data/spec/support/rack.rb +32 -0
- metadata +373 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require 'addressable/uri'
|
|
2
|
+
|
|
3
|
+
module OAuth2::Provider::Rack::Responses
|
|
4
|
+
def self.unauthorized(error = nil)
|
|
5
|
+
challenge = "OAuth2"
|
|
6
|
+
challenge << %{ error="#{error}"} if error
|
|
7
|
+
[401, {'Content-Type' => 'text/plain', 'Content-Length' => '0', 'WWW-Authenticate' => challenge}, []]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.only_supported(supported)
|
|
11
|
+
[405, {'Allow' => supported}, ["Only #{supported} requests allowed"]]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.json_error(error, options = {})
|
|
15
|
+
description = %{, "error_description": "#{options[:description]}"} if options[:description]
|
|
16
|
+
[options[:status] || 400, {'Content-Type' => 'application/json'}, [%{{"error": "#{error}"#{description}}}]]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.redirect_with_error(error, uri)
|
|
20
|
+
[302, {'Location' => append_to_uri(uri, :error => error)}, []]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.redirect_with_code(code, uri)
|
|
24
|
+
[302, {'Location' => append_to_uri(uri, :code => code)}, []]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def self.append_to_uri(uri, parameters = {})
|
|
30
|
+
u = Addressable::URI.parse(uri)
|
|
31
|
+
u.query_values = (u.query_values || {}).merge(parameters)
|
|
32
|
+
u.to_s
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'oauth2/provider'
|
|
2
|
+
|
|
3
|
+
module OAuth2::Provider::Rails
|
|
4
|
+
autoload :ControllerAuthentication, 'oauth2/provider/rails/controller_authentication'
|
|
5
|
+
|
|
6
|
+
class Railtie < Rails::Railtie
|
|
7
|
+
config.oauth2_provider = ActiveSupport::OrderedOptions.new
|
|
8
|
+
config.oauth2_provider.activerecord = ActiveSupport::OrderedOptions.new
|
|
9
|
+
config.oauth2_provider.mongoid = ActiveSupport::OrderedOptions.new
|
|
10
|
+
|
|
11
|
+
initializer "oauth2_provider.config" do |app|
|
|
12
|
+
app.config.oauth2_provider.except(:activerecord, :mongoid).each do |k,v|
|
|
13
|
+
OAuth2::Provider.send "#{k}=", v
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
app.config.oauth2_provider.activerecord.each do |k, v|
|
|
17
|
+
OAuth2::Provider::Models::ActiveRecord.send "#{k}=", v
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
app.config.oauth2_provider.mongoid.each do |k, v|
|
|
21
|
+
OAuth2::Provider::Models::Mongoid.send "#{k}=", v
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
OAuth2::Provider.activate
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
initializer "oauth2_provider.initialize_controller" do |app|
|
|
28
|
+
ActionController::Base.module_eval do
|
|
29
|
+
include OAuth2::Provider::Rails::ControllerAuthentication
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
initializer "oauth2_provider.initialize_middleware" do |app|
|
|
34
|
+
app.middleware.use ::OAuth2::Provider::Rack::Middleware
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'oauth2/provider'
|
|
2
|
+
|
|
3
|
+
module OAuth2::Provider::Rails::ControllerAuthentication
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
module ClassMethods
|
|
7
|
+
def authenticate_with_oauth(options = {})
|
|
8
|
+
around_filter AuthenticationFilter.new(options.delete(:scope)), options
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class AuthenticationFilter
|
|
12
|
+
def initialize(scope = nil)
|
|
13
|
+
@scope = scope
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def filter(controller, &block)
|
|
17
|
+
controller.request.env['oauth2'].authenticate_request! :scope => @scope, &block
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'oauth2/provider'
|
|
2
|
+
|
|
3
|
+
module OAuth2::Provider::Random
|
|
4
|
+
module Base62
|
|
5
|
+
CHARS = ('0'..'9').to_a + ('a'..'z').to_a + ('A'..'Z').to_a
|
|
6
|
+
|
|
7
|
+
# Adapted from http://refactormycode.com/codes/125-base-62-encoding
|
|
8
|
+
def self.encode(i)
|
|
9
|
+
return '0' if i == 0
|
|
10
|
+
s = ''
|
|
11
|
+
while i > 0
|
|
12
|
+
s << CHARS[i.modulo(62)]
|
|
13
|
+
i /= 62
|
|
14
|
+
end
|
|
15
|
+
s.reverse!
|
|
16
|
+
s
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def base62(length = 8)
|
|
21
|
+
number = ActiveSupport::SecureRandom.random_number(62 ** length)
|
|
22
|
+
Base62.encode(number).rjust(length, '0')
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def base36(length = 8)
|
|
26
|
+
ActiveSupport::SecureRandom.random_number(36 ** length).to_s(36).rjust(length, '0')
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
module_function :base62, :base36
|
|
30
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
|
3
|
+
require "oauth2/provider/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = "oauth2-provider"
|
|
7
|
+
s.version = OAuth2::Provider::VERSION
|
|
8
|
+
s.platform = Gem::Platform::RUBY
|
|
9
|
+
s.authors = ["Tom Ward"]
|
|
10
|
+
s.email = ["tom@popdog.net"]
|
|
11
|
+
s.homepage = "http://tomafro.net"
|
|
12
|
+
s.summary = %q{OAuth2 Provider, extracted from api.hashblue.com}
|
|
13
|
+
s.description = %q{OAuth2 Provider, extracted from api.hashblue.com}
|
|
14
|
+
|
|
15
|
+
s.files = `git ls-files`.split("\n")
|
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
18
|
+
s.require_paths = ["lib"]
|
|
19
|
+
|
|
20
|
+
# Main dependencies
|
|
21
|
+
s.add_dependency 'activesupport', '~>3.0.1'
|
|
22
|
+
s.add_dependency 'addressable', '~>2.2'
|
|
23
|
+
|
|
24
|
+
# Development only dependencies
|
|
25
|
+
s.add_development_dependency 'rails', '~>3.0.1'
|
|
26
|
+
s.add_development_dependency 'rspec-rails', '~>2.1.0'
|
|
27
|
+
s.add_development_dependency 'rake', '~>0.8.7'
|
|
28
|
+
s.add_development_dependency 'sqlite3-ruby', '~>1.3.1'
|
|
29
|
+
s.add_development_dependency 'timecop', '~>0.3.4'
|
|
30
|
+
s.add_development_dependency 'yajl-ruby', '~>0.7.5'
|
|
31
|
+
s.add_development_dependency 'mongoid', '2.0.0.rc.6'
|
|
32
|
+
s.add_development_dependency 'bson', '1.2.0'
|
|
33
|
+
s.add_development_dependency 'bson_ext', '1.2.0'
|
|
34
|
+
s.add_development_dependency 'sdoc', '~>0.2.20'
|
|
35
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe OAuth2::Provider.access_token_class do
|
|
4
|
+
describe "any instance" do
|
|
5
|
+
subject do
|
|
6
|
+
OAuth2::Provider.access_token_class.new :authorization => build_authorization
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "is valid with an access grant, expiry time and access token" do
|
|
10
|
+
subject.expires_at.should_not be_nil
|
|
11
|
+
subject.access_token.should_not be_nil
|
|
12
|
+
subject.authorization.should_not be_nil
|
|
13
|
+
|
|
14
|
+
subject.should be_valid
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "is invalid without an access token" do
|
|
18
|
+
subject.access_token = nil
|
|
19
|
+
subject.should_not be_valid
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "is invalid without an access grant" do
|
|
23
|
+
subject.authorization = nil
|
|
24
|
+
subject.should_not be_valid
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "is invalid when expires_at isn't set" do
|
|
28
|
+
subject.expires_at = nil
|
|
29
|
+
subject.should_not be_valid
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "is invalid if expires_at is later than the authorization's value" do
|
|
33
|
+
subject.authorization.expires_at = 1.minute.from_now
|
|
34
|
+
subject.expires_at = 10.minutes.from_now
|
|
35
|
+
subject.should_not be_valid
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "returns time in seconds until expiry when expires_in called" do
|
|
39
|
+
subject.expires_at = 60.minutes.from_now
|
|
40
|
+
subject.expires_in.should == (60 * 60)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "returns 0 for expired_in when already expired" do
|
|
44
|
+
subject.expires_at = 60.minutes.ago
|
|
45
|
+
subject.expires_in.should == 0
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "include expires_in, refresh_token and access token as JSON format" do
|
|
49
|
+
subject.as_json.should == {"expires_in" => subject.expires_in, "access_token" => subject.access_token, "refresh_token" => subject.refresh_token}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "include only expires_in and access token as JSON format if no refresh token set" do
|
|
53
|
+
subject.refresh_token = nil
|
|
54
|
+
subject.as_json.should == {"expires_in" => subject.expires_in, "access_token" => subject.access_token}
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "is refreshable, if it has a refresh token" do
|
|
58
|
+
subject.refresh_token = 'abcd1234'
|
|
59
|
+
subject.should be_refreshable
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "is not refreshable if it has no refresh token" do
|
|
63
|
+
subject.refresh_token = nil
|
|
64
|
+
subject.should_not be_refreshable
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "is not refreshable if it has a refresh token, but its authorization has expired" do
|
|
68
|
+
subject.refresh_token = 'abcd1234'
|
|
69
|
+
subject.authorization.expires_at = 60.minutes.ago
|
|
70
|
+
subject.should_not be_refreshable
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
describe "a new instance" do
|
|
75
|
+
subject do
|
|
76
|
+
OAuth2::Provider.access_token_class.new
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "is assigned a randomly generated access token" do
|
|
80
|
+
subject.access_token.should_not be_nil
|
|
81
|
+
OAuth2::Provider.access_token_class.new.access_token.should_not be_nil
|
|
82
|
+
subject.access_token.should_not == OAuth2::Provider.access_token_class.new.access_token
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "is assigned a randomly generated refresh token" do
|
|
86
|
+
subject.refresh_token.should_not be_nil
|
|
87
|
+
OAuth2::Provider.access_token_class.new.refresh_token.should_not be_nil
|
|
88
|
+
subject.access_token.should_not == OAuth2::Provider.access_token_class.new.refresh_token
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "expires in 1 month by default" do
|
|
92
|
+
subject.expires_at.should == 1.month.from_now
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
describe "refreshing an existing token" do
|
|
97
|
+
subject do
|
|
98
|
+
OAuth2::Provider.access_token_class.create! :authorization => create_authorization, :expires_at => 23.days.ago
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "returns a new access token with the same client, resource_owner and scope, but a new expiry time" do
|
|
102
|
+
result = OAuth2::Provider.access_token_class.refresh_with(subject.refresh_token)
|
|
103
|
+
result.should_not be_nil
|
|
104
|
+
result.expires_at.should == 1.month.from_now
|
|
105
|
+
result.authorization.should == subject.authorization
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it "returns token with expires_at set to authorization.expires_at if validation would fail otherwise" do
|
|
109
|
+
subject.authorization.update_attributes(:expires_at => 5.minutes.from_now)
|
|
110
|
+
result = OAuth2::Provider.access_token_class.refresh_with(subject.refresh_token)
|
|
111
|
+
result.expires_at.should == 5.minutes.from_now
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it "returns nil if the provided token doesn't match" do
|
|
115
|
+
OAuth2::Provider.access_token_class.refresh_with('wrong').should be_nil
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it "returns nil if the existing refresh token is nil, whatever value is provided" do
|
|
119
|
+
subject.update_attributes(:refresh_token => nil)
|
|
120
|
+
OAuth2::Provider.access_token_class.refresh_with(nil).should be_nil
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe OAuth2::Provider.authorization_code_class do
|
|
4
|
+
describe "any instance" do
|
|
5
|
+
subject do
|
|
6
|
+
OAuth2::Provider.authorization_code_class.new(
|
|
7
|
+
:authorization => create_authorization,
|
|
8
|
+
:redirect_uri => "http://redirect.example.com/callback"
|
|
9
|
+
)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "is valid with an access grant, expiry time, redirect uri and code" do
|
|
13
|
+
subject.should be_valid
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "is invalid without a redirect_uri" do
|
|
17
|
+
subject.redirect_uri = nil
|
|
18
|
+
subject.should_not be_valid
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "is invalid without a code" do
|
|
22
|
+
subject.code = nil
|
|
23
|
+
subject.should_not be_valid
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "is invalid without an access grant" do
|
|
27
|
+
subject.authorization = nil
|
|
28
|
+
subject.should_not be_valid
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "is invalid when expires_at isn't set" do
|
|
32
|
+
subject.expires_at = nil
|
|
33
|
+
subject.should_not be_valid
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "has expired when expires_at is in the past" do
|
|
37
|
+
subject.expires_at = 1.second.ago
|
|
38
|
+
subject.should be_expired
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "has not expired when expires_at is now or in the future" do
|
|
42
|
+
subject.expires_at = Time.now
|
|
43
|
+
subject.should_not be_expired
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe "a new instance" do
|
|
48
|
+
subject do
|
|
49
|
+
OAuth2::Provider.authorization_code_class.new
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "is assigned a randomly generated code" do
|
|
53
|
+
subject.code.should_not be_nil
|
|
54
|
+
OAuth2::Provider.authorization_code_class.new.code.should_not be_nil
|
|
55
|
+
subject.code.should_not == OAuth2::Provider.authorization_code_class.new.code
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "expires in 1 minute by default" do
|
|
59
|
+
subject.expires_at.should == 1.minute.from_now
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
describe "a saved instance" do
|
|
64
|
+
subject do
|
|
65
|
+
OAuth2::Provider.authorization_code_class.create!(
|
|
66
|
+
:authorization => create_authorization,
|
|
67
|
+
:redirect_uri => "https://client.example.com/callback/here"
|
|
68
|
+
)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "can be claimed with the correct code and redirect_uri" do
|
|
72
|
+
OAuth2::Provider.authorization_code_class.claim(subject.code, subject.redirect_uri).should_not be_nil
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "returns an access token when claimed" do
|
|
76
|
+
OAuth2::Provider.authorization_code_class.claim(subject.code, subject.redirect_uri).should be_instance_of(OAuth2::Provider.access_token_class)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "can't be claimed twice" do
|
|
80
|
+
OAuth2::Provider.authorization_code_class.claim(subject.code, subject.redirect_uri)
|
|
81
|
+
OAuth2::Provider.authorization_code_class.claim(subject.code, subject.redirect_uri).should be_nil
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "can't be claimed without a matching code" do
|
|
85
|
+
OAuth2::Provider.authorization_code_class.claim("incorrectCode", subject.redirect_uri).should be_nil
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it "can't be claimed without a matching redirect_uri" do
|
|
89
|
+
OAuth2::Provider.authorization_code_class.claim(subject.code, "https://wrong.example.com").should be_nil
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "can't be claimed once expired" do
|
|
93
|
+
Timecop.travel subject.expires_at + 1.minute
|
|
94
|
+
OAuth2::Provider.authorization_code_class.claim(subject.code, subject.redirect_uri).should be_nil
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
describe "the access token returned when a code is claimed" do
|
|
99
|
+
subject do
|
|
100
|
+
@code = OAuth2::Provider.authorization_code_class.create!(
|
|
101
|
+
:authorization => create_authorization,
|
|
102
|
+
:redirect_uri => "https://client.example.com/callback/here"
|
|
103
|
+
)
|
|
104
|
+
OAuth2::Provider.authorization_code_class.claim(@code.code, @code.redirect_uri)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it "is saved to the database" do
|
|
108
|
+
subject.should_not be_new_record
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it "has same access grant as claimed code" do
|
|
112
|
+
subject.authorization.should == @code.authorization
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe OAuth2::Provider.authorization_class do
|
|
4
|
+
describe "any instance" do
|
|
5
|
+
subject do
|
|
6
|
+
result = OAuth2::Provider.authorization_class.new :client => create_client
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "is valid with a client" do
|
|
10
|
+
subject.client.should_not be_nil
|
|
11
|
+
subject.should be_valid
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "is invalid without a client" do
|
|
15
|
+
subject.client = nil
|
|
16
|
+
subject.should_not be_valid
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "has a given scope, if scope string includes scope" do
|
|
20
|
+
subject.scope = "first second third"
|
|
21
|
+
subject.should have_scope("first")
|
|
22
|
+
subject.should have_scope("second")
|
|
23
|
+
subject.should have_scope("third")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "doesn't have a given scope, if scope string doesn't scope" do
|
|
27
|
+
subject.scope = "first second third"
|
|
28
|
+
subject.should_not have_scope("fourth")
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
describe "a new instance" do
|
|
33
|
+
subject do
|
|
34
|
+
OAuth2::Provider.authorization_class.new
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "has no expiry time by default" do
|
|
38
|
+
subject.expires_at.should be_nil
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "is never expired" do
|
|
42
|
+
subject.should_not be_expired
|
|
43
|
+
Timecop.travel(100.years.from_now)
|
|
44
|
+
subject.should_not be_expired
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe "after being persisted and restored" do
|
|
49
|
+
before :each do
|
|
50
|
+
@client = create_client
|
|
51
|
+
@owner = create_resource_owner
|
|
52
|
+
@original = OAuth2::Provider.authorization_class.create!(:client => @client, :resource_owner => @owner, :expires_at => 1.year.from_now)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
subject do
|
|
56
|
+
OAuth2::Provider.authorization_class.find(@original.id)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "remembers client" do
|
|
60
|
+
subject.client.should eql(@client)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "remembers resource owner" do
|
|
64
|
+
subject.resource_owner.should eql(@owner)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
describe "obtain all authorizations for a resource owner" do
|
|
69
|
+
before :each do
|
|
70
|
+
@client = create_client
|
|
71
|
+
@owner = create_resource_owner
|
|
72
|
+
@authorization = OAuth2::Provider.authorization_class.create!(:client => @client, :resource_owner => @owner, :expires_at => 1.year.from_now)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
subject do
|
|
76
|
+
OAuth2::Provider.authorization_class.all_for(@owner)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "returns correct number of authorizations" do
|
|
80
|
+
subject.count.should eql(1)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it "should hold information on the authorized client" do
|
|
84
|
+
subject[0].client.should eql(@client)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
describe "being revoked" do
|
|
89
|
+
subject do
|
|
90
|
+
OAuth2::Provider.authorization_class.create! :client => create_client
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "destroys itself" do
|
|
94
|
+
subject.revoke
|
|
95
|
+
subject.should be_destroyed
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "destroys any related authorization codes" do
|
|
99
|
+
subject.authorization_codes.create! :redirect_uri => 'https://example.com'
|
|
100
|
+
subject.revoke
|
|
101
|
+
subject.authorization_codes.should be_empty
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it "destroys any related access tokens" do
|
|
105
|
+
subject.access_tokens.create!
|
|
106
|
+
subject.revoke
|
|
107
|
+
subject.access_tokens.should be_empty
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|