Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

nuke consumers and have an api for managing auth

  • Loading branch information...
commit d8197524f4e0c603e95de088d9d59b7ce5d23420 1 parent befa1ee
Corey Donohoe authored
1  .gitignore
@@ -8,3 +8,4 @@ bin
8 8 vendor
9 9 *.gemspec
10 10 .bundle
  11 +*.rbc
15 Gemfile
... ... @@ -1,19 +1,8 @@
1 1 source :gemcutter
2 2
3   -do_version = '~>0.10.1'
4   -dm_version = '~>0.10.2'
5   -
6 3 group :runtime do
7   - gem 'dm-core', dm_version
8   - gem 'extlib', '~>0.9.14'
9 4 gem 'sinatra', '~>1.0'
10 5 gem 'haml', '~>3.0.0'
11   - gem 'do_sqlite3', do_version
12   - gem 'dm-validations', dm_version
13   - gem 'dm-timestamps', dm_version
14   - gem 'dm-aggregates', dm_version
15   - gem 'dm-migrations', dm_version
16   - gem 'dm-types', dm_version
17 6 gem 'ruby-openid', '~>2.1.7'
18 7 gem 'guid', '~>0.1.1'
19 8 gem 'rack-contrib', '~>0.9.2'
@@ -25,10 +14,8 @@ group :test do
25 14 gem 'webrat', '~>0.7.0'
26 15 gem 'rspec', '~>1.2.9', :require => 'spec'
27 16 gem 'rake'
28   - gem 'rcov'
  17 + gem 'addressable', :require => 'addressable/uri'
29 18 gem 'cucumber', '~>0.5.1'
30   - gem 'dm-sweatshop', dm_version
31 19 gem 'randexp'
32 20 gem 'ParseTree', :require => 'parse_tree'
33   - gem 'bundler', '~>0.9.24'
34 21 end
22 Rakefile
... ... @@ -1,9 +1,9 @@
1 1 require 'rubygems'
2   -require 'bundler'
  2 +require 'bundler/setup'
3 3
4 4 Bundler.setup(:runtime, :test)
  5 +
5 6 require File.expand_path(File.join('..', 'lib', 'hancock'), __FILE__)
6   -Bundler.require(:test)
7 7 require 'rake/gempackagetask'
8 8 require 'rubygems/specification'
9 9 require 'date'
@@ -28,10 +28,11 @@ spec = Gem::Specification.new do |s|
28 28 s.email = EMAIL
29 29 s.homepage = HOMEPAGE
30 30
31   - bundle = Bundler::Definition.from_gemfile("Gemfile")
32   - bundle.dependencies.
33   - select { |d| d.groups.include?(:runtime) }.
34   - each { |d| s.add_dependency(d.name, d.version_requirements.to_s) }
  31 + bundle = Bundler::Definition.build('Gemfile', 'Gemfile.lock', { })
  32 + bundle.dependencies.each do |dep|
  33 + next unless dep.groups.include?(:runtime)
  34 + s.add_dependency(dep.name, dep.version_requirements.to_s)
  35 + end
