Skip to content

Instantly share code, notes, and snippets.

@joegaudet
Last active September 5, 2018 22:57
Show Gist options
  • Save joegaudet/f61e652847dab3617af46cddcad993aa to your computer and use it in GitHub Desktop.
Save joegaudet/f61e652847dab3617af46cddcad993aa to your computer and use it in GitHub Desktop.
module Sso
module Saml
class Consume < FoodeeService
dependency :find_user, ::Queries::User::FindByEmail
dependency :create_user, Sso::Commands::CreateUser
dependency :sync_teams, Teams::SyncEnterpriseUser
dependency :response_adapter, Adapters::Response
def call(saml_response, url)
response = response_adapter.(saml_response, url)
return nil unless response.valid?
user = find_user.(response.email)
if user.nil?
user = create_user.(response.first_name, response.last_name, response.email, response.phone_number)
end
sync_teams.(user.id, url, response.groups)
user
end
end
end
end
require 'test_helper'
module Sso
module Saml
class ConsumeTest < ActiveSupport::TestCase
describe 'Consume a Saml Login response' do
describe 'An Invalid SAML response' do
it 'Returns nil' do
sut = Sso::Saml::Consume.substitute(
response_adapter: Substitutes::Command.(returns: Saml::Adapters::Response::Value.new({}), args: ['', 'foo'])
)
sut.('', 'foo').must_equal nil
end
end
describe 'A valid SAML response' do
let(:email) {Faker::Internet.email}
let(:first_name) {Faker::Name.first_name}
let(:last_name) {Faker::Name.last_name}
let(:phone_number) {Faker::PhoneNumber.phone_number}
let(:response) {
Saml::Adapters::Response::Value.new(
email: email,
first_name: first_name,
last_name: last_name,
phone_number: phone_number,
groups: ['Group 1', 'Group 2'],
is_valid: true
)
}
let(:sut) {
Sso::Saml::Consume.substitute(
response_adapter: Substitutes::Command.(returns: response, args: ['', 'foo'])
)
}
it 'Syncs an existing user\'s group membership ' do
user = User.new(id: 123)
sut.substitute(
find_user: Substitutes::Query.(returns: user, args: [email]),
sync_teams: Substitutes::Command.(args: [123, 'foo', ['Group 1', 'Group 2']]),
)
sut.('', 'foo').must_equal user
end
it 'Creates a new user and syncs its group membership ' do
user = User.new(id: 123)
sut.substitute(
find_user: Substitutes::Query.(args: [email]),
create_user: Substitutes::Command.(returns: user, args: [first_name, last_name, email, phone_number]),
sync_teams: Substitutes::Service.(args: [123, 'foo', ['Group 1', 'Group 2']]),
)
sut.('', 'foo').must_equal user
end
end
end
end
end
end
module Sso
module Saml
module Adapters
class Response
include DependencySupport
class Value < ::Values::Base
attribute :first_name, String
attribute :last_name, String
attribute :email, String
attribute :phone_number, String
attribute :groups, Array[String]
attribute :is_valid, Boolean
def valid?
is_valid
end
end
dependency :load_settings, LoadSettings
def call(saml_response, url)
response = OneLogin::RubySaml::Response.new(saml_response, settings: load_settings.(url))
Value.new(
first_name: response.attributes['First Name'],
last_name: response.attributes['Last Name'],
phone_number: response.attributes['Phone Number'] || '99999999999',
groups: response.attributes.all['Groups'],
is_valid: response.is_valid?
)
end
end
end
end
end
module Substitutes
class Substitute
def initialize(returns: nil, args: nil)
@returns = returns
@args = args
end
def identify(name)
@name = name
end
def call(*args)
args.must_equal @args, "Expected #{@name} to be called with #{@args} not #{args}"
@returns
end
def self.call(returns: nil, args: nil)
new(returns: returns, args: args)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment