rubycas-server 0.1.0

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.
@@ -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
+ }