35 36
36 37 s.require_path = 'lib'
37 38 s.files = %w(LICENSE README.md Rakefile) + Dir.glob("{features,lib,spec}/**/*")
@@ -53,19 +54,10 @@ desc "Run specs"
53 54 Spec::Rake::SpecTask.new do |t|
54 55 t.spec_files = FileList['spec/**/*_spec.rb']
55 56 t.spec_opts = %w(-fp --color)
56   -
57   - t.rcov = true
58   - t.rcov_opts << '--text-summary'
59   - t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
60   - t.rcov_opts << '--exclude' << '.gem,.rvm,.bundle,spec,examples'
61 57 end
62 58
63 59 require 'cucumber/rake/task'
64 60 Cucumber::Rake::Task.new do |t|
65 61 t.libs << 'lib'
66 62 t.cucumber_opts = "--format pretty"
67   - t.rcov = true
68   - t.rcov_opts << '--text-summary'
69   - t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
70   - t.rcov_opts << '--exclude' << '.gem,.rvm,.bundle,spec,features,examples'
71 63 end
9 lib/hancock.rb
... ... @@ -1,11 +1,3 @@
1   -require 'extlib'
2   -require 'dm-core'
3   -require 'dm-types'
4   -require 'dm-aggregates'
5   -require 'dm-migrations'
6   -require 'dm-timestamps'
7   -require 'dm-validations'
8   -
9 1 require 'openid'
10 2 require 'openid/store/filesystem'
11 3 require 'openid/extensions/sreg'
@@ -21,4 +13,3 @@
21 13
22 14 require File.join(lib_dir, 'hancock', 'sso')
23 15 require File.join(lib_dir, 'hancock', 'models', 'user')
24   -require File.join(lib_dir, 'hancock', 'models', 'consumer')
26 lib/hancock/models/consumer.rb
... ... @@ -1,26 +0,0 @@
1   -module Hancock
2   - class Consumer
3   - include DataMapper::Resource
4   -
5   - property :id, Serial
6   - property :url, String, :required => true, :unique => true, :unique_index => true, :length => 2048
7   - property :label, String, :required => false
8   - property :internal, Boolean, :required => false, :default => false
9   -
10   - def self.allowed?(host)
11   - !first(:url => host).nil?
12   - end
13   -
14   - def self.visible
15   - all(:internal => false).select do |c|
16   - c.label
17   - end
18   - end
19   -
20   - def self.internal
21   - all(:internal => true).select do |c|
22   - c.label
23   - end
24   - end
25   - end
26   -end
74 lib/hancock/models/user.rb
... ... @@ -1,73 +1,23 @@
1 1 module Hancock
2   - class User
3   - include DataMapper::Resource
4   -
5   - property :id, Serial
6   - property :first_name, String
7   - property :last_name, String
8   - property :email, String, :unique => true, :unique_index => true
9   - property :internal, Boolean, :default => false
10   - property :admin, Boolean, :default => false
11   -
12   - property :salt, String
13   - property :crypted_password, String
14   -
15   - property :enabled, Boolean, :default => false
16   - property :verified, Boolean, :default => false
17   - property :access_token, String
18   -
19   - attr_accessor :password, :password_confirmation
  2 + class UserConfigurationError < StandardError; end
20 3
21   - def reset_access_token
22   - @access_token = Digest::SHA1.hexdigest(Guid.new.to_s)
23   - end
24   -
25   - def authenticated?(password)
26   - crypted_password == encrypt(password)
27   - end
28   -
29   - def encrypt(password)
30   - self.class.encrypt(password, salt)
31   - end
32   -
33   - def password_required?
34   - crypted_password.blank? || !password.blank?
35   - end
36   -
37   - def encrypt_password
38   - return if password.blank?
39   - @salt = Digest::SHA1.hexdigest("--#{Guid.new.to_s}}--email--") if new?
40   - @crypted_password = encrypt(password)
41   - end
42   -
43   - validates_present :password, :if => proc{|m| m.password_required?}
44   - validates_is_confirmed :password, :if => proc{|m| m.password_required?}
45   -
46   - before :save, :encrypt_password
47   - before :save, :reset_access_token
48   -
49   - def self.encrypt(password, salt)
50   - Digest::SHA1.hexdigest("--#{salt}--#{password}--")
  4 + class AuthenticationUser
  5 + def self.authenticated?(password)
  6 + raise UserConfigurationError, "You need to setup a Hancock::User authentication class"
51 7 end
  8 + end
52 9
53   - def self.signup(params)
54   - pass = Digest::SHA1.hexdigest(Guid.new.to_s)
55   - user = new(:email => params['email'],
56   - :first_name => params['first_name'],
57   - :last_name => params['last_name'],
58   - :password => pass,
59   - :password_confirmation => pass)
60   - user.save
61   - user
  10 + class User
  11 + def self.authentication_class=(klass)
  12 + @authentication_class = klass
62 13 end
63 14
64   - def self.authenticate(email, password)
65   - u = first(:email => email)
66   - u && u.authenticated?(password) && u.enabled ? u : nil
  15 + def self.authentication_class
  16 + @authentication_class ||= AuthenticationUser
67 17 end
68 18
69   - def full_name
70   - "#{first_name} #{last_name}"
  19 + def self.authenticated?(username, password)
  20 + authentication_class.authenticated?(username, password)
