Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ source "http://rubygems.org"
if ENV.key?('RAILS_VERSION')
railsversion = "= #{ENV['RAILS_VERSION']}"
else
railsversion = ['>= 3.1.10']
railsversion = ['5.2.4']
end

gem 'rails', railsversion
Expand Down
47 changes: 23 additions & 24 deletions app/controllers/cassy/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@ class SessionsController < ApplicationController

def new
detect_ticketing_service(params[:service])

@renew = params['renew']
@gateway = params['gateway'] == 'true' || params['gateway'] == '1'
@hostname = env['HTTP_X_FORWARDED_FOR'] || env['REMOTE_HOST'] || env['REMOTE_ADDR']
@tgt, tgt_error = Cassy::TicketGrantingTicket.validate(request.cookies['tgt'])
@hostname = request.env['HTTP_X_FORWARDED_FOR'] || request.env['REMOTE_HOST'] || request.env['REMOTE_ADDR']
@tgt, tgt_error = Cassy::TicketGrantingTicket.validate_ticket(request.cookies['tgt'])
if @tgt
flash.now[:notice] = "You are currently logged in as '%s'." % ticketed_user(@tgt).send(settings[:username_field])
end

if params['redirection_loop_intercepted']
flash.now[:error] = "The client and server are unable to negotiate authentication. Please try logging in again later."
end

if @service
if @ticketed_user && cas_login
redirect_to @service_with_ticket
Expand All @@ -36,12 +36,12 @@ def new

@lt = generate_login_ticket.ticket
end

def create
@lt = generate_login_ticket.ticket # in case the login isn't successful, another ticket needs to be generated for the next attempt at login
detect_ticketing_service(params[:service])
@hostname = env['HTTP_X_FORWARDED_FOR'] || env['REMOTE_HOST'] || env['REMOTE_ADDR']
consume_ticket = Cassy::LoginTicket.validate(@lt)
@hostname = request.env['HTTP_X_FORWARDED_FOR'] || request.env['REMOTE_HOST'] || request.env['REMOTE_ADDR']
consume_ticket = Cassy::LoginTicket.validate_ticket(@lt)
if !consume_ticket[:valid]
flash.now[:error] = consume_ticket[:error]
@lt = generate_login_ticket.ticket
Expand All @@ -55,12 +55,12 @@ def create
else
flash.now[:notice] = "You have successfully logged in."
render :new
end
end
else
incorrect_credentials!
end
end

def destroy
# The behaviour here is somewhat non-standard. Rather than showing just a blank
# "logout" page, we take the user back to the login page with a "you have been logged out"
Expand All @@ -71,16 +71,15 @@ def destroy

@gateway = params['gateway'] == 'true' || params['gateway'] == '1'

tgt = Cassy::TicketGrantingTicket.find_by_ticket(request.cookies['tgt'])
tgt = Cassy::TicketGrantingTicket.find_by(ticket: request.cookies['tgt'])

response.delete_cookie 'tgt'

if tgt
Cassy::TicketGrantingTicket.transaction do
pgts = Cassy::ProxyGrantingTicket.find(:all,
:conditions => [ActiveRecord::Base.connection.quote_table_name(Cassy::ServiceTicket.table_name)+".username = ?", tgt.username],
:include => :service_ticket)
pgts.each do |pgt|
pgts = Cassy::ProxyGrantingTicket.where(Cassy::ServiceTicket.table_name => { :username => tgt.username }).
includes(:service_ticket)
pgts.find_each do |pgt|
pgt.destroy
end
if Cassy.config[:enable_single_sign_out]
Expand All @@ -92,7 +91,7 @@ def destroy
tgt.destroy
end
end

flash[:notice] = "You have successfully logged out."
@lt = generate_login_ticket

Expand All @@ -102,18 +101,18 @@ def destroy
redirect_to :action => :new, :service => @service
end
end

def service_validate
# takes a params[:service] and a params[:ticket] and validates them

# required
@service = clean_service_url(params['service'])
@ticket = params['ticket']
# optional
@renew = params['renew']
@pgt_url = params['pgtUrl']

@service_ticket, @error = Cassy::ServiceTicket.validate(@service, @ticket)
@service_ticket, @error = Cassy::ServiceTicket.validate_ticket(@service, @ticket)
if @service_ticket
@username = ticketed_user(@service_ticket).send(settings[:client_app_user_field])
if @pgt_url
Expand All @@ -124,7 +123,7 @@ def service_validate
end
render :proxy_validate, :layout => false, :status => @service_ticket ? 200 : 422
end

def proxy_validate
# required
@service = clean_service_url(params['service'])
Expand All @@ -135,7 +134,7 @@ def proxy_validate

