Commit 87ee6034f881b4213cdd85a3c2e204e6dbbfa292

Authored by Spencer Alan
1 parent af2a5428
Exists in master

set up dummy app

spec/controllers/scim_rails/scim_users_controller_spec.rb 0 → 100644
... ... @@ -0,0 +1,445 @@
  1 +require "spec_helper"
  2 +
  3 +RSpec.describe ScimRails::ScimUsersController, type: :controller do
  4 + include AuthHelper
  5 +
  6 + routes { ScimRails::Engine.routes }
  7 +
  8 + describe "index" do
  9 + let(:company) { create(:company) }
  10 +
  11 + context "when unauthorized" do
  12 + it "fails with no credentials" do
  13 + get :index
  14 +
  15 + expect(response.status).to eq 401
  16 + end
  17 +
  18 + it "fails with invalid credentials" do
  19 + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials("unauthorized","123456")
  20 +
  21 + get :index
  22 +
  23 + expect(response.status).to eq 401
  24 + end
  25 + end
  26 +
  27 + context "when when authorized" do
  28 + before :each do
  29 + http_login(company)
  30 + end
  31 +
  32 + it "is successful with valid credentials" do
  33 + get :index
  34 +
  35 + expect(response.status).to eq 200
  36 + end
  37 +
  38 + it "returns all results" do
  39 + create_list(:user, 10, company: company)
  40 +
  41 + get :index
  42 + response_body = JSON.parse(response.body)
  43 + expect(response_body.dig("schemas", 0)).to eq "urn:ietf:params:scim:api:messages:2.0:ListResponse"
  44 + expect(response_body["totalResults"]).to eq 10
  45 + end
  46 +
  47 + it "defaults to 100 results" do
  48 + create_list(:user, 300, company: company)
  49 +
  50 + get :index
  51 + response_body = JSON.parse(response.body)
  52 + expect(response_body["totalResults"]).to eq 300
  53 + expect(response_body["Resources"].count).to eq 100
  54 + end
  55 +
  56 + it "paginates results" do
  57 + create_list(:user, 400, company: company)
  58 + expect(company.users.first.id).to eq 1
  59 +
  60 + get :index, params: {
  61 + startIndex: 101,
  62 + count: 200,
  63 + }
  64 + response_body = JSON.parse(response.body)
  65 + expect(response_body["totalResults"]).to eq 400
  66 + expect(response_body["Resources"].count).to eq 200
  67 + expect(response_body.dig("Resources", 0, "id")).to eq 101
  68 + end
  69 +
  70 + it "paginates results by configurable scim_users_list_order" do
  71 + ScimRails.config.scim_users_list_order = { created_at: :desc }
  72 +
  73 + create_list(:user, 400, company: company)
  74 + expect(company.users.first.id).to eq 1
  75 +
  76 + get :index, params: {
  77 + startIndex: 1,
  78 + count: 10,
  79 + }
  80 + response_body = JSON.parse(response.body)
  81 + expect(response_body["totalResults"]).to eq 400
  82 + expect(response_body["Resources"].count).to eq 10
  83 + expect(response_body.dig("Resources", 0, "id")).to eq 400
  84 +
  85 + ScimRails.config.scim_users_list_order = nil
  86 + end
  87 +
  88 + it "filters results by provided email filter" do
  89 + create(:user, email: "test1@example.com", company: company)
  90 + create(:user, email: "test2@example.com", company: company)
  91 +
  92 + get :index, params: {
  93 + filter: "email eq test1@example.com"
  94 + }
  95 + response_body = JSON.parse(response.body)
  96 + expect(response_body["totalResults"]).to eq 1
  97 + expect(response_body["Resources"].count).to eq 1
  98 + end
  99 +
  100 + it "filters results by provided name filter" do
  101 + create(:user, first_name: "Chidi", last_name: "Anagonye", company: company)
  102 + create(:user, first_name: "Eleanor", last_name: "Shellstrop", company: company)
  103 +
  104 + get :index, params: {
  105 + filter: "familyName eq Shellstrop"
  106 + }
  107 + response_body = JSON.parse(response.body)
  108 + expect(response_body["totalResults"]).to eq 1
  109 + expect(response_body["Resources"].count).to eq 1
  110 + end
  111 +
  112 + it "returns no results for unfound filter parameters" do
  113 + get :index, params: {
  114 + filter: "familyName eq fake_not_there"
  115 + }
  116 + response_body = JSON.parse(response.body)
  117 + expect(response_body["totalResults"]).to eq 0
  118 + expect(response_body["Resources"].count).to eq 0
  119 + end
  120 +
  121 + it "returns no results for undefined filter queries" do
  122 + get :index, params: {
  123 + filter: "address eq 101 Nowhere USA"
  124 + }
  125 + expect(response.status).to eq 400
  126 + response_body = JSON.parse(response.body)
  127 + expect(response_body.dig("schemas", 0)).to eq "urn:ietf:params:scim:api:messages:2.0:Error"
  128 + end
  129 + end
  130 + end
  131 +
  132 +
  133 + describe "show" do
  134 + let(:company) { create(:company) }
  135 +
  136 + context "when unauthorized" do
  137 + it "fails with no credentials" do
  138 + get :show, params: { id: 1 }
  139 +
  140 + expect(response.status).to eq 401
  141 + end
  142 +
  143 + it "fails with invalid credentials" do
  144 + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials("unauthorized","123456")
  145 +
  146 + get :show, params: { id: 1 }
  147 +
  148 + expect(response.status).to eq 401
  149 + end
  150 + end
  151 +
  152 + context "when authorized" do
  153 + before :each do
  154 + http_login(company)
  155 + end
  156 +
  157 + it "is successful with valid credentials" do
  158 + create(:user, id: 1, company: company)
  159 + get :show, params: { id: 1 }
  160 +
  161 + expect(response.status).to eq 200
  162 + end
  163 +
  164 + it "returns :not_found for id that cannot be found" do
  165 + get :show, params: { id: "fake_id" }
  166 +
  167 + expect(response.status).to eq 404
  168 + end
  169 +
  170 + it "returns :not_found for a correct id but unauthorized company" do
  171 + new_company = create(:company)
  172 + create(:user, company: new_company, id: 1)
  173 +
  174 + get :show, params: { id: 1 }
  175 +
  176 + expect(response.status).to eq 404
  177 + end
  178 + end
  179 + end
  180 +
  181 +
  182 + describe "create" do
  183 + let(:company) { create(:company) }
  184 +
  185 + context "when unauthorized" do
  186 + it "fails with no credentials" do
  187 + post :create
  188 +
  189 + expect(response.status).to eq 401
  190 + end
  191 +
  192 + it "fails with invalid credentials" do
  193 + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials("unauthorized","123456")
  194 +
  195 + post :create
  196 +
  197 + expect(response.status).to eq 401
  198 + end
  199 + end
  200 +
  201 + context "when authorized" do
  202 + before :each do
  203 + http_login(company)
  204 + end
  205 +
  206 + it "is successful with valid credentials" do
  207 + post :create, params: {
  208 + name: {
  209 + givenName: "New",
  210 + familyName: "User"
  211 + },
  212 + emails: [
  213 + {
  214 + value: "new@example.com"
  215 + }
  216 + ]
  217 + }
  218 +
  219 + expect(response.status).to eq 201
  220 + expect(company.users.count).to eq 1
  221 + user = company.users.first
  222 + expect(user.persisted?).to eq true
  223 + expect(user.first_name).to eq "New"
  224 + expect(user.last_name).to eq "User"
  225 + expect(user.email).to eq "new@example.com"
  226 + end
  227 +
  228 + it "ignores unconfigured params" do
  229 + post :create, params: {
  230 + name: {
  231 + formattedName: "New User",
  232 + givenName: "New",
  233 + familyName: "User"
  234 + },
  235 + emails: [
  236 + {
  237 + value: "new@example.com"
  238 + }
  239 + ]
  240 + }
  241 +
  242 + expect(response.status).to eq 201
  243 + expect(company.users.count).to eq 1
  244 + end
  245 +
  246 + it "returns 422 if required params are missing" do
  247 + post :create, params: {
  248 + name: {
  249 + familyName: "User"
  250 + },
  251 + emails: [
  252 + {
  253 + value: "new@example.com"
  254 + }
  255 + ]
  256 + }
  257 +
  258 + expect(response.status).to eq 422
  259 + expect(company.users.count).to eq 0
  260 + end
  261 +
  262 + it "returns 409 if user already exists" do
  263 + create(:user, email: "new@example.com", company: company)
  264 +
  265 + post :create, params: {
  266 + name: {
  267 + givenName: "New",
  268 + familyName: "User"
  269 + },
  270 + emails: [
  271 + {
  272 + value: "new@example.com"
  273 + }
  274 + ]
  275 + }
  276 +
  277 + expect(response.status).to eq 409
  278 + expect(company.users.count).to eq 1
  279 + end
  280 +
  281 + it "creates and archives inactive user" do
  282 + post :create, params: {
  283 + id: 1,
  284 + userName: "test@example.com",
  285 + name: {
  286 + givenName: "Test",
  287 + familyName: "User"
  288 + },
  289 + emails: [
  290 + {
  291 + value: "test@example.com"
  292 + },
  293 + ],
  294 + active: "false"
  295 + }
  296 +
  297 + expect(response.status).to eq 201
  298 + expect(company.users.count).to eq 1
  299 + user = company.users.first
  300 + expect(user.archived?).to eq true
  301 + end
  302 + end
  303 + end
  304 +
  305 +
  306 + describe "put update" do
  307 + let(:company) { create(:company) }
  308 +
  309 + context "when unauthorized" do
  310 + it "fails with no credentials" do
  311 + put :put_update, params: { id: 1 }
  312 +
  313 + expect(response.status).to eq 401
  314 + end
  315 +
  316 + it "fails with invalid credentials" do
  317 + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials("unauthorized","123456")
  318 +
  319 + put :put_update, params: { id: 1 }
  320 +
  321 + expect(response.status).to eq 401
  322 + end
  323 + end
  324 +
  325 + context "when authorized" do
  326 + let!(:user) { create(:user, id: 1, company: company) }
  327 +
  328 + before :each do
  329 + http_login(company)
  330 + end
  331 +
  332 + it "is successful with with valid credentials" do
  333 + put :put_update, params: {
  334 + id: 1,
  335 + userName: "test@example.com",
  336 + name: {
  337 + givenName: "Test",
  338 + familyName: "User"
  339 + },
  340 + emails: [
  341 + {
  342 + value: "test@example.com"
  343 + },
  344 + ],
  345 + active: "true"
  346 + }
  347 +
  348 + expect(response.status).to eq 200
  349 + end
  350 +
  351 + it "returns :not_found for id that cannot be found" do
  352 + get :put_update, params: { id: "fake_id" }
  353 +
  354 + expect(response.status).to eq 404
  355 + end
  356 +
  357 + it "returns :not_found for a correct id but unauthorized company" do
  358 + new_company = create(:company)
  359 + create(:user, company: new_company, id: 1000)
  360 +
  361 + get :put_update, params: { id: 1000 }
  362 +
  363 + expect(response.status).to eq 404
  364 + end
  365 +
  366 + it "is returns 422 with incomplete request" do
  367 + put :put_update, params: {
  368 + id: 1,
  369 + userName: "test@example.com",
  370 + emails: [
  371 + {
  372 + value: "test@example.com"
  373 + },
  374 + ],
  375 + active: "true"
  376 + }
  377 +
  378 + expect(response.status).to eq 422
  379 + end
  380 + end
  381 + end
  382 +
  383 +
  384 + describe "patch update" do
  385 + let(:company) { create(:company) }
  386 +
  387 + context "when unauthorized" do
  388 + it "fails with no credentials" do
  389 + patch :patch_update, params: { id: 1 }
  390 +
  391 + expect(response.status).to eq 401
  392 + end
  393 +
  394 + it "fails with invalid credentials" do
  395 + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials("unauthorized","123456")
  396 +
  397 + patch :patch_update, params: { id: 1 }
  398 +
  399 + expect(response.status).to eq 401
  400 + end
  401 + end
  402 +
  403 + context "when authorized" do
  404 + let!(:user) { create(:user, id: 1, company: company) }
  405 +
  406 + before :each do
  407 + http_login(company)
  408 + end
  409 +
  410 + it "is successful with valid credentials" do
  411 + patch :patch_update, params: { id: 1 }
  412 +
  413 + expect(response.status).to eq 200
  414 + end
  415 +
  416 + it "returns :not_found for id that cannot be found" do
  417 + get :patch_update, params: { id: "fake_id" }
  418 +
  419 + expect(response.status).to eq 404
  420 + end
  421 +
  422 + it "returns :not_found for a correct id but unauthorized company" do
  423 + new_company = create(:company)
  424 + create(:user, company: new_company, id: 1000)
  425 +
  426 + get :patch_update, params: { id: 1000 }
  427 +
  428 + expect(response.status).to eq 404
  429 + end
  430 +
  431 + it "successfully archives user" do
  432 + expect(company.users.count).to eq 1
  433 + user = company.users.first
  434 + expect(user.archived?).to eq false
  435 +
  436 + patch :patch_update, params: { id: 1 }
  437 +
  438 + expect(response.status).to eq 200
  439 + expect(company.users.count).to eq 1
  440 + user.reload
  441 + expect(user.archived?).to eq true
  442 + end
  443 + end
  444 + end
  445 +end
