capcoauth 0.4.0 → 0.5.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.
- checksums.yaml +4 -4
- data/.gitignore +15 -35
- data/.rspec +1 -0
- data/.travis.yml +11 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +171 -0
- data/README.md +3 -1
- data/Rakefile +7 -7
- data/app/controllers/capcoauth/application_controller.rb +8 -1
- data/app/controllers/capcoauth/login_controller.rb +5 -1
- data/app/controllers/capcoauth/logout_controller.rb +2 -6
- data/capcoauth.gemspec +13 -6
- data/lib/capcoauth/config.rb +52 -58
- data/lib/capcoauth/errors.rb +3 -0
- data/lib/capcoauth/notifications.rb +11 -9
- data/lib/capcoauth/oauth/access_token.rb +0 -1
- data/lib/capcoauth/oauth/token_verifier.rb +15 -10
- data/lib/capcoauth/rails/helpers.rb +45 -44
- data/lib/capcoauth/version.rb +11 -1
- data/lib/capcoauth.rb +1 -9
- data/lib/generators/capcoauth/templates/initializer.rb +23 -12
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/full_protected_resources_controller.rb +12 -0
- data/spec/dummy/app/controllers/home_controller.rb +17 -0
- data/spec/dummy/app/controllers/metal_controller.rb +11 -0
- data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +11 -0
- data/spec/dummy/app/models/user.rb +3 -0
- data/spec/dummy/app/views/home/index.html.erb +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config/application.rb +16 -0
- data/spec/dummy/config/boot.rb +6 -0
- data/spec/dummy/config/database.yml +15 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +62 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/active_record_belongs_to_required_by_default.rb +6 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/capcoauth.rb +41 -0
- data/spec/dummy/config/initializers/secret_token.rb +9 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/routes.rb +50 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/migrate/20111122132257_create_users.rb +9 -0
- data/spec/dummy/db/schema.rb +22 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +26 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/generators/install_generator_spec.rb +27 -0
- data/spec/generators/templates/routes.rb +3 -0
- data/spec/lib/capcoauth/oauth/access_token_spec.rb +31 -0
- data/spec/lib/capcoauth/oauth/token_verifier_spec.rb +121 -0
- data/spec/lib/capcoauth/oauth/ttl_cache_spec.rb +88 -0
- data/spec/lib/capcoauth_spec.rb +3 -0
- data/spec/lib/config_spec.rb +215 -0
- data/spec/lib/version_spec.rb +25 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/spec_helper_integration.rb +50 -0
- data/spec/support/http_method_shim.rb +38 -0
- data/spec/support/orm/active_record.rb +3 -0
- metadata +172 -12
- data/lib/capcoauth/helpers/controller.rb +0 -15
@@ -0,0 +1,22 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# This file is auto-generated from the current state of the database. Instead
|
3
|
+
# of editing this file, please use the migrations feature of Active Record to
|
4
|
+
# incrementally modify your database, and then regenerate this schema definition.
|
5
|
+
#
|
6
|
+
# Note that this schema.rb definition is the authoritative source for your
|
7
|
+
# database schema. If you need to create the application database on another
|
8
|
+
# system, you should be using db:schema:load, not running all the migrations
|
9
|
+
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
10
|
+
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
11
|
+
#
|
12
|
+
# It's strongly recommended that you check this file into your version control system.
|
13
|
+
|
14
|
+
ActiveRecord::Schema.define(version: 20111122132257) do
|
15
|
+
|
16
|
+
create_table "users", force: :cascade do |t|
|
17
|
+
t.string "name"
|
18
|
+
t.datetime "created_at"
|
19
|
+
t.datetime "updated_at"
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The page you were looking for doesn't exist (404)</title>
|
5
|
+
<style type="text/css">
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
7
|
+
div.dialog {
|
8
|
+
width: 25em;
|
9
|
+
padding: 0 4em;
|
10
|
+
margin: 4em auto 0 auto;
|
11
|
+
border: 1px solid #ccc;
|
12
|
+
border-right-color: #999;
|
13
|
+
border-bottom-color: #999;
|
14
|
+
}
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
16
|
+
</style>
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body>
|
20
|
+
<!-- This file lives in public/404.html -->
|
21
|
+
<div class="dialog">
|
22
|
+
<h1>The page you were looking for doesn't exist.</h1>
|
23
|
+
<p>You may have mistyped the address or the page may have moved.</p>
|
24
|
+
</div>
|
25
|
+
</body>
|
26
|
+
</html>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The change you wanted was rejected (422)</title>
|
5
|
+
<style type="text/css">
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
7
|
+
div.dialog {
|
8
|
+
width: 25em;
|
9
|
+
padding: 0 4em;
|
10
|
+
margin: 4em auto 0 auto;
|
11
|
+
border: 1px solid #ccc;
|
12
|
+
border-right-color: #999;
|
13
|
+
border-bottom-color: #999;
|
14
|
+
}
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
16
|
+
</style>
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body>
|
20
|
+
<!-- This file lives in public/422.html -->
|
21
|
+
<div class="dialog">
|
22
|
+
<h1>The change you wanted was rejected.</h1>
|
23
|
+
<p>Maybe you tried to change something you didn't have access to.</p>
|
24
|
+
</div>
|
25
|
+
</body>
|
26
|
+
</html>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>We're sorry, but something went wrong (500)</title>
|
5
|
+
<style type="text/css">
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
7
|
+
div.dialog {
|
8
|
+
width: 25em;
|
9
|
+
padding: 0 4em;
|
10
|
+
margin: 4em auto 0 auto;
|
11
|
+
border: 1px solid #ccc;
|
12
|
+
border-right-color: #999;
|
13
|
+
border-bottom-color: #999;
|
14
|
+
}
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
16
|
+
</style>
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body>
|
20
|
+
<!-- This file lives in public/500.html -->
|
21
|
+
<div class="dialog">
|
22
|
+
<h1>We're sorry, but something went wrong.</h1>
|
23
|
+
<p>We've been notified about this issue and we'll take a look at it shortly.</p>
|
24
|
+
</div>
|
25
|
+
</body>
|
26
|
+
</html>
|
File without changes
|
@@ -0,0 +1,6 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
|
3
|
+
|
4
|
+
APP_PATH = File.expand_path('../../config/application', __FILE__)
|
5
|
+
require File.expand_path('../../config/boot', __FILE__)
|
6
|
+
require 'rails/commands'
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper_integration'
|
2
|
+
require 'generators/capcoauth/install_generator'
|
3
|
+
|
4
|
+
describe 'Capcoauth::InstallGenerator' do
|
5
|
+
include GeneratorSpec::TestCase
|
6
|
+
|
7
|
+
tests Capcoauth::InstallGenerator
|
8
|
+
destination ::File.expand_path('../tmp/dummy', __FILE__)
|
9
|
+
|
10
|
+
describe 'after running the generator' do
|
11
|
+
before :each do
|
12
|
+
prepare_destination
|
13
|
+
FileUtils.mkdir(::File.expand_path('config', Pathname(destination_root)))
|
14
|
+
FileUtils.mkdir(::File.expand_path('db', Pathname(destination_root)))
|
15
|
+
FileUtils.copy_file(::File.expand_path('../templates/routes.rb', __FILE__), ::File.expand_path('config/routes.rb', Pathname.new(destination_root)))
|
16
|
+
run_generator
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'creates an initializer file' do
|
20
|
+
assert_file 'config/initializers/capcoauth.rb'
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'adds sample route' do
|
24
|
+
assert_file 'config/routes.rb', /use_capcoauth/
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper_integration'
|
2
|
+
|
3
|
+
describe Capcoauth::OAuth::AccessToken do
|
4
|
+
|
5
|
+
describe '.initialize' do
|
6
|
+
it 'has token but no user ID' do
|
7
|
+
token = Capcoauth::OAuth::AccessToken.new 'abc'
|
8
|
+
expect(token.token).to eq('abc')
|
9
|
+
expect(token.user_id).to be_nil
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'calls TTLCache.user_id_for and sets user_id to return value' do
|
13
|
+
ttl_cache_double = class_double('Capcoauth::OAuth::TTLCache').as_stubbed_const
|
14
|
+
allow(ttl_cache_double).to receive(:user_id_for).and_return('123')
|
15
|
+
token = Capcoauth::OAuth::AccessToken.new 'abc'
|
16
|
+
expect(token.token).to eq('abc')
|
17
|
+
expect(token.user_id).to eq('123')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '.verify' do
|
22
|
+
it 'calls TokenVerifier.verify with self' do
|
23
|
+
verifier_double = class_double('Capcoauth::OAuth::TokenVerifier').as_stubbed_const
|
24
|
+
allow(verifier_double).to receive(:verify).and_return('CALLED')
|
25
|
+
|
26
|
+
token = Capcoauth::OAuth::AccessToken.new nil
|
27
|
+
expect(token.token).to be_nil
|
28
|
+
expect(token.verify).to eq('CALLED')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'net/http'
|
3
|
+
|
4
|
+
class MockHttpResponse
|
5
|
+
def initialize(**opts)
|
6
|
+
opts.each do |key, val|
|
7
|
+
instance_variable_set("@#{key}", val)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
def code; @code; end
|
11
|
+
def headers; @headers; end
|
12
|
+
def parsed_response; @body; end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe Capcoauth::OAuth::TokenVerifier do
|
16
|
+
subject { Capcoauth::OAuth::TokenVerifier }
|
17
|
+
describe '#verify' do
|
18
|
+
before do
|
19
|
+
Capcoauth.configuration.client_id = 'verifier_test_client_id'
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'raises UnauthorizedError when no access token object passed' do
|
23
|
+
expect{subject.verify(nil)}.to raise_error(Capcoauth::OAuth::TokenVerifier::UnauthorizedError, 'Please log in to continue')
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'raises UnauthorizedError when access token object has no token material' do
|
27
|
+
expect{subject.verify(Capcoauth::OAuth::AccessToken.new(nil))}.to raise_error(Capcoauth::OAuth::TokenVerifier::UnauthorizedError, 'Please log in to continue')
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'returns access token object if access_token is valid' do
|
31
|
+
Capcoauth::OAuth::TTLCache.update('abc', '123')
|
32
|
+
token = Capcoauth::OAuth::AccessToken.new('abc')
|
33
|
+
expect(subject.verify(token)).to equal(token)
|
34
|
+
Capcoauth::OAuth::TTLCache.remove('abc')
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'calls HTTParty.get and raises OtherError on Net::OpenTimeout' do
|
38
|
+
httparty_double = class_double('HTTParty').as_stubbed_const
|
39
|
+
expect(httparty_double).to receive(:get).and_raise(Net::OpenTimeout)
|
40
|
+
token = Capcoauth::OAuth::AccessToken.new('iamnew')
|
41
|
+
expect{subject.verify(token)}.to raise_error(Capcoauth::OAuth::TokenVerifier::OtherError, 'An error occurred while verifying your credentials (server not available)')
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'calls HTTParty.get and raises UnauthorizedError if ID type is not returned' do
|
45
|
+
Capcoauth.configuration.user_id_field = :psoft
|
46
|
+
httparty_double = class_double('HTTParty').as_stubbed_const
|
47
|
+
expect(httparty_double).to receive(:get).and_return(MockHttpResponse.new(code: 200, body: {
|
48
|
+
'resource_owner_id' => '123',
|
49
|
+
'external_ids' => {}
|
50
|
+
}))
|
51
|
+
token = Capcoauth::OAuth::AccessToken.new('iamnew')
|
52
|
+
expect{subject.verify(token)}.to raise_error(Capcoauth::OAuth::TokenVerifier::UnauthorizedError, 'The system cannot recognize you by that ID type')
|
53
|
+
Capcoauth.configuration.user_id_field = :capcoauth
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'calls HTTParty.get and raises UnauthorizedError if ID type is not returned' do
|
57
|
+
httparty_double = class_double('HTTParty').as_stubbed_const
|
58
|
+
expect(httparty_double).to receive(:get).and_return(MockHttpResponse.new(code: 200, body: {
|
59
|
+
'resource_owner_id' => '123',
|
60
|
+
'application' => {
|
61
|
+
'uid' => 'not_client_id_123'
|
62
|
+
}
|
63
|
+
}))
|
64
|
+
token = Capcoauth::OAuth::AccessToken.new('iamnew')
|
65
|
+
expect{subject.verify(token)}.to raise_error(Capcoauth::OAuth::TokenVerifier::UnauthorizedError, 'Your credentials are valid, but are not for use with this system')
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'calls HTTParty.get and raises UnauthorizedError if token is unknown' do
|
69
|
+
httparty_double = class_double('HTTParty').as_stubbed_const
|
70
|
+
expect(httparty_double).to receive(:get).and_return(MockHttpResponse.new(code: 401, body: {
|
71
|
+
'error': 'invalid_request',
|
72
|
+
'error_description': 'The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.'
|
73
|
+
}))
|
74
|
+
token = Capcoauth::OAuth::AccessToken.new('iamnew')
|
75
|
+
expect{subject.verify(token)}.to raise_error(Capcoauth::OAuth::TokenVerifier::UnauthorizedError, 'Please log in to continue')
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'calls HTTParty.get and raises UnauthorizedError if token is unknown' do
|
79
|
+
httparty_double = class_double('HTTParty').as_stubbed_const
|
80
|
+
expect(httparty_double).to receive(:get).and_return(MockHttpResponse.new(code: 12345, body: {
|
81
|
+
'error': 'invalid_request',
|
82
|
+
'error_description': 'The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.'
|
83
|
+
}))
|
84
|
+
token = Capcoauth::OAuth::AccessToken.new('iamnew')
|
85
|
+
expect{subject.verify(token)}.to raise_error(Capcoauth::OAuth::TokenVerifier::OtherError, 'An error occurred while verifying your credentials (unknown response)')
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'calls HTTParty.get and returns access token with capcoauth id type' do
|
89
|
+
httparty_double = class_double('HTTParty').as_stubbed_const
|
90
|
+
expect(httparty_double).to receive(:get).and_return(MockHttpResponse.new(code: 200, body: {
|
91
|
+
'resource_owner_id' => 'capcoauth_123',
|
92
|
+
'application' => {
|
93
|
+
'uid' => 'verifier_test_client_id'
|
94
|
+
}
|
95
|
+
}))
|
96
|
+
token = Capcoauth::OAuth::AccessToken.new('capcoauth_user_token')
|
97
|
+
expect(subject.verify(token)).to equal(token)
|
98
|
+
expect(token.user_id).to eq('capcoauth_123')
|
99
|
+
Capcoauth::OAuth::TTLCache.remove('capcoauth_user_token')
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'calls HTTParty.get and returns access token with psoft id type' do
|
103
|
+
Capcoauth.configuration.user_id_field = :psoft
|
104
|
+
httparty_double = class_double('HTTParty').as_stubbed_const
|
105
|
+
expect(httparty_double).to receive(:get).and_return(MockHttpResponse.new(code: 200, body: {
|
106
|
+
'resource_owner_id' => '123',
|
107
|
+
'application' => {
|
108
|
+
'uid' => 'verifier_test_client_id'
|
109
|
+
},
|
110
|
+
'external_ids' => {
|
111
|
+
'psoft' => 'psoft_123'
|
112
|
+
}
|
113
|
+
}))
|
114
|
+
token = Capcoauth::OAuth::AccessToken.new('psoft_user_token')
|
115
|
+
expect(subject.verify(token)).to equal(token)
|
116
|
+
expect(token.user_id).to eq('psoft_123')
|
117
|
+
Capcoauth::OAuth::TTLCache.remove('psoft_user_token')
|
118
|
+
Capcoauth.configuration.user_id_field = :capcoauth
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'spec_helper_integration'
|
2
|
+
|
3
|
+
describe Capcoauth::OAuth::TTLCache do
|
4
|
+
subject { Capcoauth::OAuth::TTLCache }
|
5
|
+
|
6
|
+
describe '#user_id_for' do
|
7
|
+
it 'returns nil when store contains no token' do
|
8
|
+
expect(subject.user_id_for('idontexist')).to be_nil
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'returns user_id when store contains token' do
|
12
|
+
subject.update('abc', '123')
|
13
|
+
expect(subject.user_id_for('abc')).to eq('123')
|
14
|
+
subject.remove('abc')
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'returns user_id when TTL is almost expired' do
|
18
|
+
subject.update('abc', '123')
|
19
|
+
Timecop.freeze(Time.zone.now + (Capcoauth.configuration.token_verify_ttl - 1).seconds) do
|
20
|
+
expect(subject.user_id_for('abc')).to eq('123')
|
21
|
+
end
|
22
|
+
subject.remove('abc')
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'returns nil when TTL is expired' do
|
26
|
+
subject.update('abc', '123')
|
27
|
+
Timecop.freeze(Time.zone.now + (Capcoauth.configuration.token_verify_ttl + 1).seconds) do
|
28
|
+
expect(subject.user_id_for('abc')).to be_nil
|
29
|
+
end
|
30
|
+
subject.remove('abc')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#update' do
|
35
|
+
it 'returns true on write' do
|
36
|
+
expect(subject.update('abc', '123')).to be true
|
37
|
+
expect(subject.user_id_for('abc')).to eq('123')
|
38
|
+
subject.remove('abc')
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'respects expires_in TTL' do
|
42
|
+
subject.update('abc', '123')
|
43
|
+
Timecop.freeze(Time.zone.now + (Capcoauth.configuration.token_verify_ttl - 1).seconds) do
|
44
|
+
expect(subject.user_id_for('abc')).to eq('123')
|
45
|
+
end
|
46
|
+
Timecop.freeze(Time.zone.now + (Capcoauth.configuration.token_verify_ttl + 1).seconds) do
|
47
|
+
expect(subject.user_id_for('abc')).to be_nil
|
48
|
+
end
|
49
|
+
subject.remove('abc')
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'overwrites existing values' do
|
53
|
+
subject.update('abc', '123')
|
54
|
+
expect(subject.update('abc', '456')).to be true
|
55
|
+
expect(subject.user_id_for('abc')).to eq('456')
|
56
|
+
subject.remove('abc')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#remove' do
|
61
|
+
it 'returns false when value doesn\'t exist' do
|
62
|
+
expect(subject.remove('idontexist')).to be false
|
63
|
+
end
|
64
|
+
it 'returns true when value exists' do
|
65
|
+
expect(subject.update('abc', '123')).to be true
|
66
|
+
expect(subject.remove('abc')).to be true
|
67
|
+
end
|
68
|
+
it 'returns true when value is expired and false after removed' do
|
69
|
+
expect(subject.update('abc', '123')).to be true
|
70
|
+
Timecop.freeze(Time.zone.now + (Capcoauth.configuration.token_verify_ttl + 1).seconds) do
|
71
|
+
expect(subject.remove('abc')).to be true
|
72
|
+
expect(subject.remove('abc')).to be false
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe '#key_for' do
|
78
|
+
it 'returns formatted key' do
|
79
|
+
expect(subject.key_for('abc')).to eq('capcoauth_token:abc')
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe '#store' do
|
84
|
+
it 'returns Capcoauth.cache_store' do
|
85
|
+
expect(subject.store).to equal(Capcoauth.configuration.cache_store)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,215 @@
|
|
1
|
+
require 'spec_helper_integration'
|
2
|
+
|
3
|
+
class DummyLogger; end
|
4
|
+
class DummyStore; end
|
5
|
+
class DummyUser
|
6
|
+
attr_reader :user_id
|
7
|
+
def initialize(user_id)
|
8
|
+
@user_id = user_id
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe Capcoauth::Config do
|
13
|
+
subject {
|
14
|
+
Capcoauth.configure do |config|
|
15
|
+
config.client_id = 'ci'
|
16
|
+
config.client_secret = 'cs'
|
17
|
+
config.user_resolver = -> user_id {
|
18
|
+
DummyUser.new user_id
|
19
|
+
}
|
20
|
+
end
|
21
|
+
}
|
22
|
+
|
23
|
+
describe 'subject' do
|
24
|
+
it 'is an instance of Capcoauth::Config' do
|
25
|
+
expect(subject).to be_a(Capcoauth::Config)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'default config requires required options' do
|
30
|
+
subject :default_config do
|
31
|
+
Capcoauth::Config::Builder.new do; end.build
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'fails when not client_id not set' do
|
35
|
+
expect{default_config.client_id}.to raise_error(Capcoauth::MissingRequiredOptionError, 'Missing required option `client_id`')
|
36
|
+
end
|
37
|
+
it 'fails when not client_secret not set' do
|
38
|
+
expect{default_config.client_secret}.to raise_error(Capcoauth::MissingRequiredOptionError, 'Missing required option `client_secret`')
|
39
|
+
end
|
40
|
+
it 'fails when not client_user_resolver not set' do
|
41
|
+
expect{default_config.user_resolver}.to raise_error(Capcoauth::MissingRequiredOptionError, 'Missing required option/lambda `user_resolver`')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'client_id' do
|
46
|
+
it 'has value of ci' do
|
47
|
+
expect(subject.client_id).to eq('ci')
|
48
|
+
end
|
49
|
+
it 'can be updated to test_123' do
|
50
|
+
subject.client_id = 'test_123'
|
51
|
+
expect(subject.client_id).to eq('test_123')
|
52
|
+
subject.client_id = 'ci'
|
53
|
+
end
|
54
|
+
it 'cannot be set to nil' do
|
55
|
+
expect{subject.client_id = nil}.to raise_error(Capcoauth::MissingRequiredOptionError, '`client_id` cannot be set to nil')
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe 'client_secret' do
|
60
|
+
it 'has value of cs' do
|
61
|
+
expect(subject.client_secret).to eq('cs')
|
62
|
+
end
|
63
|
+
it 'can be updated to test_123' do
|
64
|
+
subject.client_secret = 'test_456'
|
65
|
+
expect(subject.client_secret).to eq('test_456')
|
66
|
+
subject.client_secret = 'cs'
|
67
|
+
end
|
68
|
+
it 'cannot be set to nil' do
|
69
|
+
expect{subject.client_secret = nil}.to raise_error(Capcoauth::MissingRequiredOptionError, '`client_secret` cannot be set to nil')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'user_resolver' do
|
74
|
+
before do
|
75
|
+
@old_resolver = subject.user_resolver
|
76
|
+
end
|
77
|
+
after do
|
78
|
+
subject.user_resolver = @old_resolver
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'sets the block that is accessible via user_resolver' do
|
82
|
+
block = proc {}
|
83
|
+
subject.user_resolver = block
|
84
|
+
expect(subject.user_resolver).to equal(block)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'returns a dummy user' do
|
88
|
+
returned_user = subject.user_resolver.call('123')
|
89
|
+
expect(returned_user).to be_a(DummyUser)
|
90
|
+
expect(returned_user.user_id).to eq('123')
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'raises error from resolver' do
|
94
|
+
subject.user_resolver = -> user_id {
|
95
|
+
User.find_by! id: user_id
|
96
|
+
}
|
97
|
+
expect{subject.user_resolver.call('iwillneverexist')}.to raise_error(ActiveRecord::RecordNotFound, 'Couldn\'t find User')
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe 'logger' do
|
102
|
+
after do
|
103
|
+
subject.logger = ::Rails.logger
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'defaults to Rails.logger' do
|
107
|
+
expect(subject.logger).to equal(::Rails.logger)
|
108
|
+
end
|
109
|
+
it 'can be updated to custom logger' do
|
110
|
+
new_logger = DummyLogger.new
|
111
|
+
subject.logger = new_logger
|
112
|
+
expect(subject.logger).to equal(new_logger)
|
113
|
+
end
|
114
|
+
it 'can be set to nil' do
|
115
|
+
subject.logger = nil
|
116
|
+
expect(subject.logger).to be_nil
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe 'using_routes' do
|
121
|
+
it 'has value false by default' do
|
122
|
+
expect(subject.using_routes).to be_falsey
|
123
|
+
end
|
124
|
+
it 'can be updated to true' do
|
125
|
+
subject.using_routes = true
|
126
|
+
expect(subject.using_routes).to be_truthy
|
127
|
+
subject.using_routes = false
|
128
|
+
end
|
129
|
+
it 'is updated to true by Rails.application.routes.draw' do
|
130
|
+
subject.using_routes = false
|
131
|
+
expect(subject.using_routes).to be_falsy
|
132
|
+
Rails.application.routes.draw do
|
133
|
+
use_capcoauth
|
134
|
+
end
|
135
|
+
expect(subject.using_routes).to be_truthy
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe 'perform_login_redirects' do
|
140
|
+
it 'has value true by default' do
|
141
|
+
expect(subject.perform_login_redirects).to be_truthy
|
142
|
+
end
|
143
|
+
it 'can be updated to false' do
|
144
|
+
subject.perform_login_redirects = false
|
145
|
+
expect(subject.perform_login_redirects).to be_falsey
|
146
|
+
subject.perform_login_redirects = true
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe 'token_verify_ttl' do
|
151
|
+
it 'has value 10 by default' do
|
152
|
+
expect(subject.token_verify_ttl).to eq(Capcoauth::Config::TOKEN_VERIFY_TTL_DEFAULT)
|
153
|
+
end
|
154
|
+
it 'can be updated to other value' do
|
155
|
+
subject.token_verify_ttl = 60
|
156
|
+
expect(subject.token_verify_ttl).to eq(60)
|
157
|
+
subject.token_verify_ttl = Capcoauth::Config::TOKEN_VERIFY_TTL_DEFAULT
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe 'capcoauth_url' do
|
162
|
+
it "has value #{Capcoauth::Config::CAPCOAUTH_URL_DEFAULT} by default" do
|
163
|
+
expect(subject.capcoauth_url).to eq(Capcoauth::Config::CAPCOAUTH_URL_DEFAULT)
|
164
|
+
end
|
165
|
+
it 'can be updated to other value' do
|
166
|
+
subject.capcoauth_url = 'https://example.com'
|
167
|
+
expect(subject.capcoauth_url).to eq('https://example.com')
|
168
|
+
subject.capcoauth_url = Capcoauth::Config::CAPCOAUTH_URL_DEFAULT
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
describe 'user_id_field' do
|
173
|
+
it 'has value :capcoauth by default' do
|
174
|
+
expect(subject.user_id_field).to eq(:capcoauth)
|
175
|
+
end
|
176
|
+
it 'can be updated to false' do
|
177
|
+
subject.user_id_field = :psoft
|
178
|
+
expect(subject.user_id_field).to eq(:psoft)
|
179
|
+
subject.user_id_field = :capcoauth
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
describe 'cache_store' do
|
184
|
+
before do
|
185
|
+
@cache_store = subject.cache_store
|
186
|
+
end
|
187
|
+
after do
|
188
|
+
subject.cache_store = @cache_store
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'defaults to ActiveSupport::Cache::MemoryStore store' do
|
192
|
+
expect(subject.cache_store).to be_a(::ActiveSupport::Cache::MemoryStore)
|
193
|
+
end
|
194
|
+
it 'can be updated to custom store' do
|
195
|
+
new_store = DummyStore.new
|
196
|
+
subject.cache_store = new_store
|
197
|
+
expect(subject.cache_store).to equal(new_store)
|
198
|
+
end
|
199
|
+
it 'can be set to nil' do
|
200
|
+
subject.cache_store = nil
|
201
|
+
expect(subject.cache_store).to be_nil
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe 'require_user' do
|
206
|
+
it 'has value true by default' do
|
207
|
+
expect(subject.require_user).to be_truthy
|
208
|
+
end
|
209
|
+
it 'can be updated to false' do
|
210
|
+
subject.require_user = false
|
211
|
+
expect(subject.require_user).to be_falsey
|
212
|
+
subject.require_user = true
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe Capcoauth do
|
3
|
+
describe '#gem_version' do
|
4
|
+
subject { Capcoauth.gem_version }
|
5
|
+
|
6
|
+
it 'has a Gem::Version version' do
|
7
|
+
expect(subject).to be_a(Gem::Version)
|
8
|
+
end
|
9
|
+
it 'has semver format' do
|
10
|
+
parts = subject.to_s.split('.')
|
11
|
+
expect(parts.length).to eq(3)
|
12
|
+
parts.each do |part|
|
13
|
+
expect(part.to_i.to_s).to eq(part)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe Capcoauth::VERSION do
|
20
|
+
it 'has integer parts' do
|
21
|
+
expect(Capcoauth::VERSION::MAJOR).to be_an(Integer)
|
22
|
+
expect(Capcoauth::VERSION::MINOR).to be_an(Integer)
|
23
|
+
expect(Capcoauth::VERSION::PATCH).to be_an(Integer)
|
24
|
+
end
|
25
|
+
end
|
data/spec/spec_helper.rb
ADDED