wmernagh-rubycas-server 0.6.99.336
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.txt +1 -0
- data/History.txt +245 -0
- data/LICENSE.txt +504 -0
- data/Manifest.txt +74 -0
- data/PostInstall.txt +3 -0
- data/README.txt +25 -0
- data/Rakefile +4 -0
- data/bin/rubycas-server +26 -0
- data/bin/rubycas-server-ctl +22 -0
- data/config/hoe.rb +76 -0
- data/config/requirements.rb +15 -0
- data/config.example.yml +442 -0
- data/custom_views.example.rb +11 -0
- data/lib/casserver/authenticators/active_directory_ldap.rb +11 -0
- data/lib/casserver/authenticators/base.rb +48 -0
- data/lib/casserver/authenticators/client_certificate.rb +46 -0
- data/lib/casserver/authenticators/ldap.rb +138 -0
- data/lib/casserver/authenticators/ntlm.rb +88 -0
- data/lib/casserver/authenticators/open_id.rb +22 -0
- data/lib/casserver/authenticators/sql.rb +102 -0
- data/lib/casserver/authenticators/sql_encrypted.rb +75 -0
- data/lib/casserver/authenticators/sql_md5.rb +19 -0
- data/lib/casserver/authenticators/test.rb +19 -0
- data/lib/casserver/cas.rb +308 -0
- data/lib/casserver/conf.rb +112 -0
- data/lib/casserver/controllers.rb +452 -0
- data/lib/casserver/environment.rb +26 -0
- data/lib/casserver/models.rb +218 -0
- data/lib/casserver/postambles.rb +174 -0
- data/lib/casserver/utils.rb +30 -0
- data/lib/casserver/version.rb +9 -0
- data/lib/casserver/views.rb +243 -0
- data/lib/casserver.rb +111 -0
- data/lib/rubycas-server/version.rb +1 -0
- data/lib/rubycas-server.rb +1 -0
- data/lib/themes/cas.css +121 -0
- data/lib/themes/notice.png +0 -0
- data/lib/themes/ok.png +0 -0
- data/lib/themes/simple/bg.png +0 -0
- data/lib/themes/simple/login_box_bg.png +0 -0
- data/lib/themes/simple/logo.png +0 -0
- data/lib/themes/simple/theme.css +28 -0
- data/lib/themes/urbacon/bg.png +0 -0
- data/lib/themes/urbacon/login_box_bg.png +0 -0
- data/lib/themes/urbacon/logo.png +0 -0
- data/lib/themes/urbacon/theme.css +33 -0
- data/lib/themes/warning.png +0 -0
- data/misc/basic_cas_single_signon_mechanism_diagram.png +0 -0
- data/misc/basic_cas_single_signon_mechanism_diagram.svg +652 -0
- data/resources/init.d.sh +58 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +82 -0
- data/setup.rb +1585 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/website.rake +17 -0
- data/vendor/isaac_0.9.1/LICENSE +26 -0
- data/vendor/isaac_0.9.1/README +78 -0
- data/vendor/isaac_0.9.1/TODO +3 -0
- data/vendor/isaac_0.9.1/VERSIONS +3 -0
- data/vendor/isaac_0.9.1/crypt/ISAAC.rb +171 -0
- data/vendor/isaac_0.9.1/isaac.gemspec +39 -0
- data/vendor/isaac_0.9.1/setup.rb +596 -0
- data/vendor/isaac_0.9.1/test/TC_ISAAC.rb +76 -0
- data/website/index.html +40 -0
- data/website/index.txt +3 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +138 -0
- data/website/template.html.erb +40 -0
- metadata +146 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
module CASServer
|
|
2
|
+
module Postambles
|
|
3
|
+
|
|
4
|
+
def webrick
|
|
5
|
+
require 'webrick/httpserver'
|
|
6
|
+
require 'webrick/https'
|
|
7
|
+
require 'camping/webrick'
|
|
8
|
+
|
|
9
|
+
# TODO: verify the certificate's validity
|
|
10
|
+
# example of how to do this is here: http://pablotron.org/download/ruri-20050331.rb
|
|
11
|
+
|
|
12
|
+
cert_path = CASServer::Conf.ssl_cert
|
|
13
|
+
key_path = CASServer::Conf.ssl_key || CASServer::Conf.ssl_cert
|
|
14
|
+
# look for the key in the ssl_cert if no ssl_key is specified
|
|
15
|
+
|
|
16
|
+
webrick_options = {:BindAddress => "0.0.0.0", :Port => CASServer::Conf.port}
|
|
17
|
+
|
|
18
|
+
unless cert_path.nil? && key_path.nil?
|
|
19
|
+
raise "'#{cert_path}' is not a valid ssl certificate. Your 'ssl_cert' configuration" +
|
|
20
|
+
" setting must be a path to a valid ssl certificate file." unless
|
|
21
|
+
File.exists? cert_path
|
|
22
|
+
|
|
23
|
+
raise "'#{key_path}' is not a valid ssl private key. Your 'ssl_key' configuration" +
|
|
24
|
+
" setting must be a path to a valid ssl private key file." unless
|
|
25
|
+
File.exists? key_path
|
|
26
|
+
|
|
27
|
+
cert = OpenSSL::X509::Certificate.new(File.read(cert_path))
|
|
28
|
+
key = OpenSSL::PKey::RSA.new(File.read(key_path))
|
|
29
|
+
|
|
30
|
+
webrick_options[:SSLEnable] = true
|
|
31
|
+
webrick_options[:SSLVerifyClient] = ::OpenSSL::SSL::VERIFY_NONE
|
|
32
|
+
webrick_options[:SSLCertificate] = cert
|
|
33
|
+
webrick_options[:SSLPrivateKey] = key
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
begin
|
|
37
|
+
s = WEBrick::HTTPServer.new(webrick_options)
|
|
38
|
+
rescue Errno::EACCES
|
|
39
|
+
puts "\nThe server could not launch. Are you running on a privileged port? (e.g. port 443) If so, you must run the server as root."
|
|
40
|
+
exit 2
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
CASServer.create
|
|
44
|
+
s.mount "#{CASServer::Conf.uri_path}", WEBrick::CampingHandler, CASServer
|
|
45
|
+
|
|
46
|
+
puts "\n** CASServer is running at http#{webrick_options[:SSLEnable] ? 's' : ''}://#{Socket.gethostname}:#{CASServer::Conf.port}#{CASServer::Conf.uri_path} and logging to '#{CASServer::Conf.log[:file]}'\n\n"
|
|
47
|
+
|
|
48
|
+
# This lets Ctrl+C shut down your server
|
|
49
|
+
trap(:INT) do
|
|
50
|
+
s.shutdown
|
|
51
|
+
end
|
|
52
|
+
trap(:TERM) do
|
|
53
|
+
s.shutdown
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
if $DAEMONIZE
|
|
57
|
+
WEBrick::Daemon.start do
|
|
58
|
+
write_pid_file if $PID_FILE
|
|
59
|
+
s.start
|
|
60
|
+
clear_pid_file
|
|
61
|
+
end
|
|
62
|
+
else
|
|
63
|
+
s.start
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def mongrel
|
|
70
|
+
require 'rubygems'
|
|
71
|
+
require 'mongrel/camping'
|
|
72
|
+
|
|
73
|
+
if $DAEMONIZE
|
|
74
|
+
# check if log and pid are writable before daemonizing, otherwise we won't be able to notify
|
|
75
|
+
# the user if we run into trouble later (since once daemonized, we can't write to stdout/stderr)
|
|
76
|
+
check_pid_writable if $PID_FILE
|
|
77
|
+
check_log_writable
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
CASServer.create
|
|
81
|
+
|
|
82
|
+
puts "\n** CASServer is starting. Look in '#{CASServer::Conf.log[:file]}' for further notices."
|
|
83
|
+
|
|
84
|
+
settings = {:host => "0.0.0.0", :log_file => CASServer::Conf.log[:file], :cwd => $CASSERVER_HOME}
|
|
85
|
+
|
|
86
|
+
# need to close all IOs before daemonizing
|
|
87
|
+
$LOG.close if $DAEMONIZE
|
|
88
|
+
|
|
89
|
+
begin
|
|
90
|
+
config = Mongrel::Configurator.new settings do
|
|
91
|
+
daemonize :log_file => CASServer::Conf.log[:file], :cwd => $CASSERVER_HOME if $DAEMONIZE
|
|
92
|
+
|
|
93
|
+
listener :port => CASServer::Conf.port do
|
|
94
|
+
uri CASServer::Conf.uri_path, :handler => Mongrel::Camping::CampingHandler.new(CASServer)
|
|
95
|
+
setup_signals
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
rescue Errno::EADDRINUSE
|
|
99
|
+
exit 1
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
config.run
|
|
103
|
+
|
|
104
|
+
CASServer.init_logger
|
|
105
|
+
CASServer.init_db_logger
|
|
106
|
+
|
|
107
|
+
if $DAEMONIZE && $PID_FILE
|
|
108
|
+
write_pid_file
|
|
109
|
+
unless File.exists? $PID_FILE
|
|
110
|
+
$LOG.error "CASServer could not start because pid file '#{$PID_FILE}' could not be created."
|
|
111
|
+
exit 1
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
puts "\n** CASServer is running at http://localhost:#{CASServer::Conf.port}#{CASServer::Conf.uri_path} and logging to '#{CASServer::Conf.log[:file]}'"
|
|
116
|
+
config.join
|
|
117
|
+
|
|
118
|
+
clear_pid_file
|
|
119
|
+
|
|
120
|
+
puts "\n** CASServer is stopped (#{Time.now})"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def fastcgi
|
|
125
|
+
require 'camping/fastcgi'
|
|
126
|
+
Dir.chdir('/srv/www/camping/casserver/')
|
|
127
|
+
|
|
128
|
+
CASServer.create
|
|
129
|
+
Camping::FastCGI.start(CASServer)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def cgi
|
|
134
|
+
CASServer.create
|
|
135
|
+
puts CASServer.run
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
private
|
|
139
|
+
def check_log_writable
|
|
140
|
+
log_file = CASServer::Conf.log['file']
|
|
141
|
+
begin
|
|
142
|
+
f = open(log_file, 'w')
|
|
143
|
+
rescue
|
|
144
|
+
$stderr.puts "Couldn't write to log file at '#{log_file}' (#{$!})."
|
|
145
|
+
exit 1
|
|
146
|
+
end
|
|
147
|
+
f.close
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def check_pid_writable
|
|
151
|
+
$LOG.debug "Checking if pid file '#{$PID_FILE}' is writable"
|
|
152
|
+
begin
|
|
153
|
+
f = open($PID_FILE, 'w')
|
|
154
|
+
rescue
|
|
155
|
+
$stderr.puts "Couldn't write to log at '#{$PID_FILE}' (#{$!})."
|
|
156
|
+
exit 1
|
|
157
|
+
end
|
|
158
|
+
f.close
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def write_pid_file
|
|
162
|
+
$LOG.debug "Writing pid '#{Process.pid}' to pid file '#{$PID_FILE}'"
|
|
163
|
+
open($PID_FILE, "w") { |file| file.write(Process.pid) }
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def clear_pid_file
|
|
167
|
+
if $PID_FILE && File.exists?($PID_FILE)
|
|
168
|
+
$LOG.debug "Clearing pid file '#{$PID_FILE}'"
|
|
169
|
+
File.unlink $PID_FILE
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
end
|
|
174
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Misc utility function used throughout by the RubyCAS-server.
|
|
2
|
+
module CASServer
|
|
3
|
+
module Utils
|
|
4
|
+
def random_string(max_length = 29)
|
|
5
|
+
rg = Crypt::ISAAC.new
|
|
6
|
+
max = 4294619050
|
|
7
|
+
r = "#{Time.now.to_i}r%X%X%X%X%X%X%X%X" %
|
|
8
|
+
[rg.rand(max), rg.rand(max), rg.rand(max), rg.rand(max),
|
|
9
|
+
rg.rand(max), rg.rand(max), rg.rand(max), rg.rand(max)]
|
|
10
|
+
r[0..max_length-1]
|
|
11
|
+
end
|
|
12
|
+
module_function :random_string
|
|
13
|
+
|
|
14
|
+
def log_controller_action(controller, params)
|
|
15
|
+
$LOG << "\n"
|
|
16
|
+
|
|
17
|
+
/`(.*)'/.match(caller[1])
|
|
18
|
+
method = $~[1]
|
|
19
|
+
|
|
20
|
+
if params.respond_to? :dup
|
|
21
|
+
params2 = params.dup
|
|
22
|
+
params2['password'] = '******' if params2['password']
|
|
23
|
+
else
|
|
24
|
+
params2 = params
|
|
25
|
+
end
|
|
26
|
+
$LOG.debug("Processing #{controller}::#{method} #{params2.inspect}")
|
|
27
|
+
end
|
|
28
|
+
module_function :log_controller_action
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# The #.#.# comments (e.g. "2.1.3") refer to section numbers in the CAS protocol spec
|
|
2
|
+
# under http://www.ja-sig.org/products/cas/overview/protocol/index.html
|
|
3
|
+
|
|
4
|
+
# need auto_validation off to render CAS responses and to use the autocomplete='off' property on password field
|
|
5
|
+
Markaby::Builder.set(:auto_validation, false)
|
|
6
|
+
|
|
7
|
+
# disabled XML indentation because it was causing problems with mod_auth_cas
|
|
8
|
+
#Markaby::Builder.set(:indent, 2)
|
|
9
|
+
|
|
10
|
+
module CASServer::Views
|
|
11
|
+
|
|
12
|
+
def layout
|
|
13
|
+
# wrap as XHTML only when auto_validation is on, otherwise pass right through
|
|
14
|
+
if @use_layout
|
|
15
|
+
xhtml_strict do
|
|
16
|
+
head do
|
|
17
|
+
title { "#{organization} Central Login" }
|
|
18
|
+
link(:rel => "stylesheet", :type => "text/css", :href => "/themes/cas.css")
|
|
19
|
+
link(:rel => "stylesheet", :type => "text/css", :href => "/themes/#{current_theme}/theme.css")
|
|
20
|
+
end
|
|
21
|
+
body(:onload => "if (document.getElementById('username')) document.getElementById('username').focus()") do
|
|
22
|
+
self << yield
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
else
|
|
26
|
+
self << yield
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# 2.1.3
|
|
32
|
+
# The full login page.
|
|
33
|
+
def login
|
|
34
|
+
@use_layout = true
|
|
35
|
+
|
|
36
|
+
table(:id => "login-box") do
|
|
37
|
+
tr do
|
|
38
|
+
td(:colspan => 2) do
|
|
39
|
+
div(:id => "headline-container") do
|
|
40
|
+
strong organization
|
|
41
|
+
text " Central Login"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
if @message
|
|
46
|
+
tr do
|
|
47
|
+
td(:colspan => 2, :id => "messagebox-container") do
|
|
48
|
+
div(:class => "messagebox #{@message[:type]}") { @message[:message] }
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
tr do
|
|
53
|
+
td(:id => "logo-container") do
|
|
54
|
+
img(:id => "logo", :src => "/themes/#{current_theme}/logo.png")
|
|
55
|
+
end
|
|
56
|
+
td(:id => "login-form-container") do
|
|
57
|
+
@include_infoline = true
|
|
58
|
+
login_form
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Just the login form.
|
|
65
|
+
def login_form
|
|
66
|
+
form(:method => "post", :action => @form_action || '/login', :id => "login-form",
|
|
67
|
+
:onsubmit => "submitbutton = document.getElementById('login-submit'); submitbutton.value='Please wait...'; submitbutton.disabled=true; return true;") do
|
|
68
|
+
table(:id => "form-layout") do
|
|
69
|
+
tr do
|
|
70
|
+
td(:id => "username-label-container") do
|
|
71
|
+
label(:id => "username-label", :for => "username") { "Username" }
|
|
72
|
+
end
|
|
73
|
+
td(:id => "username-container") do
|
|
74
|
+
input(:type => "text", :id => "username", :name => "username",
|
|
75
|
+
:size => "32", :tabindex => "1", :accesskey => "u")
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
tr do
|
|
79
|
+
td(:id => "password-label-container") do
|
|
80
|
+
label(:id => "password-label", :for => "password") { "Password" }
|
|
81
|
+
end
|
|
82
|
+
td(:id => "password-container") do
|
|
83
|
+
input(:type => "password", :id => "password", :name => "password",
|
|
84
|
+
:size => "32", :tabindex => "2", :accesskey => "p", :autocomplete => "off")
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
tr do
|
|
88
|
+
td{}
|
|
89
|
+
td(:id => "submit-container") do
|
|
90
|
+
input(:type => "hidden", :id => "lt", :name => "lt", :value => @lt)
|
|
91
|
+
input(:type => "hidden", :id => "service", :name => "service", :value => @service)
|
|
92
|
+
input(:type => "submit", :class => "button", :accesskey => "l", :value => "LOGIN", :tabindex => "4", :id => "login-submit")
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
tr do
|
|
96
|
+
td(:colspan => 2, :id => "infoline") { infoline }
|
|
97
|
+
end if @include_infoline
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# 2.3.2
|
|
103
|
+
def logout
|
|
104
|
+
@use_layout = true
|
|
105
|
+
|
|
106
|
+
table(:id => "login-box") do
|
|
107
|
+
tr do
|
|
108
|
+
td(:colspan => 2) do
|
|
109
|
+
div(:id => "headline-container") do
|
|
110
|
+
strong organization
|
|
111
|
+
text " Central Login"
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
if @message
|
|
116
|
+
tr do
|
|
117
|
+
td(:colspan => 2, :id => "messagebox-container") do
|
|
118
|
+
div(:class => "messagebox #{@message[:type]}") { @message[:message] }
|
|
119
|
+
if @continue_url
|
|
120
|
+
p do
|
|
121
|
+
a(:href => @continue_url) { @continue_url }
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# 2.4.2
|
|
131
|
+
# CAS 1.0 validate response.
|
|
132
|
+
def validate
|
|
133
|
+
if @success
|
|
134
|
+
text "yes\n#{@username}\n"
|
|
135
|
+
else
|
|
136
|
+
text "no\n\n"
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# 2.5.2
|
|
141
|
+
# CAS 2.0 service validate response.
|
|
142
|
+
def service_validate
|
|
143
|
+
if @success
|
|
144
|
+
tag!("cas:serviceResponse", 'xmlns:cas' => "http://www.yale.edu/tp/cas") do
|
|
145
|
+
tag!("cas:authenticationSuccess") do
|
|
146
|
+
tag!("cas:user") {@username.to_s.to_xs}
|
|
147
|
+
@extra_attributes.each do |key, value|
|
|
148
|
+
tag!(key) {serialize_extra_attribute(value)}
|
|
149
|
+
end
|
|
150
|
+
if @pgtiou
|
|
151
|
+
tag!("cas:proxyGrantingTicket") {@pgtiou.to_s.to_xs}
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
else
|
|
156
|
+
tag!("cas:serviceResponse", 'xmlns:cas' => "http://www.yale.edu/tp/cas") do
|
|
157
|
+
tag!("cas:authenticationFailure", :code => @error.code) {@error.to_s.to_xs}
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# 2.6.2
|
|
163
|
+
# CAS 2.0 proxy validate response.
|
|
164
|
+
def proxy_validate
|
|
165
|
+
if @success
|
|
166
|
+
tag!("cas:serviceResponse", 'xmlns:cas' => "http://www.yale.edu/tp/cas") do
|
|
167
|
+
tag!("cas:authenticationSuccess") do
|
|
168
|
+
tag!("cas:user") {@username.to_s.to_xs}
|
|
169
|
+
@extra_attributes.each do |key, value|
|
|
170
|
+
tag!(key) {serialize_extra_attribute(value)}
|
|
171
|
+
end
|
|
172
|
+
if @pgtiou
|
|
173
|
+
tag!("cas:proxyGrantingTicket") {@pgtiou.to_s.to_xs}
|
|
174
|
+
end
|
|
175
|
+
if @proxies && !@proxies.empty?
|
|
176
|
+
tag!("cas:proxies") do
|
|
177
|
+
@proxies.each do |proxy_url|
|
|
178
|
+
tag!("cas:proxy") {proxy_url.to_s.to_xs}
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
else
|
|
185
|
+
tag!("cas:serviceResponse", 'xmlns:cas' => "http://www.yale.edu/tp/cas") do
|
|
186
|
+
tag!("cas:authenticationFailure", :code => @error.code) {@error.to_s.to_xs}
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# 2.7.2
|
|
192
|
+
# CAS 2.0 proxy request response.
|
|
193
|
+
def proxy
|
|
194
|
+
if @success
|
|
195
|
+
tag!("cas:serviceResponse", 'xmlns:cas' => "http://www.yale.edu/tp/cas") do
|
|
196
|
+
tag!("cas:proxySuccess") do
|
|
197
|
+
tag!("cas:proxyTicket") {@pt.to_s.to_xs}
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
else
|
|
201
|
+
tag!("cas:serviceResponse", 'xmlns:cas' => "http://www.yale.edu/tp/cas") do
|
|
202
|
+
tag!("cas:proxyFailure", :code => @error.code) {@error.to_s.to_xs}
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def configure
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
protected
|
|
211
|
+
def themes_dir
|
|
212
|
+
File.dirname(File.expand_path(__FILE__))+'../themes'
|
|
213
|
+
end
|
|
214
|
+
module_function :themes_dir
|
|
215
|
+
|
|
216
|
+
def current_theme
|
|
217
|
+
CASServer::Conf.theme || "simple"
|
|
218
|
+
end
|
|
219
|
+
module_function :current_theme
|
|
220
|
+
|
|
221
|
+
def organization
|
|
222
|
+
CASServer::Conf.organization || ""
|
|
223
|
+
end
|
|
224
|
+
module_function :organization
|
|
225
|
+
|
|
226
|
+
def infoline
|
|
227
|
+
CASServer::Conf.infoline || ""
|
|
228
|
+
end
|
|
229
|
+
module_function :infoline
|
|
230
|
+
|
|
231
|
+
def serialize_extra_attribute(value)
|
|
232
|
+
if value.kind_of?(String) || value.kind_of?(Numeric)
|
|
233
|
+
value
|
|
234
|
+
else
|
|
235
|
+
"<![CDATA[#{value.to_yaml}]]>"
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
module_function :serialize_extra_attribute
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
if CASServer::Conf.custom_views_file
|
|
242
|
+
require CASServer::Conf.custom_views_file
|
|
243
|
+
end
|
data/lib/casserver.rb
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
$: << File.dirname(File.expand_path(__FILE__))
|
|
2
|
+
require 'casserver/environment'
|
|
3
|
+
|
|
4
|
+
$APP_PATH ||= File.dirname(File.expand_path(__FILE__))
|
|
5
|
+
|
|
6
|
+
# change to current directory when invoked on its own
|
|
7
|
+
Dir.chdir($APP_PATH) if __FILE__ == $0
|
|
8
|
+
|
|
9
|
+
$: << $APP_PATH + "/../vendor/isaac_0.9.1"
|
|
10
|
+
require 'crypt/ISAAC'
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
require 'active_support'
|
|
14
|
+
require 'yaml'
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# Camping.goes must be called after the authenticator class is loaded, otherwise weird things happen
|
|
18
|
+
Camping.goes :CASServer
|
|
19
|
+
|
|
20
|
+
$CONFIG_FILE ||= '/etc/rubycas-server/config.yml'
|
|
21
|
+
|
|
22
|
+
# for some reason this makes JRuby happy
|
|
23
|
+
class CASServer::Models::Base
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
CASServer.picnic!
|
|
27
|
+
|
|
28
|
+
$CONF[:expire_sessions] ||= false
|
|
29
|
+
$CONF[:login_ticket_expiry] ||= 5.minutes
|
|
30
|
+
$CONF[:service_ticket_expiry] ||= 5.minutes # CAS Protocol Spec, sec. 3.2.1 (recommended expiry time)
|
|
31
|
+
$CONF[:proxy_granting_ticket_expiry] ||= 48.hours
|
|
32
|
+
$CONF[:ticket_granting_ticket_expiry] ||= 48.hours
|
|
33
|
+
$CONF[:log] ||= {:file => 'casserver.log', :level => 'DEBUG'}
|
|
34
|
+
$CONF[:uri_path] ||= "/"
|
|
35
|
+
|
|
36
|
+
unless $CONF[:authenticator]
|
|
37
|
+
$stderr.puts
|
|
38
|
+
$stderr.puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
|
39
|
+
$stderr.puts
|
|
40
|
+
$stderr.puts "You have not yet defined an authenticator for your CAS server!"
|
|
41
|
+
$stderr.puts "Please consult your config file at #{$CONFIG_FILE.inspect} for details."
|
|
42
|
+
$stderr.puts
|
|
43
|
+
$stderr.puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
|
44
|
+
exit 1
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
require 'casserver/utils'
|
|
48
|
+
require 'casserver/models'
|
|
49
|
+
require 'casserver/cas'
|
|
50
|
+
require 'casserver/views'
|
|
51
|
+
require 'casserver/controllers'
|
|
52
|
+
|
|
53
|
+
if $CONF[:authenticator].instance_of? Array
|
|
54
|
+
$CONF[:authenticator].each_index do |auth_index|
|
|
55
|
+
$CONF[:authenticator][auth_index] = HashWithIndifferentAccess.new($CONF[:authenticator][auth_index])
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
$AUTH = []
|
|
60
|
+
begin
|
|
61
|
+
# attempt to instantiate the authenticator
|
|
62
|
+
if $CONF[:authenticator].instance_of? Array
|
|
63
|
+
$CONF[:authenticator].each { |authenticator| $AUTH << authenticator[:class].constantize.new}
|
|
64
|
+
else
|
|
65
|
+
$AUTH << $CONF[:authenticator][:class].constantize.new
|
|
66
|
+
end
|
|
67
|
+
rescue NameError
|
|
68
|
+
if $CONF[:authenticator].instance_of? Array
|
|
69
|
+
$CONF[:authenticator].each do |authenticator|
|
|
70
|
+
if !authenticator[:source].nil?
|
|
71
|
+
# config.yml explicitly names source file
|
|
72
|
+
require authenticator[:source]
|
|
73
|
+
else
|
|
74
|
+
# the authenticator class hasn't yet been loaded, so lets try to load it from the casserver/authenticators directory
|
|
75
|
+
auth_rb = authenticator[:class].underscore.gsub('cas_server/', '')
|
|
76
|
+
require 'casserver/'+auth_rb
|
|
77
|
+
end
|
|
78
|
+
$AUTH << authenticator[:class].constantize.new
|
|
79
|
+
end
|
|
80
|
+
else
|
|
81
|
+
if !$CONF[:authenticator][:source].nil?
|
|
82
|
+
# config.yml explicitly names source file
|
|
83
|
+
require $CONF[:authenticator][:source]
|
|
84
|
+
else
|
|
85
|
+
# the authenticator class hasn't yet been loaded, so lets try to load it from the casserver/authenticators directory
|
|
86
|
+
auth_rb = $CONF[:authenticator][:class].underscore.gsub('cas_server/', '')
|
|
87
|
+
require 'casserver/'+auth_rb
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
$AUTH << $CONF[:authenticator][:class].constantize.new
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
$CONF[:public_dir] = {
|
|
95
|
+
:path => "/themes",
|
|
96
|
+
:dir => File.expand_path(File.dirname(__FILE__))+"/themes"
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
def CASServer.create
|
|
100
|
+
$LOG.info "Creating RubyCAS-Server..."
|
|
101
|
+
CASServer::Models::Base.establish_connection(CASServer::Conf.database)
|
|
102
|
+
CASServer::Models.create_schema
|
|
103
|
+
|
|
104
|
+
CASServer::Models::ServiceTicket.cleanup_expired(CASServer::Conf.service_ticket_expiry)
|
|
105
|
+
CASServer::Models::LoginTicket.cleanup_expired(CASServer::Conf.login_ticket_expiry)
|
|
106
|
+
CASServer::Models::ProxyGrantingTicket.cleanup_expired(CASServer::Conf.proxy_granting_ticket_expiry)
|
|
107
|
+
CASServer::Models::TicketGrantingTicket.cleanup_expired(CASServer::Conf.ticket_granting_ticket_expiry)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
CASServer.start_picnic
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require File.dirname(__FILE__)+'/../casserver/version.rb'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'lib/casserver'
|
data/lib/themes/cas.css
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
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
|
+
|
|
54
|
+
#username,
|
|
55
|
+
#password {
|
|
56
|
+
width: 10em;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
#login-form {
|
|
60
|
+
padding: 20px;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
#form-layout {
|
|
65
|
+
position: relative;
|
|
66
|
+
top: 6px;
|
|
67
|
+
width: 100%;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
#form-layout td {
|
|
71
|
+
text-align: center;
|
|
72
|
+
padding-bottom: 8px;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
#form-layout td#submit-container {
|
|
76
|
+
text-align: right;
|
|
77
|
+
padding-right: 10px;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
#infoline {
|
|
81
|
+
font-size: 9px;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
#messagebox-container {
|
|
85
|
+
padding-left: 11px;
|
|
86
|
+
padding-right: 16px;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
div.messagebox {
|
|
90
|
+
font-size: 12px;
|
|
91
|
+
padding: 5px;
|
|
92
|
+
padding-left: 55px;
|
|
93
|
+
text-align: center;
|
|
94
|
+
width: 70%;
|
|
95
|
+
min-height: 34px;
|
|
96
|
+
vertical-align: middle;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
div.mistake {
|
|
100
|
+
color: #d00;
|
|
101
|
+
background-image: url(warning.png);
|
|
102
|
+
background-repeat: no-repeat;
|
|
103
|
+
background-position: 10px 5px;
|
|
104
|
+
font-weight: bold;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
div.confirmation {
|
|
108
|
+
color: #280;
|
|
109
|
+
background-image: url(ok.png);
|
|
110
|
+
background-repeat: no-repeat;
|
|
111
|
+
background-position: 10px 5px;
|
|
112
|
+
font-weight: bold;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
div.notice {
|
|
116
|
+
color: #04c;
|
|
117
|
+
background-image: url(notice.png);
|
|
118
|
+
background-repeat: no-repeat;
|
|
119
|
+
background-position: 10px 5px;
|
|
120
|
+
font-weight: bold;
|
|
121
|
+
}
|
|
Binary file
|
data/lib/themes/ok.png
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|