... ...
spec/dummy/app/models/company.rb 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +class Company < ApplicationRecord
  2 + has_many :users
  3 +end
... ...
spec/dummy/app/models/user.rb 0 → 100644
... ... @@ -0,0 +1,37 @@
  1 +class User < ApplicationRecord
  2 + belongs_to :company
  3 +
  4 + validates \
  5 + :first_name,
  6 + :last_name,
  7 + :email,
  8 + presence: true
  9 +
  10 + validates \
  11 + :email,
  12 + uniqueness: {
  13 + case_insensitive: true
  14 + }
  15 +
  16 + def active?
  17 + archived_at.blank?
  18 + end
  19 +
  20 + def archived?
  21 + archived_at.present?
  22 + end
  23 +
  24 + def archive!
  25 + write_attribute(:archived_at, Time.now)
  26 + save!
  27 + end
  28 +
  29 + def unarchived?
  30 + archived_at.blank?
  31 + end
  32 +
  33 + def unarchive!
  34 + write_attribute(:archived_at, nil)
  35 + save!
  36 + end
  37 +end
... ...
spec/dummy/config/initializers/scim_rails_config.rb 0 → 100644
... ... @@ -0,0 +1,53 @@
  1 +ScimRails.configure do |config|
  2 + config.basic_auth_model = "Company"
  3 + config.scim_users_model = "User"
  4 +
  5 + config.basic_auth_model_searchable_attribute = :subdomain
  6 + config.basic_auth_model_authenticatable_attribute = :api_token
  7 + config.scim_users_scope = :users
  8 + config.scim_users_list_order = :id
  9 +
  10 + config.user_deprovision_method = :archive!
  11 + config.user_reprovision_method = :unarchive!
  12 +
  13 + config.mutable_user_attributes = [
  14 + :first_name,
  15 + :last_name,
  16 + :email
  17 + ]
  18 +
  19 + config.queryable_user_attributes = {
  20 + userName: :email,
  21 + givenName: :first_name,
  22 + familyName: :last_name,
  23 + email: :email
  24 + }
  25 +
  26 + config.mutable_user_attributes_schema = {
  27 + name: {
  28 + givenName: :first_name,
  29 + familyName: :last_name
  30 + },
  31 + emails: [
  32 + {
  33 + value: :email
  34 + }
  35 + ]
  36 + }
  37 +
  38 + config.user_schema = {
  39 + schemas: ["urn:ietf:params:scim:schemas:core:2.0:User"],
  40 + id: :id,
  41 + userName: :email,
  42 + name: {
  43 + givenName: :first_name,
  44 + familyName: :last_name
  45 + },
  46 + emails: [
  47 + {
  48 + value: :email
  49 + },
  50 + ],
  51 + active: :unarchived?
  52 + }
  53 +end
