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,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require_gem 'rubycas-server'
5
+
6
+ $RUN = true
7
+
8
+ load 'casserver.rb'
@@ -0,0 +1,197 @@
1
+ # IMPORTANT NOTE ABOUT YAML CONFIGURATION FILES
2
+ # ---> Be sure to use spaces instead of tabs for indentation. Yaml is white-space sensitive!
3
+
4
+ ##### SERVER ########################################################################
5
+
6
+ # Under what environment are you running the CAS server? The following methods
7
+ # are currently supported:
8
+ #
9
+ # webrick -- run as a stand-alone webrick server; this is the default method
10
+ # mongrel -- run as a stand-alone mongrel server; fast, but you'll need to install
11
+ # mongrel and run it behind an https reverse proxy like Pound or Apache 2.2's mod_proxy)
12
+ # cgi -- slow, but simple to set up if you're already familliar with deploying CGI scripts
13
+ # fastcgi -- see http://www.fastcgi.com (e.g. under Apache you can use this with mod_fastcgi)
14
+ #
15
+ # The cgi and fastcgi methods have not been thoroughly tested!
16
+ # Please report any problems to the authors.
17
+ #
18
+ # IMPORTANT: If you use mongrel, you will need to run the server behind a reverse proxy
19
+ # (Pound, Apache 2.2 with mod_proxy, etc.) since mongrel does not support SSL/HTTPS.
20
+ # See the RubyCAS-Server install docs for more info. Also, mongrel requries
21
+ # Camping 1.5.180 which as of writing is only available via SVN. You can install
22
+ # this by running `gem install camping --source code.whytheluckystiff.net`
23
+
24
+ ### webrick example
25
+
26
+ server: webrick
27
+ port: 443
28
+ ssl_cert: /path/to/your/ssl.pem
29
+ # ssl_key: /path/to/your/private_key.pem <-- if private key is separate from cert
30
+
31
+ ### mongrel example (you will need to run this behind an https reverse proxy,
32
+ ### since mongrel doesn't support SSL on its own)
33
+
34
+ #server: mongrel
35
+ #port: 110011
36
+
37
+ ### cgi example (you'll need to serve this via an SSL-capable server like Apache)
38
+
39
+ #server: cgi
40
+
41
+ ### fastcgi example (you'll need to serve this via an SSL-capable server like Apache)
42
+
43
+ #server: fastcgi
44
+
45
+
46
+ ##### DATABASE #######################################################################
47
+
48
+ # Set up the database connection. Make sure that this database is secure!
49
+ #
50
+ # By default, we use sqlite3 since it works without any extra configuration.
51
+ # You can also use MySQL, PostgreSQL, MSSQL, or anything else supported by ActiveRecord.
52
+ #
53
+ # For example, with MySQL, your config wold be something like:
54
+ #
55
+ #database:
56
+ # adapter: mysql
57
+ # database: casserver
58
+ # user: root
59
+ # password:
60
+ # server: localhost
61
+ #
62
+
63
+ database:
64
+ adapter: sqlite3
65
+ dbfile: /var/lib/casserver.db
66
+
67
+
68
+ ##### AUTHENTICATION #################################################################
69
+
70
+ # Configure how username/passwords are validated.
71
+ #
72
+ # !!! YOU MUST CONFIGURE ONE (AND ONLY ONE) OF THESE AUTHENTICATION METHODS !!!
73
+ #
74
+ # Currently there are three built-in methods for authentication:
75
+ # SQL, ActiveDirectory, and LDAP. If none of these work for you, it is relatively
76
+ # easy to write your own custom Authenticator class.
77
+ #
78
+ # ==> SQL Authentication:
79
+ # The simplest method is to validate against a SQL database. This assumes
80
+ # that all of your users are stored in a table that has a 'username' column
81
+ # and a 'password' column. When the user logs in, CAS conects to this database
82
+ # and look for a matching username/password in the users table. If a matching
83
+ # username and password is found, authentication is successful.
84
+ #
85
+ # Example:
86
+ #
87
+ #authenticator:
88
+ # class: CASServer::Authenticators::SQL
89
+ # database:
90
+ # adapter: mysql
91
+ # database: some_database_with_users_table
92
+ # user: root
93
+ # password:
94
+ # server: localhost
95
+ # user_table: user
96
+ # username_column: username
97
+ # password_column: password
98
+ #
99
+ #
100
+ # ==> ActiveDirectory Authentication:
101
+ # This method authenticates against Microsoft's ActiveDirectory using LDAP.
102
+ # You must enter your ActiveDirectory server, and base DN. The port number
103
+ # and LDAP filter are optional. You must also enter a username and password
104
+ # for an "authenticator" user. The authenticator users this account to
105
+ # log in to the ActiveDirectory server and search LDAP. This does not have
106
+ # to be an administrative account; it only has to be able to search for other
107
+ # users.
108
+ #
109
+ # Example:
110
+ #
111
+ #authenticator:
112
+ # class: CASServer::Authenticators::ActiveDirectoryLDAP
113
+ # ldap:
114
+ # server: ad.example.net
115
+ # port: 389
116
+ # base: dc=example,dc=net
117
+ # filter: (objectClass=person)
118
+ # auth_user: authenticator
119
+ # auth_password: itsasecret
120
+ #
121
+ #
122
+ # ==> LDAP Authentication:
123
+ # This is a more general version of the ActiveDirectory authenticator.
124
+ # The configuration is similar, except you don't need an authenticator
125
+ # username or password. Note that this authenticator hasn't been widely
126
+ # tested, so it is not guaranteed to work.
127
+ #
128
+ #authenticator:
129
+ # class: CASServer::Authenticators::ActiveDirectoryLDAP
130
+ # ldap:
131
+ # server: ad.example.net
132
+ # port: 389
133
+ # base: dc=example,dc=net
134
+ # filter: (objectClass=person)
135
+ #
136
+ #
137
+ # ==> Custom Authentication:
138
+ # It should be relatively easy to write your own Authenticator class. Have a look
139
+ # at the built-in authenticators in the casserver/authenticators directory. Your
140
+ # authenticator should extend the CASServer::Authenticators::Base class and must
141
+ # implement a validate() method that takes a single hash argument. When the user submits
142
+ # the login form, the username and password they entered is passed to validate()
143
+ # as a hash under :username and :password keys. In the future, this hash
144
+ # might also contain other data such as the domain that the user is logging in to.
145
+ #
146
+ # To use your custom authenticator, specify it's class name in the authenticator section
147
+ # of the config. You will also probably have to load the class using using a `require`
148
+ # call at the top of casserver.rb. Any other parameters you specify in the authenticator
149
+ # configuration will be passed on to the authenticator and made availabe in the validate()
150
+ # method as an @options hash.
151
+ #
152
+ # Example:
153
+ #
154
+ #authenticator:
155
+ # class: FooModule::MyCustomAuthenticator
156
+ # option_a: foo
157
+ # another_option: yeeha
158
+
159
+
160
+ ##### LOOK & FEEL ######################################################################
161
+
162
+ # Set the path to the theme directory that determines how your CAS pages look.
163
+ #
164
+ # Custom themes are not well supported yet, but will be in the near future. In the
165
+ # meantime, if you want to create a custom theme, you can create a subdirectory
166
+ # under the CASServer's themes dir (for example '/usr/lib/ruby/1.8/gems/casserver-xxx/lib/themes',
167
+ # if you installed CASServer on Linux as a gem). A theme is basically just a theme.css
168
+ # file that overrides the themes/cas.css styles along with a collection of image files
169
+ # like logo.png and bg.png.
170
+ #
171
+ # By default, we use the 'simple' theme which you can find in themes/simple.
172
+ theme: simple
173
+
174
+ # The name of your company/organization. This will show up on the login page.
175
+ organization: CAS
176
+
177
+ # A short bit of text that shows up on the login page. You can make this blank if you prefer.
178
+ infoline: Powered by <a href="http://code.google.com/p/rubycas-server/">RubyCAS-Server</a>
179
+
180
+
181
+ ##### LOGGING #########################################################################
182
+
183
+ # Configure general logging. This log is where you'll want to look in case of problems.
184
+ #
185
+ # You may want to change the file to something like /var/log/casserver.log
186
+ # Set the level to DEBUG if you want more detailed logging.
187
+
188
+ log:
189
+ file: /var/log/casserver.log
190
+ level: INFO
191
+
192
+
193
+ # If you want full database logging, uncomment this next section.
194
+ # Every SQL query will be logged here. This is useful for debugging database problems.
195
+ #
196
+ #db_log:
197
+ # file: /var/log/casserver_db.log
data/lib/casserver.rb ADDED
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # change to current directory when invoked on its own
4
+ Dir.chdir(File.dirname(File.expand_path(__FILE__))) if __FILE__ == $0
5
+
6
+ # add current directory to load path
7
+ $: << File.dirname(File.expand_path(__FILE__))
8
+
9
+ require 'rubygems'
10
+ require_gem 'camping', '~> 1.5'
11
+ require 'camping'
12
+
13
+ require 'active_support'
14
+ require 'yaml'
15
+
16
+ # enable xhtml source code indentation for debugging views
17
+ Markaby::Builder.set(:indent, 2)
18
+
19
+ # seed the random number generator (ruby does this by default, but it doesn't hurt to do it here just to be sure)
20
+ srand
21
+
22
+ # Camping.goes must be called after the authenticator class is loaded, otherwise weird things happen
23
+ Camping.goes :CASServer
24
+
25
+ module CASServer
26
+ end
27
+
28
+ require 'casserver/utils'
29
+ require 'casserver/models'
30
+ require 'casserver/cas'
31
+ require 'casserver/conf'
32
+ require 'casserver/views'
33
+ require 'casserver/controllers'
34
+
35
+ # init the logger
36
+ $LOG = CASServer::Utils::Logger.new(CASServer::Conf.log[:file])
37
+ $LOG.level = "CASServer::Utils::Logger::#{CASServer::Conf.log[:level]}".constantize
38
+
39
+ # do initialization stuff
40
+ def CASServer.create
41
+ CASServer::Models.create_schema
42
+
43
+ $LOG.info("RubyCAS-Server initialized.")
44
+
45
+ $LOG.debug("Configuration is:\n#{$CONF.to_yaml}")
46
+ $LOG.debug("Authenticator is: #{$AUTH}")
47
+
48
+ CASServer::Models::ServiceTicket.cleanup_expired(CASServer::Conf.service_ticket_expiry)
49
+ CASServer::Models::LoginTicket.cleanup_expired(CASServer::Conf.login_ticket_expiry)
50
+ CASServer::Models::ProxyGrantingTicket.cleanup_expired(CASServer::Conf.proxy_granting_ticket_expiry)
51
+ CASServer::Models::TicketGrantingTicket.cleanup_expired(CASServer::Conf.ticket_granting_ticket_expiry)
52
+ end
53
+
54
+
55
+ # this gets run if we launch directly (i.e. `ruby casserver.rb` rather than `camping casserver`)
56
+ if __FILE__ == $0 || $RUN
57
+ CASServer::Models::Base.establish_connection(CASServer::Conf.database)
58
+ if CASServer::Conf.db_log
59
+ CASServer::Models::Base.logger = Logger.new(CASServer::Conf.db_log[:file] || 'casserver_db.log')
60
+ CASServer::Models::Base.logger.level = "CASServer::Utils::Logger::#{CASServer::Conf.db_log[:level] || 'DEBUG'}".constantize
61
+ end
62
+
63
+ case CASServer::Conf.server
64
+ when "webrick", :webrick
65
+ require 'webrick/httpserver'
66
+ require 'webrick/https'
67
+ require 'camping/webrick'
68
+
69
+ # TODO: verify the certificate's validity
70
+ # example of how to do this is here: http://pablotron.org/download/ruri-20050331.rb
71
+
72
+ cert_path = CASServer::Conf.ssl_cert
73
+ key_path = CASServer::Conf.ssl_key || CASServer::Conf.ssl_cert
74
+ # look for the key in the ssl_cert if no ssl_key is specified
75
+
76
+ raise "'#{cert_path}' is not a valid ssl certificate. Your 'ssl_cert' configuration" +
77
+ " setting must be a path to a valid ssl certificate file." unless
78
+ File.exists? cert_path
79
+
80
+ raise "'#{key_path}' is not a valid ssl private key. Your 'ssl_key' configuration" +
81
+ " setting must be a path to a valid ssl private key file." unless
82
+ File.exists? key_path
83
+
84
+ cert = OpenSSL::X509::Certificate.new(File.read(cert_path))
85
+ key = OpenSSL::PKey::RSA.new(File.read(key_path))
86
+
87
+ begin
88
+ s = WEBrick::HTTPServer.new(
89
+ :BindAddress => "0.0.0.0",
90
+ :Port => CASServer::Conf.port,
91
+ :SSLEnable => true,
92
+ :SSLVerifyClient => ::OpenSSL::SSL::VERIFY_NONE,
93
+ :SSLCertificate => cert,
94
+ :SSLPrivateKey => key
95
+ )
96
+ rescue Errno::EACCES
97
+ 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."
98
+ exit 2
99
+ end
100
+
101
+ CASServer.create
102
+ s.mount "#{CASServer::Conf.uri_path}", WEBrick::CampingHandler, CASServer
103
+
104
+ puts "\n** CASServer is running at http://localhost:#{CASServer::Conf.port}#{CASServer::Conf.uri_path} and logging to '#{CASServer::Conf.log[:file]}'\n\n"
105
+
106
+ # This lets Ctrl+C shut down your server
107
+ trap(:INT) do
108
+ s.shutdown
109
+ end
110
+
111
+ s.start
112
+
113
+ when "mongrel", :mongrel
114
+ require 'rubygems'
115
+ require 'mongrel/camping'
116
+
117
+ # camping has fixes for mongrel currently only availabe in SVN
118
+ # ... you can install camping from svn (1.5.180) by running:
119
+ # gem install camping --source code.whytheluckystiff.net
120
+ require_gem 'camping', '~> 1.5.180'
121
+
122
+ CASServer.create
123
+
124
+ begin
125
+ server = Mongrel::Camping::start("0.0.0.0",CASServer::Conf.port,"#{CASServer::Conf.uri_path}",CASServer)
126
+ rescue Errno::EACCES
127
+ 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."
128
+ exit 2
129
+ end
130
+
131
+ puts "\n** CASServer is running at http://localhost:#{CASServer::Conf.port}#{CASServer::Conf.uri_path} and logging to '#{CASServer::Conf.log[:file]}'"
132
+ server.run.join
133
+
134
+ when "fastcgi", :fastcgi
135
+ require 'camping/fastcgi'
136
+ Dir.chdir('/srv/www/camping/casserver/')
137
+
138
+ CASServer.create
139
+ Camping::FastCGI.start(CASServer)
140
+
141
+ when "cgi", :cgi
142
+ CASServer.create
143
+ puts CASServer.run
144
+
145
+ else
146
+ if CASServer::Conf.server
147
+ raise "The server setting '#{CASServer::Conf.server}' in your config.yml file is invalid."
148
+ else
149
+ raise "You must have a 'server' setting in your config.yml file. Please see the RubyCAS-Server documentation."
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,8 @@
1
+ require 'casserver/authenticators/ldap'
2
+
3
+ class CASServer::Authenticators::ActiveDirectoryLDAP < CASServer::Authenticators::LDAP
4
+ protected
5
+ def default_username_attribute
6
+ "sAMAccountName"
7
+ end
8
+ end
@@ -0,0 +1,22 @@
1
+ module CASServer
2
+ module Authenticators
3
+ class Base
4
+ attr_accessor :options
5
+
6
+ def validate(credentials)
7
+ raise NotImplementedError, "This method must be implemented by a class extending #{self.class}"
8
+ end
9
+
10
+ def configure(options)
11
+ raise ArgumentError, "options must be a HashWithIndifferentAccess" unless options.kind_of? HashWithIndifferentAccess
12
+ @options = options.dup
13
+ end
14
+
15
+ protected
16
+ def read_standard_credentials(credentials)
17
+ @username = credentials[:username]
18
+ @password = credentials[:password]
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,40 @@
1
+ require 'casserver/authenticators/base'
2
+
3
+ begin
4
+ require 'net/ldap'
5
+ rescue LoadError
6
+ require 'rubygems'
7
+ require_gem 'ruby-net-ldap', '~> 0.0.4'
8
+ require 'net/ldap'
9
+ end
10
+
11
+ class CASServer::Authenticators::LDAP < CASServer::Authenticators::Base
12
+ def validate(credentials)
13
+ read_standard_credentials(credentials)
14
+
15
+ raise "Cannot validate credentials because the authenticator hasn't yet been configured" unless @options
16
+ raise "Invalid authenticator configuration!" unless @options[:ldap]
17
+ raise "You must specify an ldap server in the configuration!" unless @options[:ldap][:server]
18
+
19
+ ldap = Net::LDAP.new
20
+ ldap.host = @options[:ldap][:server]
21
+ ldap.port = @options[:ldap][:port] if @options[:ldap][:port]
22
+
23
+ if @options[:ldap][:auth_user]
24
+ raise "A password must be specified in the configuration for the authenticator user!" unless @options[:ldap][:auth_password]
25
+ ldap.authenticate(@options[:ldap][:auth_user], @options[:ldap][:auth_password])
26
+ end
27
+
28
+ filter = "(#{@options[:ldap][:username_attribute] || default_username_attribute}=#{@username})"
29
+ filter += " & (#{@options[:ldap][:filter]})" if @options[:ldap][:filter]
30
+
31
+ result = ldap.bind_as(:base => @options[:ldap][:base], :filter => filter, :password => @password)
32
+
33
+ return result
34
+ end
35
+
36
+ protected
37
+ def default_username_attribute
38
+ "uid"
39
+ end
40
+ end
@@ -0,0 +1,37 @@
1
+ require 'casserver/authenticators/base'
2
+
3
+ begin
4
+ require 'active_record'
5
+ rescue LoadError
6
+ require 'rubygems'
7
+ require 'active_record'
8
+ end
9
+
10
+ class CASServer::Authenticators::SQL < CASServer::Authenticators::Base
11
+
12
+ def validate(credentials)
13
+ read_standard_credentials(credentials)
14
+
15
+ raise "Cannot validate credentials because the authenticator hasn't yet been configured" unless @options
16
+ raise "Invalid authenticator configuration!" unless @options[:database]
17
+
18
+ CASUser.establish_connection @options[:database]
19
+ CASUser.set_table_name @options[:user_table] || "users"
20
+
21
+ username_column = @options[:username_column] || 'username'
22
+ password_column = @options[:password_column] || 'password'
23
+
24
+ results = CASUser.find(:all, :conditions => ["#{username_column} = ? AND #{password_column} = ?", @username, @password])
25
+
26
+ if results.size > 0
27
+ $LOG.warn("Multiple matches found for user '#{@username}'") if results.size > 1
28
+ return true
29
+ else
30
+ return false
31
+ end
32
+ end
33
+
34
+ class CASUser < ActiveRecord::Base
35
+ end
36
+
37
+ end