71 21 end
72 22 end
73 23 end
6 lib/hancock/sso/openid.rb
@@ -11,7 +11,7 @@ def server
11 11 end
12 12
13 13 def url_for_user
14   - absolute_url("/sso/users/#{session_user.id}")
  14 + absolute_url("/sso/users/#{session_user}")
15 15 end
16 16
17 17 def render_response(oidresp)
@@ -60,9 +60,7 @@ def self.registered(app)
60 60 oidreq.identity = oidreq.claimed_id = url_for_user
61 61 oidresp = oidreq.answer(true, nil, oidreq.identity)
62 62 sreg_data = {
63   - 'last_name' => session_user.last_name,
64   - 'first_name' => session_user.first_name,
65   - 'email' => session_user.email
  63 + 'email' => session[Hancock::SSO::SESSION_USER_KEY]
66 64 }
67 65 oidresp.add_extension(OpenID::SReg::Response.new(sreg_data))
68 66 else # associate
11 lib/hancock/sso/sessions.rb
@@ -3,7 +3,7 @@ module SSO
3 3 module Sessions
4 4 module Helpers
5 5 def session_user
6   - ::Hancock::User.get(session[Hancock::SSO::SESSION_USER_KEY])
  6 + session[Hancock::SSO::SESSION_USER_KEY]
7 7 end
8 8
9 9 def session_return_to
@@ -12,11 +12,6 @@ def session_return_to
12 12 end
13 13
14 14 def ensure_authenticated
15   - if trust_root = session_return_to
16   - unless ::Hancock::Consumer.allowed?(trust_root)
17   - raise Hancock::SSO::Forbidden
18   - end
19   - end
20 15 raise Hancock::SSO::Unauthenticated unless session_user
21 16 end
22 17 end
@@ -30,8 +25,8 @@ def self.registered(app)
30 25 end
31 26
32 27 app.post '/sso/login' do
33   - user = ::Hancock::User.authenticate(params['email'], params['password'])
34   - session[Hancock::SSO::SESSION_USER_KEY] = user && user.id
  28 + user = ::Hancock::User.authenticated?(params['username'], params['password'])
  29 + session[Hancock::SSO::SESSION_USER_KEY] = params['username']
35 30 ensure_authenticated
36 31 redirect session_return_to || raise(Hancock::SSO::RouteMeHome)
37 32 end
15 spec/helpers/app.rb
@@ -3,12 +3,7 @@ module TestApp
3 3 module Helpers
4 4 def landing_page
5 5 <<-HAML
6   -%h2 Hello #{session_user.first_name} #{session_user.last_name}!
7   -- unless @consumers.empty?
8   - %ul#consumers
9   - - @consumers.each do |consumer|
10   - %li
11   - %a{:href => consumer.url}= consumer.label
  6 +%h2 Hello #{session_user.inspect}!
12 7 HAML
13 8 end
14 9
@@ -29,15 +24,14 @@ def unauthenticated
29 24 or
30 25 %a{:href => '/sso/signup'} Signup
31 26 HAML
32   - end
  27 + end
  28 +
33 29 end
34 30
35 31 def self.registered(app)
36 32 app.helpers Helpers
37 33 app.get '/' do
38 34 ensure_authenticated
39   - @consumers = ::Hancock::Consumer.visible
40   - @consumers += ::Hancock::Consumer.internal if session_user.internal?
41 35 haml landing_page
42 36 end
43 37 end
@@ -50,6 +44,9 @@ def self.app
50 44 end
51 45
52 46 class SsoServer < ::Hancock::SSO::App
  47 + enable :raise_errors
  48 + disable :show_exceptions
  49 +
