synapses-cas 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.
- data/CHANGELOG +3 -0
 - data/Gemfile +3 -0
 - data/LICENSE +27 -0
 - data/README.md +20 -0
 - data/Rakefile +2 -0
 - data/bin/synapses-cas +30 -0
 - data/config.ru +17 -0
 - data/config/config.example.yml +592 -0
 - data/config/unicorn.rb +88 -0
 - data/db/migrate/001_create_initial_structure.rb +47 -0
 - data/lib/casserver.rb +11 -0
 - data/lib/casserver/authenticators/active_directory_ldap.rb +19 -0
 - data/lib/casserver/authenticators/active_resource.rb +127 -0
 - data/lib/casserver/authenticators/authlogic_crypto_providers/aes256.rb +43 -0
 - data/lib/casserver/authenticators/authlogic_crypto_providers/bcrypt.rb +92 -0
 - data/lib/casserver/authenticators/authlogic_crypto_providers/md5.rb +34 -0
 - data/lib/casserver/authenticators/authlogic_crypto_providers/sha1.rb +59 -0
 - data/lib/casserver/authenticators/authlogic_crypto_providers/sha512.rb +50 -0
 - data/lib/casserver/authenticators/base.rb +67 -0
 - data/lib/casserver/authenticators/client_certificate.rb +47 -0
 - data/lib/casserver/authenticators/google.rb +58 -0
 - data/lib/casserver/authenticators/ldap.rb +147 -0
 - data/lib/casserver/authenticators/ntlm.rb +88 -0
 - data/lib/casserver/authenticators/open_id.rb +22 -0
 - data/lib/casserver/authenticators/sql.rb +133 -0
 - data/lib/casserver/authenticators/sql_authlogic.rb +93 -0
 - data/lib/casserver/authenticators/sql_encrypted.rb +75 -0
 - data/lib/casserver/authenticators/sql_md5.rb +19 -0
 - data/lib/casserver/authenticators/sql_rest_auth.rb +82 -0
 - data/lib/casserver/authenticators/test.rb +22 -0
 - data/lib/casserver/cas.rb +323 -0
 - data/lib/casserver/localization.rb +13 -0
 - data/lib/casserver/model.rb +270 -0
 - data/lib/casserver/server.rb +758 -0
 - data/lib/casserver/utils.rb +32 -0
 - data/lib/casserver/views/_login_form.erb +42 -0
 - data/lib/casserver/views/layout.erb +18 -0
 - data/lib/casserver/views/login.erb +30 -0
 - data/lib/casserver/views/proxy.builder +12 -0
 - data/lib/casserver/views/proxy_validate.builder +25 -0
 - data/lib/casserver/views/service_validate.builder +18 -0
 - data/lib/casserver/views/validate.erb +2 -0
 - data/locales/de.yml +27 -0
 - data/locales/en.yml +26 -0
 - data/locales/es.yml +26 -0
 - data/locales/es_ar.yml +26 -0
 - data/locales/fr.yml +26 -0
 - data/locales/jp.yml +26 -0
 - data/locales/pl.yml +26 -0
 - data/locales/pt.yml +26 -0
 - data/locales/ru.yml +26 -0
 - data/locales/zh.yml +26 -0
 - data/locales/zh_tw.yml +26 -0
 - data/public/themes/cas.css +126 -0
 - data/public/themes/notice.png +0 -0
 - data/public/themes/ok.png +0 -0
 - data/public/themes/simple/bg.png +0 -0
 - data/public/themes/simple/favicon.png +0 -0
 - data/public/themes/simple/login_box_bg.png +0 -0
 - data/public/themes/simple/logo.png +0 -0
 - data/public/themes/simple/theme.css +28 -0
 - data/public/themes/urbacon/bg.png +0 -0
 - data/public/themes/urbacon/login_box_bg.png +0 -0
 - data/public/themes/urbacon/logo.png +0 -0
 - data/public/themes/urbacon/theme.css +33 -0
 - data/public/themes/warning.png +0 -0
 - data/resources/init.d.sh +58 -0
 - data/setup.rb +1585 -0
 - data/spec/alt_config.yml +50 -0
 - data/spec/authenticators/active_resource_spec.rb +109 -0
 - data/spec/authenticators/ldap_spec.rb +53 -0
 - data/spec/casserver_spec.rb +156 -0
 - data/spec/default_config.yml +50 -0
 - data/spec/model_spec.rb +42 -0
 - data/spec/spec.opts +4 -0
 - data/spec/spec_helper.rb +89 -0
 - data/spec/utils_spec.rb +53 -0
 - data/tasks/bundler.rake +4 -0
 - data/tasks/db/migrate.rake +12 -0
 - data/tasks/spec.rake +10 -0
 - metadata +380 -0
 
| 
         @@ -0,0 +1,323 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'uri'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'net/https'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            require 'casserver/model'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            # Encapsulates CAS functionality. This module is meant to be included in
         
     | 
| 
      
 7 
     | 
    
         
            +
            # the CASServer::Controllers module.
         
     | 
| 
      
 8 
     | 
    
         
            +
            module CASServer::CAS
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              include CASServer::Model
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              def generate_login_ticket
         
     | 
| 
      
 13 
     | 
    
         
            +
                # 3.5 (login ticket)
         
     | 
| 
      
 14 
     | 
    
         
            +
                lt = LoginTicket.new
         
     | 
| 
      
 15 
     | 
    
         
            +
                lt.ticket = "LT-" + CASServer::Utils.random_string
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                lt.client_hostname = @env['HTTP_X_FORWARDED_FOR'] || @env['REMOTE_HOST'] || @env['REMOTE_ADDR']
         
     | 
| 
      
 18 
     | 
    
         
            +
                lt.save!
         
     | 
| 
      
 19 
     | 
    
         
            +
                $LOG.debug("Generated login ticket '#{lt.ticket}' for client" +
         
     | 
| 
      
 20 
     | 
    
         
            +
                  " at '#{lt.client_hostname}'")
         
     | 
| 
      
 21 
     | 
    
         
            +
                lt
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              # Creates a TicketGrantingTicket for the given username. This is done when the user logs in
         
     | 
| 
      
 25 
     | 
    
         
            +
              # for the first time to establish their SSO session (after their credentials have been validated).
         
     | 
| 
      
 26 
     | 
    
         
            +
              #
         
     | 
| 
      
 27 
     | 
    
         
            +
              # The optional 'extra_attributes' parameter takes a hash of additional attributes
         
     | 
| 
      
 28 
     | 
    
         
            +
              # that will be sent along with the username in the CAS response to subsequent
         
     | 
| 
      
 29 
     | 
    
         
            +
              # validation requests from clients.
         
     | 
| 
      
 30 
     | 
    
         
            +
              def generate_ticket_granting_ticket(username, extra_attributes = {})
         
     | 
| 
      
 31 
     | 
    
         
            +
                # 3.6 (ticket granting cookie/ticket)
         
     | 
| 
      
 32 
     | 
    
         
            +
                tgt = TicketGrantingTicket.new
         
     | 
| 
      
 33 
     | 
    
         
            +
                tgt.ticket = "TGC-" + CASServer::Utils.random_string
         
     | 
| 
      
 34 
     | 
    
         
            +
                tgt.username = username
         
     | 
| 
      
 35 
     | 
    
         
            +
                tgt.extra_attributes = extra_attributes
         
     | 
| 
      
 36 
     | 
    
         
            +
                tgt.client_hostname = @env['HTTP_X_FORWARDED_FOR'] || @env['REMOTE_HOST'] || @env['REMOTE_ADDR']
         
     | 
