aker-confident 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +11 -0
- data/.rbenv-version +1 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +159 -0
- data/LICENSE +19 -0
- data/README +33 -0
- data/Rakefile +2 -0
- data/aker-confident.gemspec +34 -0
- data/assets/templates/agreement.haml +24 -0
- data/init_testbed.rakefile +113 -0
- data/lib/aker-confident.rb +1 -0
- data/lib/aker/confident.rb +62 -0
- data/lib/aker/confident/aker_slice.rb +13 -0
- data/lib/aker/confident/aker_user_ext.rb +12 -0
- data/lib/aker/confident/configuration.rb +131 -0
- data/lib/aker/confident/rack.rb +24 -0
- data/lib/aker/confident/signer.rb +24 -0
- data/lib/aker/confident/sinatra.rb +15 -0
- data/lib/aker/confident/version.rb +5 -0
- data/spec/aker_user_spec.rb +38 -0
- data/spec/assets/test-users.yml +5 -0
- data/spec/assets/test_agreement.txt +1 -0
- data/spec/conf_rack_spec.rb +132 -0
- data/spec/conf_sinatra_spec.rb +24 -0
- data/spec/confident_spec.rb +28 -0
- data/spec/configuration_spec.rb +103 -0
- data/spec/integration/rails_integration_spec.rb +56 -0
- data/spec/signer_spec.rb +23 -0
- data/spec/spec_helper.rb +31 -0
- metadata +262 -0
@@ -0,0 +1,131 @@
|
|
1
|
+
module Aker
|
2
|
+
module Confident
|
3
|
+
class ConfigurationError < RuntimeError
|
4
|
+
end
|
5
|
+
|
6
|
+
class Configuration
|
7
|
+
attr_accessor :agreement, :root_url, :host_hook
|
8
|
+
attr_reader :pass_through_hooks
|
9
|
+
def initialize(options_hash={})
|
10
|
+
@pass_through_hooks = []
|
11
|
+
conf_model(options_hash[:conf_model])
|
12
|
+
conf_file(options_hash[:conf_file])
|
13
|
+
set_url options_hash[:root_url]
|
14
|
+
if options_hash[:conf_host_hook]
|
15
|
+
conf_host_hook options_hash[:conf_host_hook]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def define &block
|
20
|
+
instance_eval &block
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def conf_model(model_name)
|
25
|
+
if model_name == :default
|
26
|
+
@model = Confident::DefaultSignature
|
27
|
+
else
|
28
|
+
@model = model_name
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def set_url(url)
|
33
|
+
@root_url = url
|
34
|
+
end
|
35
|
+
|
36
|
+
def conf_file(file_name)
|
37
|
+
@agreement_file = file_name
|
38
|
+
end
|
39
|
+
|
40
|
+
def conf_host_hook(callable)
|
41
|
+
@pass_through_hooks << callable
|
42
|
+
end
|
43
|
+
|
44
|
+
def verify!
|
45
|
+
validate_agreement_file!
|
46
|
+
load_agreement_file
|
47
|
+
validate_hook!
|
48
|
+
validate_model!
|
49
|
+
end
|
50
|
+
|
51
|
+
def agreement
|
52
|
+
@agreement ||= load_agreement_file
|
53
|
+
end
|
54
|
+
|
55
|
+
def model
|
56
|
+
if @model.is_a? String
|
57
|
+
@model.constantize
|
58
|
+
else
|
59
|
+
@model
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def validate_agreement_file!
|
66
|
+
raise Aker::Confident::ConfigurationError unless @agreement_file.present?
|
67
|
+
end
|
68
|
+
|
69
|
+
def load_agreement_file
|
70
|
+
begin
|
71
|
+
@agreement = File.read(@agreement_file)
|
72
|
+
rescue Errno::ENOENT => e
|
73
|
+
raise Aker::Confident::ConfigurationError.new "The specified file does not exist"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def valid_option_keys?(options_hash)
|
78
|
+
options_hash.keys.include?(:conf_model) &&
|
79
|
+
options_hash.keys.include?(:conf_file)
|
80
|
+
end
|
81
|
+
private :valid_option_keys?
|
82
|
+
|
83
|
+
def valid_conf_model_value?(options_hash)
|
84
|
+
if options_hash[:conf_model].is_a? Symbol
|
85
|
+
options_hash[:conf_model] == :default
|
86
|
+
elsif options_hash[:conf_model].is_a? String
|
87
|
+
!options_hash[:conf_model].empty?
|
88
|
+
else
|
89
|
+
!options_hash[:conf_model].nil?
|
90
|
+
end
|
91
|
+
end
|
92
|
+
private :valid_conf_model_value?
|
93
|
+
|
94
|
+
def valid_conf_file_value?(options_hash)
|
95
|
+
if options_hash[:conf_file].is_a? String
|
96
|
+
!options_hash[:conf_file].empty?
|
97
|
+
else
|
98
|
+
!options_hash[:conf_file].nil?
|
99
|
+
end
|
100
|
+
end
|
101
|
+
private :valid_conf_file_value?
|
102
|
+
|
103
|
+
def validate_model!
|
104
|
+
unless model.respond_to?(:signed?)
|
105
|
+
raise Aker::Confident::ConfigurationError.new "Confidentiality must respond to signed? method."
|
106
|
+
end
|
107
|
+
unless model.respond_to?(:sign)
|
108
|
+
raise Aker::Confident::ConfigurationError.new "Confidentiality must respond to sign method."
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def validate_hook!
|
113
|
+
unless pass_through_hooks.empty?
|
114
|
+
unless pass_through_hooks.all?{ |hook| hook.respond_to?(:call)}
|
115
|
+
raise Aker::Confident::ConfigurationError.new "Host hook must respond to call"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def validate_options(options_hash)
|
121
|
+
unless valid_option_keys?(options_hash)
|
122
|
+
raise Aker::Confident::ConfigurationError.new "Valid Configurations require a conf_model and a conf_file!"
|
123
|
+
end
|
124
|
+
unless valid_conf_model_value?(options_hash) && valid_conf_file_value?(options_hash)
|
125
|
+
raise Aker::Confident::ConfigurationError.new "Valid Configuration conf_model and conf_file cannot be nil or blank"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
private :validate_options
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rack/request'
|
2
|
+
module Aker
|
3
|
+
module Confident
|
4
|
+
class Rack
|
5
|
+
def initialize(app)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
if Aker::Confident.pass_through?(env)
|
11
|
+
@app.call(env)
|
12
|
+
else
|
13
|
+
if env['REQUEST_METHOD'] == 'POST'
|
14
|
+
env['aker.check'].user.sign
|
15
|
+
req = ::Rack::Request.new(env)
|
16
|
+
[303, {"Location" => "#{req[:original]}"}, ""]
|
17
|
+
else
|
18
|
+
Aker::Confident::Sinatra.call(env)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Aker
|
2
|
+
module Confident
|
3
|
+
module Signer
|
4
|
+
|
5
|
+
def signed?(user)
|
6
|
+
validate_argument!(user)
|
7
|
+
configuration.model.signed?(user)
|
8
|
+
end
|
9
|
+
|
10
|
+
def sign(user)
|
11
|
+
validate_argument!(user)
|
12
|
+
configuration.model.sign(user)
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def validate_argument!(arg)
|
17
|
+
unless arg.is_a? Aker::User
|
18
|
+
raise ArgumentError.new("Requires an instance of Aker::User as argument")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
private :validate_argument!
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'haml'
|
3
|
+
module Aker
|
4
|
+
module Confident
|
5
|
+
class Sinatra < Sinatra::Base
|
6
|
+
set :views, File.dirname(__FILE__) + '/../../../assets/templates'
|
7
|
+
get // do
|
8
|
+
@original_target = request.url
|
9
|
+
@conf_agreement = Aker::Confident.configuration.agreement
|
10
|
+
@root_url = request.scheme + "://" + request.host_with_port + request.script_name
|
11
|
+
haml :agreement
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Aker
|
4
|
+
class User
|
5
|
+
#add this for convenience in testing
|
6
|
+
attr_accessor :signed
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe Aker::User do
|
11
|
+
before(:all) do
|
12
|
+
Aker::User.send(:include, Aker::Confident::AkerUserExt)
|
13
|
+
end
|
14
|
+
before(:each) do
|
15
|
+
@user = Aker::User.new(1)
|
16
|
+
end
|
17
|
+
describe "#signed?" do
|
18
|
+
it "is true if confident.signed? is true" do
|
19
|
+
Aker::Confident.stub(:signed?).and_return(true)
|
20
|
+
@user.signed?.should be_true
|
21
|
+
end
|
22
|
+
it "sets the users signed attribute" do
|
23
|
+
Aker::Confident.stub(:signed?).and_return(false)
|
24
|
+
@user.signed.should be_false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
describe "#sign" do
|
28
|
+
it "calls confidents sign method" do
|
29
|
+
Aker::Confident.should_receive(:sign).with(@user).and_return(true)
|
30
|
+
@user.sign
|
31
|
+
end
|
32
|
+
it "updates the users signed attribute" do
|
33
|
+
Aker::Confident.should_receive(:sign).with(@user).and_return(true)
|
34
|
+
@user.sign
|
35
|
+
@user.signed.should == true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
This is an agreement
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Aker::Confident::Rack do
|
4
|
+
include Rack::Test::Methods
|
5
|
+
|
6
|
+
class MockApp
|
7
|
+
def call(env)
|
8
|
+
[200, {}, 'Hello from Mock App!']
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def app
|
13
|
+
configure_conf
|
14
|
+
@app = Rack::Builder.new {
|
15
|
+
use Aker::Confident::Rack
|
16
|
+
run MockApp.new
|
17
|
+
}
|
18
|
+
@app.to_app
|
19
|
+
end
|
20
|
+
|
21
|
+
context "a non-interactive request" do
|
22
|
+
let(:env){ {"aker.interactive" => false} }
|
23
|
+
it "should ignore all non-interactive requests" do
|
24
|
+
get '/foo', {}, env
|
25
|
+
last_response.body.should include "Hello from Mock App!"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "there is a pass_through_hook defined" do
|
30
|
+
let(:env){ {"aker.check" => stub(:user => stub(:signed? => false)), "aker.interactive" => true} }
|
31
|
+
let(:mock_app){ mock(:call => [200, {}, 'ok']) }
|
32
|
+
it 'calls the host hook with the rack env' do
|
33
|
+
host_hook = stub
|
34
|
+
Aker::Confident.stub(:configuration).
|
35
|
+
and_return (stub(:pass_through_hooks => [host_hook]))
|
36
|
+
host_hook.should_receive(:call)
|
37
|
+
get '/foo', {}, env
|
38
|
+
end
|
39
|
+
context 'the hook is true' do
|
40
|
+
let(:host_hook){ lambda{ |env| true } }
|
41
|
+
before do
|
42
|
+
MockApp.stub(:new).
|
43
|
+
and_return mock_app
|
44
|
+
Aker::Confident.stub(:configuration).
|
45
|
+
and_return stub(:pass_through_hooks => [host_hook])
|
46
|
+
end
|
47
|
+
it 'skips confident' do
|
48
|
+
mock_app.should_receive(:call)
|
49
|
+
get '/foo', {}, env
|
50
|
+
end
|
51
|
+
end
|
52
|
+
context 'the hook is false' do
|
53
|
+
let(:host_hook){ lambda{ |env| false } }
|
54
|
+
before do
|
55
|
+
MockApp.stub(:new).
|
56
|
+
and_return mock_app
|
57
|
+
Aker::Confident.stub(:configuration).
|
58
|
+
and_return stub(:pass_through_hooks => [host_hook])
|
59
|
+
end
|
60
|
+
it 'calls sinatra' do
|
61
|
+
Aker::Confident::Sinatra.should_receive(:call).and_return [200, {}, 'ok']
|
62
|
+
get '/foo', {}, env
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "an interactive request" do
|
68
|
+
let(:mock_user){ stub(:signed? => false) }
|
69
|
+
let(:env){
|
70
|
+
{"aker.check" => stub(:user => mock_user),
|
71
|
+
"aker.interactive" => true}
|
72
|
+
}
|
73
|
+
context "post /sign_agreement" do
|
74
|
+
it "should call aker user sign method" do
|
75
|
+
mock_user.should_receive(:sign).and_return true
|
76
|
+
post '/sign_agreement', {:original => "/foo"}, env
|
77
|
+
end
|
78
|
+
it "should redirect to url in params" do
|
79
|
+
mock_user.stub(:sign).and_return true
|
80
|
+
post '/sign_agreement', {:original => "/foo"}, env
|
81
|
+
last_response.should be_redirect
|
82
|
+
last_response.headers['Location'].should == "/foo"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "post elsewhere" do
|
87
|
+
before do
|
88
|
+
@mock_app = mock(:call => [200, {}, 'ok'])
|
89
|
+
MockApp.stub(:new).
|
90
|
+
and_return @mock_app
|
91
|
+
end
|
92
|
+
it "should call the app" do
|
93
|
+
@mock_app.should_receive(:call)
|
94
|
+
post '/junk', {}, env
|
95
|
+
end
|
96
|
+
end
|
97
|
+
context "get logout" do
|
98
|
+
before do
|
99
|
+
@mock_app = mock(:call => [200, {}, 'ok'])
|
100
|
+
MockApp.stub(:new).
|
101
|
+
and_return @mock_app
|
102
|
+
end
|
103
|
+
it "calls the app" do
|
104
|
+
@mock_app.should_receive(:call)
|
105
|
+
get '/logout', {}, env
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
context "when agreement is not signed" do
|
111
|
+
before(:each) do
|
112
|
+
mock_user.stub(:signed?).and_return false
|
113
|
+
end
|
114
|
+
it "should call the confident sinatra" do
|
115
|
+
Aker::Confident::Sinatra.should_receive(:call).
|
116
|
+
and_return [200, {}, 'Foo']
|
117
|
+
get '/foo', {}, env
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context "when agreement is signed" do
|
122
|
+
before(:each) do
|
123
|
+
mock_user.stub(:signed?).and_return true
|
124
|
+
end
|
125
|
+
it "should call the app" do
|
126
|
+
get '/foo', {}, env
|
127
|
+
last_response.should be_ok
|
128
|
+
last_response.body.should include "Hello from Mock App!"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Aker::Confident::Sinatra do
|
4
|
+
include Rack::Test::Methods
|
5
|
+
def app
|
6
|
+
configure_conf
|
7
|
+
@app = Aker::Confident::Sinatra
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should respond to /sign_agreement" do
|
11
|
+
get '/sign_agreement'
|
12
|
+
last_response.should be_ok
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should render the agreement from the configuration" do
|
16
|
+
get '/sign_agreement'
|
17
|
+
last_response.body.should include "This is an agreement"
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "capybara tests" do
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Aker::Confident do
|
4
|
+
describe "#configure" do
|
5
|
+
let(:dummy_conf){ stub.as_null_object }
|
6
|
+
it "builds a new config object" do
|
7
|
+
Aker::Confident::Configuration.should_receive(:new).and_return dummy_conf
|
8
|
+
Aker::Confident.configure
|
9
|
+
end
|
10
|
+
it "uses a block to define the configuration" do
|
11
|
+
Signature = Class.new
|
12
|
+
def Signature.signed? ; end
|
13
|
+
def Signature.sign ; end
|
14
|
+
Aker::Confident.configure do
|
15
|
+
conf_file __FILE__
|
16
|
+
conf_model Signature
|
17
|
+
end
|
18
|
+
Aker::Confident.configuration.model.should == Signature
|
19
|
+
Aker::Confident.configuration.agreement.should == File.read(__FILE__)
|
20
|
+
end
|
21
|
+
it "verifys the configuration" do
|
22
|
+
Aker::Confident::Configuration.stub(:new).and_return dummy_conf
|
23
|
+
dummy_conf.stub(:define).and_return dummy_conf
|
24
|
+
dummy_conf.should_receive(:verify!)
|
25
|
+
Aker::Confident.configure do ; end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|