bmedia-casserver 1.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.
- data/CHANGELOG +325 -0
- data/Gemfile +3 -0
- data/LICENSE +26 -0
- data/README.md +19 -0
- data/Rakefile +2 -0
- data/bin/rubycas-server +30 -0
- data/config/config.example.yml +592 -0
- data/config/unicorn.rb +88 -0
- data/config.ru +17 -0
- data/db/migrate/001_create_initial_structure.rb +47 -0
- data/lib/casserver/authenticators/active_directory_ldap.rb +19 -0
- data/lib/casserver/authenticators/active_resource.rb +127 -0
- data/lib/casserver/authenticators/authlogic_crypto_providers/aes256.rb +43 -0
- data/lib/casserver/authenticators/authlogic_crypto_providers/bcrypt.rb +92 -0
- data/lib/casserver/authenticators/authlogic_crypto_providers/md5.rb +34 -0
- data/lib/casserver/authenticators/authlogic_crypto_providers/sha1.rb +59 -0
- data/lib/casserver/authenticators/authlogic_crypto_providers/sha512.rb +50 -0
- data/lib/casserver/authenticators/base.rb +67 -0
- data/lib/casserver/authenticators/client_certificate.rb +47 -0
- data/lib/casserver/authenticators/google.rb +58 -0
- data/lib/casserver/authenticators/ldap.rb +147 -0
- data/lib/casserver/authenticators/ntlm.rb +88 -0
- data/lib/casserver/authenticators/open_id.rb +22 -0
- data/lib/casserver/authenticators/sql.rb +133 -0
- data/lib/casserver/authenticators/sql_authlogic.rb +93 -0
- data/lib/casserver/authenticators/sql_encrypted.rb +75 -0
- data/lib/casserver/authenticators/sql_md5.rb +19 -0
- data/lib/casserver/authenticators/sql_rest_auth.rb +82 -0
- data/lib/casserver/authenticators/test.rb +22 -0
- data/lib/casserver/cas.rb +323 -0
- data/lib/casserver/localization.rb +13 -0
- data/lib/casserver/model.rb +270 -0
- data/lib/casserver/server.rb +758 -0
- data/lib/casserver/utils.rb +32 -0
- data/lib/casserver/views/_login_form.erb +42 -0
- data/lib/casserver/views/layout.erb +18 -0
- data/lib/casserver/views/login.erb +30 -0
- data/lib/casserver/views/proxy.builder +12 -0
- data/lib/casserver/views/proxy_validate.builder +25 -0
- data/lib/casserver/views/service_validate.builder +18 -0
- data/lib/casserver/views/validate.erb +2 -0
- data/lib/casserver.rb +11 -0
- data/locales/de.yml +27 -0
- data/locales/en.yml +26 -0
- data/locales/es.yml +26 -0
- data/locales/es_ar.yml +26 -0
- data/locales/fr.yml +26 -0
- data/locales/jp.yml +26 -0
- data/locales/pl.yml +26 -0
- data/locales/pt.yml +26 -0
- data/locales/ru.yml +26 -0
- data/locales/zh.yml +26 -0
- data/locales/zh_tw.yml +26 -0
- data/public/themes/cas.css +126 -0
- data/public/themes/notice.png +0 -0
- data/public/themes/ok.png +0 -0
- data/public/themes/simple/bg.png +0 -0
- data/public/themes/simple/favicon.png +0 -0
- data/public/themes/simple/login_box_bg.png +0 -0
- data/public/themes/simple/logo.png +0 -0
- data/public/themes/simple/theme.css +28 -0
- data/public/themes/urbacon/bg.png +0 -0
- data/public/themes/urbacon/login_box_bg.png +0 -0
- data/public/themes/urbacon/logo.png +0 -0
- data/public/themes/urbacon/theme.css +33 -0
- data/public/themes/warning.png +0 -0
- data/resources/init.d.sh +58 -0
- data/setup.rb +1585 -0
- data/spec/alt_config.yml +50 -0
- data/spec/authenticators/active_resource_spec.rb +109 -0
- data/spec/authenticators/ldap_spec.rb +53 -0
- data/spec/casserver_spec.rb +156 -0
- data/spec/default_config.yml +50 -0
- data/spec/model_spec.rb +42 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +89 -0
- data/spec/utils_spec.rb +53 -0
- data/tasks/bundler.rake +4 -0
- data/tasks/db/migrate.rake +12 -0
- data/tasks/spec.rake +10 -0
- metadata +308 -0
data/spec/alt_config.yml
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
server: webrick
|
2
|
+
port: 6543
|
3
|
+
#ssl_cert: test.pem
|
4
|
+
uri_path: /test
|
5
|
+
#bind_address: 0.0.0.0
|
6
|
+
|
7
|
+
# database:
|
8
|
+
# adapter: mysql
|
9
|
+
# database: casserver
|
10
|
+
# username: root
|
11
|
+
# password:
|
12
|
+
# host: localhost
|
13
|
+
# reconnect: true
|
14
|
+
database:
|
15
|
+
adapter: sqlite3
|
16
|
+
database: spec/casserver_spec.db
|
17
|
+
|
18
|
+
disable_auto_migrations: true
|
19
|
+
|
20
|
+
quiet: true
|
21
|
+
|
22
|
+
authenticator:
|
23
|
+
class: CASServer::Authenticators::Test
|
24
|
+
password: spec_password
|
25
|
+
|
26
|
+
theme: simple
|
27
|
+
|
28
|
+
organization: "RSPEC-TEST"
|
29
|
+
|
30
|
+
infoline: "This is an rspec test."
|
31
|
+
|
32
|
+
#custom_views: /path/to/custom/views
|
33
|
+
|
34
|
+
default_locale: en
|
35
|
+
|
36
|
+
log:
|
37
|
+
file: casserver_spec.log
|
38
|
+
level: DEBUG
|
39
|
+
|
40
|
+
#db_log:
|
41
|
+
# file: casserver_spec_db.log
|
42
|
+
|
43
|
+
enable_single_sign_out: true
|
44
|
+
|
45
|
+
#maximum_unused_login_ticket_lifetime: 300
|
46
|
+
#maximum_unused_service_ticket_lifetime: 300
|
47
|
+
|
48
|
+
#maximum_session_lifetime: 172800
|
49
|
+
|
50
|
+
#downcase_username: true
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
3
|
+
|
4
|
+
require 'casserver/authenticators/active_resource'
|
5
|
+
|
6
|
+
describe CASServer::Authenticators::Helpers::Identity do
|
7
|
+
|
8
|
+
it { should be_an ActiveResource::Base }
|
9
|
+
|
10
|
+
it "class should respond to :authenticate" do
|
11
|
+
subject.class.should respond_to :authenticate
|
12
|
+
end
|
13
|
+
|
14
|
+
it "class should have a method_name accessor" do
|
15
|
+
CASServer::Authenticators::Helpers::Identity.method_name.should == :authenticate
|
16
|
+
end
|
17
|
+
|
18
|
+
it "class should have a method_name accessor" do
|
19
|
+
CASServer::Authenticators::Helpers::Identity.method_type.should == :post
|
20
|
+
end
|
21
|
+
|
22
|
+
it "class method_type accessor should validate type" do
|
23
|
+
expect {
|
24
|
+
CASServer::Authenticators::Helpers::Identity.method_type = :foo
|
25
|
+
}.to raise_error(ArgumentError)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
describe CASServer::Authenticators::ActiveResource do
|
31
|
+
|
32
|
+
describe "#setup" do
|
33
|
+
|
34
|
+
it "should configure the identity object" do
|
35
|
+
CASServer::Authenticators::Helpers::Identity.should_receive(:user=).with('httpuser').once
|
36
|
+
CASServer::Authenticators::ActiveResource.setup :site => 'http://api.example.org', :user => 'httpuser'
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should configure the method_type" do
|
40
|
+
CASServer::Authenticators::Helpers::Identity.should_receive(:method_type=).with('get').once
|
41
|
+
CASServer::Authenticators::ActiveResource.setup :site => 'http://api.example.org', :method_type => 'get'
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should raise if site option is missing" do
|
45
|
+
expect {
|
46
|
+
CASServer::Authenticators::ActiveResource.setup({}).should
|
47
|
+
}.to raise_error(CASServer::AuthenticatorError, /site option/)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#validate" do
|
52
|
+
|
53
|
+
let(:credentials) { {:username => 'validusername',
|
54
|
+
:password => 'validpassword',
|
55
|
+
:service => 'test.service'} }
|
56
|
+
|
57
|
+
let(:auth) { CASServer::Authenticators::ActiveResource.new }
|
58
|
+
|
59
|
+
def mock_authenticate identity = nil
|
60
|
+
identity = CASServer::Authenticators::Helpers::Identity.new if identity.nil?
|
61
|
+
CASServer::Authenticators::Helpers::Identity.stub!(:authenticate).and_return(identity)
|
62
|
+
end
|
63
|
+
|
64
|
+
def sample_identity attrs = {}
|
65
|
+
identity = CASServer::Authenticators::Helpers::Identity.new
|
66
|
+
attrs.each { |k,v| identity.send "#{k}=", v }
|
67
|
+
identity
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should call Identity#autenticate with the given params" do
|
71
|
+
CASServer::Authenticators::Helpers::Identity.should_receive(:authenticate).with(credentials).once
|
72
|
+
auth.validate(credentials)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should return identity object attributes as extra attributes" do
|
76
|
+
auth.configure({}.with_indifferent_access)
|
77
|
+
identity = sample_identity({:email => 'foo@example.org'})
|
78
|
+
mock_authenticate identity
|
79
|
+
auth.validate(credentials).should be_true
|
80
|
+
auth.extra_attributes.should == identity.attributes
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should return false when http raises" do
|
84
|
+
CASServer::Authenticators::Helpers::Identity.stub!(:authenticate).and_raise(ActiveResource::ForbiddenAccess.new({}))
|
85
|
+
auth.validate(credentials).should be_false
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should apply extra_attribute filter" do
|
89
|
+
auth.configure({ :extra_attributes => 'age'}.with_indifferent_access)
|
90
|
+
mock_authenticate sample_identity({ :email => 'foo@example.org', :age => 28 })
|
91
|
+
auth.validate(credentials).should be_true
|
92
|
+
auth.extra_attributes.should == { "age" => "28" }
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should only extract not filtered attributes" do
|
96
|
+
auth.configure({ :filter_attributes => 'age'}.with_indifferent_access)
|
97
|
+
mock_authenticate sample_identity({ :email => 'foo@example.org', :age => 28 })
|
98
|
+
auth.validate(credentials).should be_true
|
99
|
+
auth.extra_attributes.should == { "email" => 'foo@example.org' }
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should filter password if filter attributes is not given" do
|
103
|
+
auth.configure({}.with_indifferent_access)
|
104
|
+
mock_authenticate sample_identity({ :email => 'foo@example.org', :password => 'secret' })
|
105
|
+
auth.validate(credentials).should be_true
|
106
|
+
auth.extra_attributes.should == { "email" => 'foo@example.org' }
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
3
|
+
|
4
|
+
require 'casserver/authenticators/ldap'
|
5
|
+
|
6
|
+
describe CASServer::Authenticators::LDAP do
|
7
|
+
before do
|
8
|
+
@ldap_entry = mock(Net::LDAP::Entry.new)
|
9
|
+
@ldap_entry.stub!(:[]).and_return("Test")
|
10
|
+
|
11
|
+
@ldap = mock(Net::LDAP)
|
12
|
+
@ldap.stub!(:host=)
|
13
|
+
@ldap.stub!(:port=)
|
14
|
+
@ldap.stub!(:encryption)
|
15
|
+
@ldap.stub!(:bind_as).and_return(true)
|
16
|
+
@ldap.stub!(:authenticate).and_return(true)
|
17
|
+
@ldap.stub!(:search).and_return([@ldap_entry])
|
18
|
+
|
19
|
+
Net::LDAP.stub!(:new).and_return(@ldap)
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#validate' do
|
23
|
+
|
24
|
+
it 'validate with preauthentication and with extra attributes' do
|
25
|
+
auth = CASServer::Authenticators::LDAP.new
|
26
|
+
|
27
|
+
auth_config = HashWithIndifferentAccess.new(
|
28
|
+
:ldap => {
|
29
|
+
:host => "ad.example.net",
|
30
|
+
:port => 389,
|
31
|
+
:base => "dc=example,dc=net",
|
32
|
+
:filter => "(objectClass=person)",
|
33
|
+
:auth_user => "authenticator",
|
34
|
+
:auth_password => "itsasecret"
|
35
|
+
},
|
36
|
+
:extra_attributes => [:full_name, :address]
|
37
|
+
)
|
38
|
+
|
39
|
+
auth.configure(auth_config.merge('auth_index' => 0))
|
40
|
+
auth.validate(
|
41
|
+
:username => 'validusername',
|
42
|
+
:password => 'validpassword',
|
43
|
+
:service => 'test.service',
|
44
|
+
:request => {}
|
45
|
+
).should == true
|
46
|
+
|
47
|
+
auth.extra_attributes.should == {:full_name => 'Test', :address => 'Test'}
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
3
|
+
|
4
|
+
$LOG = Logger.new(File.basename(__FILE__).gsub('.rb','.log'))
|
5
|
+
|
6
|
+
RSpec.configure do |config|
|
7
|
+
config.include Capybara::DSL
|
8
|
+
end
|
9
|
+
|
10
|
+
VALID_USERNAME = 'spec_user'
|
11
|
+
VALID_PASSWORD = 'spec_password'
|
12
|
+
|
13
|
+
ATTACK_USERNAME = '%3E%22%27%3E%3Cscript%3Ealert%2826%29%3C%2Fscript%3E&password=%3E%22%27%3E%3Cscript%3Ealert%2826%29%3C%2Fscript%3E<=%3E%22%27%3E%3Cscript%3Ealert%2826%29%3C%2Fscript%3E&service=%3E%22%27%3E%3Cscript%3Ealert%2826%29%3C%2Fscript%3E'
|
14
|
+
INVALID_PASSWORD = 'invalid_password'
|
15
|
+
|
16
|
+
describe 'CASServer' do
|
17
|
+
|
18
|
+
before do
|
19
|
+
@target_service = 'http://my.app.test'
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "/login" do
|
23
|
+
before do
|
24
|
+
load_server(File.dirname(__FILE__) + "/default_config.yml")
|
25
|
+
reset_spec_database
|
26
|
+
end
|
27
|
+
|
28
|
+
it "logs in successfully with valid username and password without a target service" do
|
29
|
+
visit "/login"
|
30
|
+
|
31
|
+
fill_in 'username', :with => VALID_USERNAME
|
32
|
+
fill_in 'password', :with => VALID_PASSWORD
|
33
|
+
click_button 'login-submit'
|
34
|
+
|
35
|
+
page.should have_content("You have successfully logged in")
|
36
|
+
end
|
37
|
+
|
38
|
+
it "fails to log in with invalid password" do
|
39
|
+
visit "/login"
|
40
|
+
fill_in 'username', :with => VALID_USERNAME
|
41
|
+
fill_in 'password', :with => INVALID_PASSWORD
|
42
|
+
click_button 'login-submit'
|
43
|
+
|
44
|
+
page.should have_content("Incorrect username or password")
|
45
|
+
end
|
46
|
+
|
47
|
+
it "logs in successfully with valid username and password and redirects to target service" do
|
48
|
+
visit "/login?service="+CGI.escape(@target_service)
|
49
|
+
|
50
|
+
fill_in 'username', :with => VALID_USERNAME
|
51
|
+
fill_in 'password', :with => VALID_PASSWORD
|
52
|
+
|
53
|
+
click_button 'login-submit'
|
54
|
+
|
55
|
+
page.current_url.should =~ /^#{Regexp.escape(@target_service)}\/?\?ticket=ST\-[1-9rA-Z]+/
|
56
|
+
end
|
57
|
+
|
58
|
+
it "preserves target service after invalid login" do
|
59
|
+
visit "/login?service="+CGI.escape(@target_service)
|
60
|
+
|
61
|
+
fill_in 'username', :with => VALID_USERNAME
|
62
|
+
fill_in 'password', :with => INVALID_PASSWORD
|
63
|
+
click_button 'login-submit'
|
64
|
+
|
65
|
+
page.should have_content("Incorrect username or password")
|
66
|
+
page.should have_xpath('//input[@id="service"]', :value => @target_service)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "uses appropriate localization based on Accept-Language header" do
|
70
|
+
|
71
|
+
page.driver.options[:headers] = {'HTTP_ACCEPT_LANGUAGE' => 'pl'}
|
72
|
+
#visit "/login?lang=pl"
|
73
|
+
visit "/login"
|
74
|
+
page.should have_content("Użytkownik")
|
75
|
+
|
76
|
+
page.driver.options[:headers] = {'HTTP_ACCEPT_LANGUAGE' => 'pt_BR'}
|
77
|
+
#visit "/login?lang=pt_BR"
|
78
|
+
visit "/login"
|
79
|
+
page.should have_content("Usuário")
|
80
|
+
|
81
|
+
page.driver.options[:headers] = {'HTTP_ACCEPT_LANGUAGE' => 'en'}
|
82
|
+
#visit "/login?lang=en"
|
83
|
+
visit "/login"
|
84
|
+
page.should have_content("Username")
|
85
|
+
end
|
86
|
+
|
87
|
+
it "is not vunerable to Cross Site Scripting" do
|
88
|
+
visit '/login?service=%22%2F%3E%3cscript%3ealert%2832%29%3c%2fscript%3e'
|
89
|
+
page.should_not have_content("alert(32)")
|
90
|
+
page.should_not have_xpath("//script")
|
91
|
+
#page.should have_xpath("<script>alert(32)</script>")
|
92
|
+
end
|
93
|
+
|
94
|
+
end # describe '/login'
|
95
|
+
|
96
|
+
|
97
|
+
describe '/logout' do
|
98
|
+
|
99
|
+
before do
|
100
|
+
load_server(File.dirname(__FILE__) + "/default_config.yml")
|
101
|
+
reset_spec_database
|
102
|
+
end
|
103
|
+
|
104
|
+
it "logs out successfully" do
|
105
|
+
visit "/logout"
|
106
|
+
|
107
|
+
page.should have_content("You have successfully logged out")
|
108
|
+
end
|
109
|
+
|
110
|
+
it "logs out successfully and redirects to target service" do
|
111
|
+
visit "/logout?gateway=true&service="+CGI.escape(@target_service)
|
112
|
+
|
113
|
+
page.current_url.should =~ /^#{Regexp.escape(@target_service)}\/?/
|
114
|
+
end
|
115
|
+
|
116
|
+
end # describe '/logout'
|
117
|
+
|
118
|
+
describe 'Configuration' do
|
119
|
+
it "uri_path value changes prefix of routes" do
|
120
|
+
load_server(File.dirname(__FILE__) + "/alt_config.yml")
|
121
|
+
@target_service = 'http://my.app.test'
|
122
|
+
|
123
|
+
visit "/test/login"
|
124
|
+
page.status_code.should_not == 404
|
125
|
+
|
126
|
+
visit "/test/logout"
|
127
|
+
page.status_code.should_not == 404
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "proxyValidate" do
|
132
|
+
before do
|
133
|
+
load_server(File.dirname(__FILE__) + "/default_config.yml")
|
134
|
+
reset_spec_database
|
135
|
+
|
136
|
+
visit "/login?service="+CGI.escape(@target_service)
|
137
|
+
|
138
|
+
fill_in 'username', :with => VALID_USERNAME
|
139
|
+
fill_in 'password', :with => VALID_PASSWORD
|
140
|
+
|
141
|
+
click_button 'login-submit'
|
142
|
+
|
143
|
+
page.current_url.should =~ /^#{Regexp.escape(@target_service)}\/?\?ticket=ST\-[1-9rA-Z]+/
|
144
|
+
@ticket = page.current_url.match(/ticket=(.*)$/)[1]
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should have extra attributes in proper format" do
|
148
|
+
visit "/serviceValidate?service=#{CGI.escape(@target_service)}&ticket=#{@ticket}"
|
149
|
+
|
150
|
+
encoded_utf_string = "Ютф" # actual string is "Ютф"
|
151
|
+
page.body.should match("<test_utf_string>#{encoded_utf_string}</test_utf_string>")
|
152
|
+
page.body.should match("<test_numeric>123.45</test_numeric>")
|
153
|
+
page.body.should match("<test_utf_string>Ютф</test_utf_string>")
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
server: webrick
|
2
|
+
port: 6543
|
3
|
+
#ssl_cert: test.pem
|
4
|
+
#uri_path: /cas
|
5
|
+
#bind_address: 0.0.0.0
|
6
|
+
|
7
|
+
# database:
|
8
|
+
# adapter: mysql
|
9
|
+
# database: casserver
|
10
|
+
# username: root
|
11
|
+
# password:
|
12
|
+
# host: localhost
|
13
|
+
# reconnect: true
|
14
|
+
database:
|
15
|
+
adapter: sqlite3
|
16
|
+
database: spec/casserver_spec.db
|
17
|
+
|
18
|
+
disable_auto_migrations: true
|
19
|
+
|
20
|
+
quiet: true
|
21
|
+
|
22
|
+
authenticator:
|
23
|
+
class: CASServer::Authenticators::Test
|
24
|
+
password: spec_password
|
25
|
+
|
26
|
+
theme: simple
|
27
|
+
|
28
|
+
organization: "RSPEC-TEST"
|
29
|
+
|
30
|
+
infoline: "This is an rspec test."
|
31
|
+
|
32
|
+
#custom_views: /path/to/custom/views
|
33
|
+
|
34
|
+
default_locale: en
|
35
|
+
|
36
|
+
log:
|
37
|
+
file: casserver_spec.log
|
38
|
+
level: DEBUG
|
39
|
+
|
40
|
+
#db_log:
|
41
|
+
# file: casserver_spec_db.log
|
42
|
+
|
43
|
+
enable_single_sign_out: true
|
44
|
+
|
45
|
+
#maximum_unused_login_ticket_lifetime: 300
|
46
|
+
#maximum_unused_service_ticket_lifetime: 300
|
47
|
+
|
48
|
+
#maximum_session_lifetime: 172800
|
49
|
+
|
50
|
+
#downcase_username: true
|
data/spec/model_spec.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
3
|
+
|
4
|
+
module CASServer
|
5
|
+
end
|
6
|
+
require 'casserver/model'
|
7
|
+
|
8
|
+
describe CASServer::Model::LoginTicket, '.cleanup(max_lifetime, max_unconsumed_lifetime)' do
|
9
|
+
let(:max_lifetime) { -1 }
|
10
|
+
let(:max_unconsumed_lifetime) { -2 }
|
11
|
+
|
12
|
+
before do
|
13
|
+
load_server(File.dirname(__FILE__) + "/default_config.yml")
|
14
|
+
reset_spec_database
|
15
|
+
|
16
|
+
CASServer::Model::LoginTicket.create :ticket => 'test', :client_hostname => 'test.local'
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should destroy all tickets created before the max lifetime' do
|
20
|
+
expect {
|
21
|
+
CASServer::Model::LoginTicket.cleanup(max_lifetime, max_unconsumed_lifetime)
|
22
|
+
}.to change(CASServer::Model::LoginTicket, :count).by(-1)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should destroy all unconsumed tickets not exceeding the max lifetime' do
|
26
|
+
expect {
|
27
|
+
CASServer::Model::LoginTicket.cleanup(max_lifetime, max_unconsumed_lifetime)
|
28
|
+
}.to change(CASServer::Model::LoginTicket, :count).by(-1)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe CASServer::Model::LoginTicket, '#to_s' do
|
33
|
+
let(:ticket) { 'test' }
|
34
|
+
|
35
|
+
before do
|
36
|
+
@login_ticket = CASServer::Model::LoginTicket.new :ticket => ticket
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should delegate #to_s to #ticket' do
|
40
|
+
@login_ticket.to_s.should == ticket
|
41
|
+
end
|
42
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sinatra'
|
3
|
+
require 'rack/test'
|
4
|
+
require 'rspec'
|
5
|
+
#require 'spec/autorun'
|
6
|
+
#require 'spec/interop/test'
|
7
|
+
require 'logger'
|
8
|
+
require 'ostruct'
|
9
|
+
|
10
|
+
require 'capybara'
|
11
|
+
require 'capybara/dsl'
|
12
|
+
|
13
|
+
# set test environment
|
14
|
+
set :environment, :test
|
15
|
+
set :run, false
|
16
|
+
set :raise_errors, true
|
17
|
+
set :logging, false
|
18
|
+
|
19
|
+
|
20
|
+
if Dir.getwd =~ /\/spec$/
|
21
|
+
# Avoid potential weirdness by changing the working directory to the CASServer root
|
22
|
+
FileUtils.cd('..')
|
23
|
+
end
|
24
|
+
|
25
|
+
def silence_warnings
|
26
|
+
old_verbose, $VERBOSE = $VERBOSE, nil
|
27
|
+
yield
|
28
|
+
ensure
|
29
|
+
$VERBOSE = old_verbose
|
30
|
+
end
|
31
|
+
|
32
|
+
# Ugly monkeypatch to allow us to test for correct redirection to
|
33
|
+
# external services.
|
34
|
+
#
|
35
|
+
# This will likely break in the future when Capybara or RackTest are upgraded.
|
36
|
+
class Capybara::RackTest::Browser
|
37
|
+
def current_url
|
38
|
+
if @redirected_to_external_url
|
39
|
+
@redirected_to_external_url
|
40
|
+
else
|
41
|
+
request.url rescue ""
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def follow_redirects!
|
46
|
+
if last_response.redirect? && last_response['Location'] =~ /^http[s]?:/
|
47
|
+
puts "FOLLOWING REDIECT: #{last_response['Location']}"
|
48
|
+
@redirected_to_external_url = last_response['Location']
|
49
|
+
else
|
50
|
+
5.times do
|
51
|
+
follow_redirect! if last_response.redirect?
|
52
|
+
end
|
53
|
+
raise Capybara::InfiniteRedirectError, "redirected more than 5 times, check for infinite redirects." if last_response.redirect?
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# This called in specs' `before` block.
|
59
|
+
# Due to the way Sinatra applications are loaded,
|
60
|
+
# we're forced to delay loading of the server code
|
61
|
+
# until the start of each test so that certain
|
62
|
+
# configuraiton options can be changed (e.g. `uri_path`)
|
63
|
+
def load_server(config_file)
|
64
|
+
ENV['CONFIG_FILE'] = config_file
|
65
|
+
|
66
|
+
silence_warnings do
|
67
|
+
load File.dirname(__FILE__) + '/../lib/casserver/server.rb'
|
68
|
+
end
|
69
|
+
|
70
|
+
CASServer::Server.enable(:raise_errors)
|
71
|
+
CASServer::Server.disable(:show_exceptions)
|
72
|
+
|
73
|
+
#Capybara.current_driver = :selenium
|
74
|
+
Capybara.app = CASServer::Server
|
75
|
+
end
|
76
|
+
|
77
|
+
# Deletes the sqlite3 database specified in the app's config
|
78
|
+
# and runs the db:migrate rake tasks to rebuild the database schema.
|
79
|
+
def reset_spec_database
|
80
|
+
raise "Cannot reset the spec database because config[:database][:database] is not defined." unless
|
81
|
+
CASServer::Server.config[:database] && CASServer::Server.config[:database][:database]
|
82
|
+
|
83
|
+
FileUtils.rm_f(CASServer::Server.config[:database][:database])
|
84
|
+
|
85
|
+
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
86
|
+
ActiveRecord::Base.logger.level = Logger::ERROR
|
87
|
+
ActiveRecord::Migration.verbose = false
|
88
|
+
ActiveRecord::Migrator.migrate("db/migrate")
|
89
|
+
end
|
data/spec/utils_spec.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
3
|
+
|
4
|
+
module CASServer
|
5
|
+
end
|
6
|
+
require 'casserver/utils'
|
7
|
+
|
8
|
+
describe CASServer::Utils, '#random_string(max_length = 29)' do
|
9
|
+
before do
|
10
|
+
load_server(File.dirname(__FILE__) + "/default_config.yml")
|
11
|
+
reset_spec_database
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'when max length is not passed in' do
|
15
|
+
it 'should return a random string of length 29' do
|
16
|
+
subject.random_string.length.should == 29
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when max length is passed in' do
|
21
|
+
it 'should return a random string of the desired length' do
|
22
|
+
subject.random_string(30).length.should == 30
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should include the letter r in the random string' do
|
27
|
+
subject.random_string.should include 'r'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should return a random string' do
|
31
|
+
random_string = subject.random_string
|
32
|
+
another_random_string = subject.random_string
|
33
|
+
random_string.should_not == another_random_string
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe CASServer::Utils, '#log_controller_action(controller, params)' do
|
38
|
+
let(:params) { {} }
|
39
|
+
let(:params_with_password) { { 'password' => 'test' } }
|
40
|
+
let(:params_with_password_filtered) { { 'password' => '******' } }
|
41
|
+
|
42
|
+
it 'should log the controller action' do
|
43
|
+
$LOG.should_receive(:debug).with 'Processing application::instance_eval {}'
|
44
|
+
|
45
|
+
subject.log_controller_action('application', params)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should filter password parameters in the log' do
|
49
|
+
$LOG.should_receive(:debug).with "Processing application::instance_eval #{params_with_password_filtered.inspect}"
|
50
|
+
|
51
|
+
subject.log_controller_action('application', params_with_password)
|
52
|
+
end
|
53
|
+
end
|
data/tasks/bundler.rake
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
namespace :db do
|
2
|
+
desc "bring your CAS server database schema up to date (options CONFIG=/path/to/config.yml)"
|
3
|
+
task :migrate do |t|
|
4
|
+
$:.unshift File.dirname(__FILE__) + "/../../lib"
|
5
|
+
|
6
|
+
require 'casserver/server'
|
7
|
+
|
8
|
+
CASServer::Model::Base.logger = Logger.new(STDOUT)
|
9
|
+
ActiveRecord::Migration.verbose = true
|
10
|
+
ActiveRecord::Migrator.migrate("db/migrate")
|
11
|
+
end
|
12
|
+
end
|
data/tasks/spec.rake
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
begin
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
desc 'Run RSpecs to confirm that all functionality is working as expected'
|
4
|
+
RSpec::Core::RakeTask.new('spec') do |t|
|
5
|
+
t.rspec_opts = ['--colour', '--format nested']
|
6
|
+
t.pattern = 'spec/**/*_spec.rb'
|
7
|
+
end
|
8
|
+
rescue LoadError
|
9
|
+
puts "Hiding spec tasks because RSpec is not available"
|
10
|
+
end
|