| 
      
 37 
     | 
    
         
            +
                tgt.save!
         
     | 
| 
      
 38 
     | 
    
         
            +
                $LOG.debug("Generated ticket granting ticket '#{tgt.ticket}' for user" +
         
     | 
| 
      
 39 
     | 
    
         
            +
                  " '#{tgt.username}' at '#{tgt.client_hostname}'" +
         
     | 
| 
      
 40 
     | 
    
         
            +
                  (extra_attributes.blank? ? "" : " with extra attributes #{extra_attributes.inspect}"))
         
     | 
| 
      
 41 
     | 
    
         
            +
                tgt
         
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
              def generate_service_ticket(service, username, tgt)
         
     | 
| 
      
 45 
     | 
    
         
            +
                # 3.1 (service ticket)
         
     | 
| 
      
 46 
     | 
    
         
            +
                st = ServiceTicket.new
         
     | 
| 
      
 47 
     | 
    
         
            +
                st.ticket = "ST-" + CASServer::Utils.random_string
         
     | 
| 
      
 48 
     | 
    
         
            +
                st.service = service
         
     | 
| 
      
 49 
     | 
    
         
            +
                st.username = username
         
     | 
| 
      
 50 
     | 
    
         
            +
                st.granted_by_tgt_id = tgt.id
         
     | 
| 
      
 51 
     | 
    
         
            +
                st.client_hostname = @env['HTTP_X_FORWARDED_FOR'] || @env['REMOTE_HOST'] || @env['REMOTE_ADDR']
         
     | 
| 
      
 52 
     | 
    
         
            +
                st.save!
         
     | 
| 
      
 53 
     | 
    
         
            +
                $LOG.debug("Generated service ticket '#{st.ticket}' for service '#{st.service}'" +
         
     | 
| 
      
 54 
     | 
    
         
            +
                  " for user '#{st.username}' at '#{st.client_hostname}'")
         
     | 
| 
      
 55 
     | 
    
         
            +
                st
         
     | 
| 
      
 56 
     | 
    
         
            +
              end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
              def generate_proxy_ticket(target_service, pgt)
         
     | 
| 
      
 59 
     | 
    
         
            +
                # 3.2 (proxy ticket)
         
     | 
| 
      
 60 
     | 
    
         
            +
                pt = ProxyTicket.new
         
     | 
| 
      
 61 
     | 
    
         
            +
                pt.ticket = "PT-" + CASServer::Utils.random_string
         
     | 
| 
      
 62 
     | 
    
         
            +
                pt.service = target_service
         
     | 
| 
      
 63 
     | 
    
         
            +
                pt.username = pgt.service_ticket.username
         
     | 
| 
      
 64 
     | 
    
         
            +
                pt.granted_by_pgt_id = pgt.id
         
     | 
| 
      
 65 
     | 
    
         
            +
                pt.granted_by_tgt_id = pgt.service_ticket.granted_by_tgt.id
         
     | 
| 
      
 66 
     | 
    
         
            +
                pt.client_hostname = @env['HTTP_X_FORWARDED_FOR'] || @env['REMOTE_HOST'] || @env['REMOTE_ADDR']
         
     | 
| 
      
 67 
     | 
    
         
            +
                pt.save!
         
     | 
| 
      
 68 
     | 
    
         
            +
                $LOG.debug("Generated proxy ticket '#{pt.ticket}' for target service '#{pt.service}'" +
         
     | 
| 
      
 69 
     | 
    
         
            +
                  " for user '#{pt.username}' at '#{pt.client_hostname}' using proxy-granting" +
         
     | 
| 
      
 70 
     | 
    
         
            +
                  " ticket '#{pgt.ticket}'")
         
     | 
| 
      
 71 
     | 
    
         
            +
                pt
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
              def generate_proxy_granting_ticket(pgt_url, st)
         
     | 
| 
      
 75 
     | 
    
         
            +
                uri = URI.parse(pgt_url)
         
     | 
| 
      
 76 
     | 
    
         
            +
                https = Net::HTTP.new(uri.host,uri.port)
         
     | 
| 
      
 77 
     | 
    
         
            +
                https.use_ssl = true
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                # Here's what's going on here:
         
     | 
| 
      
 80 
     | 
    
         
            +
                #
         
     | 
| 
      
 81 
     | 
    
         
            +
                #   1. We generate a ProxyGrantingTicket (but don't store it in the database just yet)
         
     | 
| 
      
 82 
     | 
    
         
            +
                #   2. Deposit the PGT and it's associated IOU at the proxy callback URL.
         
     | 
| 
      
 83 
     | 
    
         
            +
                #   3. If the proxy callback URL responds with HTTP code 200, store the PGT and return it;
         
     | 
| 
      
 84 
     | 
    
         
            +
                #      otherwise don't save it and return nothing.
         
     | 
| 
      
 85 
     | 
    
         
            +
                #
         
     | 
| 
      
 86 
     | 
    
         
            +
                https.start do |conn|
         
     | 
| 
      
 87 
     | 
    
         
            +
                  path = uri.path.empty? ? '/' : uri.path
         
     | 
| 
      
 88 
     | 
    
         
            +
                  path += '?' + uri.query unless (uri.query.nil? || uri.query.empty?)
         
     | 
| 
      
 89 
     | 
    
         
            +
                  
         
     | 
| 
      
 90 
     | 
    
         
            +
                  pgt = ProxyGrantingTicket.new
         
     | 
| 
      
 91 
     | 
    
         
            +
                  pgt.ticket = "PGT-" + CASServer::Utils.random_string(60)
         
     | 
| 
      
 92 
     | 
    
         
            +
                  pgt.iou = "PGTIOU-" + CASServer::Utils.random_string(57)
         
     | 
| 
      
 93 
     | 
    
         
            +
                  pgt.service_ticket_id = st.id
         
     | 
| 
      
 94 
     | 
    
         
            +
                  pgt.client_hostname = @env['HTTP_X_FORWARDED_FOR'] || @env['REMOTE_HOST'] || @env['REMOTE_ADDR']
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                  # FIXME: The CAS protocol spec says to use 'pgt' as the parameter, but in practice
         
     | 
| 
      
 97 
     | 
    
         
            +
                  #         the JA-SIG and Yale server implementations use pgtId. We'll go with the
         
     | 
| 
      
 98 
     | 
    
         
            +
                  #         in-practice standard.
         
     | 
| 
      
 99 
     | 
    
         
            +
                  path += (uri.query.nil? || uri.query.empty? ? '?' : '&') + "pgtId=#{pgt.ticket}&pgtIou=#{pgt.iou}"
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                  response = conn.request_get(path)
         
     | 
| 
      
 102 
     | 
    
         
            +
                  # TODO: follow redirects... 2.5.4 says that redirects MAY be followed
         
     | 
| 
      
 103 
     | 
    
         
            +
                  # NOTE: The following response codes are valid according to the JA-SIG implementation even without following redirects
         
     | 
| 
      
 104 
     | 
    
         
            +
                  
         
     | 
| 
      
 105 
     | 
    
         
            +
                  if %w(200 202 301 302 304).include?(response.code)
         
     | 
| 
      
 106 
     | 
    
         
            +
                    # 3.4 (proxy-granting ticket IOU)
         
     | 
| 
      
 107 
     | 
    
         
            +
                    pgt.save!
         
     | 