53 50 error Hancock::SSO::Unauthenticated do
54 51 haml(unauthenticated)
55 52 end
42 spec/helpers/fixtures.rb
... ... @@ -1,42 +0,0 @@
1   -Hancock::User.fix {{
2   - :enabled => true,
3   - :email => /\w+@\w+.\w{2,3}/.gen.downcase,
4   - :first_name => /\w+/.gen.capitalize,
5   - :last_name => /\w+/.gen.capitalize,
6   - :verified => true,
7   - :admin => false,
8   - :password => (pass = /\w+/.gen.downcase),
9   - :password_confirmation => pass,
10   - :salt => (salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--email--")),
11   - :crypted_password => Hancock::User.encrypt(pass, salt)
12   -}}
13   -
14   -Hancock::User.fix(:internal) {{
15   - :enabled => true,
16   - :email => /\w+@\w+.\w{2,3}/.gen.downcase,
17   - :first_name => /\w+/.gen.capitalize,
18   - :last_name => /\w+/.gen.capitalize,
19   - :verified => true,
20   - :password => (pass = /\w+/.gen.downcase),
21   - :password_confirmation => pass,
22   - :salt => (salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--email--")),
23   - :crypted_password => Hancock::User.encrypt(pass, salt),
24   - :internal => true
25   -}}
26   -
27   -Hancock::Consumer.fix(:internal) {{
28   - :url => %r!http://(\w+).example.org/login!.gen.downcase,
29   - :label => /(\w+) (\w+)/.gen,
30   - :internal => true
31   -}}
32   -
33   -Hancock::Consumer.fix(:visible_to_all) {{
34   - :url => %r!http://(\w+).consumerapp.com/login!.gen.downcase,
35   - :label => /(\w+) (\w+)/.gen,
36   - :internal => false
37   -}}
38   -
39   -Hancock::Consumer.fix(:hidden) {{
40   - :url => 'http://localhost:9292/login',
41   - :internal => true
42   -}}
44 spec/helpers/matchers.rb
@@ -3,6 +3,7 @@ module Matchers
3 3 class LoginForm
4 4 include ::Webrat::Methods
5 5 include ::Webrat::Matchers
  6 +
6 7 def matches?(target)
7 8 target.should have_selector("form[action='/sso/login'][method='POST']")
8 9 target.should have_selector("form[action='/sso/login'][method='POST'] input[type='text'][name='email']")
@@ -10,6 +11,7 @@ def matches?(target)
10 11 target.should have_selector("form[action='/sso/login'][method='POST'] input[type='submit'][value='Login']")
11 12 true
12 13 end
  14 +
13 15 def failure_message
14 16 puts "Expected a login form to be displayed, it wasn't"
15 17 end
@@ -44,9 +46,10 @@ class RedirectToConsumer
44 46 include Spec::Matchers
45 47 include Webrat::Methods
46 48 include Webrat::Matchers
47   - def initialize(consumer, user)
48   - @consumer, @user = consumer, user
49   - @identity_url = "http://example.org/sso/users/#{user.id}"
  49 +
  50 + def initialize(consumer_url, username)
  51 + @consumer_url, @username = consumer_url, username
  52 + @identity_url = "http://example.org/sso/users/#{username}"
50 53 end
51 54
52 55 def matches?(target)
@@ -56,34 +59,34 @@ def matches?(target)
56 59
57 60 redirect_params['openid.ns'].should == 'http://specs.openid.net/auth/2.0'
58 61 redirect_params['openid.mode'].should == 'id_res'
59   - redirect_params['openid.return_to'].should == @consumer.url
  62 + redirect_params['openid.return_to'].should == @consumer_url
60 63 redirect_params['openid.assoc_handle'].should =~ /^\{HMAC-SHA1\}\{[^\}]{8}\}\{[^\}]{8}\}$/
61   - redirect_params['openid.op_endpoint'].should == 'http://example.org/sso'
  64 + redirect_params['openid.op_endpoint'].should == 'http://example.org/sso'
62 65 redirect_params['openid.claimed_id'].should == @identity_url
63 66 redirect_params['openid.identity'].should == @identity_url
64 67
65   - redirect_params['openid.sreg.email'].should == @user.email
66   - redirect_params['openid.sreg.last_name'].should == @user.last_name
67   - redirect_params['openid.sreg.first_name'].should == @user.first_name
  68 + redirect_params['openid.sreg.email'].should == @username
68 69
69 70 redirect_params['openid.sig'].should_not be_nil
70 71 redirect_params['openid.signed'].should_not be_nil
71 72 redirect_params['openid.response_nonce'].should_not be_nil
72 73 true
73 74 end
  75 +
74 76 def failure_message
75 77 puts "Expected a redirect to the consumer"
76 78 end
77 79 end
78 80
79   - def be_a_redirect_to_the_consumer(consumer, user)
80   - RedirectToConsumer.new(consumer, user)
  81 + def be_a_redirect_to_the_consumer(consumer_url, username)
  82 + RedirectToConsumer.new(consumer_url, username)
