synapse-rubycas-server 1.1.3alpha
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.
- checksums.yaml +15 -0
- data/CHANGELOG +353 -0
- data/Gemfile +12 -0
- data/LICENSE +26 -0
- data/README.md +38 -0
- data/Rakefile +3 -0
- data/bin/rubycas-server +30 -0
- data/config/config.example.yml +552 -0
- data/config/unicorn.rb +88 -0
- data/config.ru +11 -0
- data/db/migrate/001_create_initial_structure.rb +47 -0
- data/db/migrate/002_add_indexes_for_performance.rb +15 -0
- data/lib/casserver/authenticators/active_directory_ldap.rb +17 -0
- data/lib/casserver/authenticators/active_resource.rb +113 -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 +70 -0
- data/lib/casserver/authenticators/client_certificate.rb +47 -0
- data/lib/casserver/authenticators/google.rb +62 -0
- data/lib/casserver/authenticators/ldap.rb +131 -0
- data/lib/casserver/authenticators/ntlm.rb +88 -0
- data/lib/casserver/authenticators/open_id.rb +19 -0
- data/lib/casserver/authenticators/sql.rb +158 -0
- data/lib/casserver/authenticators/sql_authlogic.rb +93 -0
- data/lib/casserver/authenticators/sql_bcrypt.rb +17 -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 +21 -0
- data/lib/casserver/base.rb +13 -0
- data/lib/casserver/cas.rb +324 -0
- data/lib/casserver/core_ext/directory_user.rb +81 -0
- data/lib/casserver/core_ext/securerandom.rb +17 -0
- data/lib/casserver/core_ext/string.rb +22 -0
- data/lib/casserver/core_ext.rb +12 -0
- data/lib/casserver/model/consumable.rb +31 -0
- data/lib/casserver/model/ticket.rb +19 -0
- data/lib/casserver/model.rb +248 -0
- data/lib/casserver/server.rb +796 -0
- data/lib/casserver/utils.rb +20 -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 +13 -0
- data/lib/casserver/views/proxy_validate.builder +31 -0
- data/lib/casserver/views/service_validate.builder +24 -0
- data/lib/casserver/views/validate.erb +2 -0
- data/lib/casserver.rb +19 -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/it.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/warning.png +0 -0
- data/resources/init.d.sh +58 -0
- data/spec/casserver/authenticators/active_resource_spec.rb +116 -0
- data/spec/casserver/authenticators/ldap_spec.rb +57 -0
- data/spec/casserver/cas_spec.rb +148 -0
- data/spec/casserver/model_spec.rb +42 -0
- data/spec/casserver/utils_spec.rb +24 -0
- data/spec/casserver_spec.rb +221 -0
- data/spec/config/alt_config.yml +50 -0
- data/spec/config/default_config.yml +56 -0
- data/spec/core_ext/string_spec.rb +28 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +126 -0
- data/tasks/bundler.rake +4 -0
- data/tasks/db/migrate.rake +12 -0
- data/tasks/spec.rake +10 -0
- metadata +405 -0
@@ -0,0 +1,126 @@
|
|
1
|
+
* {
|
2
|
+
font-family: Verdana, sans-serif;
|
3
|
+
}
|
4
|
+
|
5
|
+
body {
|
6
|
+
text-align: center; /* hack for IE */
|
7
|
+
}
|
8
|
+
|
9
|
+
label {
|
10
|
+
font-weight: bold;
|
11
|
+
font-size: 9px;
|
12
|
+
}
|
13
|
+
|
14
|
+
input {
|
15
|
+
font-weight: normal;
|
16
|
+
font-size: 12px;
|
17
|
+
}
|
18
|
+
|
19
|
+
input.button {
|
20
|
+
/*font-weight: bold;*/
|
21
|
+
font-size: 10px;
|
22
|
+
}
|
23
|
+
|
24
|
+
#login-box {
|
25
|
+
margin: 0 auto;
|
26
|
+
width: 350px;
|
27
|
+
top: 130px;
|
28
|
+
position: relative;
|
29
|
+
}
|
30
|
+
|
31
|
+
#headline-container {
|
32
|
+
text-align: right;
|
33
|
+
border-bottom: 1px solid #899989;
|
34
|
+
font-family: Tahoma, Verdana, sans-serif;
|
35
|
+
font-size: 22px;
|
36
|
+
margin-right: 0px;
|
37
|
+
padding-right: 7px;
|
38
|
+
margin-left: 10px;
|
39
|
+
letter-spacing: -0.25px;
|
40
|
+
}
|
41
|
+
|
42
|
+
#logo-container {
|
43
|
+
vertical-align: top;
|
44
|
+
}
|
45
|
+
|
46
|
+
#logo {
|
47
|
+
}
|
48
|
+
|
49
|
+
#login-form-container {
|
50
|
+
vertical-align: top;
|
51
|
+
}
|
52
|
+
|
53
|
+
#username,
|
54
|
+
#password {
|
55
|
+
width: 10em;
|
56
|
+
}
|
57
|
+
|
58
|
+
#login-form {
|
59
|
+
padding: 20px;
|
60
|
+
}
|
61
|
+
|
62
|
+
|
63
|
+
#form-layout {
|
64
|
+
position: relative;
|
65
|
+
top: 6px;
|
66
|
+
width: 100%;
|
67
|
+
}
|
68
|
+
|
69
|
+
#form-layout td {
|
70
|
+
text-align: center;
|
71
|
+
padding-bottom: 8px;
|
72
|
+
}
|
73
|
+
|
74
|
+
#form-layout td#submit-container {
|
75
|
+
text-align: right;
|
76
|
+
padding-right: 10px;
|
77
|
+
}
|
78
|
+
|
79
|
+
#form-layout #username-label-container,
|
80
|
+
#form-layout #password-label-container {
|
81
|
+
text-align: right;
|
82
|
+
}
|
83
|
+
|
84
|
+
|
85
|
+
#infoline {
|
86
|
+
font-size: 9px;
|
87
|
+
}
|
88
|
+
|
89
|
+
#messagebox-container {
|
90
|
+
padding-left: 11px;
|
91
|
+
padding-right: 16px;
|
92
|
+
}
|
93
|
+
|
94
|
+
div.messagebox {
|
95
|
+
font-size: 12px;
|
96
|
+
padding: 5px;
|
97
|
+
padding-left: 55px;
|
98
|
+
text-align: center;
|
99
|
+
width: 70%;
|
100
|
+
min-height: 34px;
|
101
|
+
vertical-align: middle;
|
102
|
+
}
|
103
|
+
|
104
|
+
div.mistake {
|
105
|
+
color: #d00;
|
106
|
+
background-image: url(warning.png);
|
107
|
+
background-repeat: no-repeat;
|
108
|
+
background-position: 10px 5px;
|
109
|
+
font-weight: bold;
|
110
|
+
}
|
111
|
+
|
112
|
+
div.confirmation {
|
113
|
+
color: #280;
|
114
|
+
background-image: url(ok.png);
|
115
|
+
background-repeat: no-repeat;
|
116
|
+
background-position: 10px 5px;
|
117
|
+
font-weight: bold;
|
118
|
+
}
|
119
|
+
|
120
|
+
div.notice {
|
121
|
+
color: #04c;
|
122
|
+
background-image: url(notice.png);
|
123
|
+
background-repeat: no-repeat;
|
124
|
+
background-position: 10px 5px;
|
125
|
+
font-weight: bold;
|
126
|
+
}
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,28 @@
|
|
1
|
+
body {
|
2
|
+
background-image: url(bg.png);
|
3
|
+
}
|
4
|
+
|
5
|
+
#headline-container {
|
6
|
+
margin-bottom: 5px;
|
7
|
+
}
|
8
|
+
|
9
|
+
#login-box {
|
10
|
+
margin: 0 auto;
|
11
|
+
width: 450px;
|
12
|
+
top: 110px;
|
13
|
+
position: relative;
|
14
|
+
}
|
15
|
+
|
16
|
+
#login-form {
|
17
|
+
background-color: #fff;
|
18
|
+
border: 1px #aaa solid;
|
19
|
+
}
|
20
|
+
|
21
|
+
#logo-container {
|
22
|
+
vertical-align: middle;
|
23
|
+
}
|
24
|
+
|
25
|
+
#logo {
|
26
|
+
width: 128px;
|
27
|
+
height: 128px;
|
28
|
+
}
|
Binary file
|
data/resources/init.d.sh
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
#! /bin/sh
|
2
|
+
#
|
3
|
+
# Copyright (c) 2008 Urbacon Ltd.
|
4
|
+
#
|
5
|
+
# System startup script for the RubyCAS-Server
|
6
|
+
#
|
7
|
+
# Instructions:
|
8
|
+
# 1. Rename this file to 'rubycas-server'
|
9
|
+
# 2. Copy it to your '/etc/init.d' directory
|
10
|
+
# 3. chmod +x /etc/init.d/rubycas-server
|
11
|
+
#
|
12
|
+
# chkconfig - 85 15
|
13
|
+
# description: Provides single-sign-on authentication for web applications.
|
14
|
+
#
|
15
|
+
### BEGIN INIT INFO
|
16
|
+
# Provides: rubycas-server
|
17
|
+
# Required-Start: $syslog
|
18
|
+
# Should-Start:
|
19
|
+
# Required-Stop: $syslog
|
20
|
+
# Should-Stop:
|
21
|
+
# Default-Start: 3 5
|
22
|
+
# Default-Stop: 0 1 2 6
|
23
|
+
# Description: Start the RubyCAS-Server
|
24
|
+
### END INIT INFO
|
25
|
+
|
26
|
+
CASSERVER_CTL=rubycas-server-ctl
|
27
|
+
|
28
|
+
# Gracefully exit if the controller is missing.
|
29
|
+
which $CASSERVER_CTL > /dev/null || exit 0
|
30
|
+
|
31
|
+
# Source config
|
32
|
+
. /etc/rc.status
|
33
|
+
|
34
|
+
rc_reset
|
35
|
+
case "$1" in
|
36
|
+
start)
|
37
|
+
$CASSERVER_CTL start
|
38
|
+
rc_status -v
|
39
|
+
;;
|
40
|
+
stop)
|
41
|
+
$CASSERVER_CTL stop
|
42
|
+
rc_status -v
|
43
|
+
;;
|
44
|
+
restart)
|
45
|
+
$0 stop
|
46
|
+
$0 start
|
47
|
+
rc_status
|
48
|
+
;;
|
49
|
+
status)
|
50
|
+
$CASSERVER_CTL status
|
51
|
+
rc_status -v
|
52
|
+
;;
|
53
|
+
*)
|
54
|
+
echo "Usage: $0 {start|stop|status|restart}"
|
55
|
+
exit 1
|
56
|
+
;;
|
57
|
+
esac
|
58
|
+
rc_exit
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe "CASServer::Authenticators::ActiveResource" do
|
5
|
+
before do
|
6
|
+
pending("Skip ActiveResource test due to missing gems") unless gem_available?("activeresource")
|
7
|
+
# Trigger autoload to load also Helpers module
|
8
|
+
# TODO this helper module should be inside activeresource namespace
|
9
|
+
CASServer::Authenticators::ActiveResource
|
10
|
+
end
|
11
|
+
describe "CASServer::Authenticators::Helpers::Identity" do
|
12
|
+
subject { CASServer::Authenticators::Helpers::Identity.new }
|
13
|
+
|
14
|
+
it { should be_an ActiveResource::Base }
|
15
|
+
|
16
|
+
it "class should respond to :authenticate" do
|
17
|
+
subject.class.should respond_to :authenticate
|
18
|
+
end
|
19
|
+
|
20
|
+
it "class should have a method_name accessor" do
|
21
|
+
CASServer::Authenticators::Helpers::Identity.method_name.should == :authenticate
|
22
|
+
end
|
23
|
+
|
24
|
+
it "class should have a method_name accessor" do
|
25
|
+
CASServer::Authenticators::Helpers::Identity.method_type.should == :post
|
26
|
+
end
|
27
|
+
|
28
|
+
it "class method_type accessor should validate type" do
|
29
|
+
expect {
|
30
|
+
CASServer::Authenticators::Helpers::Identity.method_type = :foo
|
31
|
+
}.to raise_error(ArgumentError)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "CASServer::Authenticators::ActiveResource" do
|
37
|
+
|
38
|
+
describe "#setup" do
|
39
|
+
|
40
|
+
it "should configure the identity object" do
|
41
|
+
CASServer::Authenticators::Helpers::Identity.should_receive(:user=).with('httpuser').once
|
42
|
+
CASServer::Authenticators::ActiveResource.setup :site => 'http://api.example.org', :user => 'httpuser'
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should configure the method_type" do
|
46
|
+
CASServer::Authenticators::Helpers::Identity.should_receive(:method_type=).with('get').once
|
47
|
+
CASServer::Authenticators::ActiveResource.setup :site => 'http://api.example.org', :method_type => 'get'
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should raise if site option is missing" do
|
51
|
+
expect {
|
52
|
+
CASServer::Authenticators::ActiveResource.setup({}).should
|
53
|
+
}.to raise_error(CASServer::AuthenticatorError, /site option/)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#validate" do
|
58
|
+
|
59
|
+
let(:credentials) { {:username => 'validusername',
|
60
|
+
:password => 'validpassword',
|
61
|
+
:service => 'test.service'} }
|
62
|
+
|
63
|
+
let(:auth) { CASServer::Authenticators::ActiveResource.new }
|
64
|
+
|
65
|
+
def mock_authenticate identity = nil
|
66
|
+
identity = CASServer::Authenticators::Helpers::Identity.new if identity.nil?
|
67
|
+
CASServer::Authenticators::Helpers::Identity.stub!(:authenticate).and_return(identity)
|
68
|
+
end
|
69
|
+
|
70
|
+
def sample_identity attrs = {}
|
71
|
+
identity = CASServer::Authenticators::Helpers::Identity.new
|
72
|
+
attrs.each { |k,v| identity.send "#{k}=", v }
|
73
|
+
identity
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should call Identity#autenticate with the given params" do
|
77
|
+
CASServer::Authenticators::Helpers::Identity.should_receive(:authenticate).with(credentials).once
|
78
|
+
auth.validate(credentials)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should return identity object attributes as extra attributes" do
|
82
|
+
auth.configure({}.with_indifferent_access)
|
83
|
+
identity = sample_identity({:email => 'foo@example.org'})
|
84
|
+
mock_authenticate identity
|
85
|
+
auth.validate(credentials).should be_true
|
86
|
+
auth.extra_attributes.should == identity.attributes
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should return false when http raises" do
|
90
|
+
CASServer::Authenticators::Helpers::Identity.stub!(:authenticate).and_raise(ActiveResource::ForbiddenAccess.new({}))
|
91
|
+
auth.validate(credentials).should be_false
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should apply extra_attribute filter" do
|
95
|
+
auth.configure({ :extra_attributes => 'age'}.with_indifferent_access)
|
96
|
+
mock_authenticate sample_identity({ :email => 'foo@example.org', :age => 28 })
|
97
|
+
auth.validate(credentials).should be_true
|
98
|
+
auth.extra_attributes.should == { "age" => "28" }
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should only extract not filtered attributes" do
|
102
|
+
auth.configure({ :filter_attributes => 'age'}.with_indifferent_access)
|
103
|
+
mock_authenticate sample_identity({ :email => 'foo@example.org', :age => 28 })
|
104
|
+
auth.validate(credentials).should be_true
|
105
|
+
auth.extra_attributes.should == { "email" => 'foo@example.org' }
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should filter password if filter attributes is not given" do
|
109
|
+
auth.configure({}.with_indifferent_access)
|
110
|
+
mock_authenticate sample_identity({ :email => 'foo@example.org', :password => 'secret' })
|
111
|
+
auth.validate(credentials).should be_true
|
112
|
+
auth.extra_attributes.should == { "email" => 'foo@example.org' }
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe "CASServer::Authenticators::LDAP" do
|
5
|
+
before do
|
6
|
+
pending("Skip LDAP test due to missing gems") unless gem_available?("net-ldap")
|
7
|
+
|
8
|
+
if $LOG.nil?
|
9
|
+
load_server('default_config') # a lazy way to make sure the logger is set up
|
10
|
+
end
|
11
|
+
# Trigger autoload to load net ldap
|
12
|
+
CASServer::Authenticators::LDAP
|
13
|
+
|
14
|
+
@ldap_entry = mock(Net::LDAP::Entry.new)
|
15
|
+
@ldap_entry.stub!(:[]).and_return("Test")
|
16
|
+
|
17
|
+
@ldap = mock(Net::LDAP)
|
18
|
+
@ldap.stub!(:host=)
|
19
|
+
@ldap.stub!(:port=)
|
20
|
+
@ldap.stub!(:encryption)
|
21
|
+
@ldap.stub!(:bind_as).and_return(true)
|
22
|
+
@ldap.stub!(:authenticate).and_return(true)
|
23
|
+
@ldap.stub!(:search).and_return([@ldap_entry])
|
24
|
+
|
25
|
+
Net::LDAP.stub!(:new).and_return(@ldap)
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#validate' do
|
29
|
+
|
30
|
+
it 'validate with preauthentication and with extra attributes' do
|
31
|
+
auth = CASServer::Authenticators::LDAP.new
|
32
|
+
|
33
|
+
auth_config = HashWithIndifferentAccess.new(
|
34
|
+
:ldap => {
|
35
|
+
:host => "ad.example.net",
|
36
|
+
:port => 389,
|
37
|
+
:base => "dc=example,dc=net",
|
38
|
+
:filter => "(objectClass=person)",
|
39
|
+
:auth_user => "authenticator",
|
40
|
+
:auth_password => "itsasecret"
|
41
|
+
},
|
42
|
+
:extra_attributes => [:full_name, :address]
|
43
|
+
)
|
44
|
+
|
45
|
+
auth.configure(auth_config.merge('auth_index' => 0))
|
46
|
+
auth.validate(
|
47
|
+
:username => 'validusername',
|
48
|
+
:password => 'validpassword',
|
49
|
+
:service => 'test.service',
|
50
|
+
:request => {}
|
51
|
+
).should == true
|
52
|
+
|
53
|
+
auth.extra_attributes.should == {:full_name => 'Test', :address => 'Test'}
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module CASServer; end
|
4
|
+
require 'casserver/cas'
|
5
|
+
require 'nokogiri'
|
6
|
+
require 'cgi'
|
7
|
+
|
8
|
+
describe CASServer::CAS do
|
9
|
+
before do
|
10
|
+
load_server("default_config")
|
11
|
+
@klass = Class.new {
|
12
|
+
include CASServer::CAS
|
13
|
+
}
|
14
|
+
@client_hostname = 'myhost.test'
|
15
|
+
@host = @klass.new
|
16
|
+
@host.instance_variable_set(:@env, {
|
17
|
+
'REMOTE_HOST' => @client_hostname
|
18
|
+
})
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#generate_login_ticket" do
|
22
|
+
before do
|
23
|
+
@lt = @host.generate_login_ticket
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should return a login ticket" do
|
27
|
+
@lt.class.should == CASServer::Model::LoginTicket
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should set the client_hostname" do
|
31
|
+
@lt.client_hostname.should == @client_hostname
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should set the ticket string" do
|
35
|
+
@lt.ticket.should_not be_nil
|
36
|
+
end
|
37
|
+
|
38
|
+
it "SHOULD set the ticket string starting with 'LT'" do
|
39
|
+
@lt.ticket.should match /^LT/
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should not mark the ticket as consumed" do
|
43
|
+
@lt.consumed.should be_nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#generate_ticket_granting_ticket(username, extra_attributes = {})" do
|
48
|
+
before do
|
49
|
+
@username = 'myuser'
|
50
|
+
@tgt = @host.generate_ticket_granting_ticket(@username)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should return a TicketGrantingTicket" do
|
54
|
+
@tgt.class.should == CASServer::Model::TicketGrantingTicket
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should set the tgt's ticket string" do
|
58
|
+
@tgt.ticket.should_not be_nil
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should generate a ticket string starting with 'TGC'" do
|
62
|
+
@tgt.ticket.should match /^TGC/
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should set the tgt's username string" do
|
66
|
+
@tgt.username.should == @username
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should set the tgt's client_hostname" do
|
70
|
+
@tgt.client_hostname.should == @client_hostname
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "#generate_service_ticket(service, username, tgt)" do
|
75
|
+
before do
|
76
|
+
@username = 'testuser'
|
77
|
+
@service = 'myservice.test'
|
78
|
+
@tgt = double(CASServer::Model::TicketGrantingTicket)
|
79
|
+
@tgt.stub(:id => rand(10000))
|
80
|
+
@st = @host.generate_service_ticket(@service, @username, @tgt)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should return a ServiceTicket" do
|
84
|
+
@st.class.should == CASServer::Model::ServiceTicket
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should not include the service identifer in the ticket string" do
|
88
|
+
@st.ticket.should_not match /#{@service}/
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should not mark the ST as consumed" do
|
92
|
+
@st.consumed.should be_nil
|
93
|
+
end
|
94
|
+
|
95
|
+
it "MUST generate a ticket that starts with 'ST-'" do
|
96
|
+
@st.ticket.should match /^ST-/
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should assoicate the ST with the supplied TGT" do
|
100
|
+
@st.granted_by_tgt_id.should == @tgt.id
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe "#generate_proxy_ticket(target_service, pgt)" do
|
105
|
+
before do
|
106
|
+
@target_service = 'remoteservice.test'
|
107
|
+
@st = CASServer::Model::ServiceTicket.new({
|
108
|
+
:username => 'joe',
|
109
|
+
:granted_by_tgt_id => rand(10000)
|
110
|
+
})
|
111
|
+
@pgt = double(CASServer::Model::ProxyGrantingTicket)
|
112
|
+
@pgt.stub({
|
113
|
+
:id => rand(10000),
|
114
|
+
:service_ticket => @st,
|
115
|
+
:ticket => 'some ticket'
|
116
|
+
})
|
117
|
+
@pt = @host.generate_proxy_ticket(@target_service, @pgt)
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should return a ProxyGrantingTicket" do
|
121
|
+
@pt.class.should == CASServer::Model::ProxyTicket
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should not consume the generated ticket" do
|
125
|
+
@pt.consumed.should be_nil
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should start the ticket string with PT-" do
|
129
|
+
@pt.ticket.should match /^PT-/
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe "#send_logout_notification_for_service_ticket(st)" do
|
134
|
+
it "should send valid single sign out XML to the service URL" do
|
135
|
+
service_stub = stub_request(:post, 'http://example.com')
|
136
|
+
st = CASServer::Model::ServiceTicket.new(
|
137
|
+
:ticket => 'ST-0123456789ABCDEFGHIJKLMNOPQRS',
|
138
|
+
:service => 'http://example.com'
|
139
|
+
)
|
140
|
+
@host.send_logout_notification_for_service_ticket(st)
|
141
|
+
|
142
|
+
a_request(:post, 'example.com').with{ |req|
|
143
|
+
xml = CGI.parse(req.body)['logoutRequest'].first
|
144
|
+
Nokogiri::XML(xml).at_xpath('//samlp:SessionIndex').text.strip == st.ticket
|
145
|
+
}.should have_been_made
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require '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("default_config")
|
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
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
module CASServer
|
5
|
+
end
|
6
|
+
require 'casserver/utils'
|
7
|
+
|
8
|
+
describe CASServer::Utils, '#log_controller_action(controller, params)' do
|
9
|
+
let(:params) { {} }
|
10
|
+
let(:params_with_password) { { 'password' => 'test' } }
|
11
|
+
let(:params_with_password_filtered) { { 'password' => '******' } }
|
12
|
+
|
13
|
+
it 'should log the controller action' do
|
14
|
+
$LOG.should_receive(:debug).with 'Processing application::instance_eval {}'
|
15
|
+
|
16
|
+
subject.log_controller_action('application', params)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should filter password parameters in the log' do
|
20
|
+
$LOG.should_receive(:debug).with "Processing application::instance_eval #{params_with_password_filtered.inspect}"
|
21
|
+
|
22
|
+
subject.log_controller_action('application', params_with_password)
|
23
|
+
end
|
24
|
+
end
|