| 
      
 108 
     | 
    
         
            +
                    $LOG.debug "PGT generated for pgt_url '#{pgt_url}': #{pgt.inspect}"
         
     | 
| 
      
 109 
     | 
    
         
            +
                    pgt
         
     | 
| 
      
 110 
     | 
    
         
            +
                  else
         
     | 
| 
      
 111 
     | 
    
         
            +
                    $LOG.warn "PGT callback server responded with a bad result code '#{response.code}'. PGT will not be stored."
         
     | 
| 
      
 112 
     | 
    
         
            +
                    nil
         
     | 
| 
      
 113 
     | 
    
         
            +
                  end
         
     | 
| 
      
 114 
     | 
    
         
            +
                end
         
     | 
| 
      
 115 
     | 
    
         
            +
              end
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
              def validate_login_ticket(ticket)
         
     | 
| 
      
 118 
     | 
    
         
            +
                $LOG.debug("Validating login ticket '#{ticket}'")
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                success = false
         
     | 
| 
      
 121 
     | 
    
         
            +
                if ticket.nil?
         
     | 
| 
      
 122 
     | 
    
         
            +
                  error = t.error.no_login_ticket
         
     | 
| 
      
 123 
     | 
    
         
            +
                  $LOG.warn "Missing login ticket."
         
     | 
| 
      
 124 
     | 
    
         
            +
                elsif lt = LoginTicket.find_by_ticket(ticket)
         
     | 
| 
      
 125 
     | 
    
         
            +
                  if lt.consumed?
         
     | 
| 
      
 126 
     | 
    
         
            +
                    error = t.error.login_ticket_already_used
         
     | 
| 
      
 127 
     | 
    
         
            +
                    $LOG.warn "Login ticket '#{ticket}' previously used up"
         
     | 
| 
      
 128 
     | 
    
         
            +
                  elsif Time.now - lt.created_on < settings.config[:maximum_unused_login_ticket_lifetime]
         
     | 
| 
      
 129 
     | 
    
         
            +
                    $LOG.info "Login ticket '#{ticket}' successfully validated"
         
     | 
| 
      
 130 
     | 
    
         
            +
                  else
         
     | 
| 
      
 131 
     | 
    
         
            +
                    error = t.error.login_timeout
         
     | 
| 
      
 132 
     | 
    
         
            +
                    $LOG.warn "Expired login ticket '#{ticket}'"
         
     | 
| 
      
 133 
     | 
    
         
            +
                  end
         
     | 
| 
      
 134 
     | 
    
         
            +
                else
         
     | 
| 
      
 135 
     | 
    
         
            +
                  error = t.error.invalid_login_ticket
         
     | 
| 
      
 136 
     | 
    
         
            +
                  $LOG.warn "Invalid login ticket '#{ticket}'"
         
     | 
| 
      
 137 
     | 
    
         
            +
                end
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                lt.consume! if lt
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                error
         
     | 
| 
      
 142 
     | 
    
         
            +
              end
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
              def validate_ticket_granting_ticket(ticket)
         
     | 
| 
      
 145 
     | 
    
         
            +
                $LOG.debug("Validating ticket granting ticket '#{ticket}'")
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                if ticket.nil?
         
     | 
| 
      
 148 
     | 
    
         
            +
                  error = "No ticket granting ticket given."
         
     | 
| 
      
 149 
     | 
    
         
            +
                  $LOG.debug error
         
     | 
| 
      
 150 
     | 
    
         
            +
                elsif tgt = TicketGrantingTicket.find_by_ticket(ticket)
         
     | 
| 
      
 151 
     | 
    
         
            +
                  if settings.config[:maximum_session_lifetime] && Time.now - tgt.created_on > settings.config[:maximum_session_lifetime]
         
     | 
| 
      
 152 
     | 
    
         
            +
            	tgt.destroy
         
     | 
| 
      
 153 
     | 
    
         
            +
                    error = "Your session has expired. Please log in again."
         
     | 
| 
      
 154 
     | 
    
         
            +
                    $LOG.info "Ticket granting ticket '#{ticket}' for user '#{tgt.username}' expired."
         
     | 
| 
      
 155 
     | 
    
         
            +
                  else
         
     | 
| 
      
 156 
     | 
    
         
            +
                    $LOG.info "Ticket granting ticket '#{ticket}' for user '#{tgt.username}' successfully validated."
         
     | 
| 
      
 157 
     | 
    
         
            +
                  end
         
     | 
| 
      
 158 
     | 
    
         
            +
                else
         
     | 
| 
      
 159 
     | 
    
         
            +
                  error = "Invalid ticket granting ticket '#{ticket}' (no matching ticket found in the database)."
         
     | 
| 
      
 160 
     | 
    
         
            +
                  $LOG.warn(error)
         
     | 
| 
      
 161 
     | 
    
         
            +
                end
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
                [tgt, error]
         
     | 
| 
      
 164 
     | 
    
         
            +
              end
         
     | 
| 
      
 165 
     | 
    
         
            +
             
     | 
| 
      
 166 
     | 
    
         
            +
              def validate_service_ticket(service, ticket, allow_proxy_tickets = false)
         
     | 
| 
      
 167 
     | 
    
         
            +
                $LOG.debug "Validating service/proxy ticket '#{ticket}' for service '#{service}'"
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
                if service.nil? or ticket.nil?
         
     | 
| 
      
 170 
     | 
    
         
            +
                  error = Error.new(:INVALID_REQUEST, "Ticket or service parameter was missing in the request.")
         
     | 
| 
      
 171 
     | 
    
         
            +
                  $LOG.warn "#{error.code} - #{error.message}"
         
     | 
| 
      
 172 
     | 
    
         
            +
                elsif st = ServiceTicket.find_by_ticket(ticket)
         
     | 
| 
      
 173 
     | 
    
         
            +
                  if st.consumed?
         
     | 
| 
      
 174 
     | 
    
         
            +
                    error = Error.new(:INVALID_TICKET, "Ticket '#{ticket}' has already been used up.")
         
     | 
| 
      
 175 
     | 
    
         
            +
                    $LOG.warn "#{error.code} - #{error.message}"
         
     | 
| 
      
 176 
     | 
    
         
            +
                  elsif st.kind_of?(CASServer::Model::ProxyTicket) && !allow_proxy_tickets
         
     | 
| 
      
 177 
     | 
    
         
            +
                    error = Error.new(:INVALID_TICKET, "Ticket '#{ticket}' is a proxy ticket, but only service tickets are allowed here.")
         
     | 
| 
      
 178 
     | 
    
         
            +
                    $LOG.warn "#{error.code} - #{error.message}"
         
     | 
| 
      
 179 
     | 
    
         
            +
                  elsif Time.now - st.created_on > settings.config[:maximum_unused_service_ticket_lifetime]
         
     | 
| 
      
 180 
     | 
    
         
            +
                    error = Error.new(:INVALID_TICKET, "Ticket '#{ticket}' has expired.")
         
     | 
| 
      
 181 
     | 
    
         
            +
                    $LOG.warn "Ticket '#{ticket}' has expired."
         
     | 
| 
      
 182 
     | 
    
         
            +
                  elsif !st.matches_service? service
         
     | 
| 
      
 183 
     | 
    
         
            +
                    error = Error.new(:INVALID_SERVICE, "The ticket '#{ticket}' belonging to user '#{st.username}' is valid,"+
         
     | 
| 
      
 184 
     | 
    
         
            +
                      " but the requested service '#{service}' does not match the service '#{st.service}' associated with this ticket.")
         
     | 