81 83 end
82 84
83 85 class ReturnAnOpenIDAssociateResponse
84 86 include Spec::Matchers
85 87 include Webrat::Methods
86 88 include Webrat::Matchers
  89 +
87 90 def initialize(session)
88 91 @openid_session = session
89 92 end
@@ -107,6 +110,7 @@ def failure_message
107 110 puts "Expected an OpenID Associate Response"
108 111 end
109 112 end
  113 +
110 114 def be_an_openid_associate_response(openid_session)
111 115 ReturnAnOpenIDAssociateResponse.new(openid_session)
112 116 end
@@ -115,9 +119,10 @@ class ReturnAnOpenIDImmediateResponse
115 119 include Spec::Matchers
116 120 include Webrat::Methods
117 121 include Webrat::Matchers
118   - def initialize(consumer, user)
119   - @consumer, @user = consumer, user
120   - @identity_url = "http://example.org/sso/users/#{user.id}"
  122 +
  123 + def initialize(consumer_url, username)
  124 + @consumer_url, @username = consumer_url, username
  125 + @identity_url = "http://example.org/sso/users/#{username}"
121 126 end
122 127
123 128 def matches?(target)
@@ -127,15 +132,13 @@ def matches?(target)
127 132
128 133 redirect_params['openid.ns'].should == 'http://specs.openid.net/auth/2.0'
129 134 redirect_params['openid.mode'].should == 'id_res'
130   - redirect_params['openid.return_to'].should == @consumer.url
  135 + redirect_params['openid.return_to'].should == @consumer_url
131 136 redirect_params['openid.assoc_handle'].should =~ /^\{HMAC-SHA1\}\{[^\}]{8}\}\{[^\}]{8}\}$/
132   - redirect_params['openid.op_endpoint'].should == 'http://example.org/sso'
  137 + redirect_params['openid.op_endpoint'].should == 'http://example.org/sso'
133 138 redirect_params['openid.claimed_id'].should == @identity_url
134 139 redirect_params['openid.identity'].should == @identity_url
135 140
136   - redirect_params['openid.sreg.email'].should == @user.email
137   - redirect_params['openid.sreg.last_name'].should == @user.last_name
138   - redirect_params['openid.sreg.first_name'].should == @user.first_name
  141 + redirect_params['openid.sreg.email'].should == @username
139 142
140 143 redirect_params['openid.sig'].should_not be_nil
141 144 redirect_params['openid.signed'].should_not be_nil
@@ -146,8 +149,9 @@ def failure_message
146 149 puts "Expected an OpenID Associate Response"
147 150 end
148 151 end
149   - def be_an_openid_immediate_response(consumer, user)
150   - ReturnAnOpenIDImmediateResponse.new(consumer, user)
  152 +
  153 + def be_an_openid_immediate_response(consumer_url, username)
  154 + ReturnAnOpenIDImmediateResponse.new(consumer_url, username)
151 155 end
152 156 end
153 157 end
34 spec/requests/login_spec.rb
... ... @@ -1,45 +1,33 @@
1 1 require File.expand_path(File.dirname(__FILE__)+'/../spec_helper')
2 2
3 3 describe "posting to /sso/login" do
4   - before(:each) do
5   - @user = Hancock::User.gen
6   - @consumer = Hancock::Consumer.gen(:internal)
  4 + before(:all) do
  5 + Hancock::User.authentication_class = MyUserClass
7 6 end
  7 +
8 8 describe "with a valid password" do
9 9 it "should authenticate a user and redirect to /" do
10   - post '/sso/login', :email => @user.email, :password => @user.password
  10 + login('atmos', 'hancock')
  11 +
11 12 last_response.status.should eql(302)
12   - last_response.headers['Location'].should eql('/')
  13 + last_response.headers['Location'].should eql('http://example.org/')
13 14 end
14 15 end
15 16 describe "with an invalid password" do
16 17 it "should display a form to login" do
17   - post '/sso/login', :email => @user.email, :password => 's3cr3t'
  18 + login('atmos', 'xxxxxx')
  19 +