... ...
spec/dummy/config/routes.rb 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +Rails.application.routes.draw do
  2 + mount ScimRails::Engine => "/scim_rails"
  3 +end
... ...
spec/dummy/db/migrate/20181206184304_create_users.rb 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +class CreateUsers < ActiveRecord::Migration[5.0]
  2 + def change
  3 + create_table :users do |t|
  4 + t.string :first_name, null: false
  5 + t.string :last_name, null: false
  6 + t.string :email, null: false
  7 +
  8 + t.integer :company_id
  9 +
  10 + t.timestamp :archived_at
  11 +
  12 + t.timestamps null: false
  13 + end
  14 + end
  15 +end
... ...
spec/dummy/db/migrate/20181206184313_create_companies.rb 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +class CreateCompanies < ActiveRecord::Migration[5.0]
  2 + def change
  3 + create_table :companies do |t|
  4 + t.string :name, null: false
  5 + t.string :subdomain, null: false
  6 + t.string :api_token, null: false
  7 +
  8 + t.timestamps null: false
  9 + end
  10 + end
  11 +end
... ...
spec/dummy/db/schema.rb 0 → 100644
... ... @@ -0,0 +1,33 @@
  1 +# This file is auto-generated from the current state of the database. Instead
  2 +# of editing this file, please use the migrations feature of Active Record to
  3 +# incrementally modify your database, and then regenerate this schema definition.
  4 +#
  5 +# Note that this schema.rb definition is the authoritative source for your
  6 +# database schema. If you need to create the application database on another
  7 +# system, you should be using db:schema:load, not running all the migrations
  8 +# from scratch. The latter is a flawed and unsustainable approach (the more migrations
  9 +# you'll amass, the slower it'll run and the greater likelihood for issues).
  10 +#
  11 +# It's strongly recommended that you check this file into your version control system.
  12 +
  13 +ActiveRecord::Schema.define(version: 20181206184313) do
  14 +
  15 + create_table "companies", force: :cascade do |t|
  16 + t.string "name", null: false
  17 + t.string "subdomain", null: false
  18 + t.string "api_token", null: false
  19 + t.datetime "created_at", null: false
  20 + t.datetime "updated_at", null: false
  21 + end
  22 +
  23 + create_table "users", force: :cascade do |t|
  24 + t.string "first_name", null: false
  25 + t.string "last_name", null: false
  26 + t.string "email", null: false
  27 + t.integer "company_id"
  28 + t.datetime "archived_at"
  29 + t.datetime "created_at", null: false
  30 + t.datetime "updated_at", null: false
  31 + end
  32 +
  33 +end
