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