casino_core 0.0.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.
- data/.document +5 -0
- data/.rspec +1 -0
- data/.rvmrc +48 -0
- data/.travis.yml +3 -0
- data/Gemfile +24 -0
- data/Gemfile.lock +64 -0
- data/LICENSE.txt +20 -0
- data/README.md +19 -0
- data/Rakefile +44 -0
- data/VERSION +1 -0
- data/casino_core.gemspec +126 -0
- data/config/cas.yml +26 -0
- data/config/database.yml +18 -0
- data/db/migrate/20121112154930_create_ticket_granting_tickets.rb +11 -0
- data/db/migrate/20121112160009_create_login_tickets.rb +9 -0
- data/db/migrate/20121112165804_ticket_should_not_be_null.rb +5 -0
- data/db/migrate/20121122180310_add_user_agent_to_ticket_granting_tickets.rb +5 -0
- data/db/migrate/20121124170004_add_index_for_username_to_ticket_granting_tickets.rb +5 -0
- data/db/migrate/20121124183542_create_service_tickets.rb +13 -0
- data/db/migrate/20121124183732_add_ticket_indexes.rb +6 -0
- data/db/migrate/20121124195013_add_consumed_to_service_tickets.rb +5 -0
- data/db/migrate/20121125091934_add_issued_from_credentials_to_service_tickets.rb +5 -0
- data/db/migrate/20121125185415_create_proxy_granting_tickets.rb +14 -0
- data/db/migrate/20121125190013_tickets_should_be_unique.rb +8 -0
- data/db/schema.rb +61 -0
- data/lib/casino_core.rb +33 -0
- data/lib/casino_core/authenticator.rb +9 -0
- data/lib/casino_core/authenticator/static.rb +23 -0
- data/lib/casino_core/helper.rb +21 -0
- data/lib/casino_core/helper/browser.rb +16 -0
- data/lib/casino_core/helper/service_tickets.rb +30 -0
- data/lib/casino_core/model.rb +10 -0
- data/lib/casino_core/model/login_ticket.rb +11 -0
- data/lib/casino_core/model/proxy_granting_ticket.rb +8 -0
- data/lib/casino_core/model/service_ticket.rb +32 -0
- data/lib/casino_core/model/service_ticket/single_sign_out_notifier.rb +53 -0
- data/lib/casino_core/model/ticket_granting_ticket.rb +9 -0
- data/lib/casino_core/processor.rb +15 -0
- data/lib/casino_core/processor/legacy_validator.rb +49 -0
- data/lib/casino_core/processor/login_credential_acceptor.rb +67 -0
- data/lib/casino_core/processor/login_credential_requestor.rb +45 -0
- data/lib/casino_core/processor/logout.rb +23 -0
- data/lib/casino_core/processor/session_destroyer.rb +17 -0
- data/lib/casino_core/railtie.rb +10 -0
- data/lib/casino_core/rake_tasks.rb +14 -0
- data/lib/casino_core/settings.rb +26 -0
- data/lib/casino_core/tasks/cleanup.rake +26 -0
- data/lib/casino_core/tasks/database.rake +60 -0
- data/spec/authenticator/static_spec.rb +42 -0
- data/spec/model/login_ticket_spec.rb +16 -0
- data/spec/model/service_ticket_spec.rb +45 -0
- data/spec/processor/legacy_validator_spec.rb +87 -0
- data/spec/processor/login_credential_acceptor_spec.rb +70 -0
- data/spec/processor/login_credential_requestor_spec.rb +75 -0
- data/spec/processor/logout_spec.rb +55 -0
- data/spec/processor/session_destroyer_spec.rb +68 -0
- data/spec/spec_helper.rb +33 -0
- metadata +234 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'casino_core/processor'
|
2
|
+
require 'casino_core/helper'
|
3
|
+
|
4
|
+
class CASinoCore::Processor::LoginCredentialAcceptor < CASinoCore::Processor
|
5
|
+
include CASinoCore::Helper
|
6
|
+
include CASinoCore::Helper::ServiceTickets
|
7
|
+
|
8
|
+
def process(params = nil, cookies = nil, user_agent = nil)
|
9
|
+
params ||= {}
|
10
|
+
cookies ||= {}
|
11
|
+
if login_ticket_valid?(params[:lt])
|
12
|
+
user_data = validate_login_credentials(params[:username], params[:password])
|
13
|
+
if !user_data.nil?
|
14
|
+
ticket_granting_ticket = acquire_ticket_granting_ticket(user_data, user_agent)
|
15
|
+
url = unless params[:service].nil?
|
16
|
+
acquire_service_ticket(ticket_granting_ticket, params[:service], true).service_with_ticket_url
|
17
|
+
end
|
18
|
+
@listener.user_logged_in(url, ticket_granting_ticket.ticket)
|
19
|
+
else
|
20
|
+
@listener.invalid_login_credentials
|
21
|
+
end
|
22
|
+
else
|
23
|
+
@listener.invalid_login_ticket
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def login_ticket_valid?(lt)
|
29
|
+
ticket = CASinoCore::Model::LoginTicket.find_by_ticket lt
|
30
|
+
if ticket.nil?
|
31
|
+
logger.info "Login ticket '#{lt}' not found"
|
32
|
+
false
|
33
|
+
elsif ticket.created_at < CASinoCore::Settings.login_ticket[:lifetime].seconds.ago
|
34
|
+
logger.info "Login ticket '#{ticket.ticket}' expired"
|
35
|
+
false
|
36
|
+
else
|
37
|
+
logger.debug "Login ticket '#{ticket.ticket}' successfully validated"
|
38
|
+
ticket.delete
|
39
|
+
true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def validate_login_credentials(username, password)
|
44
|
+
user_data = nil
|
45
|
+
CASinoCore::Settings.authenticators.each do |authenticator|
|
46
|
+
data = authenticator.validate(username, password)
|
47
|
+
if data
|
48
|
+
if data[:username].nil?
|
49
|
+
data[:username] = username
|
50
|
+
end
|
51
|
+
user_data = data
|
52
|
+
logger.info("Credentials for username '#{data[:username]}' successfully validated using #{authenticator.class}")
|
53
|
+
break
|
54
|
+
end
|
55
|
+
end
|
56
|
+
user_data
|
57
|
+
end
|
58
|
+
|
59
|
+
def acquire_ticket_granting_ticket(user_data, user_agent = nil)
|
60
|
+
CASinoCore::Model::TicketGrantingTicket.create!({
|
61
|
+
ticket: random_ticket_string('TGC'),
|
62
|
+
username: user_data[:username],
|
63
|
+
extra_attributes: user_data[:extra_attributes],
|
64
|
+
user_agent: user_agent
|
65
|
+
})
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'casino_core/processor'
|
2
|
+
require 'casino_core/helper'
|
3
|
+
|
4
|
+
class CASinoCore::Processor::LoginCredentialRequestor < CASinoCore::Processor
|
5
|
+
include CASinoCore::Helper
|
6
|
+
include CASinoCore::Helper::ServiceTickets
|
7
|
+
include CASinoCore::Helper::Browser
|
8
|
+
|
9
|
+
def process(params = nil, cookies = nil, user_agent = nil)
|
10
|
+
params ||= {}
|
11
|
+
cookies ||= {}
|
12
|
+
request_env ||= {}
|
13
|
+
if !params[:renew] && (ticket_granting_ticket = find_valid_ticket_granting_ticket(cookies[:tgt], user_agent))
|
14
|
+
# TODO create new service ticket and url
|
15
|
+
service_url_with_ticket = unless params[:service].nil?
|
16
|
+
acquire_service_ticket(ticket_granting_ticket, params[:service], true).service_with_ticket_url
|
17
|
+
end
|
18
|
+
@listener.user_logged_in(service_url_with_ticket)
|
19
|
+
else
|
20
|
+
login_ticket = acquire_login_ticket
|
21
|
+
@listener.user_not_logged_in(login_ticket)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def acquire_login_ticket
|
27
|
+
ticket = CASinoCore::Model::LoginTicket.create ticket: random_ticket_string('LT')
|
28
|
+
logger.debug "Created login ticket '#{ticket.ticket}'"
|
29
|
+
ticket
|
30
|
+
end
|
31
|
+
|
32
|
+
def find_valid_ticket_granting_ticket(tgt, user_agent)
|
33
|
+
ticket_granting_ticket = CASinoCore::Model::TicketGrantingTicket.where(ticket: tgt).first
|
34
|
+
unless ticket_granting_ticket.nil?
|
35
|
+
if same_browser?(ticket_granting_ticket.user_agent, user_agent)
|
36
|
+
ticket_granting_ticket.user_agent = user_agent
|
37
|
+
ticket_granting_ticket.save!
|
38
|
+
ticket_granting_ticket
|
39
|
+
else
|
40
|
+
logger.info 'User-Agent changed: ticket-granting ticket not valid for this browser'
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'casino_core/processor'
|
2
|
+
require 'casino_core/helper'
|
3
|
+
require 'casino_core/model'
|
4
|
+
|
5
|
+
class CASinoCore::Processor::Logout < CASinoCore::Processor
|
6
|
+
include CASinoCore::Helper
|
7
|
+
|
8
|
+
def process(params = nil, cookies = nil)
|
9
|
+
params = params || {}
|
10
|
+
cookies ||= {}
|
11
|
+
session_destroyer = CASinoCore::Processor::SessionDestroyer.new(DummyListener.new)
|
12
|
+
session_destroyer.process(cookies[:tgt])
|
13
|
+
@listener.user_logged_out(params[:url])
|
14
|
+
end
|
15
|
+
|
16
|
+
class DummyListener
|
17
|
+
def ticket_deleted(*args)
|
18
|
+
end
|
19
|
+
|
20
|
+
def ticket_not_found(*args)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'casino_core/processor'
|
2
|
+
require 'casino_core/helper'
|
3
|
+
require 'casino_core/model'
|
4
|
+
|
5
|
+
class CASinoCore::Processor::SessionDestroyer < CASinoCore::Processor
|
6
|
+
include CASinoCore::Helper
|
7
|
+
|
8
|
+
def process(tgt)
|
9
|
+
ticket = CASinoCore::Model::TicketGrantingTicket.where(ticket: tgt).first
|
10
|
+
if ticket.nil?
|
11
|
+
@listener.ticket_not_found
|
12
|
+
else
|
13
|
+
ticket.destroy
|
14
|
+
@listener.ticket_deleted
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'casino_core/authenticator'
|
2
|
+
|
3
|
+
module CASinoCore
|
4
|
+
class Settings
|
5
|
+
class << self
|
6
|
+
attr_accessor :login_ticket, :service_ticket, :authenticators
|
7
|
+
def init(config = {})
|
8
|
+
config.each do |key,value|
|
9
|
+
if respond_to?("#{key}=")
|
10
|
+
send("#{key}=", value)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def authenticators=(authenticators)
|
16
|
+
@authenticators = []
|
17
|
+
authenticators.each do |authenticator|
|
18
|
+
unless authenticator.is_a?(CASinoCore::Authenticator)
|
19
|
+
authenticator = authenticator[:class].constantize.new(authenticator[:options])
|
20
|
+
end
|
21
|
+
@authenticators << authenticator
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'logger'
|
3
|
+
require 'active_record'
|
4
|
+
require 'casino_core/model'
|
5
|
+
|
6
|
+
namespace :casino_core do
|
7
|
+
namespace :cleanup do
|
8
|
+
desc 'Remove expired service tickets.'
|
9
|
+
task service_tickets: 'casino_core:db:configure_connection' do
|
10
|
+
[:consumed, :unconsumed].each do |type|
|
11
|
+
rows_affected = CASinoCore::Model::ServiceTicket.send("cleanup_#{type}")
|
12
|
+
puts "Deleted #{rows_affected} #{type} service tickets."
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Remove expired login tickets.'
|
17
|
+
task login_tickets: 'casino_core:db:configure_connection' do
|
18
|
+
rows_affected = CASinoCore::Model::LoginTicket.cleanup
|
19
|
+
puts "Deleted #{rows_affected} login tickets."
|
20
|
+
end
|
21
|
+
|
22
|
+
desc 'Perform all cleanup tasks.'
|
23
|
+
task all: [:service_tickets, :login_tickets] do
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'logger'
|
3
|
+
require 'active_record'
|
4
|
+
|
5
|
+
namespace :casino_core do
|
6
|
+
namespace :db do
|
7
|
+
task :environment do
|
8
|
+
BASE_DIR = if Gem.loaded_specs['casino_core'].nil?
|
9
|
+
Dir.pwd
|
10
|
+
else
|
11
|
+
Gem.loaded_specs['casino_core'].full_gem_path
|
12
|
+
end
|
13
|
+
DATABASE_ENV = ENV['DATABASE_ENV'] || ENV['RAILS_ENV'] || 'development'
|
14
|
+
MIGRATIONS_DIR = File.join(BASE_DIR, 'db', 'migrate')
|
15
|
+
SCHEMA_PATH = ENV['SCHEMA'] || File.join(BASE_DIR, 'db', 'schema.rb')
|
16
|
+
end
|
17
|
+
|
18
|
+
task :configuration => :environment do
|
19
|
+
@config = YAML.load_file('config/database.yml')[DATABASE_ENV]
|
20
|
+
end
|
21
|
+
|
22
|
+
task :configure_connection => :configuration do
|
23
|
+
ActiveRecord::Base.establish_connection @config
|
24
|
+
ActiveRecord::Base.logger = Logger.new STDOUT if @config['logger']
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'Migrate the database (options: VERSION=x, VERBOSE=false)'
|
28
|
+
task :migrate => :configure_connection do
|
29
|
+
ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
|
30
|
+
ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, ENV["VERSION"] ? ENV["VERSION"].to_i : nil) do |migration|
|
31
|
+
ENV["SCOPE"].blank? || (ENV["SCOPE"] == migration.scope)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
desc 'Rolls the schema back to the previous version (specify steps w/ STEP=n).'
|
36
|
+
task :rollback => [:environment, :load_config] do
|
37
|
+
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
|
38
|
+
ActiveRecord::Migrator.rollback(ActiveRecord::Migrator.migrations_paths, step)
|
39
|
+
end
|
40
|
+
|
41
|
+
namespace :schema do
|
42
|
+
desc 'Create a db/schema.rb file that can be portably used against any DB supported by AR'
|
43
|
+
task :dump => :configure_connection do
|
44
|
+
require 'active_record/schema_dumper'
|
45
|
+
File.open(SCHEMA_PATH, "w:utf-8") do |file|
|
46
|
+
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
desc 'Load a schema.rb file into the database'
|
51
|
+
task :load => :configure_connection do
|
52
|
+
if File.exists?(SCHEMA_PATH)
|
53
|
+
load(SCHEMA_PATH)
|
54
|
+
else
|
55
|
+
abort %{#{SCHEMA_PATH} doesn't exist yet.}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CASinoCore::Authenticator::Static do
|
4
|
+
subject {
|
5
|
+
CASinoCore::Authenticator::Static.new({
|
6
|
+
users: {
|
7
|
+
user: {
|
8
|
+
password: 'testing123',
|
9
|
+
fullname: 'Example User'
|
10
|
+
}
|
11
|
+
}
|
12
|
+
})
|
13
|
+
}
|
14
|
+
|
15
|
+
context '#validate' do
|
16
|
+
context 'with invalid credentials' do
|
17
|
+
it 'returns false for an unknown username' do
|
18
|
+
subject.validate('foobar', 'test').should == false
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'returns false for a known username with wrong password' do
|
22
|
+
subject.validate('user', 'test').should == false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'with valid credentials' do
|
27
|
+
let(:result) { subject.validate('user', 'testing123') }
|
28
|
+
|
29
|
+
it 'does not return false' do
|
30
|
+
result.should_not == false
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'returns the username' do
|
34
|
+
result[:username].should == 'user'
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'returns extra attributes' do
|
38
|
+
result[:extra_attributes][:fullname].should == 'Example User'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CASinoCore::Model::LoginTicket do
|
4
|
+
describe '.cleanup' do
|
5
|
+
it 'deletes expired login tickets' do
|
6
|
+
ticket = described_class.new ticket: 'LT-12345'
|
7
|
+
ticket.save!
|
8
|
+
ticket.created_at = 10.hours.ago
|
9
|
+
ticket.save!
|
10
|
+
lambda do
|
11
|
+
described_class.cleanup
|
12
|
+
end.should change(described_class, :count).by(-1)
|
13
|
+
described_class.find_by_ticket('LT-12345').should be_false
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CASinoCore::Model::ServiceTicket do
|
4
|
+
let(:ticket) {
|
5
|
+
ticket = described_class.new ticket: 'ST-12345', service: 'https://example.com/cas-service'
|
6
|
+
ticket.ticket_granting_ticket_id = 1
|
7
|
+
ticket
|
8
|
+
}
|
9
|
+
|
10
|
+
describe '.cleanup_unconsumed' do
|
11
|
+
it 'deletes expired unconsumed service tickets' do
|
12
|
+
ticket.created_at = 10.hours.ago
|
13
|
+
ticket.save!
|
14
|
+
lambda do
|
15
|
+
described_class.cleanup_unconsumed
|
16
|
+
end.should change(described_class, :count).by(-1)
|
17
|
+
described_class.find_by_ticket('ST-12345').should be_false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '.cleanup_consumed' do
|
22
|
+
before(:each) do
|
23
|
+
described_class::SingleSignOutNotifier.any_instance.stub(:notify).and_return(true)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'deletes expired consumed service tickets' do
|
27
|
+
ticket.consumed = true
|
28
|
+
ticket.created_at = 10.days.ago
|
29
|
+
ticket.save!
|
30
|
+
lambda do
|
31
|
+
described_class.cleanup_consumed
|
32
|
+
end.should change(described_class, :count).by(-1)
|
33
|
+
described_class.find_by_ticket('ST-12345').should be_false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '.destroy' do
|
38
|
+
it 'sends out a single sign out notification' do
|
39
|
+
described_class::SingleSignOutNotifier.any_instance.should_receive(:notify).and_return(true)
|
40
|
+
ticket.consumed = true
|
41
|
+
ticket.save!
|
42
|
+
ticket.destroy
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CASinoCore::Processor::LegacyValidator do
|
4
|
+
describe '#process' do
|
5
|
+
let(:listener) { Object.new }
|
6
|
+
let(:processor) { described_class.new(listener) }
|
7
|
+
let(:user_agent) { 'TestBrowser 1.0' }
|
8
|
+
let(:ticket_granting_ticket) {
|
9
|
+
CASinoCore::Model::TicketGrantingTicket.create!({
|
10
|
+
ticket: 'TGC-HXdkW233TsRtiqYGq4b8U7',
|
11
|
+
username: 'test',
|
12
|
+
extra_attributes: nil,
|
13
|
+
user_agent: user_agent
|
14
|
+
})
|
15
|
+
}
|
16
|
+
let(:service) { 'https://example.com/cas-service' }
|
17
|
+
let(:service_ticket) { ticket_granting_ticket.service_tickets.create! ticket: 'ST-2nOcXx56dtPTsB069yYf0h', service: service }
|
18
|
+
let(:parameters) { { service: service, ticket: service_ticket.ticket }}
|
19
|
+
|
20
|
+
before(:each) do
|
21
|
+
listener.stub(:validation_failed)
|
22
|
+
listener.stub(:validation_succeeded)
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with an unconsumed service ticket' do
|
26
|
+
context 'without renew flag' do
|
27
|
+
it 'consumes the service ticket' do
|
28
|
+
processor.process(parameters)
|
29
|
+
service_ticket.reload
|
30
|
+
service_ticket.consumed.should == true
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'calls the #validation_succeeded method on the listener' do
|
34
|
+
listener.should_receive(:validation_succeeded).with("yes\ntest\n")
|
35
|
+
processor.process(parameters)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'with renew flag' do
|
40
|
+
let(:parameters) { { service: service, ticket: service_ticket.ticket, renew: 'true' }}
|
41
|
+
|
42
|
+
context 'with a service ticket without issued_from_credentials flag' do
|
43
|
+
it 'consumes the service ticket' do
|
44
|
+
processor.process(parameters)
|
45
|
+
service_ticket.reload
|
46
|
+
service_ticket.consumed.should == true
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'calls the #validation_failed method on the listener' do
|
50
|
+
listener.should_receive(:validation_failed).with("no\n\n")
|
51
|
+
processor.process(parameters)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'with a service ticket with issued_from_credentials flag' do
|
56
|
+
before(:each) do
|
57
|
+
service_ticket.issued_from_credentials = true
|
58
|
+
service_ticket.save!
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'consumes the service ticket' do
|
62
|
+
processor.process(parameters)
|
63
|
+
service_ticket.reload
|
64
|
+
service_ticket.consumed.should == true
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'calls the #validation_succeeded method on the listener' do
|
68
|
+
listener.should_receive(:validation_succeeded).with("yes\ntest\n")
|
69
|
+
processor.process(parameters)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'with a consumed service ticket' do
|
76
|
+
before(:each) do
|
77
|
+
service_ticket.consumed = true
|
78
|
+
service_ticket.save!
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'calls the #validation_failed method on the listener' do
|
82
|
+
listener.should_receive(:validation_failed).with("no\n\n")
|
83
|
+
processor.process(parameters)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|