| 
      
 185 
     | 
    
         
            +
                    $LOG.warn "#{error.code} - #{error.message}"
         
     | 
| 
      
 186 
     | 
    
         
            +
                  else
         
     | 
| 
      
 187 
     | 
    
         
            +
                    $LOG.info("Ticket '#{ticket}' for service '#{service}' for user '#{st.username}' successfully validated.")
         
     | 
| 
      
 188 
     | 
    
         
            +
                  end
         
     | 
| 
      
 189 
     | 
    
         
            +
                else
         
     | 
| 
      
 190 
     | 
    
         
            +
                  error = Error.new(:INVALID_TICKET, "Ticket '#{ticket}' not recognized.")
         
     | 
| 
      
 191 
     | 
    
         
            +
                  $LOG.warn("#{error.code} - #{error.message}")
         
     | 
| 
      
 192 
     | 
    
         
            +
                end
         
     | 
| 
      
 193 
     | 
    
         
            +
             
     | 
| 
      
 194 
     | 
    
         
            +
                if st
         
     | 
| 
      
 195 
     | 
    
         
            +
                  st.consume!
         
     | 
| 
      
 196 
     | 
    
         
            +
                end
         
     | 
| 
      
 197 
     | 
    
         
            +
             
     | 
| 
      
 198 
     | 
    
         
            +
             
     | 
| 
      
 199 
     | 
    
         
            +
                [st, error]
         
     | 
| 
      
 200 
     | 
    
         
            +
              end
         
     | 
| 
      
 201 
     | 
    
         
            +
             
     | 
| 
      
 202 
     | 
    
         
            +
              def validate_proxy_ticket(service, ticket)
         
     | 
| 
      
 203 
     | 
    
         
            +
                pt, error = validate_service_ticket(service, ticket, true)
         
     | 
| 
      
 204 
     | 
    
         
            +
             
     | 
| 
      
 205 
     | 
    
         
            +
                if pt.kind_of?(CASServer::Model::ProxyTicket) && !error
         
     | 
| 
      
 206 
     | 
    
         
            +
                  if not pt.granted_by_pgt
         
     | 
| 
      
 207 
     | 
    
         
            +
                    error = Error.new(:INTERNAL_ERROR, "Proxy ticket '#{pt}' belonging to user '#{pt.username}' is not associated with a proxy granting ticket.")
         
     | 
| 
      
 208 
     | 
    
         
            +
                  elsif not pt.granted_by_pgt.service_ticket
         
     | 
| 
      
 209 
     | 
    
         
            +
                    error = Error.new(:INTERNAL_ERROR, "Proxy granting ticket '#{pt.granted_by_pgt}'"+
         
     | 
| 
      
 210 
     | 
    
         
            +
                      " (associated with proxy ticket '#{pt}' and belonging to user '#{pt.username}' is not associated with a service ticket.")
         
     | 
| 
      
 211 
     | 
    
         
            +
                  end
         
     | 
| 
      
 212 
     | 
    
         
            +
                end
         
     | 
| 
      
 213 
     | 
    
         
            +
             
     | 
| 
      
 214 
     | 
    
         
            +
                [pt, error]
         
     | 
| 
      
 215 
     | 
    
         
            +
              end
         
     | 
| 
      
 216 
     | 
    
         
            +
             
     | 
| 
      
 217 
     | 
    
         
            +
              def validate_proxy_granting_ticket(ticket)
         
     | 
| 
      
 218 
     | 
    
         
            +
                if ticket.nil?
         
     | 
| 
      
 219 
     | 
    
         
            +
                  error = Error.new(:INVALID_REQUEST, "pgt parameter was missing in the request.")
         
     | 
| 
      
 220 
     | 
    
         
            +
                  $LOG.warn("#{error.code} - #{error.message}")
         
     | 
| 
      
 221 
     | 
    
         
            +
                elsif pgt = ProxyGrantingTicket.find_by_ticket(ticket)
         
     | 
| 
      
 222 
     | 
    
         
            +
                  if pgt.service_ticket
         
     | 
| 
      
 223 
     | 
    
         
            +
                    $LOG.info("Proxy granting ticket '#{ticket}' belonging to user '#{pgt.service_ticket.username}' successfully validated.")
         
     | 
| 
      
 224 
     | 
    
         
            +
                  else
         
     | 
| 
      
 225 
     | 
    
         
            +
                    error = Error.new(:INTERNAL_ERROR, "Proxy granting ticket '#{ticket}' is not associated with a service ticket.")
         
     | 
| 
      
 226 
     | 
    
         
            +
                    $LOG.error("#{error.code} - #{error.message}")
         
     | 
| 
      
 227 
     | 
    
         
            +
                  end
         
     | 
| 
      
 228 
     | 
    
         
            +
                else
         
     | 
| 
      
 229 
     | 
    
         
            +
                  error = Error.new(:BAD_PGT, "Invalid proxy granting ticket '#{ticket}' (no matching ticket found in the database).")
         
     | 
| 
      
 230 
     | 
    
         
            +
                  $LOG.warn("#{error.code} - #{error.message}")
         
     | 
| 
      
 231 
     | 
    
         
            +
                end
         
     | 
| 
      
 232 
     | 
    
         
            +
             
     | 
| 
      
 233 
     | 
    
         
            +
                [pgt, error]
         
     | 
| 
      
 234 
     | 
    
         
            +
              end
         
     | 
| 
      
 235 
     | 
    
         
            +
             
     | 
| 
      
 236 
     | 
    
         
            +
              # Takes an existing ServiceTicket object (presumably pulled from the database)
         
     | 
| 
      
 237 
     | 
    
         
            +
              # and sends a POST with logout information to the service that the ticket
         
     | 
| 
      
 238 
     | 
    
         
            +
              # was generated for.
         
     | 
| 
      
 239 
     | 
    
         
            +
              #
         
     | 
| 
      
 240 
     | 
    
         
            +
              # This makes possible the "single sign-out" functionality added in CAS 3.1.
         
     | 
| 
      
 241 
     | 
    
         
            +
              # See http://www.ja-sig.org/wiki/display/CASUM/Single+Sign+Out
         
     | 
| 
      
 242 
     | 
    
         
            +
              def send_logout_notification_for_service_ticket(st)
         
     | 
| 
      
 243 
     | 
    
         
            +
                uri = URI.parse(st.service)
         
     | 
| 
      
 244 
     | 
    
         
            +
                uri.path = '/' if uri.path.empty?
         
     | 
| 
      
 245 
     | 
    
         
            +
                time = Time.now
         
     | 
| 
      
 246 
     | 
    
         
            +
                rand = CASServer::Utils.random_string
         
     | 
| 
      
 247 
     | 
    
         
            +
                path = uri.path
         
     | 
| 
      
 248 
     | 
    
         
            +
                req = Net::HTTP::Post.new(path)
         
     | 
| 
      
 249 
     | 
    
         
            +
                req.set_form_data('logoutRequest' => %{<samlp:LogoutRequest ID="#{rand}" Version="2.0" IssueInstant="#{time.rfc2822}">
         
     | 
| 
      
 250 
     | 
    
         
            +
             <saml:NameID></saml:NameID>
         
     | 
| 
      
 251 
     | 
    
         
            +
             <samlp:SessionIndex>#{st.ticket}</samlp:SessionIndex>
         
     | 
| 
      
 252 
     | 
    
         
            +
             </samlp:LogoutRequest>})
         
     | 