18 20 last_response.body.should be_a_login_form
19 21 end
20 22 end
21 23 end
22   -describe "getting /sso/login" do
23   - before(:each) do
24   - @user = Hancock::User.gen
25   - @consumer = Hancock::Consumer.gen(:internal)
26   - end
27 24
28   - describe "with a valid session" do
29   - describe "from an invalid consumer" do
30   - it "should return forbidden" do
31   - get '/sso/login'
32   - login(@user)
33   -
34   - get '/sso/login'
35   - last_response['Location'].should eql('/')
36   - end
37   - end
38   - end
  25 +describe "getting /sso/login" do
  26 + let(:consumer_url) { "http://foo.example.org" }
39 27
40 28 describe "without a valid session" do
41 29 it "should prompt the user to login" do
42   - get '/sso/login', { 'return_to' => @consumer.url }
  30 + get '/sso/login', { 'return_to' => consumer_url }
43 31 last_response.body.should be_a_login_form
44 32 end
45 33 end
14 spec/requests/logout_spec.rb
... ... @@ -1,22 +1,20 @@
1 1 require File.expand_path(File.dirname(__FILE__)+'/../spec_helper')
2 2
3 3 describe "visiting /sso/logout" do
4   - before(:each) do
5   - @user = Hancock::User.gen
6   - @consumer = Hancock::Consumer.gen(:internal)
7   - end
8 4 describe "when authenticated" do
9   - it "should clear the session and redirec to /" do
  5 + it "clears the session and redirects to /" do
  6 + login('atmos', 'hancock')
  7 +
10 8 get '/sso/logout'
11 9 last_response.status.should eql(302)
12   - last_response.headers['Location'].should eql('/')
  10 + last_response.headers['Location'].should eql('http://example.org/')
13 11 end
14 12 end
15 13 describe "when unauthenticated" do
16   - it "should redirect to /" do
  14 + it "redirects to /" do
17 15 get '/sso/logout'
18 16 last_response.status.should eql(302)
19   - last_response.headers['Location'].should eql('/')
  17 + last_response.headers['Location'].should eql('http://example.org/')
20 18 end
21 19 end
22 20 end
59 spec/requests/openid_spec.rb
... ... @@ -1,9 +1,14 @@
1 1 require File.expand_path(File.dirname(__FILE__)+'/../spec_helper')
2 2
3 3 describe "visiting /sso" do
4   - let(:user) { Hancock::User.gen }
5   - let(:consumer) { Hancock::Consumer.gen(:internal) }
6   - let(:identity_url) { "http://example.org/sso/users/#{user.id}" }
  4 + let(:user) { 'atmos' }
  5 + let(:password) { 'hancock' }
  6 + let(:consumer_url) { "http://foo.example.org" }
  7 + let(:identity_url) { "http://example.org/sso/users/#{user}" }
  8 +
  9 + before(:all) do
  10 + Hancock::User.authentication_class = MyUserClass
  11 + end
7 12
8 13 it "should throw a bad request if there aren't any openid params" do
9 14 get '/sso'
@@ -31,30 +36,14 @@
31 36 params = {
32 37 "openid.ns" => "http://specs.openid.net/auth/2.0",
33 38 "openid.mode" => "checkid_setup",
34   - "openid.return_to" => consumer.url,
  39 + "openid.return_to" => consumer_url,
35 40 "openid.identity" => identity_url,
36 41 "openid.claimed_id" => identity_url
37 42 }
38 43
39   - login(user)
  44 + login(user, password)
40 45 get "/sso", params
41   - last_response.should be_a_redirect_to_the_consumer(consumer, user)
42   - end
43   -
44   - describe "attempting to access from an untrusted consumer" do
45   - it "cancel the openid request" do
46   - params = {
47   - "openid.ns" => "http://specs.openid.net/auth/2.0",
48   - "openid.mode" => "checkid_setup",
49   - "openid.return_to" => "http://rogueconsumerapp.com/",
50   - "openid.identity" => identity_url,
51   - "openid.claimed_id" => identity_url
52   - }
53   -
54   - login(user)
55   - get "/sso", params
56   - last_response.status.should == 403
57   - end
  46 + last_response.should be_a_redirect_to_the_consumer(consumer_url, user)
