synapse-rubycas-server 1.1.3alpha
Sign up to get free protection for your applications and to get access to all the features.
- 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
|