diff --git a/.gitignore b/.gitignore index 9028aad..81e7255 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.gem *.rbc +log .bundle .config .yardoc @@ -16,3 +17,4 @@ test/tmp test/version_tmp tmp *.DS_Store +*.db diff --git a/.ruby-gemset b/.ruby-gemset deleted file mode 100644 index d1ae265..0000000 --- a/.ruby-gemset +++ /dev/null @@ -1 +0,0 @@ -rubycas-server-core diff --git a/Gemfile b/Gemfile index 4617764..0e39a2a 100644 --- a/Gemfile +++ b/Gemfile @@ -17,4 +17,5 @@ end group :test do gem 'rake' gem 'rspec' + gem 'rubycas-server-memory', github: 'vasilakisfil/rubycas-server-memory' end diff --git a/README.md b/README.md index d122101..a5f6b9c 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,60 @@ rubycas-server-core =================== -[![Build Status](https://travis-ci.org/rubycas/rubycas-server-core.png)](https://travis-ci.org/rubycas/rubycas-server-core) -The core logic for handling CAS requests independent of any particular storage or web presentation technology. +[![Circle CI](https://circleci.com/gh/vasilakisfil/rubycas-server-core.svg?style=svg)](https://circleci.com/gh/vasilakisfil/rubycas-server-core) +The core logic for handling CAS requests independent of any particular storage or web presentation technology. ## Requirements * ruby 2.1.x +## Adapters +Currently available adapters are: +* [rubycas-server-activerecord](https://github.com/kollegorna/rubycas-server-activerecord) +* [rubycas-server-memory](https://github.com/vasilakisfil/rubycas-server-memory) + +If you want to create a new adapter check these 2 adapters how they are implemented. Essentially you need to implement the following methods for each ticket: + +```ruby + +class XXXTicket + def initialize(options = {}) + end + + #deprecated + def self.find_by_ticket(ticket) + #returns the ticket based on the ticket id + #it will be removed soon + end + + def self.find_by(opts = {}) + #returns the ticket based on the constraints in the hash (activerecord-style) + end + + def save! + #saves the ticket in the storage + #throws an exception in case of an error + end + + def save + #saves the ticket in the storage + end + + def consumed? + #returns true if ticket is already consumed + end + + def consume! + #consumes the ticket + end + + def expired?(max_lifetime = 100) + #checks if the ticket is already expired + end + +end +``` + ## Contributing 1. Fork it diff --git a/circle.yml b/circle.yml new file mode 100644 index 0000000..6508ed0 --- /dev/null +++ b/circle.yml @@ -0,0 +1,3 @@ +machine: + ruby: + version: 2.1.2 diff --git a/lib/rubycas-server-core.rb b/lib/rubycas-server-core.rb index 2fa2804..381f81f 100644 --- a/lib/rubycas-server-core.rb +++ b/lib/rubycas-server-core.rb @@ -1,12 +1,14 @@ require "logger" require "r18n-core" require "rubycas-server-core/version" +require "rubycas-server-core/error" require "rubycas-server-core/authenticator" require "rubycas-server-core/settings" require "rubycas-server-core/database" require "rubycas-server-core/util" -require "rubycas-server-core/tickets" +require "rubycas-server-core/tickets/generations" require "rubycas-server-core/tickets/validations" +require "rubycas-server-core/tickets" module RubyCAS module Server diff --git a/lib/rubycas-server-core/adapters/in_memory.rb b/lib/rubycas-server-core/adapters/in_memory.rb deleted file mode 100644 index 490b702..0000000 --- a/lib/rubycas-server-core/adapters/in_memory.rb +++ /dev/null @@ -1,21 +0,0 @@ -require 'securerandom' -require "rubycas-server-core/adapters/in_memory/storage" -require "rubycas-server-core/adapters/in_memory/login_ticket" -require "rubycas-server-core/adapters/in_memory/ticket_granting_ticket" -require "rubycas-server-core/adapters/in_memory/service_ticket" -require "rubycas-server-core/adapters/in_memory/proxy_ticket" -require "rubycas-server-core/adapters/in_memory/proxy_granting_ticket" - -module RubyCAS - module Server - module Core - module Database - extend self - def setup(config_file) - # InMemory adapter do not require any settings - return true - end - end - end - end -end diff --git a/lib/rubycas-server-core/adapters/in_memory/login_ticket.rb b/lib/rubycas-server-core/adapters/in_memory/login_ticket.rb deleted file mode 100644 index 7bfaba7..0000000 --- a/lib/rubycas-server-core/adapters/in_memory/login_ticket.rb +++ /dev/null @@ -1,45 +0,0 @@ -module RubyCAS - module Server - module Core - module Tickets - class LoginTicket < Storage - attr_accessor :id, :ticket, :consumed, :client_hostname, - :created_at, :updated_at - - - def initialize(lt = {}) - @id = SecureRandom.uuid - @ticket = lt[:ticket] - @consumed = lt[:consumed] - @client_hostname = lt[:client_hostname] - @created_at = DateTime.now - @updated_at = DateTime.now - super() - end - - def self.find_by_ticket(ticket) - @storage.each do |id,lt| - return lt if lt.ticket == ticket - end - return nil - end - - def consumed? - consumed - end - - def consume! - consumed = true - self.save - end - - def expired?(max_lifetime = 100) - lifetime = Time.now.to_i - created_at.to_time.to_i - lifetime > max_lifetime - end - - end - end - end - end -end diff --git a/lib/rubycas-server-core/adapters/in_memory/proxy_granting_ticket.rb b/lib/rubycas-server-core/adapters/in_memory/proxy_granting_ticket.rb deleted file mode 100644 index e78f52c..0000000 --- a/lib/rubycas-server-core/adapters/in_memory/proxy_granting_ticket.rb +++ /dev/null @@ -1,38 +0,0 @@ -module RubyCAS - module Server - module Core - module Tickets - class ProxyGrantingTicket < Storage - - attr_accessor :id, :ticket, :client_hostname, :iou, - :created_at, :updated_at, :service_ticket, - :proxy_tickets - - def initialize(pgt = {}) - @id = SecureRandom.uuid - @ticket = pgt[:ticket] - @client_hostname = pgt[:client_hostname] - @created_at = DateTime.now - @updated_at = DateTime.now - @service_ticket = pgt[:service_ticket] - @proxy_tickets = pgt[:proxy_tickets] - super() - end - - - def self.find_by_ticket(ticket) - @storage.each do |id,pgt| - return pgt if pgt.ticket == ticket - end - return nil - end - - def expired?(max_lifetime = 100) - lifetime = Time.now.to_i - created_at.to_time.to_i - lifetime > max_lifetime - end - end - end - end - end -end diff --git a/lib/rubycas-server-core/adapters/in_memory/proxy_ticket.rb b/lib/rubycas-server-core/adapters/in_memory/proxy_ticket.rb deleted file mode 100644 index d81f8ff..0000000 --- a/lib/rubycas-server-core/adapters/in_memory/proxy_ticket.rb +++ /dev/null @@ -1,50 +0,0 @@ -module RubyCAS - module Server - module Core - module Tickets - class ProxyTicket < Storage - - attr_accessor :id, :ticket, :service, :consumed, :client_hostname, - :username, :created_at, :updated_at, :proxy_granting_ticket, - :ticket_granting_ticket - - def initialize(pt = {}) - @id = SecureRandom.uuid - @ticket = pt[:ticket] - @service = pt[:service] - @consumed = pt[:consumed] - @client_hostname = pt[:client_hostname] - @username = pt[:username] - @created_at = DateTime.now - @updated_at = DateTime.now - @proxy_granting_ticket = pt[:proxy_granting_ticket] - @ticket_granting_ticket = pt[:ticket_granting_ticket] - super() - end - - - def self.find_by_ticket(ticket) - @storage.each do |id,pt| - return pt if pt.ticket == ticket - end - return nil - end - - def consumed? - consumed - end - - def consume! - consumed = true - self.save - end - - def expired?(max_lifetime = 100) - lifetime = Time.now.to_i - created_at.to_time.to_i - lifetime > max_lifetime - end - end - end - end - end -end diff --git a/lib/rubycas-server-core/adapters/in_memory/service_ticket.rb b/lib/rubycas-server-core/adapters/in_memory/service_ticket.rb deleted file mode 100644 index 0cc7e0d..0000000 --- a/lib/rubycas-server-core/adapters/in_memory/service_ticket.rb +++ /dev/null @@ -1,56 +0,0 @@ -module RubyCAS - module Server - module Core - module Tickets - class ServiceTicket < Storage - - attr_accessor :id, :ticket, :consumed, :client_hostname, - :username, :created_at, :updated_at, :proxy_granting_ticket, - :ticket_granting_ticket - attr_reader :service - - def initialize(st = {}) - @id = SecureRandom.uuid - @ticket = st[:ticket] - @service = st[:service] - @consumed = st[:consumed] - @client_hostname = st[:client_hostname] - @username = st[:username] - @created_at = DateTime.now - @updated_at = DateTime.now - @proxy_granting_ticket = st[:proxy_granting_ticket] - @ticket_granting_ticket = st[:ticket_granting_ticket] - super() - end - - - def self.find_by_ticket(ticket) - @storage.each do |id,st| - return st if st.ticket == ticket - end - return nil - end - - def consumed? - consumed - end - - def consume! - consumed = true - self.save - end - - def expired?(max_lifetime = 100) - lifetime = Time.now.to_i - created_at.to_time.to_i - lifetime > max_lifetime - end - - def service=(url) - @service = RubyCAS::Server::Core::Util.clean_service_url(url) - end - - end - end - end - end -end diff --git a/lib/rubycas-server-core/adapters/in_memory/storage.rb b/lib/rubycas-server-core/adapters/in_memory/storage.rb deleted file mode 100644 index 37464f9..0000000 --- a/lib/rubycas-server-core/adapters/in_memory/storage.rb +++ /dev/null @@ -1,23 +0,0 @@ -module RubyCAS - module Server - module Core - module Tickets - class Storage - class << self - attr_accessor :storage - end - - def initialize - self.class.storage = {} unless self.class.storage - end - - def save - self.class.storage[@id] = self - return true - end - - end - end - end - end -end diff --git a/lib/rubycas-server-core/adapters/in_memory/ticket_granting_ticket.rb b/lib/rubycas-server-core/adapters/in_memory/ticket_granting_ticket.rb deleted file mode 100644 index 03d2e87..0000000 --- a/lib/rubycas-server-core/adapters/in_memory/ticket_granting_ticket.rb +++ /dev/null @@ -1,38 +0,0 @@ -module RubyCAS - module Server - module Core - module Tickets - class TicketGrantingTicket < Storage - attr_accessor :id, :ticket, :client_hostname, :username, - :extra_attributes, :service_tickets, :proxy_tickets, - :created_at, :updated_at - - def initialize(tgt = {}) - @id = SecureRandom.uuid - @ticket = tgt[:ticket] - @client_hostname = tgt[:client_hostname] - @username = tgt[:username] - @extra_attributes = tgt[:extra_attributes] - @service_tickets = tgt[:service_tickets] - @proxy_tickets = tgt[:proxy_tickets] - @created_at = DateTime.now - @updated_at = DateTime.now - super() - end - - def self.find_by_ticket(ticket) - @storage.each do |id, tgt| - return tgt if tgt.ticket == ticket - end - return nil - end - - def expired?(max_lifetime) - lifetime = Time.now.to_i - created_at.to_time.to_i - lifetime > max_lifetime - end - end - end - end - end -end diff --git a/lib/rubycas-server-core/database.rb b/lib/rubycas-server-core/database.rb index adb148b..63851f9 100644 --- a/lib/rubycas-server-core/database.rb +++ b/lib/rubycas-server-core/database.rb @@ -4,7 +4,7 @@ module Core module Database extend self def setup(config_file) - raise NotImplementedError, "Database adapter is missing, add it to your Gemfile, please refer to https://github.com/rubycas/rubycas-server-core/wiki for more details" + #raise NotImplementedError, "Database adapter is missing, add it to your Gemfile, please refer to https://github.com/rubycas/rubycas-server-core/wiki for more details" end end end diff --git a/lib/rubycas-server-core/error.rb b/lib/rubycas-server-core/error.rb new file mode 100644 index 0000000..46783dc --- /dev/null +++ b/lib/rubycas-server-core/error.rb @@ -0,0 +1,24 @@ +module RubyCAS::Server::Core + # TODO: Add better dependency injection + # TODO: add predefined messages/errors + module Error + class Error + attr_reader :code, :message + + def initialize(code, message) + @code = code + @message = message + end + + def to_s + message + end + end + + class RubyCASServerCoreError < StandardError + end + + class RecordNotFound < RubyCASServerCoreError + end + end +end diff --git a/lib/rubycas-server-core/settings.rb b/lib/rubycas-server-core/settings.rb index c075e5a..8a47918 100644 --- a/lib/rubycas-server-core/settings.rb +++ b/lib/rubycas-server-core/settings.rb @@ -11,9 +11,13 @@ module Settings @_settings = HashWithIndifferentAccess.new attr_reader :_settings - def load!(file_name) - config = YAML::load_file(file_name).with_indifferent_access - @_settings.merge!(config) + def load!(config) + + if config.is_a? String + @_settings.merge! YAML::load_file(config).with_indifferent_access + elsif config.is_a? Hash + @_settings.merge!(config) + end end def method_missing(name, *args, &block) diff --git a/lib/rubycas-server-core/tickets.rb b/lib/rubycas-server-core/tickets.rb index 34708d6..9e2999a 100644 --- a/lib/rubycas-server-core/tickets.rb +++ b/lib/rubycas-server-core/tickets.rb @@ -4,64 +4,123 @@ module RubyCAS module Server module Core module Tickets + class LT + extend ::RubyCAS::Server::Core::Tickets::Generations + extend ::RubyCAS::Server::Core::Tickets::Validations - # One time login ticket for given client - def self.generate_login_ticket(client) - lt = LoginTicket.new - lt.ticket = "LT-" + Util.random_string - lt.client_hostname = client - if lt.save - $LOG.debug("Login ticket '#{lt.ticket} has been created for '#{lt.client_hostname}'") + def self.create!(client = "localhost") + lt = generate_login_ticket(client) + raise 'error that should be handled by rubycas-server-core gem' if !lt + return lt + end + + def self.create(client = "localhost") + generate_login_ticket(client) + end + + def self.validate(lt) + validate_login_ticket(lt) + end + + def self.find_by(options) + Tickets::LoginTicket.find_by( + options + ) + end + + def self.find_by!(options) + lt = Tickets::LoginTicket.find_by( + options + ) + raise 'error that should be handled by rubycas-server-core gem' if !lt return lt - else - return nil 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). - # - # The optional 'extra_attributes' parameter takes a hash of additional attributes - # that will be sent along with the username in the CAS response to subsequent - # validation requests from clients. - def self.generate_ticket_granting_ticket(username, client, extra_attributes = {}) - tgt = TicketGrantingTicket.new - tgt.ticket = "TGC-" + Util.random_string - tgt.username = username - tgt.extra_attributes = extra_attributes - tgt.client_hostname = client - if tgt.save - $LOG.debug("Generated ticket granting ticket '#{tgt.ticket}' for user" + - " '#{tgt.username}' at '#{tgt.client_hostname}'" + - (extra_attributes.empty? ? "" : " with extra attributes #{extra_attributes.inspect}")) + class TGT + extend ::RubyCAS::Server::Core::Tickets::Generations + extend ::RubyCAS::Server::Core::Tickets::Validations + + def self.create!(user, client = "localhost", remember_me = false, extra_attributes = {}) + tgt = generate_ticket_granting_ticket( + user, client, remember_me, extra_attributes + ) + raise 'error that should be handled by rubycas-server-core gem' if !tgt + return tgt + end + + def self.create(user, client = "localhost", remember_me = false, extra_attributes = {}) + generate_ticket_granting_ticket( + user, client, remember_me, extra_attributes + ) + end + + def self.validate(tgt) + validate_ticket_granting_ticket(tgt) + end + + + def self.find_by(options) + Tickets::TicketGrantingTicket.find_by( + options + ) + end + + def self.find_by!(options) + tgt = Tickets::TicketGrantingTicket.find_by( + options + ) + raise 'error that should be handled by rubycas-server-core gem' if !tgt return tgt - else - return nil end end - def self.generate_service_ticket(service, username, tgt, client) - st = ServiceTicket.new - st.ticket = "ST-" + Util.random_string - st.service = service - st.username = username - st.ticket_granting_ticket = tgt - st.client_hostname = client - if st.save - $LOG.debug("Generated service ticket '#{st.ticket}' for service '#{st.service}'" + - " for user '#{st.username}' at '#{st.client_hostname}'") + class ST + extend ::RubyCAS::Server::Core::Tickets::Generations + extend ::RubyCAS::Server::Core::Tickets::Validations + + def self.create!(service, user, tgt, client="localhost") + st = generate_service_ticket(service, user, tgt, client) + raise 'error that should be handled by rubycas-server-core gem' if !st return st - else - return nil end - end - def self.generate_proxy_ticket(target_service, pgt, client) - raise NotImplementedError + def self.create(service, user, tgt, client="localhost") + generate_service_ticket(service, user, tgt, client) + end + + def self.validate(service, ticket) + validate_service_ticket(service, ticket) + end + + def self.find_by(options) + Tickets::ServiceTicket.find_by( + options + ) + end + + def self.find_by!(options) + st = Tickets::ServiceTicket.find_by( + options + ) + raise 'error that should be handled by rubycas-server-core gem' if !st + return st + end end - def self.generate_proxy_granting_ticket(pgt_url, st, client) - raise NotImplementedError + class Utils + include ::RubyCAS::Server::Core + + def self.clean_service_url(service_url) + return "" if service_url.nil? + service_url.encode!('UTF-16', 'UTF-8', invalid: :replace, replace: '') + service_url.encode!('UTF-8', 'UTF-16') + Util.clean_service_url(service_url) + end + + def self.build_ticketed_url(service, ticket) + Util.build_ticketed_url(service, ticket) + end end end end diff --git a/lib/rubycas-server-core/tickets/generations.rb b/lib/rubycas-server-core/tickets/generations.rb new file mode 100644 index 0000000..4b35e37 --- /dev/null +++ b/lib/rubycas-server-core/tickets/generations.rb @@ -0,0 +1,76 @@ +require 'rubycas-server-core/util' + +module RubyCAS + module Server + module Core + module Tickets + module Generations + # One time login ticket for given client + def generate_login_ticket(client) + lt = LoginTicket.new + lt.ticket = "LT-" + Util.random_string + lt.client_hostname = client + if lt.save! + $LOG.debug("Login ticket '#{lt.ticket} has been created for '#{lt.client_hostname}'") + return lt + else + return nil + 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). + # + # The optional 'extra_attributes' parameter takes a hash of additional attributes + # that will be sent along with the username in the CAS response to subsequent + # validation requests from clients. + def generate_ticket_granting_ticket( + username, + client, + remember_me = false, + extra_attributes = {} + ) + tgt = TicketGrantingTicket.new + tgt.ticket = "TGC-" + Util.random_string + tgt.username = username + tgt.remember_me = remember_me + tgt.extra_attributes = extra_attributes.to_s + tgt.client_hostname = client + if tgt.save! + $LOG.debug("Generated ticket granting ticket '#{tgt.ticket}' for user" + + " '#{tgt.username}' at '#{tgt.client_hostname}'" + + (extra_attributes.empty? ? "" : " with extra attributes #{extra_attributes.inspect}")) + return tgt + else + return nil + end + end + + def generate_service_ticket(service, username, tgt, client) + st = tgt.service_tickets.new + st.ticket = "ST-" + Util.random_string + st.service = service + st.username = username + st.ticket_granting_ticket = tgt + st.client_hostname = client + if st.save + $LOG.debug("Generated service ticket '#{st.ticket}' for service '#{st.service}'" + + " for user '#{st.username}' at '#{st.client_hostname}'") + return st + else + return nil + end + end + + def generate_proxy_ticket(target_service, pgt, client) + raise NotImplementedError + end + + def generate_proxy_granting_ticket(pgt_url, st, client) + raise NotImplementedError + end + end + end + end + end +end diff --git a/lib/rubycas-server-core/tickets/validations.rb b/lib/rubycas-server-core/tickets/validations.rb index cdb62f0..4d6566b 100644 --- a/lib/rubycas-server-core/tickets/validations.rb +++ b/lib/rubycas-server-core/tickets/validations.rb @@ -1,6 +1,9 @@ +require "rubycas-server-core/error" + module RubyCAS::Server::Core::Tickets module Validations include R18n::Helpers + include RubyCAS::Server::Core::Error # Validate login ticket # @@ -17,11 +20,11 @@ def validate_login_ticket(ticket) if lt.consumed? error = t.error.login_ticket_already_used $LOG.warn "Login ticket '#{ticket}' already consumed!" - elsif not lt.expired?(RubyCAS::Server::Core::Settings.maximum_unused_service_ticket_lifetime) + elsif not lt.expired?(RubyCAS::Server::Core::Settings.maximum_unused_login_ticket_lifetime) $LOG.info "Login ticket '#{ticket}' successfully validated" lt.consume! success = true - elsif lt.expired?(RubyCAS::Server::Core::Settings.maximum_unused_service_ticket_lifetime) + elsif lt.expired?(RubyCAS::Server::Core::Settings.maximum_unused_login_ticket_lifetime) error = t.error.login_timeout $LOG.warn "Expired login ticket '#{ticket}'" end @@ -38,7 +41,13 @@ def validate_ticket_granting_ticket(ticket) $LOG.debug "No ticket granting ticket given." if ticket.nil? if tgt = TicketGrantingTicket.find_by_ticket(ticket) - if tgt.expired?(RubyCAS::Server::Core::Settings.maximum_session_lifetime) + if tgt.remember_me + max_lifetime = RubyCAS::Server::Core::Settings.maximum_session_lifetime + else + max_lifetime = RubyCAS::Server::Core::Settings.maximum_remember_me_lifetime + end + + if tgt.expired?(max_lifetime) tgt.destroy error = "Your session has expired. Please log in again." $LOG.info "Ticket granting ticket '#{ticket}' for user '#{tgt.username}' expired." diff --git a/lib/rubycas-server-core/version.rb b/lib/rubycas-server-core/version.rb index 59bff30..96bb2dc 100644 --- a/lib/rubycas-server-core/version.rb +++ b/lib/rubycas-server-core/version.rb @@ -4,11 +4,10 @@ module Core module Version # :nodoc: all MAJOR = 0 - MINOR = 1 - PATCH = 0 - TAG = 'alpha' + MINOR = 2 + PATCH = 1 - STRING = [MAJOR, MINOR, PATCH, TAG].join('.') + STRING = [MAJOR, MINOR, PATCH].join('.') end end end diff --git a/rubycas-server-core.gemspec b/rubycas-server-core.gemspec index 033fe05..0a61173 100644 --- a/rubycas-server-core.gemspec +++ b/rubycas-server-core.gemspec @@ -17,6 +17,15 @@ Gem::Specification.new do |gem| gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) gem.require_paths = ["lib"] - gem.add_dependency "r18n-core" - gem.add_dependency "activesupport", ">= 3.0" + gem.required_ruby_version = '>= 1.9.2' + gem.required_rubygems_version = '>= 1.3.6' + + gem.add_dependency 'r18n-core', '~> 2.0.3' + gem.add_dependency 'activesupport', '>= 3.0' + + gem.add_development_dependency 'rspec', '~> 3.1.0' + gem.add_development_dependency 'rake' + gem.add_development_dependency 'bundler' + gem.add_development_dependency 'pry' + gem.add_development_dependency 'rubycas-server-memory', '0.0.2' end diff --git a/spec/config/config.yml b/spec/config/config.yml index cf7cfe1..a549e60 100644 --- a/spec/config/config.yml +++ b/spec/config/config.yml @@ -28,6 +28,7 @@ maximum_unused_login_ticket_lifetime: 300 maximum_unused_service_ticket_lifetime: 300 maximum_session_lifetime: 172800 +maximum_remember_me_lifetime: 604800 downcase_username: true default_locale: en diff --git a/spec/rubycas-server-core/tickets/generations_spec.rb b/spec/rubycas-server-core/tickets/generations_spec.rb new file mode 100644 index 0000000..042ec86 --- /dev/null +++ b/spec/rubycas-server-core/tickets/generations_spec.rb @@ -0,0 +1,109 @@ +require "spec_helper" + +module RubyCAS::Server::Core::Tickets + describe RubyCAS::Server::Core::Tickets::Generations do + let(:client_hostname) { 'myhost.test' } + let(:username) { 'myuser' } + let(:service) { 'https://myservice.test' } + + before do + RubyCAS::Server::Core.setup("spec/config/config.yml") + @generations = Class.new + @generations.extend(RubyCAS::Server::Core::Tickets::Generations) + end + + describe '.generate_login_ticket(client_hostname)' do + before do + @lt = @generations.generate_login_ticket(client_hostname) + end + + it "should return a login ticket" do + @lt.class.should == LoginTicket + end + + it "should set the client_hostname" do + @lt.client_hostname.should == client_hostname + end + + it "should set the ticket string" do + @lt.ticket.should_not be_nil + end + + it "should set the ticket string starting with 'LT'" do + @lt.ticket.should(match(/^LT/)) + end + + it "should not mark the ticket as consumed" do + @lt.consumed.should be_nil + end + end + + describe ".generate_ticket_granting_ticket(username, extra_attributes = {})" do + before do + @tgt = @generations.generate_ticket_granting_ticket(username, client_hostname) + end + + it "should return a TicketGrantingTicket" do + @tgt.class.should == TicketGrantingTicket + end + + it "should set the tgt's ticket string" do + @tgt.ticket.should_not be_nil + end + + it "should generate a ticket string starting with 'TGC'" do + @tgt.ticket.should(match(/^TGC/)) + end + + it "should set the tgt's username string" do + @tgt.username.should == username + end + + it "should set the tgt's client_hostname" do + @tgt.client_hostname.should == client_hostname + end + end + + describe ".generate_service_ticket(service, username, tgt)" do + before do + @tgt = @generations.generate_ticket_granting_ticket(username, client_hostname) + @st = @generations.generate_service_ticket(service, username, @tgt, client_hostname) + end + + it "should return a ServiceTicket" do + @st.class.should == ServiceTicket + end + + it "should not include the service identifer in the ticket string" do + @st.ticket.should_not(match(/#{service}/)) + end + + it "should not mark the ST as consumed" do + @st.consumed.should be_nil + end + + it "must generate a ticket that starts with 'ST-'" do + @st.ticket.should(match(/^ST-/)) + end + + it "should assoicate the ST with the supplied TGT" do + @st.ticket_granting_ticket.id.should == @tgt.id + end + end + + describe ".generate_proxy_ticket(target_service, pgt)" do + it "should return a ProxyGrantingTicket" do + skip('Not supported') + end + + it "should not consume the generated ticket" do + skip('Not supported') + end + + it "should start the ticket string with PT-" do + skip('Not supported') + end + end + end +end + diff --git a/spec/rubycas-server-core/tickets/validations_spec.rb b/spec/rubycas-server-core/tickets/validations_spec.rb index 6ddc1d9..4b07842 100644 --- a/spec/rubycas-server-core/tickets/validations_spec.rb +++ b/spec/rubycas-server-core/tickets/validations_spec.rb @@ -1,62 +1,108 @@ require "spec_helper" describe RubyCAS::Server::Core::Tickets::Validations do + before do - RubyCAS::Server::Core.setup("spec/config/config.yml") - klass = Class.new { - include RubyCAS::Server::Core::Tickets - include RubyCAS::Server::Core::Tickets::Validations - } - @cas = klass.new - @client_hostname = "myhost.test" - Tickets = RubyCAS::Server::Core::Tickets + RubyCAS::Server::Core.setup("spec/config/config.yml") + @generations = Class.new + @generations.extend(RubyCAS::Server::Core::Tickets::Generations) + @validations = Class.new + @validations.extend(RubyCAS::Server::Core::Tickets::Validations) end describe "validate login ticket" do it "should validate login ticket" do - @lt = Tickets.generate_login_ticket(@client_hostname) - success, error = @cas.validate_login_ticket(@lt.ticket) + @lt = @generations.generate_login_ticket(@client_hostname) + success, error = @validations.validate_login_ticket(@lt.ticket) success.should be_truthy error.should be_nil end end + describe "validations" + describe "#validate_login_ticket" do + context "with valid ticket" do + it "should validate login ticket" do + @lt = @generations.generate_login_ticket(@client_hostname) + success, error = @validations.validate_login_ticket(@lt.ticket) + success.should be_truthy + error.should be_nil + end + end - describe "validate ticket_granting_ticket(username, extra_attributes = {})" do - before do - @username = 'myuser' - @client_hostname = "myhost.test" - @tgt = Tickets.generate_ticket_granting_ticket(@username, @client_hostname) + context "with invalid ticket" do + it "should not validate login ticket" do + @lt = @generations.generate_login_ticket(@client_hostname) + success, error = @validations.validate_login_ticket("#{@lt.ticket}random") + expect(success).to be false + expect(error).not_to be nil + end + end end - it "should validate ticket granting ticket" do - success, error = @cas.validate_ticket_granting_ticket(@tgt.ticket) - success.should be_truthy - error.should be_nil - end - end + describe "#validate_ticket_granting_ticket(username, extra_attributes = {})" do + before do + @username = 'myuser' + @client_hostname = "myhost.test" + @tgt = @generations.generate_ticket_granting_ticket(@username, @client_hostname) + end - describe "validate service_ticket(service, username, tgt)" do - before do - @username = 'testuser' - @client_hostname = "myhost.test" - @service = 'myservice.test' - @tgt = Tickets.generate_ticket_granting_ticket(@username, @client_hostname) - @st = Tickets.generate_service_ticket(@service, @username, @tgt, @client_hostname) - end + context "with valid tgt" do + it "should validate ticket granting ticket" do + success, error = @validations.validate_ticket_granting_ticket(@tgt.ticket) + expect(success).to eq @tgt + expect(error).to eq nil + end + end - it "should validate service ticket" do - success, error = @cas.validate_service_ticket(@service, @st.ticket) - success.should be_truthy - error.should be_nil + context "with invalid gt" do + it "should not validate ticket granting ticket" do + success, error = @validations.validate_ticket_granting_ticket("#{@tgt.ticket}random") + expect(success).to eq nil + expect(error).not_to eq nil + end + end end - end - describe "validate proxy_ticket(target_service, pgt)" do + describe "validate service_ticket(service, username, tgt)" do + context "with valid ticket" do + before do + @username = 'testuser' + @client_hostname = "myhost.test" + @service = 'myservice.test' + @tgt = @generations.generate_ticket_granting_ticket(@username, @client_hostname) + @st = @generations.generate_service_ticket(@service, @username, @tgt, @client_hostname) + end + + it "should validate service ticket" do + success, error = @validations.validate_service_ticket(@service, @st.ticket) + expect(success).to eq true + expect(error).to be nil + end + end + + context "with invalid ticket" do + before do + @username = 'testuser' + @client_hostname = "myhost.test" + @service = 'myservice.test' + @tgt = @generations.generate_ticket_granting_ticket(@username, @client_hostname) + @st = @generations.generate_service_ticket(@service, @username, @tgt, @client_hostname) + end + + it "does not validate service ticket (throws an error)" do + _, error = @validations.validate_service_ticket(@service, "#{@st.ticket}-random_string") + expect(error).not_to be nil + end + end - before do - pending("Proxy ticket is not yet implemented") end - end + describe "validate proxy_ticket(target_service, pgt)" do + + before do + pending("Proxy ticket is not yet implemented") + end + + end end diff --git a/spec/rubycas-server-core/tickets_spec.rb b/spec/rubycas-server-core/tickets_spec.rb index 30f6ab8..d8aa045 100644 --- a/spec/rubycas-server-core/tickets_spec.rb +++ b/spec/rubycas-server-core/tickets_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -module RubyCAS::Server::Core +module RubyCAS::Server::Core::Tickets describe RubyCAS::Server::Core::Tickets do let(:client_hostname) { 'myhost.test' } let(:username) { 'myuser' } @@ -8,18 +8,13 @@ module RubyCAS::Server::Core before do RubyCAS::Server::Core.setup("spec/config/config.yml") - klass = Class.new { - include RubyCAS::Server::Core::Tickets - } - @cas = klass.new - @client_hostname = "myhost.test" end - describe '.generate_login_ticket(client_hostname)' do - let(:lt) { Tickets.generate_login_ticket(client_hostname) } + describe LT do + let(:lt) { LT.create!(client_hostname) } it "should return a login ticket" do - lt.class.should == Tickets::LoginTicket + lt.class.should == LoginTicket end it "should set the client_hostname" do @@ -31,7 +26,7 @@ module RubyCAS::Server::Core end it "should set the ticket string starting with 'LT'" do - lt.ticket.should match /^LT/ + lt.ticket.should(match(/^LT/)) end it "should not mark the ticket as consumed" do @@ -39,40 +34,42 @@ module RubyCAS::Server::Core end end - describe ".generate_ticket_granting_ticket(username, extra_attributes = {})" do - let(:tgt) { Tickets.generate_ticket_granting_ticket(username, client_hostname) } + describe TGT do + before do + @tgt = TGT.create!(username, client_hostname) + end it "should return a TicketGrantingTicket" do - tgt.class.should == Tickets::TicketGrantingTicket + @tgt.class.should == TicketGrantingTicket end it "should set the tgt's ticket string" do - tgt.ticket.should_not be_nil + @tgt.ticket.should_not be_nil end it "should generate a ticket string starting with 'TGC'" do - tgt.ticket.should match /^TGC/ + @tgt.ticket.should(match(/^TGC/)) end it "should set the tgt's username string" do - tgt.username.should == username + @tgt.username.should == username end it "should set the tgt's client_hostname" do - tgt.client_hostname.should == client_hostname + @tgt.client_hostname.should == client_hostname end end - describe ".generate_service_ticket(service, username, tgt)" do - let(:tgt) { Tickets.generate_ticket_granting_ticket(username, client_hostname) } - let(:st) { Tickets.generate_service_ticket(service, username, tgt, client_hostname) } + describe ST do + let(:tgt) { TGT.create!(username, client_hostname) } + let(:st) { ST.create!(service, username, tgt, client_hostname) } it "should return a ServiceTicket" do - st.class.should == Tickets::ServiceTicket + st.class.should == ServiceTicket end it "should not include the service identifer in the ticket string" do - st.ticket.should_not match /#{service}/ + st.ticket.should_not(match(/#{service}/)) end it "should not mark the ST as consumed" do @@ -80,7 +77,7 @@ module RubyCAS::Server::Core end it "must generate a ticket that starts with 'ST-'" do - st.ticket.should match /^ST-/ + st.ticket.should(match(/^ST-/)) end it "should assoicate the ST with the supplied TGT" do @@ -90,18 +87,15 @@ module RubyCAS::Server::Core describe ".generate_proxy_ticket(target_service, pgt)" do it "should return a ProxyGrantingTicket" do - pending("Proxy ticket is not implemented yet") - fail + skip('Not supported') end it "should not consume the generated ticket" do - pending("Proxy ticket is not implemented yet") - fail + skip('Not supported') end it "should start the ticket string with PT-" do - pending("Proxy ticket is not implemented yet") - fail + skip('Not supported') end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 641cea1..5d8f948 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,7 +1,8 @@ require 'rubygems' require 'bundler/setup' require 'rubycas-server-core' -require 'rubycas-server-core/adapters/in_memory' +require 'rubycas/server/memory' + begin require 'debugger' rescue LoadError