58 47 end
59 48 end
60 49
@@ -63,7 +52,7 @@
63 52 params = {
64 53 "openid.ns" => "http://specs.openid.net/auth/2.0",
65 54 "openid.mode" => "checkid_setup",
66   - "openid.return_to" => consumer.url,
  55 + "openid.return_to" => consumer_url,
67 56 "openid.identity" => identity_url,
68 57 "openid.claimed_id" => identity_url
69 58 }
@@ -80,7 +69,7 @@
80 69 params = {
81 70 "openid.ns" => "http://specs.openid.net/auth/2.0",
82 71 "openid.mode" => "checkid_immediate",
83   - "openid.return_to" => consumer.url,
  72 + "openid.return_to" => consumer_url,
84 73 "openid.identity" => identity_url,
85 74 "openid.claimed_id" => identity_url
86 75 }
@@ -96,30 +85,14 @@
96 85 params = {
97 86 "openid.ns" => "http://specs.openid.net/auth/2.0",
98 87 "openid.mode" => "checkid_immediate",
99   - "openid.return_to" => consumer.url,
100   - "openid.identity" => identity_url,
101   - "openid.claimed_id" => identity_url
102   - }
103   -
104   - login(user)
105   - get "/sso", params
106   - last_response.should be_an_openid_immediate_response(consumer, user)
107   - end
108   - end
109   -
110   - describe "attempting to access from an untrusted consumer" do
111   - it "cancel the openid request" do
112   - params = {
113   - "openid.ns" => "http://specs.openid.net/auth/2.0",
114   - "openid.mode" => "checkid_immediate",
115   - "openid.return_to" => "http://rogueconsumerapp.com/",
  88 + "openid.return_to" => consumer_url,
116 89 "openid.identity" => identity_url,
117 90 "openid.claimed_id" => identity_url
118 91 }
119 92
120   - login(user)
  93 + login(user, password)
121 94 get "/sso", params
122   - last_response.status.should == 403
  95 + last_response.should be_an_openid_immediate_response(consumer_url, user)
123 96 end
124 97 end
125 98 end
20 spec/spec_helper.rb
@@ -8,11 +8,8 @@
8 8
9 9 Bundler.require(:test)
10 10
11   -%w(app matchers fixtures).each do |helper|
12   - require File.join(project_root, 'spec', 'helpers', helper)
13   -end
14   -
15   -DataMapper.setup(:default, 'sqlite3::memory:')
  11 +require File.join(project_root, 'spec', 'helpers', 'app')
  12 +require File.join(project_root, 'spec', 'helpers', 'matchers')
16 13
17 14 Webrat.configure do |config|
18 15 config.mode = :rack
@@ -20,20 +17,23 @@
20 17 config.application_port = 4567
21 18 end
22 19
  20 +class MyUserClass
  21 + def self.authenticated?(username, password)
  22 + username == 'atmos' && password == 'hancock'
  23 + end
  24 +end
  25 +
23 26 Spec::Runner.configure do |config|
24 27 def app
25 28 Hancock::TestApp.app
26 29 end
27 30
28   - def login(user)
29   - post '/sso/login', :email => user.email, :password => user.password
  31 + def login(username, password)
  32 + post '/sso/login', :username => username, :password => password
30 33 end
31 34
32 35 config.include(Rack::Test::Methods)
33 36 config.include(Webrat::Methods)
34 37 config.include(Webrat::Matchers)
35 38 config.include(Hancock::Matchers)
36   - config.before(:each) do
37   - DataMapper.auto_migrate!
38   - end
39 39 end
43 spec/units/consumer_spec.rb
... ... @@ -1,43 +0,0 @@
1   -require File.expand_path(File.dirname(__FILE__)+'/../spec_helper')
2   -
3   -describe Hancock::Consumer do
4   - describe "when queried about a disallowed host" do
5   - it "returns false" do
6   - Hancock::Consumer.allowed?('http://blogspot.com').should be_false
7   - end
8   - end
9   -
10   - describe "visible to staff" do
11   - before(:each) do
12   - @consumer = Hancock::Consumer.gen(:internal)
13   - @consumer.save
14   - end
15   - describe "when queried about an allowed host" do
16   - it "returns true" do
17   - Hancock::Consumer.allowed?(@consumer.url).should be_true
18   - end
19   - end
20   - end
21   - describe "visible to customers and staff" do
22   - before(:each) do
23   - @consumer = Hancock::Consumer.gen(:visible_to_all)
24   - @consumer.save
25   - end
26   - describe "when queried about an allowed host" do
27   - it "returns true" do
28   - Hancock::Consumer.allowed?(@consumer.url).should be_true
29   - end
30   - end
31   - end
32   - describe "hidden (API) apps" do
33   - before(:each) do
34   - @consumer = Hancock::Consumer.gen(:hidden)
35   - @consumer.save
36   - end
37   - describe "when queried about an allowed host" do
38   - it "returns true" do
39   - Hancock::Consumer.allowed?(@consumer.url).should be_true
40   - end
41   - end
42   - end
43   -end
41 spec/units/landing_page_spec.rb
... ... @@ -1,38 +1,25 @@
1 1 require File.expand_path(File.dirname(__FILE__)+'/../spec_helper')
2 2
  3 +class MyUserClass
  4 + def self.authenticated?(username, password)
  5 + username == 'atmos' && password == 'hancock'
  6 + end
  7 +end
  8 +
