aker-confident 0.1.1

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.
@@ -0,0 +1,13 @@
1
+ module Aker
2
+ module Confident
3
+ class AkerSlice < Aker::Configuration::Slice
4
+ def initialize
5
+ super do
6
+ after_authentication_middleware do |builder|
7
+ builder.use Confident::Rack
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ module Aker
2
+ module Confident
3
+ module AkerUserExt
4
+ def sign
5
+ @signed = Confident.sign(self)
6
+ end
7
+ def signed?
8
+ @signed ||= Confident.signed?(self)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -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,5 @@
1
+ module Aker
2
+ module Confident
3
+ VERSION = "0.1.1"
4
+ end
5
+ 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,5 @@
1
+ users:
2
+ wakibbe:
3
+ password: password
4
+ portals:
5
+ - test
@@ -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