rubycas-server 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,109 @@
1
+ require 'camping/db'
2
+
3
+ module CASServer::Models
4
+
5
+ module Consumable
6
+ def consume!
7
+ self.consumed = Time.now
8
+ self.save!
9
+ end
10
+ end
11
+
12
+ class Ticket < Base
13
+ self.abstract_class = true
14
+ def to_s
15
+ ticket
16
+ end
17
+
18
+ def self.cleanup_expired(expiry_time)
19
+ transaction do
20
+ expired_tickets = find(:all,
21
+ :conditions => ["created_on < ?", Time.now - expiry_time])
22
+
23
+ $LOG.debug("Destroying #{expired_tickets.size} expired #{self}"+
24
+ "#{'s' if expired_tickets.size > 1}.") if expired_tickets.size > 0
25
+
26
+ expired_tickets.each do |t|
27
+ t.destroy
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ class LoginTicket < Ticket
34
+ include Consumable
35
+ end
36
+
37
+ class ServiceTicket < Ticket
38
+ include Consumable
39
+ end
40
+
41
+ class ProxyTicket < ServiceTicket
42
+ belongs_to :proxy_granting_ticket
43
+ end
44
+
45
+ class TicketGrantingTicket < Ticket
46
+ end
47
+
48
+ class ProxyGrantingTicket < Ticket
49
+ belongs_to :service_ticket
50
+ has_many :proxy_tickets, :dependent => :destroy
51
+ end
52
+
53
+ class Error
54
+ attr_reader :code, :message
55
+
56
+ def initialize(code, message)
57
+ @code = code
58
+ @message = message
59
+ end
60
+
61
+ def to_s
62
+ message
63
+ end
64
+ end
65
+
66
+ class CreateCASServer < V 0.1
67
+ def self.up
68
+ $LOG.info("Migrating database")
69
+
70
+ create_table :casserver_login_tickets, :force => true do |t|
71
+ t.column :ticket, :string, :null => false
72
+ t.column :created_on, :timestamp, :null => false
73
+ t.column :consumed, :datetime, :null => true
74
+ t.column :client_hostname, :string, :null => false
75
+ end
76
+
77
+ create_table :casserver_service_tickets, :force => true do |t|
78
+ t.column :ticket, :string, :null => false
79
+ t.column :service, :string, :null => false
80
+ t.column :created_on, :timestamp, :null => false
81
+ t.column :consumed, :datetime, :null => true
82
+ t.column :client_hostname, :string, :null => false
83
+ t.column :username, :string, :null => false
84
+ t.column :type, :string, :null => false
85
+ t.column :proxy_granting_ticket_id, :integer, :null => true
86
+ end
87
+
88
+ create_table :casserver_ticket_granting_tickets, :force => true do |t|
89
+ t.column :ticket, :string, :null => false
90
+ t.column :created_on, :timestamp, :null => false
91
+ t.column :client_hostname, :string, :null => false
92
+ t.column :username, :string, :null => false
93
+ end
94
+
95
+ create_table :casserver_proxy_granting_tickets, :force => true do |t|
96
+ t.column :ticket, :string, :null => false
97
+ t.column :created_on, :timestamp, :null => false
98
+ t.column :client_hostname, :string, :null => false
99
+ t.column :iou, :string, :null => false
100
+ t.column :service_ticket_id, :integer, :null => false
101
+ end
102
+ end
103
+
104
+ def self.down
105
+ drop_table :casserver_service_tickets
106
+ drop_table :casserver_login_tickets
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,33 @@
1
+ # Misc utility function used throughout by the RubyCAS-server.
2
+ module CASServer
3
+ module Utils
4
+ def random_string
5
+ "#{Time.now.to_i}r%X" % rand(10**32)
6
+ end
7
+ module_function :random_string
8
+
9
+ class Logger < ::Logger
10
+ def initialize(logdev, shift_age = 0, shift_size = 1048576)
11
+ begin
12
+ super
13
+ rescue Exception
14
+ puts "WARNING: Couldn't create Logger with output '#{logdev}'. Logger output will be redirected to STDOUT."
15
+ super(STDOUT, shift_age, shift_size)
16
+ end
17
+ end
18
+
19
+ def format_message(severity, datetime, progrname, msg)
20
+ (@formatter || @default_formatter).call(severity, datetime, progname, msg)
21
+ end
22
+ end
23
+ end
24
+
25
+ class LogFormatter < ::Logger::Formatter
26
+ Format = "[%s#%d] %5s -- %s: %s\n"
27
+
28
+ def call(severity, time, progname, msg)
29
+ Format % [format_datetime(time), $$, severity, progname,
30
+ msg2str(msg)]
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,9 @@
1
+ module CASServer
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ TINY = 0
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -0,0 +1,185 @@
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
+ module CASServer::Views
5
+
6
+ # need to turn off autovalidation to render CAS xml responses
7
+ #
8
+
9
+ def layout
10
+ # wrap as XHTML only when auto_validation is on, otherwise pass right through
11
+ if @auto_validation
12
+ xhtml_strict do
13
+ head do
14
+ title { "#{organization} Central Login" }
15
+ link(:rel => "stylesheet", :type => "text/css", :href => "/themes/cas.css")
16
+ link(:rel => "stylesheet", :type => "text/css", :href => "/themes/#{current_theme}/theme.css")
17
+ end
18
+ body(:onload => "if (document.getElementById('username')) document.getElementById('username').focus()") do
19
+ self << yield
20
+ end
21
+ end
22
+ else
23
+ self << yield
24
+ end
25
+ end
26
+
27
+
28
+ # 2.1.3
29
+ def login
30
+ @logo =
31
+
32
+ table(:id => "login-box") do
33
+ tr do
34
+ td(:colspan => 2) do
35
+ div(:id => "headline-container") do
36
+ strong organization
37
+ text "Central Login"
38
+ end
39
+ end
40
+ end
41
+ if @message
42
+ tr do
43
+ td(:colspan => 2, :id => "messagebox-container") do
44
+ div(:class => "messagebox #{@message[:type]}") { @message[:message] }
45
+ end
46
+ end
47
+ end
48
+ tr do
49
+ td(:id => "logo-container") do
50
+ img(:id => "logo", :src => "/themes/#{current_theme}/logo.png")
51
+ end
52
+ td(:id => "login-form-container") do
53
+ form(:method => "post", :action => "/login", :id => "login-form",
54
+ :onsubmit => "submit = document.getElementById('login-submit'); submit.value='Please wait...'; submit.disabled=true; return true;") do
55
+ table(:id => "form-layout") do
56
+ tr do
57
+ td(:id => "username-label-container") do
58
+ label(:id => "username-label", :for => "username") { "Username" }
59
+ end
60
+ td(:id => "username-container") do
61
+ input(:type => "text", :id => "username", :name => "username", :size => "32", :tabindex => "1", :accesskey => "n")
62
+ end
63
+ end
64
+ tr do
65
+ td(:id => "password-label-container") do
66
+ label(:id => "password-label", :for => "password") { "Password" }
67
+ end
68
+ td(:id => "password-container") do
69
+ input(:type => "password", :id => "password", :name => "password", :size => "32", :tabindex => "2", :accesskey => "p")
70
+ end
71
+ end
72
+ tr do
73
+ td{}
74
+ td(:id => "submit-container") do
75
+ input(:type => "hidden", :id => "lt", :name => "lt", :value => @lt)
76
+ input(:type => "hidden", :id => "service", :name => "service", :value => @service)
77
+ input(:type => "hidden", :id => "warn", :name => "warn", :value => @warn)
78
+ input(:type => "submit", :class => "button", :accesskey => "l", :value => "LOGIN", :tabindex => "4", :id => "login-submit")
79
+ end
80
+ end
81
+ tr do
82
+ td(:colspan => 2, :id => "infoline") { infoline }
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ # 2.4.2
92
+ def validate
93
+ @auto_validation = false
94
+ if @success
95
+ text "yes\n#{@username}\n"
96
+ else
97
+ text "no\n\n"
98
+ end
99
+ end
100
+
101
+ # 2.5.2
102
+ def service_validate
103
+ @auto_validation = false
104
+ if @success
105
+ tag!("cas:serviceResponse", 'xmlns:cas' => "http://www.yale.edu/tp/cas") do
106
+ tag!("cas:authenticationSuccess") do
107
+ tag!("cas:user") {@username}
108
+ if @pgtiou
109
+ tag!("cas:proxyGrantingTicket") {@pgtiou}
110
+ end
111
+ end
112
+ end
113
+ else
114
+ tag!("cas:serviceResponse", 'xmlns:cas' => "http://www.yale.edu/tp/cas") do
115
+ tag!("cas:authenticationFailure", :code => @error.code) {@error}
116
+ end
117
+ end
118
+ end
119
+
120
+ # 2.6.2
121
+ def proxy_validate
122
+ @auto_validation = false
123
+ if @success
124
+ tag!("cas:serviceResponse", 'xmlns:cas' => "http://www.yale.edu/tp/cas") do
125
+ tag!("cas:authenticationSuccess") do
126
+ tag!("cas:user") {@username}
127
+ if @pgtiou
128
+ tag!("cas:proxyGrantingTicket") {@pgtiou}
129
+ end
130
+ if @proxies && !@proxies.empty?
131
+ tag!("cas:proxies") do
132
+ @proxies.each do |proxy_url|
133
+ tag!("cas:proxy") {proxy_url}
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
139
+ else
140
+ tag!("cas:serviceResponse", 'xmlns:cas' => "http://www.yale.edu/tp/cas") do
141
+ tag!("cas:authenticationFailure", :code => @error.code) {@error}
142
+ end
143
+ end
144
+ end
145
+
146
+ # 2.7.2
147
+ def proxy
148
+ @auto_validation = false
149
+ if @success
150
+ tag!("cas:serviceResponse", 'xmlns:cas' => "http://www.yale.edu/tp/cas") do
151
+ tag!("cas:proxySuccess") do
152
+ tag!("cas:proxyTicket") {@pt}
153
+ end
154
+ end
155
+ else
156
+ tag!("cas:serviceResponse", 'xmlns:cas' => "http://www.yale.edu/tp/cas") do
157
+ tag!("cas:proxyFailure", :code => @error.code) {@error}
158
+ end
159
+ end
160
+ end
161
+
162
+ def configure
163
+ end
164
+
165
+ protected
166
+ def themes_dir
167
+ File.dirname(File.expand_path(__FILE__))+'../themes'
168
+ end
169
+ module_function :themes_dir
170
+
171
+ def current_theme
172
+ CASServer::Conf.theme || "simple"
173
+ end
174
+ module_function :current_theme
175
+
176
+ def organization
177
+ CASServer::Conf.organization || ""
178
+ end
179
+ module_function :organization
180
+
181
+ def infoline
182
+ CASServer::Conf.infoline || ""
183
+ end
184
+ module_function :infoline
185
+ end
@@ -0,0 +1,112 @@
1
+ * {
2
+ font-family: Verdana, sans-serif;
3
+ }
4
+
5
+ body {
6
+ }
7
+
8
+ label {
9
+ font-weight: bold;
10
+ font-size: 9px;
11
+ }
12
+
13
+ input {
14
+ font-weight: normal;
15
+ font-size: 12px;
16
+ }
17
+
18
+ input.button {
19
+ /*font-weight: bold;*/
20
+ font-size: 10px;
21
+ }
22
+
23
+ #login-box {
24
+ margin: 0 auto;
25
+ width: 350px;
26
+ top: 130px;
27
+ position: relative;
28
+ }
29
+
30
+ #headline-container {
31
+ text-align: right;
32
+ border-bottom: 1px solid #899989;
33
+ font-family: Tahoma, Verdana, sans-serif;
34
+ font-size: 22px;
35
+ margin-right: 0px;
36
+ padding-right: 7px;
37
+ margin-left: 10px;
38
+ letter-spacing: -0.25px;
39
+ }
40
+
41
+ #logo-container {
42
+ vertical-align: top;
43
+ }
44
+
45
+ #logo {
46
+ }
47
+
48
+ #login-form-container {
49
+ vertical-align: top;
50
+ }
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
+ #infoline {
80
+ font-size: 9px;
81
+ }
82
+
83
+ #messagebox-container {
84
+ padding-left: 11px;
85
+ padding-right: 16px;
86
+ }
87
+
88
+ div.messagebox {
89
+ font-size: 12px;
90
+ padding: 5px;
91
+ padding-left: 55px;
92
+ text-align: center;
93
+ width: 70%;
94
+ min-height: 34px;
95
+ vertical-align: middle;
96
+ }
97
+
98
+ div.mistake {
99
+ color: #d00;
100
+ background-image: url(warning.png);
101
+ background-repeat: no-repeat;
102
+ background-position: 10px 5px;
103
+ font-weight: bold;
104
+ }
105
+
106
+ div.confirmation {
107
+ color: #280;
108
+ background-image: url(ok.png);
109
+ background-repeat: no-repeat;
110
+ background-position: 10px 5px;
111
+ font-weight: bold;
112
+ }