| 
      
 253 
     | 
    
         
            +
             
         
     | 
| 
      
 254 
     | 
    
         
            +
                begin
         
     | 
| 
      
 255 
     | 
    
         
            +
                  http = Net::HTTP.new(uri.host, uri.port)
         
     | 
| 
      
 256 
     | 
    
         
            +
                  http.use_ssl = true if uri.scheme =='https'
         
     | 
| 
      
 257 
     | 
    
         
            +
                  
         
     | 
| 
      
 258 
     | 
    
         
            +
                  http.start do |conn|
         
     | 
| 
      
 259 
     | 
    
         
            +
                    response = conn.request(req)
         
     | 
| 
      
 260 
     | 
    
         
            +
                    if response.kind_of? Net::HTTPSuccess
         
     | 
| 
      
 261 
     | 
    
         
            +
                      $LOG.info "Logout notification successfully posted to #{st.service.inspect}."
         
     | 
| 
      
 262 
     | 
    
         
            +
                      return true
         
     | 
| 
      
 263 
     | 
    
         
            +
                    else
         
     | 
| 
      
 264 
     | 
    
         
            +
                      $LOG.error "Service #{st.service.inspect} responed to logout notification with code '#{response.code}'!"
         
     | 
| 
      
 265 
     | 
    
         
            +
                      return false
         
     | 
| 
      
 266 
     | 
    
         
            +
                    end
         
     | 
| 
      
 267 
     | 
    
         
            +
                  end
         
     | 
| 
      
 268 
     | 
    
         
            +
                rescue Exception => e
         
     | 
| 
      
 269 
     | 
    
         
            +
                  $LOG.error "Failed to send logout notification to service #{st.service.inspect} due to #{e}"
         
     | 
| 
      
 270 
     | 
    
         
            +
                  return false
         
     | 
| 
      
 271 
     | 
    
         
            +
                end
         
     | 
| 
      
 272 
     | 
    
         
            +
              end
         
     | 
| 
      
 273 
     | 
    
         
            +
             
     | 
| 
      
 274 
     | 
    
         
            +
              def service_uri_with_ticket(service, st)
         
     | 
| 
      
 275 
     | 
    
         
            +
                raise ArgumentError, "Second argument must be a ServiceTicket!" unless st.kind_of? CASServer::Model::ServiceTicket
         
     | 
| 
      
 276 
     | 
    
         
            +
             
     | 
| 
      
 277 
     | 
    
         
            +
                # This will choke with a URI::InvalidURIError if service URI is not properly URI-escaped...
         
     | 
| 
      
 278 
     | 
    
         
            +
                # This exception is handled further upstream (i.e. in the controller).
         
     | 
| 
      
 279 
     | 
    
         
            +
                service_uri = URI.parse(service)
         
     | 
| 
      
 280 
     | 
    
         
            +
             
     | 
| 
      
 281 
     | 
    
         
            +
                if service.include? "?"
         
     | 
| 
      
 282 
     | 
    
         
            +
                  if service_uri.query.empty?
         
     | 
| 
      
 283 
     | 
    
         
            +
                    query_separator = ""
         
     | 
| 
      
 284 
     | 
    
         
            +
                  else
         
     | 
| 
      
 285 
     | 
    
         
            +
                    query_separator = "&"
         
     | 
| 
      
 286 
     | 
    
         
            +
                  end
         
     | 
| 
      
 287 
     | 
    
         
            +
                else
         
     | 
| 
      
 288 
     | 
    
         
            +
                  query_separator = "?"
         
     | 
| 
      
 289 
     | 
    
         
            +
                end
         
     | 
| 
      
 290 
     | 
    
         
            +
             
     | 
| 
      
 291 
     | 
    
         
            +
                service_with_ticket = service + query_separator + "ticket=" + st.ticket
         
     | 
| 
      
 292 
     | 
    
         
            +
                service_with_ticket
         
     | 
| 
      
 293 
     | 
    
         
            +
              end
         
     | 
| 
      
 294 
     | 
    
         
            +
             
     | 
| 
      
 295 
     | 
    
         
            +
              # Strips CAS-related parameters from a service URL and normalizes it,
         
     | 
| 
      
 296 
     | 
    
         
            +
              # removing trailing / and ?. Also converts any spaces to +.
         
     | 
| 
      
 297 
     | 
    
         
            +
              #
         
     | 
| 
      
 298 
     | 
    
         
            +
              # For example, "http://google.com?ticket=12345" will be returned as
         
     | 
| 
      
 299 
     | 
    
         
            +
              # "http://google.com". Also, "http://google.com/" would be returned as
         
     | 
| 
      
 300 
     | 
    
         
            +
              # "http://google.com".
         
     | 
| 
      
 301 
     | 
    
         
            +
              #
         
     | 
| 
      
 302 
     | 
    
         
            +
              # Note that only the first occurance of each CAS-related parameter is
         
     | 
| 
      
 303 
     | 
    
         
            +
              # removed, so that "http://google.com?ticket=12345&ticket=abcd" would be
         
     | 
| 
      
 304 
     | 
    
         
            +
              # returned as "http://google.com?ticket=abcd".
         
     | 
| 
      
 305 
     | 
    
         
            +
              def clean_service_url(dirty_service)
         
     | 
| 
      
 306 
     | 
    
         
            +
                return dirty_service if dirty_service.blank?
         
     | 
| 
      
 307 
     | 
    
         
            +
                clean_service = dirty_service.dup
         
     | 
| 
      
 308 
     | 
    
         
            +
                ['service', 'ticket', 'gateway', 'renew'].each do |p|
         
     | 
| 
      
 309 
     | 
    
         
            +
                  clean_service.sub!(Regexp.new("&?#{p}=[^&]*"), '')
         
     | 
| 
      
 310 
     | 
    
         
            +
                end
         
     | 
| 
      
 311 
     | 
    
         
            +
             
     | 
| 
      
 312 
     | 
    
         
            +
                clean_service.gsub!(/[\/\?&]$/, '') # remove trailing ?, /, or &
         
     | 
| 
      
 313 
     | 
    
         
            +
                clean_service.gsub!('?&', '?')
         
     | 
| 
      
 314 
     | 
    
         
            +
                clean_service.gsub!(' ', '+')
         
     | 
| 
      
 315 
     | 
    
         
            +
             
     | 
| 
      
 316 
     | 
    
         
            +
                $LOG.debug("Cleaned dirty service URL #{dirty_service.inspect} to #{clean_service.inspect}") if
         
     | 
| 
      
 317 
     | 
    
         
            +
                  dirty_service != clean_service
         
     | 
| 
      
 318 
     | 
    
         
            +
             
     | 
| 
      
 319 
     | 
    
         
            +
                return clean_service
         
     | 
| 
      
 320 
     | 
    
         
            +
              end
         
     | 
| 
      
 321 
     | 
    
         
            +
              module_function :clean_service_url
         
     | 
| 
      
 322 
     | 
    
         
            +
             
     | 
| 
      
 323 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'sinatra/r18n'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module CASServer
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Localization
         
     | 
| 
      
 5 
     | 
    
         
            +
                def self.included(mod)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  mod.module_eval do
         
     | 
| 
      
 7 
     | 
    
         
            +
                    register Sinatra::R18n
         
     | 
| 
      
 8 
     | 
    
         
            +
                    set :default_locale, 'en'
         
     | 
| 
      
 9 
     | 
    
         
            +
                    set :translations, File.dirname(__FILE__) + "/../../locales"
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,270 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'active_record'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'active_record/base'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module CASServer::Model
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              module Consumable
         
     | 
