diff --git a/casserver.rb b/casserver.rb index 1e6713e..52c471f 100644 --- a/casserver.rb +++ b/casserver.rb @@ -59,11 +59,40 @@ if __FILE__ == $0 case CASServer::Conf.server when "webrick", :webrick require 'webrick/httpserver' + require 'webrick/https' require 'camping/webrick' - s = WEBrick::HTTPServer.new :BindAddress => "0.0.0.0", :Port => CASServer::Conf.port + # TODO: verify the certificate's validity + # example of how to do this is here: http://pablotron.org/download/ruri-20050331.rb + + cert_path = CASServer::Conf.ssl_cert + key_path = CASServer::Conf.ssl_key || CASServer::Conf.ssl_cert + # look for the key in the ssl_cert if no ssl_key is specified + + raise "'#{cert_path}' is not a valid ssl certificate. Your 'ssl_cert' configuration" + + " setting must be a path to a valid ssl certificate file." unless + File.exists? cert_path + + raise "'#{key_path}' is not a valid ssl private key. Your 'ssl_key' configuration" + + " setting must be a path to a valid ssl private key file." unless + File.exists? key_path + + cert = OpenSSL::X509::Certificate.new(File.read(cert_path)) + key = OpenSSL::PKey::RSA.new(File.read(key_path)) + + s = WEBrick::HTTPServer.new( + :BindAddress => "0.0.0.0", + :Port => CASServer::Conf.port, + :SSLEnable => true, + :SSLVerifyClient => ::OpenSSL::SSL::VERIFY_NONE, + :SSLCertificate => cert, + :SSLPrivateKey => key + ) + CASServer.create - s.mount "/", WEBrick::CampingHandler, CASServer + s.mount "#{CASServer::Conf.uri_path}", WEBrick::CampingHandler, CASServer + + puts "\n** CASServer is running at http://localhost:#{CASServer::Conf.port}#{CASServer::Conf.uri_path} and logging to '#{CASServer::Conf.log[:file]}'\n\n" # This lets Ctrl+C shut down your server trap(:INT) do @@ -79,8 +108,8 @@ if __FILE__ == $0 CASServer.create - server = Mongrel::Camping::start("0.0.0.0",CASServer::Conf.port,"/#{CASServer::Conf.uri_path}",CASServer) - puts "\n** CASServer is running at http://localhost:#{CASServer::Conf.port}/#{CASServer::Conf.uri_path} and logging to '#{CASServer::Conf.log[:file]}'" + server = Mongrel::Camping::start("0.0.0.0",CASServer::Conf.port,"#{CASServer::Conf.uri_path}",CASServer) + puts "\n** CASServer is running at http://localhost:#{CASServer::Conf.port}#{CASServer::Conf.uri_path} and logging to '#{CASServer::Conf.log[:file]}'" server.run.join when "fastcgi", :fastcgi diff --git a/casserver/cas.rb b/casserver/cas.rb index e364492..fec52be 100644 --- a/casserver/cas.rb +++ b/casserver/cas.rb @@ -13,6 +13,8 @@ module CASServer::CAS lt.ticket = "LT-" + CASServer::Utils.random_string lt.client_hostname = env['REMOTE_HOST'] || env['REMOTE_ADDR'] lt.save! + $LOG.debug("Generated login ticket '#{lt.ticket}' for client" + + " at '#{lt.client_hostname}'") lt end @@ -23,6 +25,8 @@ module CASServer::CAS tgt.username = username tgt.client_hostname = env['REMOTE_HOST'] || env['REMOTE_ADDR'] tgt.save! + $LOG.debug("Generated ticket granting ticket '#{tgt.ticket}' for user" + + " '#{tgt.username}' at '#{tgt.client_hostname}'") tgt end @@ -34,6 +38,8 @@ module CASServer::CAS st.username = username st.client_hostname = env['REMOTE_HOST'] || env['REMOTE_ADDR'] st.save! + $LOG.debug("Generated service ticket '#{st.ticket}' for service '#{st.service}'" + + " for user '#{st.username}' at '#{st.client_hostname}'") st end @@ -46,6 +52,9 @@ module CASServer::CAS pt.proxy_granting_ticket_id = pgt.id pt.client_hostname = env['REMOTE_HOST'] || env['REMOTE_ADDR'] pt.save! + $LOG.debug("Generated proxy ticket '#{pt.ticket}' for target service '#{pt.service}'" + + " for user '#{pt.username}' at '#{pt.client_hostname}' using proxy-granting" + + " ticket '#{pgt.ticket}'") pt end diff --git a/casserver/conf.rb b/casserver/conf.rb index 3d3f981..f4e3248 100644 --- a/casserver/conf.rb +++ b/casserver/conf.rb @@ -33,7 +33,8 @@ module CASServer :service_ticket_expiry => 5.minutes, # CAS Protocol Spec, sec. 3.2.1 (recommended expiry time) :proxy_granting_ticket_expiry => 48.hours, :ticket_granting_ticket_expiry => 48.hours, - :log => {:file => 'casserver.log', :level => 'DEBUG'} + :log => {:file => 'casserver.log', :level => 'DEBUG'}, + :uri_path => "/" } def [](key) diff --git a/casserver/controllers.rb b/casserver/controllers.rb index 3e9a95a..5d3c244 100644 --- a/casserver/controllers.rb +++ b/casserver/controllers.rb @@ -70,14 +70,14 @@ module CASServer::Controllers $LOG.debug("Ticket granting cookie '#{@cookies[:tgt]}' granted to '#{@username}'") if @service.blank? - $LOG.info("Successfully authenticated user '#{@username}'. No service param was given, so we will not redirect.") + $LOG.info("Successfully authenticated user '#{@username}' at '#{tgt.client_hostname}'. No service param was given, so we will not redirect.") @message = {:type => 'confirmation', :message => "You have successfully logged in."} render :login else @st = generate_service_ticket(@service, @username) service_with_ticket = service_uri_with_ticket(@service, @st) - $LOG.info("Redirecting authenticated user '#{@username}' to service '#{@service}'") + $LOG.info("Redirecting authenticated user '#{@username}' at '#{@st.client_hostname}' to service '#{@service}'") return redirect(service_with_ticket, :status => 303) # response code 303 means "See Other" (see Appendix B in CAS Protocol spec) end else @@ -114,7 +114,7 @@ module CASServer::Controllers $LOG.debug("Deleting Ticket-Granting Ticket '#{tgt}' for user '#{tgt.username}'") - $LOG.info("User #{tgt.username} logged out.") + $LOG.info("User '#{tgt.username}' logged out.") else $LOG.warn("User tried to log out without a valid ticket-granting ticket.") end @@ -224,7 +224,7 @@ module CASServer::Controllers @ticket = @input['pgt'] @target_service = @input['targetService'] - pgt, @error = validate_proxy_granting_ticket(@ticket, @target_service) + pgt, @error = validate_proxy_granting_ticket(@ticket) @success = pgt && !@error if @success diff --git a/casserver/views.rb b/casserver/views.rb index 082d1e2..8db41cc 100644 --- a/casserver/views.rb +++ b/casserver/views.rb @@ -12,8 +12,8 @@ module CASServer::Views xhtml_strict do head do title { "#{organization} Central Login" } - link(:rel => "stylesheet", :type => "text/css", :href => "themes/cas.css") - link(:rel => "stylesheet", :type => "text/css", :href => "themes/#{current_theme}/theme.css") + link(:rel => "stylesheet", :type => "text/css", :href => "/themes/cas.css") + link(:rel => "stylesheet", :type => "text/css", :href => "/themes/#{current_theme}/theme.css") end body(:onload => "if (document.getElementById('username')) document.getElementById('username').focus()") do self << yield diff --git a/config.example.yml b/config.example.yml index 61b010f..75c0c8f 100644 --- a/config.example.yml +++ b/config.example.yml @@ -7,18 +7,40 @@ # are currently supported: # # webrick -- run as a stand-alone webrick server; this is the default method -# mongrel -- run as a stand-alone mongrel server; fast, but you'll need to install mongrel first +# mongrel -- run as a stand-alone mongrel server; fast, but you'll need to install +# mongrel and run it behind an https reverse proxy like Pound or Apache 2.2's mod_proxy) # cgi -- slow, but simple to set up if you're already familliar with deploying CGI scripts # fastcgi -- see http://www.fastcgi.com (e.g. under Apache you can use this with mod_fastcgi) # -# The cgi and fastcgi methods have not been thoroughly tested! Please report any problems to the authors. +# The cgi and fastcgi methods have not been thoroughly tested! +# Please report any problems to the authors. # -# IMPORTANT: If you use the webrick or mongrel methods, you will need to run the server behind reverse proxy -# (Pound, Apache 2.2 with mod_proxy, etc.) since neither webrick nor mongrel support SSL/HTTPS. -# See the RubyCAS-Server install docs for more info. +# IMPORTANT: If you use mongrel, you will need to run the server behind a reverse proxy +# (Pound, Apache 2.2 with mod_proxy, etc.) since mongrel does not support SSL/HTTPS. +# See the RubyCAS-Server install docs for more info. Also, mongrel requries +# Camping 1.5.180 which as of writing is only available via SVN. You can install +# this by running `gem install camping --source code.whytheluckystiff.net` + +### webrick example server: webrick -port: 110011 # the port setting is only used when using 'webrick' or 'mongrel' +port: 443 +ssl_cert: /path/to/your/ssl.pem +# ssl_key: /path/to/your/private_key.pem <-- if private key is separate from cert + +### mongrel example (you will need to run this behind an https reverse proxy, +### since mongrel doesn't support SSL on its own) + +#server: mongrel +#port: 110011 + +### cgi example (you'll need to serve this via an SSL-capable server like Apache) + +#server: cgi + +### fastcgi example (you'll need to serve this via an SSL-capable server like Apache) + +#server: fastcgi ##### DATABASE #######################################################################