@proxies = []

@service_ticket, @error = Cassy::ServiceTicket.validate(@service, @ticket)
@service_ticket, @error = Cassy::ServiceTicket.validate_ticket(@service, @ticket)
@extra_attributes = {}
if @service_ticket
@username = ticketed_user(@service_ticket).send(settings[:client_app_user_field])
Expand All @@ -153,11 +152,11 @@ def proxy_validate
end

render :proxy_validate, :layout => false, :status => @service_ticket ? 200 : 422

end

private

def incorrect_credentials!
@lt = generate_login_ticket.ticket
flash.now[:error] = "Incorrect username or password."
Expand Down
8 changes: 4 additions & 4 deletions app/models/cassy/login_ticket.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ class LoginTicket < ActiveRecord::Base
include Cassy::Ticket
self.table_name = 'casserver_lt'
include Consumable
def self.validate(ticket="invalid")
ticket = LoginTicket.find_by_ticket(ticket)

def self.validate_ticket(ticket="invalid")
ticket = LoginTicket.find_by(ticket: ticket)
if ticket
if ticket.consumed?
{:valid => false, :error => "The login ticket you provided has already been used up. Please try logging in again."}
Expand All @@ -18,6 +18,6 @@ def self.validate(ticket="invalid")
{:valid => false, :error => "The login ticket you provided is invalid. There may be a problem with the authentication system."}
end
end

end
end
8 changes: 4 additions & 4 deletions app/models/cassy/proxy_granting_ticket.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ class ProxyGrantingTicket < ActiveRecord::Base
:class_name => 'Cassy::ProxyTicket',
:foreign_key => :granted_by_pgt_id
end
def self.validate(ticket)

def self.validate_ticket(ticket)
if ticket.nil?
error = Error.new(:INVALID_REQUEST, "pgt parameter was missing in the request.")
logger.warn("#{error.code} - #{error.message}")
elsif pgt = ProxyGrantingTicket.find_by_ticket(ticket)
elsif pgt = ProxyGrantingTicket.find_by(ticket: ticket)
if pgt.service_ticket
logger.info("Proxy granting ticket '#{ticket}' belonging to user '#{pgt.service_ticket.username}' successfully validated.")
else
Expand All @@ -26,5 +26,5 @@ def self.validate(ticket)

[pgt, error]
end

end
10 changes: 5 additions & 5 deletions app/models/cassy/proxy_ticket.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ class ProxyTicket < ServiceTicket
:class_name => 'Cassy::ProxyGrantingTicket',
:foreign_key => :granted_by_pgt_id
end
def validate(service, ticket)
pt, error = Cassy::ServiceTicket.validate(service, ticket, true)

def validate_ticket(service, ticket)
pt, error = Cassy::ServiceTicket.validate_ticket(service, ticket, true)

if pt.kind_of?(Cassy::ProxyTicket) && !error
if not pt.granted_by_pgt
Expand All @@ -19,5 +19,5 @@ def validate(service, ticket)

[pt, error]
end
end

end
18 changes: 9 additions & 9 deletions app/models/cassy/service_ticket.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ def set_type_column

belongs_to :granted_by_tgt, :class_name => 'Cassy::TicketGrantingTicket', :foreign_key => :granted_by_tgt_id
has_one :proxy_granting_ticket, :foreign_key => :created_by_st_id
def self.validate(service, ticket, allow_proxy_tickets = false)

def self.validate_ticket(service, ticket, allow_proxy_tickets = false)
logger.debug "Validating service ticket '#{ticket}' for service '#{service}'"

if service.nil?
logger.warn "Service not provided to validate service ticket"
[nil, "Ticket or service parameter was missing in the request"]
elsif st = Cassy::ServiceTicket.find_by_ticket(ticket)
elsif st = Cassy::ServiceTicket.find_by(ticket: ticket)
if st.consumed?
logger.warn "Ticket #{ticket} has already been used"
[nil, "Ticket #{ticket} has already been consumed."]
Expand All @@ -49,7 +49,7 @@ def self.validate(service, ticket, allow_proxy_tickets = false)
[nil, "Ticket '#{ticket}' not recognized."]
end
end


def matches_service?(service)
if Cassy.config[:loosely_match_services] == true
Expand All @@ -58,7 +58,7 @@ def matches_service?(service)
Cassy::CAS.clean_service_url(self.service) == Cassy::CAS.clean_service_url(service)
end
end

# Takes an existing ServiceTicket object (presumably pulled from the database)
# and sends a POST with logout information to the service that the ticket
# was generated for.
Expand Down Expand Up @@ -89,20 +89,20 @@ def send_logout_notification
return false
end
end