| 
      
 7 
     | 
    
         
            +
                def consume!
         
     | 
| 
      
 8 
     | 
    
         
            +
                  self.consumed = Time.now
         
     | 
| 
      
 9 
     | 
    
         
            +
                  self.save!
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def self.included(mod)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  mod.extend(ClassMethods)
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                module ClassMethods
         
     | 
| 
      
 17 
     | 
    
         
            +
                  def cleanup(max_lifetime, max_unconsumed_lifetime)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    transaction do
         
     | 
| 
      
 19 
     | 
    
         
            +
                      conditions = ["created_on < ? OR (consumed IS NULL AND created_on < ?)",
         
     | 
| 
      
 20 
     | 
    
         
            +
                                      Time.now - max_lifetime,
         
     | 
| 
      
 21 
     | 
    
         
            +
                                      Time.now - max_unconsumed_lifetime]
         
     | 
| 
      
 22 
     | 
    
         
            +
                                    
         
     | 
| 
      
 23 
     | 
    
         
            +
                      expired_tickets_count = count(:conditions => conditions)
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                      $LOG.debug("Destroying #{expired_tickets_count} expired #{self.name.demodulize}"+
         
     | 
| 
      
 26 
     | 
    
         
            +
                        "#{'s' if expired_tickets_count > 1}.") if expired_tickets_count > 0
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                      destroy_all(conditions)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    end
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              class Base < ActiveRecord::Base
         
     | 
| 
      
 35 
     | 
    
         
            +
              end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
              class Ticket < Base
         
     | 
| 
      
 38 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 39 
     | 
    
         
            +
                  ticket
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                def self.cleanup(max_lifetime)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  transaction do
         
     | 
| 
      
 44 
     | 
    
         
            +
                    conditions = ["created_on < ?", Time.now - max_lifetime]
         
     | 
| 
      
 45 
     | 
    
         
            +
                    expired_tickets_count = count(:conditions => conditions)
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                    $LOG.debug("Destroying #{expired_tickets_count} expired #{self.name.demodulize}"+
         
     | 
| 
      
 48 
     | 
    
         
            +
                      "#{'s' if expired_tickets_count > 1}.") if expired_tickets_count > 0
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    destroy_all(conditions)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
              end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
              class LoginTicket < Ticket
         
     | 
| 
      
 56 
     | 
    
         
            +
                set_table_name 'casserver_lt'
         
     | 
| 
      
 57 
     | 
    
         
            +
                include Consumable
         
     | 
| 
      
 58 
     | 
    
         
            +
              end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
              class ServiceTicket < Ticket
         
     | 
| 
      
 61 
     | 
    
         
            +
                set_table_name 'casserver_st'
         
     | 
| 
      
 62 
     | 
    
         
            +
                include Consumable
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                belongs_to :granted_by_tgt,
         
     | 
| 
      
 65 
     | 
    
         
            +
                  :class_name => 'CASServer::Model::TicketGrantingTicket',
         
     | 
| 
      
 66 
     | 
    
         
            +
                  :foreign_key => :granted_by_tgt_id
         
     | 
| 
      
 67 
     | 
    
         
            +
                has_one :proxy_granting_ticket,
         
     | 
| 
      
 68 
     | 
    
         
            +
                  :foreign_key => :created_by_st_id
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                def matches_service?(service)
         
     | 
| 
      
 71 
     | 
    
         
            +
                  CASServer::CAS.clean_service_url(self.service) ==
         
     | 
| 
      
 72 
     | 
    
         
            +
                    CASServer::CAS.clean_service_url(service)
         
     | 
| 
      
 73 
     | 
    
         
            +
                end
         
     | 
| 
      
 74 
     | 
    
         
            +
              end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
              class ProxyTicket < ServiceTicket
         
     | 
| 
      
 77 
     | 
    
         
            +
                belongs_to :granted_by_pgt,
         
     | 
| 
      
 78 
     | 
    
         
            +
                  :class_name => 'CASServer::Model::ProxyGrantingTicket',
         
     | 
| 
      
 79 
     | 
    
         
            +
                  :foreign_key => :granted_by_pgt_id
         
     | 
| 
      
 80 
     | 
    
         
            +
              end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
              class TicketGrantingTicket < Ticket
         
     | 
| 
      
 83 
     | 
    
         
            +
                set_table_name 'casserver_tgt'
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                serialize :extra_attributes
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                has_many :granted_service_tickets,
         
     | 
| 
      
 88 
     | 
    
         
            +
                  :class_name => 'CASServer::Model::ServiceTicket',
         
     | 
| 
      
 89 
     | 
    
         
            +
                  :foreign_key => :granted_by_tgt_id
         
     | 
| 
      
 90 
     | 
    
         
            +
              end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
              class ProxyGrantingTicket < Ticket
         
     | 
| 
      
 93 
     | 
    
         
            +
                set_table_name 'casserver_pgt'
         
     | 
| 
      
 94 
     | 
    
         
            +
                belongs_to :service_ticket
         
     | 
| 
      
 95 
     | 
    
         
            +
                has_many :granted_proxy_tickets,
         
     | 
| 
      
 96 
     | 
    
         
            +
                  :class_name => 'CASServer::Model::ProxyTicket',
         
     | 
| 
      
 97 
     | 
    
         
            +
                  :foreign_key => :granted_by_pgt_id
         
     | 
| 
      
 98 
     | 
    
         
            +
              end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
              class Error
         
     | 
| 
      
 101 
     | 
    
         
            +
                attr_reader :code, :message
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                def initialize(code, message)
         
     | 
| 
      
 104 
     | 
    
         
            +
                  @code = code
         
     | 
| 
      
 105 
     | 
    
         
            +
                  @message = message
         
     | 
| 
      
 106 
     | 
    
         
            +
                end
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 109 
     | 
    
         
            +
                  message
         
     | 
| 
      
 110 
     | 
    
         
            +
                end
         
     | 
| 
      
 111 
     | 
    
         
            +
              end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
            #  class CreateCASServer < V 0.1
         
     | 
| 
      
 114 
     | 
    
         
            +
            #    def self.up
         
     | 
| 
      
 115 
     | 
    
         
            +
            #      if ActiveRecord::Base.connection.table_alias_length > 30
         
     | 
| 
      
 116 
     | 
    
         
            +
            #        $LOG.info("Creating database with long table names...")
         
     | 
| 
      
 117 
     | 
    
         
            +
            #
         
     | 
| 
      
 118 
     | 
    
         
            +
            #        create_table :casserver_login_tickets, :force => true do |t|
         
     | 
| 
      
 119 
     | 
    
         
            +
            #          t.column :ticket,     :string,   :null => false
         
     | 
| 
      
 120 
     | 
    
         
            +
            #          t.column :created_on, :timestamp, :null => false
         
     | 
| 
      
 121 
     | 
    
         
            +
            #          t.column :consumed,   :datetime, :null => true
         
     | 
| 
      
 122 
     | 
    
         
            +
            #          t.column :client_hostname, :string, :null => false
         
     | 
| 
      
 123 
     | 
    
         
            +
            #        end
         
     | 
| 
      
 124 
     | 
    
         
            +
            #
         
     | 
| 
      
 125 
     | 
    
         
            +
            #        create_table :casserver_service_tickets, :force => true do |t|
         
     | 
| 
      
 126 
     | 
    
         
            +
            #          t.column :ticket,     :string,    :null => false
         
     | 