3 9 describe "visiting /" do
4   - before(:each) do
5   - @last = Hancock::Consumer.gen(:internal)
6   - @first = Hancock::Consumer.gen(:visible_to_all)
  10 + before(:all) do
  11 + Hancock::User.authentication_class = MyUserClass
7 12 end
8   - describe "when authenticated" do
9   - describe "as an internal user" do
10   - before(:each) do
11   - @user = Hancock::User.gen(:internal)
12   - end
13   - it "should greet the user" do
14   - login(@user)
15   - get '/'
16 13
17   - last_response.body.to_s.should have_selector("h2:contains('Hello #{@user.first_name} #{@user.last_name}')")
18   - last_response.body.to_s.should have_selector("ul#consumers li a[href='#{@first.url}']:contains('#{@first.label}')")
19   - last_response.body.to_s.should have_selector("ul#consumers li a[href='#{@last.url}']:contains('#{@last.label}')")
20   - end
21   - end
22   - describe "as an external user" do
23   - before(:each) do
24   - @user = Hancock::User.gen
25   - end
26   - it "should greet the user" do
27   - login(@user)
28   - get '/'
  14 + describe "when authenticated" do
  15 + it "should greet the user" do
  16 + login('atmos', 'hancock')
  17 + get '/'
29 18
30   - last_response.body.to_s.should have_selector("h2:contains('Hello #{@user.first_name} #{@user.last_name}')")
31   - last_response.body.to_s.should have_selector("ul#consumers li a[href='#{@first.url}']:contains('#{@first.label}')")
32   - last_response.body.to_s.should_not have_selector("ul#consumers li a[href='#{@last.url}']:contains('#{@last.label}')")
33   - end
  19 + last_response.should have_selector("h2:contains('Hello \"atmos\"')")
34 20 end
35 21 end
  22 +
36 23 describe "when unauthenticated" do
37 24 it "should prompt the user to login" do
38 25 get '/'
25 spec/units/user_spec.rb
... ... @@ -1,10 +1,27 @@
1 1 require File.expand_path(File.dirname(__FILE__)+'/../spec_helper')
2 2
3 3 describe Hancock::User do
4   - before(:each) do
5   - @user = Hancock::User.gen
  4 + describe "with an authentication class set" do
  5 + before(:all) do
  6 + Hancock::User.authentication_class = MyUserClass
  7 + end
  8 +
  9 + it "authenticates with good credentials" do
  10 + Hancock::User.authenticated?('atmos', 'hancock').should be_true
  11 + end
  12 +
  13 + it "does not authenticate bad credentials" do
  14 + Hancock::User.authenticated?('atmos', 'xxxxxxx').should be_false
  15 + end
6 16 end
7   - it "should save successfully" do
8   - @user.save.should be_true
  17 + describe "without an authentication class set" do
  18 + before(:each) do
  19 + Hancock::User.authentication_class = Hancock::AuthenticationUser
  20 + end
  21 + it "raises and error trying to authenticate" do
  22 + lambda {
  23 + Hancock::User.authenticated?('atmos', 'hancock')
  24 + }.should raise_error
  25 + end
9 26 end
10 27 end

0 comments on commit d819752

Please sign in to comment.
Something went wrong with that request. Please try again.