# XML to be posted when using single sign out
def logout_notification_message
time = Time.now
rand = Cassy::Utils.random_string
{'logoutRequest' => %{<samlp:LogoutRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="#{rand}" Version="2.0" IssueInstant="#{time.rfc2822}"><saml:NameID></saml:NameID><samlp:SessionIndex>#{self.ticket}</samlp:SessionIndex></samlp:LogoutRequest>}}
end

# Try to find an existing service ticket for the given user and service
def self.find_or_generate(service, username, tgt, hostname)
st = tgt.granted_service_tickets.where(:service => service).where("created_on > ?", Time.now - Cassy.config[:maximum_session_lifetime]).order("created_on DESC").first
st || self.generate(service, username, tgt, hostname)
end

def self.generate(service, username, tgt, hostname)
st = ServiceTicket.new
st.ticket = "ST-" + Cassy::Utils.random_string
Expand All @@ -115,6 +115,6 @@ def self.generate(service, username, tgt, hostname)
" for user '#{st.username}' at '#{st.client_hostname}'")
st
end

end
end
18 changes: 9 additions & 9 deletions app/models/cassy/ticket_granting_ticket.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ class TicketGrantingTicket < ActiveRecord::Base
:class_name => 'Cassy::ServiceTicket',
:foreign_key => :granted_by_tgt_id,
:dependent => :destroy
def self.validate(ticket)


def self.validate_ticket(ticket)
if ticket.nil?
[nil, "No ticket provided."]
elsif tgt = TicketGrantingTicket.find_by_ticket(ticket)
elsif tgt = TicketGrantingTicket.find_by(ticket: ticket)
if Cassy.config[:maximum_session_lifetime] && Time.now - Cassy.config[:maximum_session_lifetime] > tgt.created_on
tgt.destroy
[nil, "Ticket TGT-12345678901234567890 has expired. Please log in again."]
Expand All @@ -28,7 +28,7 @@ def self.validate(ticket)
[nil, "Ticket '#{ticket}' not recognized."]
end
end

# Creates a TicketGrantingTicket for the given username. This is done when the user logs in
# for the first time to establish their SSO session (after their credentials have been validated).
#
Expand All @@ -51,17 +51,17 @@ def self.generate(username, extra_attributes={}, hostname)
end
tgt
end

# Returns the users previous ticket_granting_ticket
def previous_ticket
Cassy::TicketGrantingTicket.where(:username => username.to_s).where("id <> ?",self.id).where("created_on > ?", Time.now - Cassy.config[:maximum_session_lifetime]).order("created_on DESC").first
end

# Returns true if the ticket is not the most recent ticket granting ticket for that username
def not_the_latest_for_this_user?
Cassy::TicketGrantingTicket.where(:username => username).where("created_on > ? AND id <> ?",created_on,self.id).any?
end

# If enable_single_sign_out is true, sends a logout notification to each service before destroying the ticket
def destroy_and_logout_all_service_tickets
if Cassy.config[:enable_single_sign_out]
Expand All @@ -73,6 +73,6 @@ def destroy_and_logout_all_service_tickets
raise "Single Sign Out is not enabled for Cassy. If you want to enable it, add 'enable_single_sign_out: true' to the Cassy config file."
end
end

end
end
6 changes: 3 additions & 3 deletions cassy.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ Gem::Specification.new do |s|
s.add_dependency 'crypt-isaac'
s.add_dependency 'rails', '>= 3.0.9'

s.add_development_dependency 'rspec-rails', '~> 2.7.0'
s.add_development_dependency 'capybara', '~> 1.0'
s.add_development_dependency 'rspec-rails', '~> 3.9.0'
s.add_development_dependency 'capybara', '~> 2.2.0'
s.add_development_dependency 'database_cleaner'
s.add_development_dependency 'sqlite3'
s.add_development_dependency 'launchy'
s.add_development_dependency 'devise', '~> 3.2.4'
s.add_development_dependency 'devise', '~> 4.7.1'
s.add_development_dependency 'webmock'
end
10 changes: 5 additions & 5 deletions lib/cassy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,23 @@

module Cassy
extend ActiveSupport::Autoload

autoload :CAS
autoload :Utils
autoload :Engine

def self.root
Pathname.new(File.dirname(__FILE__) + "../..")
end

# Just an easier way to get to the configuration for the engine
def self.config
Cassy::Engine.config.configuration
end

class AuthenticatorError < Exception
end
end

require 'cassy/authenticators'
require 'cassy/engine'
require 'cassy/engine'
Loading