Skip to content
This repository was archived by the owner on Feb 6, 2024. It is now read-only.
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: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@
/spec/dummy/log/*.log
/spec/dummy/tmp
/spec/dummy/db/*.sqlite3

.rvmrc
2 changes: 1 addition & 1 deletion app/builders/casino/ticket_validation_response_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def build
proxies = []
service_ticket = ticket
while service_ticket.is_a?(CASino::ProxyTicket)
proxy_granting_ticket = ticket.proxy_granting_ticket
proxy_granting_ticket = service_ticket.proxy_granting_ticket
proxies << proxy_granting_ticket.pgt_url
service_ticket = proxy_granting_ticket.granter
end
Expand Down
16 changes: 16 additions & 0 deletions app/models/casino/auth_token_signer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
require 'openssl'

module CASino
class AuthTokenSigner < ActiveRecord::Base

def public_key
OpenSSL::PKey::RSA.new(public_key_pem_content)
end

def signature_valid?(signature, token)
digest = OpenSSL::Digest::SHA256.new
public_key.verify(digest, signature, token)
end

end
end
8 changes: 8 additions & 0 deletions app/services/casino/auth_token_validation_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ def signature_valid?
return true
end
end

CASino::AuthTokenSigner.where(enabled: true).each do |auth_token_signer|
if auth_token_signer.signature_valid?(signature, token)
Rails.logger.info("Successfully validated auth token signature with #{auth_token_signer.name}")
return true
end
end

Rails.logger.warn('Signature could not be validated: No matching key found.')
false
end
Expand Down
11 changes: 11 additions & 0 deletions db/migrate/20150827142603_create_casino_auth_token_signers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class CreateCASinoAuthTokenSigners < ActiveRecord::Migration
def change
create_table :casino_auth_token_signers do |t|
t.string :name, null: :false
t.text :public_key_pem_content, null: false
t.boolean :enabled, null: false, default: true

t.timestamps null: false
end
end
end
171 changes: 171 additions & 0 deletions lib/casino/tasks/auth_token_signer.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
require 'io/console'

namespace :casino do
namespace :auth_token_signer do

namespace :add do

desc 'Add Auth Token Signer from environment variable'
task :env, [:name, :env_key] => :environment do |task, args|
name = args[:name]
env_key = args[:env_key]
if !name.present?
print 'Name of Auth Token Signer: '
name = STDIN.gets.chomp
end
if !env_key.present?
print 'Environment variable containing PEM content: '
env_key = STDIN.gets.chomp
end
puts
if name.present? && env_key.present?
if ENV[env_key].present?
auth_token_signer = CASino::AuthTokenSigner.create!(name: name, public_key_pem_content: ENV[env_key])
puts "Created Auth Token Signer '#{auth_token_signer.name}' with ID #{auth_token_signer.id}."
else
puts "ERROR: There is no value for the environment variable '#{env_key}'."
end
else
puts 'ERROR: Both Name of Auth Token Signer and Public Key PEM File are required.'
end
puts
end

desc 'Add Auth Token Signer from PEM file'
task :file, [:name, :public_key_pem_file_path] => :environment do |task, args|
name = args[:name]
public_key_pem_file_path = args[:public_key_pem_file_path]
if !name.present?
print 'Name of Auth Token Signer: '
name = STDIN.gets.chomp
end
if !public_key_pem_file_path.present?
print 'Public Key PEM File: '
public_key_pem_file_path = STDIN.gets.chomp
end
puts
if name.present? && public_key_pem_file_path.present?
auth_token_signer = CASino::AuthTokenSigner.create!(name: name, public_key_pem_content: File.read(public_key_pem_file_path))
puts "Created Auth Token Signer '#{auth_token_signer.name}' with ID #{auth_token_signer.id}."
else
puts "ERROR: Both Name of Auth Token Signer and Public Key PEM File are required."
end
puts
end

desc 'Add Auth Token Signer from STDIN'
task :stdin, [:name] => :environment do |task, args|
name = args[:name]
public_key_pem_content = STDIN.gets(nil)
puts
if name.present? && public_key_pem_content.present?
auth_token_signer = CASino::AuthTokenSigner.create!(name: name, public_key_pem_content: public_key_pem_content)
puts "Created Auth Token Signer '#{auth_token_signer.name}' with ID #{auth_token_signer.id}."
else
puts "ERROR: Both Name of Auth Token Signer and Public Key PEM Content are required."
end
puts
end

end

desc 'Remove Auth Token Signer'
task :remove, [:id] => :environment do |task, args|
id = args[:id]
if !id.present?
has_records = false
CASino::AuthTokenSigner.all.each do |auth_token_signer|
puts "#{auth_token_signer.id}: #{auth_token_signer.name}"
has_records = true
end
if has_records
puts
print 'Enter the ID of the Auth Token Signer to remove: '
id = STDIN.gets.chomp
else
puts 'There are no Auth Token Signers to remove.'
end
end
puts
if id.present?
deleted_count = CASino::AuthTokenSigner.delete(id)
if deleted_count > 0
puts "Deleted Auth Token Signer with ID #{id}."
else
puts "ERROR: Auth Token Signer with ID #{id} does not exist."
end
end
puts
end

desc 'List Auth Token Signers'
task :list => :environment do |task, args|
has_records = false
CASino::AuthTokenSigner.all.each do |auth_token_signer|
puts "#{auth_token_signer.id}: #{auth_token_signer.name} (#{auth_token_signer.enabled ? 'enabled' : 'disabled'})"
has_records = true
end
if !has_records
puts 'There are no Auth Token Signers.'
end
puts
end

desc 'Enable Auth Token Signer'
task :enable, [:id] => :environment do |task, args|
id = args[:id]
if !id.present?
has_records = false
CASino::AuthTokenSigner.where(enabled: false).each do |auth_token_signer|
puts "#{auth_token_signer.id}: #{auth_token_signer.name}"
has_records = true
end
if has_records
puts
print 'Enter the ID of the Auth Token Signer to enable: '
id = STDIN.gets.chomp
else
puts 'There are no Auth Token Signers to enable.'
end
end
puts
if id.present?
if CASino::AuthTokenSigner.find(id).update(enabled: true)
puts "Auth Token Signer with ID #{id} has been enabled."
end
else
puts 'ERROR: ID is required.'
end
puts
end

desc 'Disable Auth Token Signer'
task :disable, [:id] => :environment do |task, args|
id = args[:id]
if !id.present?
has_records = false
CASino::AuthTokenSigner.where(enabled: true).each do |auth_token_signer|
puts "#{auth_token_signer.id}: #{auth_token_signer.name}"
has_records = true
end
if has_records
puts
print 'Enter the ID of the Auth Token Signer to disable: '
id = STDIN.gets.chomp
else
puts 'There are no Auth Token Signers to disable.'
end
end
puts
if id.present?
if CASino::AuthTokenSigner.find(id).update(enabled: false)
puts "Auth Token Signer with ID #{id} has been disabled."
end
else
puts 'ERROR: ID is required.'
end
puts
end

end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# This migration comes from casino (originally 20150827142603)
class CreateCASinoAuthTokenSigners < ActiveRecord::Migration
def change
create_table :casino_auth_token_signers do |t|
t.string :name, null: :false
t.text :public_key_pem_content, null: false
t.boolean :enabled, null: false, default: true

t.timestamps null: false
end
end
end
26 changes: 17 additions & 9 deletions spec/dummy/db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,31 @@

ActiveRecord::Schema.define(version: 20151026130743) do

create_table "casino_auth_token_tickets", force: true do |t|
create_table "casino_auth_token_signers", force: :cascade do |t|
t.string "name"
t.text "public_key_pem_content", null: false
t.boolean "enabled", default: true, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

create_table "casino_auth_token_tickets", force: :cascade do |t|
t.string "ticket", null: false
t.datetime "created_at"
t.datetime "updated_at"
end

add_index "casino_auth_token_tickets", ["ticket"], name: "index_casino_auth_token_tickets_on_ticket", unique: true

create_table "casino_login_tickets", force: true do |t|
create_table "casino_login_tickets", force: :cascade do |t|
t.string "ticket", null: false
t.datetime "created_at"
t.datetime "updated_at"
end

add_index "casino_login_tickets", ["ticket"], name: "index_casino_login_tickets_on_ticket", unique: true

create_table "casino_proxy_granting_tickets", force: true do |t|
create_table "casino_proxy_granting_tickets", force: :cascade do |t|
t.string "ticket", null: false
t.string "iou", null: false
t.integer "granter_id", null: false
Expand All @@ -44,7 +52,7 @@
add_index "casino_proxy_granting_tickets", ["iou"], name: "index_casino_proxy_granting_tickets_on_iou", unique: true
add_index "casino_proxy_granting_tickets", ["ticket"], name: "index_casino_proxy_granting_tickets_on_ticket", unique: true

create_table "casino_proxy_tickets", force: true do |t|
create_table "casino_proxy_tickets", force: :cascade do |t|
t.string "ticket", null: false
t.text "service", null: false
t.boolean "consumed", default: false, null: false
Expand All @@ -56,7 +64,7 @@
add_index "casino_proxy_tickets", ["proxy_granting_ticket_id"], name: "casino_proxy_tickets_on_pgt_id"
add_index "casino_proxy_tickets", ["ticket"], name: "index_casino_proxy_tickets_on_ticket", unique: true

create_table "casino_service_rules", force: true do |t|
create_table "casino_service_rules", force: :cascade do |t|
t.boolean "enabled", default: true, null: false
t.integer "order", default: 10, null: false
t.string "name", null: false
Expand All @@ -68,7 +76,7 @@

add_index "casino_service_rules", ["url"], name: "index_casino_service_rules_on_url", unique: true

create_table "casino_service_tickets", force: true do |t|
create_table "casino_service_tickets", force: :cascade do |t|
t.string "ticket", null: false
t.text "service", null: false
t.integer "ticket_granting_ticket_id"
Expand All @@ -81,7 +89,7 @@
add_index "casino_service_tickets", ["ticket"], name: "index_casino_service_tickets_on_ticket", unique: true
add_index "casino_service_tickets", ["ticket_granting_ticket_id"], name: "casino_service_tickets_on_tgt_id"

create_table "casino_ticket_granting_tickets", force: true do |t|
create_table "casino_ticket_granting_tickets", force: :cascade do |t|
t.string "ticket", null: false
t.text "user_agent"
t.integer "user_id", null: false
Expand All @@ -94,7 +102,7 @@

add_index "casino_ticket_granting_tickets", ["ticket"], name: "index_casino_ticket_granting_tickets_on_ticket", unique: true

create_table "casino_two_factor_authenticators", force: true do |t|
create_table "casino_two_factor_authenticators", force: :cascade do |t|
t.integer "user_id", null: false
t.string "secret", null: false
t.boolean "active", default: false, null: false
Expand All @@ -104,7 +112,7 @@

add_index "casino_two_factor_authenticators", ["user_id"], name: "index_casino_two_factor_authenticators_on_user_id"

create_table "casino_users", force: true do |t|
create_table "casino_users", force: :cascade do |t|
t.string "authenticator", null: false
t.string "username", null: false
t.text "extra_attributes"
Expand Down
33 changes: 33 additions & 0 deletions spec/model/auth_token_signer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
require 'spec_helper'

describe CASino::AuthTokenSigner do

describe '#public_key' do
it 'returns the public key from the pem content' do
private_key = OpenSSL::PKey::RSA.new 4096
auth_token_signer = FactoryGirl.build(:auth_token_signer, public_key_pem_content: private_key.public_key.to_pem)
expect(auth_token_signer.public_key.to_pem).to eq(private_key.public_key.to_pem)
end
end

describe '#signature_valid?' do
it 'returns true if the signature is valid' do
private_key = OpenSSL::PKey::RSA.new 4096
auth_token_signer = FactoryGirl.build(:auth_token_signer, public_key_pem_content: private_key.public_key.to_pem)
token = 'MY_TOKEN'
digest = OpenSSL::Digest::SHA256.new
signature = private_key.sign(digest, token)
expect(auth_token_signer.signature_valid?(signature, token)).to be true
end

it 'returns false if the signature is not valid' do
private_key = OpenSSL::PKey::RSA.new 4096
auth_token_signer = FactoryGirl.build(:auth_token_signer, public_key_pem_content: private_key.public_key.to_pem)
token = 'MY_TOKEN'
digest = OpenSSL::Digest::SHA256.new
signature = private_key.sign(digest, token)
expect(auth_token_signer.signature_valid?(signature, 'BAD_TOKEN')).to be false
end
end

end
Loading