aker-confident 0.1.1

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