rubycas-server 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +37 -0
- data/Manifest.txt +10 -0
- data/Rakefile +3 -2
- data/bin/rubycas-server-ctl +1 -1
- data/config.example.yml +44 -11
- data/custom_views.example.rb +11 -0
- data/lib/casserver/authenticators/ldap.rb +11 -5
- data/lib/casserver/conf.rb +35 -12
- data/lib/casserver/controllers.rb +111 -23
- data/lib/casserver/models.rb +23 -0
- data/lib/casserver/postambles.rb +21 -24
- data/lib/casserver/utils.rb +16 -0
- data/lib/casserver/version.rb +3 -3
- data/lib/casserver/views.rb +50 -36
- data/lib/casserver.rb +9 -2
- data/lib/themes/cas.css +1 -0
- data/vendor/camping-1.5.180/lib/camping/db.rb +78 -0
- data/vendor/camping-1.5.180/lib/camping/fastcgi.rb +244 -0
- data/vendor/camping-1.5.180/lib/camping/reloader.rb +163 -0
- data/vendor/camping-1.5.180/lib/camping/session.rb +123 -0
- data/vendor/camping-1.5.180/lib/camping/webrick.rb +65 -0
- data/vendor/camping-1.5.180/lib/camping-unabridged.rb +762 -0
- data/vendor/camping-1.5.180/lib/camping.rb +55 -0
- metadata +10 -11
@@ -0,0 +1,163 @@
|
|
1
|
+
module Camping
|
2
|
+
# == The Camping Reloader
|
3
|
+
#
|
4
|
+
# Camping apps are generally small and predictable. Many Camping apps are
|
5
|
+
# contained within a single file. Larger apps are split into a handful of
|
6
|
+
# other Ruby libraries within the same directory.
|
7
|
+
#
|
8
|
+
# Since Camping apps (and their dependencies) are loaded with Ruby's require
|
9
|
+
# method, there is a record of them in $LOADED_FEATURES. Which leaves a
|
10
|
+
# perfect space for this class to manage auto-reloading an app if any of its
|
11
|
+
# immediate dependencies changes.
|
12
|
+
#
|
13
|
+
# == Wrapping Your Apps
|
14
|
+
#
|
15
|
+
# Since bin/camping and the Camping::FastCGI class already use the Reloader,
|
16
|
+
# you probably don't need to hack it on your own. But, if you're rolling your
|
17
|
+
# own situation, here's how.
|
18
|
+
#
|
19
|
+
# Rather than this:
|
20
|
+
#
|
21
|
+
# require 'yourapp'
|
22
|
+
#
|
23
|
+
# Use this:
|
24
|
+
#
|
25
|
+
# require 'camping/reloader'
|
26
|
+
# Camping::Reloader.new('/path/to/yourapp.rb')
|
27
|
+
#
|
28
|
+
# The reloader will take care of requiring the app and monitoring all files
|
29
|
+
# for alterations.
|
30
|
+
class Reloader
|
31
|
+
attr_accessor :klass, :mtime, :mount, :requires
|
32
|
+
|
33
|
+
# Creates the reloader, assigns a +script+ to it and initially loads the
|
34
|
+
# application. Pass in the full path to the script, otherwise the script
|
35
|
+
# will be loaded relative to the current working directory.
|
36
|
+
def initialize(script)
|
37
|
+
@script = File.expand_path(script)
|
38
|
+
@mount = File.basename(script, '.rb')
|
39
|
+
@requires = nil
|
40
|
+
load_app
|
41
|
+
end
|
42
|
+
|
43
|
+
# Find the application, based on the script name.
|
44
|
+
def find_app(title)
|
45
|
+
@klass = Object.const_get(Object.constants.grep(/^#{title}$/i)[0]) rescue nil
|
46
|
+
end
|
47
|
+
|
48
|
+
# If the file isn't found, if we need to remove the app from the global
|
49
|
+
# namespace, this will be sure to do so and set @klass to nil.
|
50
|
+
def remove_app
|
51
|
+
Object.send :remove_const, @klass.name if @klass
|
52
|
+
@klass = nil
|
53
|
+
end
|
54
|
+
|
55
|
+
# Loads (or reloads) the application. The reloader will take care of calling
|
56
|
+
# this for you. You can certainly call it yourself if you feel it's warranted.
|
57
|
+
def load_app
|
58
|
+
title = File.basename(@script)[/^([\w_]+)/,1].gsub /_/,''
|
59
|
+
begin
|
60
|
+
all_requires = $LOADED_FEATURES.dup
|
61
|
+
load @script
|
62
|
+
@requires = ($LOADED_FEATURES - all_requires).select do |req|
|
63
|
+
req.index(File.basename(@script) + "/") == 0 || req.index(title + "/") == 0
|
64
|
+
end
|
65
|
+
rescue Exception => e
|
66
|
+
puts "!! trouble loading #{title}: [#{e.class}] #{e.message}"
|
67
|
+
puts e.backtrace.join("\n")
|
68
|
+
find_app title
|
69
|
+
remove_app
|
70
|
+
return
|
71
|
+
end
|
72
|
+
|
73
|
+
@mtime = mtime
|
74
|
+
find_app title
|
75
|
+
unless @klass and @klass.const_defined? :C
|
76
|
+
puts "!! trouble loading #{title}: not a Camping app, no #{title.capitalize} module found"
|
77
|
+
remove_app
|
78
|
+
return
|
79
|
+
end
|
80
|
+
|
81
|
+
Reloader.conditional_connect
|
82
|
+
@klass.create if @klass.respond_to? :create
|
83
|
+
@klass
|
84
|
+
end
|
85
|
+
|
86
|
+
# The timestamp of the most recently modified app dependency.
|
87
|
+
def mtime
|
88
|
+
((@requires || []) + [@script]).map do |fname|
|
89
|
+
fname = fname.gsub(/^#{Regexp::quote File.dirname(@script)}\//, '')
|
90
|
+
begin
|
91
|
+
File.mtime(File.join(File.dirname(@script), fname))
|
92
|
+
rescue Errno::ENOENT
|
93
|
+
remove_app
|
94
|
+
@mtime
|
95
|
+
end
|
96
|
+
end.max
|
97
|
+
end
|
98
|
+
|
99
|
+
# Conditional reloading of the app. This gets called on each request and
|
100
|
+
# only reloads if the modification times on any of the files is updated.
|
101
|
+
def reload_app
|
102
|
+
return if @klass and @mtime and mtime <= @mtime
|
103
|
+
|
104
|
+
if @requires
|
105
|
+
@requires.each { |req| $LOADED_FEATURES.delete(req) }
|
106
|
+
end
|
107
|
+
k = @klass
|
108
|
+
Object.send :remove_const, k.name if k
|
109
|
+
load_app
|
110
|
+
end
|
111
|
+
|
112
|
+
# Conditionally reloads (using reload_app.) Then passes the request through
|
113
|
+
# to the wrapped Camping app.
|
114
|
+
def run(*a)
|
115
|
+
reload_app
|
116
|
+
if @klass
|
117
|
+
@klass.run(*a)
|
118
|
+
else
|
119
|
+
Camping.run(*a)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Returns source code for the main script in the application.
|
124
|
+
def view_source
|
125
|
+
File.read(@script)
|
126
|
+
end
|
127
|
+
|
128
|
+
class << self
|
129
|
+
def database=(db)
|
130
|
+
@database = db
|
131
|
+
end
|
132
|
+
def log=(log)
|
133
|
+
@log = log
|
134
|
+
end
|
135
|
+
def conditional_connect
|
136
|
+
# If database models are present, `autoload?` will return nil.
|
137
|
+
unless Camping::Models.autoload? :Base
|
138
|
+
require 'logger'
|
139
|
+
require 'camping/session'
|
140
|
+
Camping::Models::Base.establish_connection @database if @database
|
141
|
+
|
142
|
+
case @log
|
143
|
+
when Logger
|
144
|
+
Camping::Models::Base.logger = @log
|
145
|
+
when String
|
146
|
+
Camping::Models::Base.logger = Logger.new(@log == "-" ? STDOUT : @log)
|
147
|
+
end
|
148
|
+
|
149
|
+
Camping::Models::Session.create_schema
|
150
|
+
|
151
|
+
if @database and @database[:adapter] == 'sqlite3'
|
152
|
+
begin
|
153
|
+
require 'sqlite3_api'
|
154
|
+
rescue LoadError
|
155
|
+
puts "!! Your SQLite3 adapter isn't a compiled extension."
|
156
|
+
abort "!! Please check out http://code.whytheluckystiff.net/camping/wiki/BeAlertWhenOnSqlite3 for tips."
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# == About camping/session.rb
|
2
|
+
#
|
3
|
+
# This file contains two modules which supply basic sessioning to your Camping app.
|
4
|
+
# Again, we're dealing with a pretty little bit of code: approx. 60 lines.
|
5
|
+
#
|
6
|
+
# * Camping::Models::Session is a module which adds a single <tt>sessions</tt> table
|
7
|
+
# to your database.
|
8
|
+
# * Camping::Session is a module which you will mix into your application (or into
|
9
|
+
# specific controllers which require sessions) to supply a <tt>@state</tt> variable
|
10
|
+
# you can use in controllers and views.
|
11
|
+
#
|
12
|
+
# For a basic tutorial, see the *Getting Started* section of the Camping::Session module.
|
13
|
+
require 'camping'
|
14
|
+
|
15
|
+
module Camping::Models
|
16
|
+
# A database table for storing Camping sessions. Contains a unique 32-character hashid, a
|
17
|
+
# creation timestamp, and a column of serialized data called <tt>ivars</tt>.
|
18
|
+
class Session < Base
|
19
|
+
serialize :ivars
|
20
|
+
def []=(k, v) # :nodoc:
|
21
|
+
self.ivars[k] = v
|
22
|
+
end
|
23
|
+
def [](k) # :nodoc:
|
24
|
+
self.ivars[k] rescue nil
|
25
|
+
end
|
26
|
+
|
27
|
+
RAND_CHARS = [*'A'..'Z'] + [*'0'..'9'] + [*'a'..'z']
|
28
|
+
|
29
|
+
# Generates a new session ID and creates a row for the new session in the database.
|
30
|
+
def self.generate cookies
|
31
|
+
rand_max = RAND_CHARS.size
|
32
|
+
sid = (0...32).inject("") { |ret,_| ret << RAND_CHARS[rand(rand_max)] }
|
33
|
+
sess = Session.create :hashid => sid, :ivars => Camping::H[]
|
34
|
+
cookies.camping_sid = sess.hashid
|
35
|
+
sess
|
36
|
+
end
|
37
|
+
|
38
|
+
# Gets the existing session based on the <tt>camping_sid</tt> available in cookies.
|
39
|
+
# If none is found, generates a new session.
|
40
|
+
def self.persist cookies
|
41
|
+
if cookies.camping_sid
|
42
|
+
session = Camping::Models::Session.find_by_hashid cookies.camping_sid
|
43
|
+
end
|
44
|
+
unless session
|
45
|
+
session = Camping::Models::Session.generate cookies
|
46
|
+
end
|
47
|
+
session
|
48
|
+
end
|
49
|
+
|
50
|
+
# Builds the session table in the database. To be used in your application's
|
51
|
+
# <tt>create</tt> method.
|
52
|
+
#
|
53
|
+
# Like so:
|
54
|
+
#
|
55
|
+
# def Blog.create
|
56
|
+
# Camping::Models::Session.create_schema
|
57
|
+
# unless Blog::Models::Post.table_exists?
|
58
|
+
# ActiveRecord::Schema.define(&Blog::Models.schema)
|
59
|
+
# end
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
def self.create_schema
|
63
|
+
unless table_exists?
|
64
|
+
ActiveRecord::Schema.define do
|
65
|
+
create_table :sessions, :force => true do |t|
|
66
|
+
t.column :id, :integer, :null => false
|
67
|
+
t.column :hashid, :string, :limit => 32
|
68
|
+
t.column :created_at, :datetime
|
69
|
+
t.column :ivars, :text
|
70
|
+
end
|
71
|
+
end
|
72
|
+
reset_column_information
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
module Camping
|
79
|
+
# The Camping::Session module is designed to be mixed into your application or into specific
|
80
|
+
# controllers which require sessions. This module defines a <tt>service</tt> method which
|
81
|
+
# intercepts all requests handed to those controllers.
|
82
|
+
#
|
83
|
+
# == Getting Started
|
84
|
+
#
|
85
|
+
# To get sessions working for your application:
|
86
|
+
#
|
87
|
+
# 1. <tt>require 'camping/session'</tt>
|
88
|
+
# 2. Mixin the module: <tt>module YourApp; include Camping::Session end</tt>
|
89
|
+
# 3. In your application's <tt>create</tt> method, add a call to <tt>Camping::Models::Session.create_schema</tt>
|
90
|
+
# 4. Throughout your application, use the <tt>@state</tt> var like a hash to store your application's data.
|
91
|
+
#
|
92
|
+
# If you are unfamiliar with the <tt>create</tt> method, see
|
93
|
+
# http://code.whytheluckystiff.net/camping/wiki/GiveUsTheCreateMethod.
|
94
|
+
#
|
95
|
+
# == A Few Notes
|
96
|
+
#
|
97
|
+
# * The session ID is stored in a cookie. Look in <tt>@cookies.camping_sid</tt>.
|
98
|
+
# * The session data is stored in the <tt>sessions</tt> table in your database.
|
99
|
+
# * All mounted Camping apps using this class will use the same database table.
|
100
|
+
# * However, your application's data is stored in its own hash.
|
101
|
+
# * Session data is only saved if it has changed.
|
102
|
+
module Session
|
103
|
+
# This <tt>service</tt> method, when mixed into controllers, intercepts requests
|
104
|
+
# and wraps them with code to start and close the session. If a session isn't found
|
105
|
+
# in the database it is created. The <tt>@state</tt> variable is set and if it changes,
|
106
|
+
# it is saved back into the database.
|
107
|
+
def service(*a)
|
108
|
+
session = Camping::Models::Session.persist @cookies
|
109
|
+
app = self.class.name.gsub(/^(\w+)::.+$/, '\1')
|
110
|
+
@state = (session[app] ||= Camping::H[])
|
111
|
+
hash_before = Marshal.dump(@state).hash
|
112
|
+
s = super(*a)
|
113
|
+
if session
|
114
|
+
hash_after = Marshal.dump(@state).hash
|
115
|
+
unless hash_before == hash_after
|
116
|
+
session[app] = @state
|
117
|
+
session.save
|
118
|
+
end
|
119
|
+
end
|
120
|
+
s
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# == About camping/webrick.rb
|
2
|
+
#
|
3
|
+
# For many who have Ruby installed, Camping and WEBrick is a great option.
|
4
|
+
# It's definitely the easiest configuration, however some performance is sacrificed.
|
5
|
+
# For better speed, check out Mongrel at http://mongrel.rubyforge.org/, which comes
|
6
|
+
# with Camping hooks and is supported by the Camping Tool.
|
7
|
+
require 'camping'
|
8
|
+
require 'webrick/httpservlet/abstract.rb'
|
9
|
+
|
10
|
+
module WEBrick
|
11
|
+
# WEBrick::CampingHandler is a very simple handle for hosting Camping apps in
|
12
|
+
# a WEBrick server. It's used much like any other WEBrick handler.
|
13
|
+
#
|
14
|
+
# == Mounting a Camping App
|
15
|
+
#
|
16
|
+
# Assuming Camping.goes(:Blog), the Blog application can be mounted alongside
|
17
|
+
# other WEBrick mounts.
|
18
|
+
#
|
19
|
+
# s = WEBrick::HTTPServer.new(:BindAddress => host, :Port => port)
|
20
|
+
# s.mount "/blog", WEBrick::CampingHandler, Blog
|
21
|
+
# s.mount_proc("/") { ... }
|
22
|
+
#
|
23
|
+
# == How Does it Compare?
|
24
|
+
#
|
25
|
+
# Compared to other handlers, WEBrick is well-equipped in terms of features.
|
26
|
+
#
|
27
|
+
# * The <tt>X-Sendfile</tt> header is supported, along with etags and
|
28
|
+
# modification time headers for the file served. Since this handler
|
29
|
+
# is a subclass of WEBrick::HTTPServlet::DefaultFileHandler, all of its
|
30
|
+
# logic is used.
|
31
|
+
# * IO is streaming up and down. When you upload a file, it is streamed to
|
32
|
+
# the server's filesystem. When you download a file, it is streamed to
|
33
|
+
# your browser.
|
34
|
+
#
|
35
|
+
# While WEBrick is a bit slower than Mongrel and FastCGI options, it's
|
36
|
+
# a decent choice, for sure!
|
37
|
+
class CampingHandler < WEBrick::HTTPServlet::DefaultFileHandler
|
38
|
+
# Creates a CampingHandler, which answers for the application within +klass+.
|
39
|
+
def initialize(server, klass)
|
40
|
+
super(server, klass)
|
41
|
+
@klass = klass
|
42
|
+
end
|
43
|
+
# Handler for WEBrick requests (also aliased as do_POST).
|
44
|
+
def service(req, resp)
|
45
|
+
controller = @klass.run((req.body and StringIO.new(req.body)), req.meta_vars)
|
46
|
+
resp.status = controller.status
|
47
|
+
@local_path = nil
|
48
|
+
controller.headers.each do |k, v|
|
49
|
+
if k =~ /^X-SENDFILE$/i
|
50
|
+
@local_path = v
|
51
|
+
else
|
52
|
+
[*v].each do |vi|
|
53
|
+
resp[k] = vi
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
if @local_path
|
59
|
+
do_GET(req, resp)
|
60
|
+
else
|
61
|
+
resp.body = controller.body.to_s
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|