... ...
spec/dummy/db/seeds.rb 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +company = Company.create(
  2 + name: "Test Company",
  3 + subdomain: "test_company",
  4 + api_token: 1
  5 +)
  6 +
  7 +1.upto(1000) do |n|
  8 + User.create(
  9 + company: company,
  10 + first_name: "Test#{n}",
  11 + last_name: "User#{n}",
  12 + email: "#{n}@example.com"
  13 + )
  14 +end
... ...
spec/factories/company.rb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +FactoryBot.define do
  2 + factory :company do
  3 + name { "Test Company" }
  4 + subdomain { "test" }
  5 + api_token { "1" }
  6 + end
  7 +end
... ...
spec/factories/user.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +FactoryBot.define do
  2 + factory :user do
  3 + company
  4 +
  5 + first_name { "Test" }
  6 + last_name { "User" }
  7 + sequence(:email) { |n| "#{n}@example.com" }
  8 + end
  9 +end
... ...
spec/spec_helper.rb 0 → 100644
... ... @@ -0,0 +1,17 @@
  1 +ENV['RAILS_ENV'] = 'test'
  2 +
  3 +require File.expand_path("../dummy/config/environment.rb", __FILE__)
  4 +require 'rspec/rails'
  5 +require 'factory_bot_rails'
  6 +
  7 +Rails.backtrace_cleaner.remove_silencers!
  8 +
  9 +# Load support files
  10 +Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
  11 +
  12 +RSpec.configure do |config|
  13 + config.mock_with :rspec
  14 + config.use_transactional_fixtures = true
  15 + config.infer_base_class_for_anonymous_controllers = false
  16 + config.order = "random"
  17 +end
... ...
spec/support/auth_helper.rb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +module AuthHelper
  2 + def http_login(company)
  3 + user = company.subdomain
  4 + password = company.api_token
  5 + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(user,password)
  6 + end
  7 +end
... ...
spec/support/factory_bot.rb 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +RSpec.configure do |config|
  2 + config.include FactoryBot::Syntax::Methods
  3 +end
... ...