| 
      
 127 
     | 
    
         
            +
            #          t.column :service,    :string,    :null => false
         
     | 
| 
      
 128 
     | 
    
         
            +
            #          t.column :created_on, :timestamp, :null => false
         
     | 
| 
      
 129 
     | 
    
         
            +
            #          t.column :consumed,   :datetime, :null => true
         
     | 
| 
      
 130 
     | 
    
         
            +
            #          t.column :client_hostname, :string, :null => false
         
     | 
| 
      
 131 
     | 
    
         
            +
            #          t.column :username,   :string,  :null => false
         
     | 
| 
      
 132 
     | 
    
         
            +
            #          t.column :type,       :string,   :null => false
         
     | 
| 
      
 133 
     | 
    
         
            +
            #          t.column :proxy_granting_ticket_id, :integer, :null => true
         
     | 
| 
      
 134 
     | 
    
         
            +
            #        end
         
     | 
| 
      
 135 
     | 
    
         
            +
            #
         
     | 
| 
      
 136 
     | 
    
         
            +
            #        create_table :casserver_ticket_granting_tickets, :force => true do |t|
         
     | 
| 
      
 137 
     | 
    
         
            +
            #          t.column :ticket,     :string,    :null => false
         
     | 
| 
      
 138 
     | 
    
         
            +
            #          t.column :created_on, :timestamp, :null => false
         
     | 
| 
      
 139 
     | 
    
         
            +
            #          t.column :client_hostname, :string, :null => false
         
     | 
| 
      
 140 
     | 
    
         
            +
            #          t.column :username,   :string,    :null => false
         
     | 
| 
      
 141 
     | 
    
         
            +
            #        end
         
     | 
| 
      
 142 
     | 
    
         
            +
            #
         
     | 
| 
      
 143 
     | 
    
         
            +
            #        create_table :casserver_proxy_granting_tickets, :force => true do |t|
         
     | 
| 
      
 144 
     | 
    
         
            +
            #          t.column :ticket,     :string,    :null => false
         
     | 
| 
      
 145 
     | 
    
         
            +
            #          t.column :created_on, :timestamp, :null => false
         
     | 
| 
      
 146 
     | 
    
         
            +
            #          t.column :client_hostname, :string, :null => false
         
     | 
| 
      
 147 
     | 
    
         
            +
            #          t.column :iou,        :string,    :null => false
         
     | 
| 
      
 148 
     | 
    
         
            +
            #          t.column :service_ticket_id, :integer, :null => false
         
     | 
| 
      
 149 
     | 
    
         
            +
            #        end
         
     | 
| 
      
 150 
     | 
    
         
            +
            #      end
         
     | 
| 
      
 151 
     | 
    
         
            +
            #    end
         
     | 
| 
      
 152 
     | 
    
         
            +
            #
         
     | 
| 
      
 153 
     | 
    
         
            +
            #    def self.down
         
     | 
| 
      
 154 
     | 
    
         
            +
            #      if ActiveRecord::Base.connection.table_alias_length > 30
         
     | 
| 
      
 155 
     | 
    
         
            +
            #        drop_table :casserver_proxy_granting_tickets
         
     | 
| 
      
 156 
     | 
    
         
            +
            #        drop_table :casserver_ticket_granting_tickets
         
     | 
| 
      
 157 
     | 
    
         
            +
            #        drop_table :casserver_service_tickets
         
     | 
| 
      
 158 
     | 
    
         
            +
            #        drop_table :casserver_login_tickets
         
     | 
| 
      
 159 
     | 
    
         
            +
            #      end
         
     | 
| 
      
 160 
     | 
    
         
            +
            #    end
         
     | 
| 
      
 161 
     | 
    
         
            +
            #  end
         
     | 
| 
      
 162 
     | 
    
         
            +
            #
         
     | 
| 
      
 163 
     | 
    
         
            +
            #  # Oracle table names cannot exceed 30 chars...
         
     | 
| 
      
 164 
     | 
    
         
            +
            #  # See http://code.google.com/p/rubycas-server/issues/detail?id=15
         
     | 
| 
      
 165 
     | 
    
         
            +
            #  class ShortenTableNames < V 0.5
         
     | 
| 
      
 166 
     | 
    
         
            +
            #    def self.up
         
     | 
| 
      
 167 
     | 
    
         
            +
            #      if ActiveRecord::Base.connection.table_alias_length > 30
         
     | 
| 
      
 168 
     | 
    
         
            +
            #        $LOG.info("Shortening table names")
         
     | 
| 
      
 169 
     | 
    
         
            +
            #        rename_table :casserver_login_tickets, :casserver_lt
         
     | 
| 
      
 170 
     | 
    
         
            +
            #        rename_table :casserver_service_tickets, :casserver_st
         
     | 
| 
      
 171 
     | 
    
         
            +
            #        rename_table :casserver_ticket_granting_tickets, :casserver_tgt
         
     | 
| 
      
 172 
     | 
    
         
            +
            #        rename_table :casserver_proxy_granting_tickets, :casserver_pgt
         
     | 
| 
      
 173 
     | 
    
         
            +
            #      else
         
     | 
| 
      
 174 
     | 
    
         
            +
            #        create_table :casserver_lt, :force => true do |t|
         
     | 
| 
      
 175 
     | 
    
         
            +
            #          t.column :ticket,     :string,   :null => false
         
     | 
| 
      
 176 
     | 
    
         
            +
            #          t.column :created_on, :timestamp, :null => false
         
     | 
| 
      
 177 
     | 
    
         
            +
            #          t.column :consumed,   :datetime, :null => true
         
     | 
| 
      
 178 
     | 
    
         
            +
            #          t.column :client_hostname, :string, :null => false
         
     | 
| 
      
 179 
     | 
    
         
            +
            #        end
         
     | 
| 
      
 180 
     | 
    
         
            +
            #
         
     | 
| 
      
 181 
     | 
    
         
            +
            #        create_table :casserver_st, :force => true do |t|
         
     | 
| 
      
 182 
     | 
    
         
            +
            #          t.column :ticket,     :string,    :null => false
         
     | 
| 
      
 183 
     | 
    
         
            +
            #          t.column :service,    :string,    :null => false
         
     | 
| 
      
 184 
     | 
    
         
            +
            #          t.column :created_on, :timestamp, :null => false
         
     | 
| 
      
 185 
     | 
    
         
            +
            #          t.column :consumed,   :datetime, :null => true
         
     | 
| 
      
 186 
     | 
    
         
            +
            #          t.column :client_hostname, :string, :null => false
         
     | 
| 
      
 187 
     | 
    
         
            +
            #          t.column :username,   :string,  :null => false
         
     | 
| 
      
 188 
     | 
    
         
            +
            #          t.column :type,       :string,   :null => false
         
     | 
| 
      
 189 
     | 
    
         
            +
            #          t.column :proxy_granting_ticket_id, :integer, :null => true
         
     | 
| 
      
 190 
     | 
    
         
            +
            #        end
         
     | 
| 
      
 191 
     | 
    
         
            +
            #
         
     | 
| 
      
 192 
     | 
    
         
            +
            #        create_table :casserver_tgt, :force => true do |t|
         
     | 
| 
      
 193 
     | 
    
         
            +
            #          t.column :ticket,     :string,    :null => false
         
     | 
| 
      
 194 
     | 
    
         
            +
            #          t.column :created_on, :timestamp, :null => false
         
     | 
| 
      
 195 
     | 
    
         
            +
            #          t.column :client_hostname, :string, :null => false
         
     | 
| 
      
 196 
     | 
    
         
            +
            #          t.column :username,   :string,    :null => false
         
     | 
| 
      
 197 
     | 
    
         
            +
            #        end
         
     | 
| 
      
 198 
     | 
    
         
            +
            #
         
     | 
| 
      
 199 
     | 
    
         
            +
            #        create_table :casserver_pgt, :force => true do |t|
         
     | 
| 
      
 200 
     | 
    
         
            +
            #          t.column :ticket,     :string,    :null => false
         
     | 
| 
      
 201 
     | 
    
         
            +
            #          t.column :created_on, :timestamp, :null => false
         
     | 
| 
      
 202 
     | 
    
         
            +
            #          t.column :client_hostname, :string, :null => false
         
     | 
| 
      
 203 
     | 
    
         
            +
            #          t.column :iou,        :string,    :null => false
         
     | 
| 
      
 204 
     | 
    
         
            +
            #          t.column :service_ticket_id, :integer, :null => false
         
     | 
| 
      
 205 
     | 
    
         
            +
            #        end
         
     | 
| 
      
 206 
     | 
    
         
            +
            #      end
         
     | 
| 
      
 207 
     | 
    
         
            +
            #    end
         
     | 
| 
      
 208 
     | 
    
         
            +
            #
         
     | 
| 
      
 209 
     | 
    
         
            +
            #    def self.down
         
     | 
| 
      
 210 
     | 
    
         
            +
            #      if ActiveRecord::Base.connection.table_alias_length > 30
         
     | 
| 
      
 211 
     | 
    
         
            +
            #        rename_table :casserver_lt, :cassserver_login_tickets
         
     | 
| 
      
 212 
     | 
    
         
            +
            #        rename_table :casserver_st, :casserver_service_tickets
         
     | 
| 
      
 213 
     | 
    
         
            +
            #        rename_table :casserver_tgt, :casserver_ticket_granting_tickets
         
     | 
| 
      
 214 
     | 
    
         
            +
            #        rename_table :casserver_pgt, :casserver_proxy_granting_tickets
         
     | 
| 
      
 215 
     | 
    
         
            +
            #      else
         
     | 
| 
      
 216 
     | 
    
         
            +
            #        drop_table :casserver_pgt
         
     | 
| 
      
 217 
     | 
    
         
            +
            #        drop_table :casserver_tgt
         
     | 
| 
      
 218 
     | 
    
         
            +
            #        drop_table :casserver_st
         
     | 
| 
      
 219 
     | 
    
         
            +
            #        drop_table :casserver_lt
         
     | 
| 
      
 220 
     | 
    
         
            +
            #      end
         
     | 
| 
      
 221 
     | 
    
         
            +
            #    end
         
     | 
| 
      
 222 
     | 
    
         
            +
            #  end
         
     | 
| 
      
 223 
     | 
    
         
            +
            #
         
     | 
| 
      
 224 
     | 
    
         
            +
            #  class AddTgtToSt < V 0.7
         
     | 
| 
      
 225 
     | 
    
         
            +
            #    def self.up
         
     | 
| 
      
 226 
     | 
    
         
            +
            #      add_column :casserver_st, :tgt_id, :integer, :null => true
         
     | 
| 
      
 227 
     | 
    
         
            +
            #    end
         
     | 
| 
      
 228 
     | 
    
         
            +
            #
         
     | 
| 
      
 229 
     | 
    
         
            +
            #    def self.down
         
     | 
| 
      
 230 
     | 
    
         
            +
            #      remove_column :casserver_st, :tgt_id, :integer
         
     | 
| 
      
 231 
     | 
    
         
            +
            #    end
         
     | 
| 
      
 232 
     | 
    
         
            +
            #  end
         
     | 
| 
      
 233 
     | 
    
         
            +
            #
         
     | 
| 
      
 234 
     | 
    
         
            +
            #  class ChangeServiceToText < V 0.71
         
     | 
| 
      
 235 
     | 
    
         
            +
            #    def self.up
         
     | 
| 
      
 236 
     | 
    
         
            +
            #      # using change_column to change the column type from :string to :text
         
     | 
| 
      
 237 
     | 
    
         
            +
            #      # doesn't seem to work, at least under MySQL, so we drop and re-create
         
     | 
| 
      
 238 
     | 
    
         
            +
            #      # the column instead
         
     | 
| 
      
 239 
     | 
    
         
            +
            #      remove_column :casserver_st, :service
         
     | 
| 
      
 240 
     | 
    
         
            +
            #      say "WARNING: All existing service tickets are being deleted."
         
     | 
| 
      
 241 
     | 
    
         
            +
            #      add_column :casserver_st, :service, :text
         
     | 
| 
      
 242 
     | 
    
         
            +
            #    end
         
     | 
| 
      
 243 
     | 
    
         
            +
            #
         
     | 
| 
      
 244 
     | 
    
         
            +
            #    def self.down
         
     | 
| 
      
 245 
     | 
    
         
            +
            #      change_column :casserver_st, :service, :string
         
     | 
| 
      
 246 
     | 
    
         
            +
            #    end
         
     | 
| 
      
 247 
     | 
    
         
            +
            #  end
         
     | 
| 
      
 248 
     | 
    
         
            +
            #
         
     | 
| 
      
 249 
     | 
    
         
            +
            #  class AddExtraAttributes < V 0.72
         
     | 
| 
      
 250 
     | 
    
         
            +
            #    def self.up
         
     | 
| 
      
 251 
     | 
    
         
            +
            #      add_column :casserver_tgt, :extra_attributes, :text
         
     | 
| 
      
 252 
     | 
    
         
            +
            #    end
         
     | 
| 
      
 253 
     | 
    
         
            +
            #
         
     | 
| 
      
 254 
     | 
    
         
            +
            #    def self.down
         
     | 
| 
      
 255 
     | 
    
         
            +
            #      remove_column :casserver_tgt, :extra_attributes
         
     | 
| 
      
 256 
     | 
    
         
            +
            #    end
         
     | 
| 
      
 257 
     | 
    
         
            +
            #  end
         
     | 
| 
      
 258 
     | 
    
         
            +
            #
         
     | 
| 
      
 259 
     | 
    
         
            +
            #  class RenamePgtForeignKeys < V 0.80
         
     | 
| 
      
 260 
     | 
    
         
            +
            #    def self.up
         
     | 
| 
      
 261 
     | 
    
         
            +
            #      rename_column :casserver_st,  :proxy_granting_ticket_id,  :granted_by_pgt_id
         
     | 
| 
      
 262 
     | 
    
         
            +
            #      rename_column :casserver_st,  :tgt_id,                    :granted_by_tgt_id
         
     | 
| 
      
 263 
     | 
    
         
            +
            #    end
         
     | 
| 
      
 264 
     | 
    
         
            +
            #
         
     | 
| 
      
 265 
     | 
    
         
            +
            #    def self.down
         
     | 
| 
      
 266 
     | 
    
         
            +
            #      rename_column :casserver_st,  :granted_by_pgt_id,         :proxy_granting_ticket_id
         
     | 
| 
      
 267 
     | 
    
         
            +
            #      rename_column :casserver_st,  :granted_by_tgt_id,         :tgt_id
         
     | 
| 
      
 268 
     | 
    
         
            +
            #    end
         
     | 
| 
      
 269 
     | 
    
         
            +
            #  end
         
     | 
| 
      
 270 
     | 
    
         
            +
            end
         
     |