capcoauth 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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