nulogy_sso 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +90 -0
- data/Rakefile +22 -0
- data/app/assets/images/nulogy_sso/favicon.png +0 -0
- data/app/assets/stylesheets/nulogy_sso/sso_error.css +214 -0
- data/app/controllers/nulogy_sso/auth_controller.rb +100 -0
- data/app/services/nulogy_sso/authenticator.rb +61 -0
- data/app/views/sso_error.html.erb +45 -0
- data/config/initializers/inflections.rb +7 -0
- data/config/routes.rb +5 -0
- data/lib/nulogy_sso/controller_helper.rb +32 -0
- data/lib/nulogy_sso/engine.rb +29 -0
- data/lib/nulogy_sso/test_utilities/auth_mock.rb +94 -0
- data/lib/nulogy_sso/test_utilities/cert.der +0 -0
- data/lib/nulogy_sso/test_utilities/key.pem +52 -0
- data/lib/nulogy_sso/test_utilities/test_helper.rb +55 -0
- data/lib/nulogy_sso/version.rb +3 -0
- data/lib/nulogy_sso.rb +39 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/config/manifest.js +3 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
- data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
- data/spec/dummy/app/controllers/application_controller.rb +12 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/jobs/application_job.rb +2 -0
- data/spec/dummy/app/models/application_record.rb +3 -0
- data/spec/dummy/app/models/user.rb +5 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +36 -0
- data/spec/dummy/bin/update +31 -0
- data/spec/dummy/bin/yarn +11 -0
- data/spec/dummy/config/application.rb +41 -0
- data/spec/dummy/config/auth_sso.yml +20 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/cable.yml +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +49 -0
- data/spec/dummy/config/environments/production.rb +79 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/content_security_policy.rb +25 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +33 -0
- data/spec/dummy/config/puma.rb +34 -0
- data/spec/dummy/config/routes.rb +6 -0
- data/spec/dummy/config/spring.rb +6 -0
- data/spec/dummy/config/storage.yml +34 -0
- data/spec/dummy/config.ru +5 -0
- data/spec/dummy/db/migrate/20190912211120_create_users.rb +12 -0
- data/spec/dummy/db/schema.rb +22 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/test.log +837 -0
- data/spec/dummy/package.json +5 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/dummy/public/apple-touch-icon.png +0 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/robots.txt +5 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/-I/-IQzWZBVpyNJ9dwZO5AyzvfeT_L1FhLt_VKtEYstioM.cache +3 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/-w/-wQxmZSFnAYuueO3wv-SMcI6GpkF0zb93Bk-K1nh6-I.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/03/03X-YlLKeQbKg9UgFMNeO-pNRjTrufgGcONruMJMhus.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/0v/0vQlHhWsvfiQYmfJVne6KDdCTrM9Ct1ZBUv1wI12fXc.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/1c/1cSa1S_Ik-wQeXi-Pb1sJX4_CC_Gu6CJ6THxM2ZxOTQ.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/3A/3ACRNidm75IdG2lgWCRExd2yOtmLtKsdRrgsvML8gc4.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/3o/3ogX5PjkplRXrsO2QZTSkbohBKS3xuy3yHXRf30Vsho.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/4J/4J2ZSEfqkzjpNHLlEPvd-5laPYz8eA0Tm6lt04YfVc4.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/4y/4ySQY2DeEDqx7mPwZF2m9dK9u5dtKOZj6PfLlWnRyEQ.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/5J/5JVr1JuiYXAwKzD64wxtFHroGbE9K2aMWb6f67tfVDQ.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/5u/5uuIL6SiWAHDNxQ63Bb-mEptuzUArLXyoTBDHJ5RTM4.cache +5 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/6b/6bIKFgIunI8QwnhOiCTyQOSHwPOCUNQbSzAVYhaqq8E.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/8Q/8QavKcHzS_5D2q2DLfuAtFkJXKtNBAASd3oLAhmCNQs.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/8a/8avIYxo88yDqslmUypali4ILLE-OVrryLchYsJuc9uE.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/8i/8izW0a4Zw0ZIpyJ2h1olnHKpWoSj6Yu39_6iziqxvzc.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/9J/9J6tFdjgXdjYE9Oc9ar9ti5spP_tdq-1_PiYhlD9t6I.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/9q/9qxBVp_Ackolv-Ir9TIGtC3Jg4cbqj6mxxLcoimAilw.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Ac/AccyOixh8iQFR7XBSzGVVKalgdg64T1yeAp7NBwDtTg.cache +3 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/An/An4y7wYtShMDQHwnRlEj4qcTQOlebrjVIrH-ZjRXlTw.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/D2/D2kPITeQ0WkknzjDQuPSbkXklgS6LtKcdtgyC3pu50k.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/DO/DOjY5JRYb7u9e6jD6doIfYt5nrvUEjacjyhiTjXal2M.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/DU/DUMR4O60Nd02Z9uDvlfLbFUhubOiMbJnYrbJR_AKo4k.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Dt/Dt8q0fkQgUXw6I6nWfcPb4ZYGY-_UebKwhNObSrdkT8.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Ez/EzXtHEm-xBGVH72qLdvc7siqWebRocOJzp2iPwJm1TM.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/FP/FPL9y7t_40uxIV9w2IGRZJnEh_5N6NmXaOWLgvn2wmI.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/I-/I-aV6d9rIPlPNI2uOoWp7Il9fdzqpAmpJXcnd08TMxI.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/J0/J030bfDTH7OJpzAVdkIlvcx8n0gY-en4t63QpRh83Yo.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/KL/KLHTElxq3T60mK7oURgiZow2JiCXYvKCYEUdhhctZKM.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/L2/L2uA8R_LKv75JnGXHF4Z-0J1AGG5VObLLPSObFUwov0.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/M7/M7sD_tg1aMFHF-gHYiCM_ml6S44geHzvefKgdasAhz8.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/M7/m7xag7aON7xLeWIpCQBJ70HcdFqJ1ZUZUg46oU89Zfw.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/MA/MAsN3JftLnlWpSVqP84N8tvQ0c5DQ2AJBjL8nWVUINI.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Mo/Mo6cKTdohqOXUaEUYOXwkpUewtRun6oC_arZQltPGZg.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/OI/OIl8YRbsB6--l_CKIzlqpMNk31xMfPSe8IEGgNnNSQA.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/OJ/OJjACgGreSmoal4FQO9QFdjAyRFG8y8Q6urqK9jarR0.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/OS/OSjUgSyEOb3ZvdTPFeGkLQQzpdqEaIc_WDb9eOTANH8.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/PJ/PJg5JJZQpAq56ZK4RlLkLk3EO_C_PfhhcQcgX155Q3Y.cache +3 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/QO/QO59HgQ2MIHck98-gaQqUM3ia4uzM138LlZsO5TsjLI.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Qb/QblQL05XuRs4iHdx96hOHN5mI_37pNeik6NWB99iuxY.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/R6/R678edDsoAWc6Bijbe0DN2gc--95iwiQo75-zILHS2Y.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Rv/RvFFKTRBnfZgEO-gWwKl_MUeogSPgvYvqivJkjtHF1c.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/St/StXiB3ZVbOvvg1eN7OMHH9g_uCljMP209iDbVkqVPaQ.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Uj/UjohEpOjNl1G6DoHx_DiqYWORyFy_SIY-Z_3iTgvaNY.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/W7/W7lea8dViN-zKiB0YDymngohwzY780_bafIrifdvdEU.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Wv/Wv5smlMR8HZlVpUVszeSJC2Z3y9tNVOCXkBcRXb3PK0.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/XZ/XZcPRDhkBL2jpJUwZciwFizBlxNz2CsMDBvM71F7Y6M.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Y4/Y4XV3TFQk_FtIsIDm735D9Gxqs2n-nVssI7ItEbHlT4.cache +4 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/YU/YUZTikjrtYByH5K9PQpw9o9incNNYKhsjekDQLhPniE.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Yp/YpMKz0G1Yf2acXo2K2vXpxKyND46cz69bF5q1zn5dWY.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Zk/Zk5OwH10pLNWcgDncIB2KDdKjiMNtG7tzFnAiL4tITw.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Zs/ZsxGMLE5q7daf8xX9wxiISEfgaSSkWQG13xtjs5oGvU.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/_c/_c0OX2xSAUonHyl--ScIJdqu4dOIv5eWSiRCpsNIat4.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/_v/_vB_dHVUtju7m6FGk-MvQutohQFkt58fsmuf3Y1EFgU.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/aT/aTPoDhk5o9HqzSqn8VjurVSrWbYTbh3dAJmXhgLEZyc.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/aZ/aZgVZIZURvHb9-rOh2SivDHU-aBn-Jn1nKOPuI7lF0U.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/bB/bBrouo-AbmaOmmI5w0EatyvJIj6Zel6BDOqpXUub-YM.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/bC/bCGetG10_IPS-4Lea1FrjonfYd1QJf5j7J23dBSgxMI.cache +3 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/bd/bde0sI4pua76cCQiJr5-4YPdoGOq7zUcE5JUFy10wEQ.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/c3/c3MkD92XKFFo7SIHfkh3Zf3b7TTV7PPhLy04Ak1iOuY.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/cI/cIXdHUyJ1umwlEmauLUx-whf_06eJvzlxEoPVPlG-4s.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ck/ckZOTlrjGXnk3bJ7dEgh6ld9VFFg1rV7MGXqEv1Fb9I.cache +3 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/dC/dCxhpA2j6Pi1XDXa12EUmvdpLN_MJ3GPOZBqgg7GcVw.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ej/ejwFH71RbcAzfpFyRxO8czavHqoOs9SzC10c-PwS60Y.cache +4 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/fl/flex8byqqPRlAhCuyDZsaMg2gOeDj3NHAIzid-OS2Hg.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/gu/guEVVxdrH6uyyJ_m1VYsBVD566zTNeSBDgppqYGy-sk.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/hV/hVXlJWvvr6NsDbr1qABWR3CFv36YU7970jmxU_L2NuY.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ju/juWsFPPdDAbfJ4X3-dknffITj4HcW0Fu5U9UiaPn4b4.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/kG/kG0KlJGmHu0kwLwZDKon08APGF3Z3GpbRt6BuyKJUf4.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/kG/kGyYNYLbPlxoTk3K-8slRw-fuDznBFYnl-0y2jK6_cI.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/lS/lStvx9Beg2l4s8L-QdTSKuc5_qQPQAZPnIcRI7JkpPE.cache +4 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/m9/m9S3GxTAovnGptmIbSxuSLVFWJCND5v6jetYN2IsHMQ.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/mJ/mJ-X19ke9W8_XFBJqqn9Hd4LZNsntZzZjcGZUyStW3s.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/n_/n_xYqQYhwEMQknb3jFQnjlxxBE9TzMNHCdJ-bEyZFIw.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/nx/nxTv3sKVUQZADJyM3dPaVmUA78MIsMLD_K279yN_GsI.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/pM/pM_tvcMleZAXoskYgAVEJ8IPTDCzNUrpHakxVWTZPNQ.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/pt/ptleYqvprORReM2iFj-HW9O98Nhoy5qCF4iUWwtyve0.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/q6/q6VE6KTZtyGRe8Cuj9izRDMuieCcGKOKzBUH2niWYpc.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/q_/q_IgK4QolU1_5AK7pudGtHR2hiob-XkEZIMUgZY_iFM.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/qj/qjq5Ug3S2i5pydfGSIfUa7Y0s8s0FwqXzt0kkFijToI.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/rd/rd8rR4dvQJUvFyyzVHdNbHilCTfHWlGn6kEU65JL2Fw.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/rx/rxqqFB2TXY1MQjq34u1hkkJgqenfyj2ZbYVtb2wEDvc.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/sa/sab7V2jcUIn2nRakbXijIbvYmHyOOf6ShENXDRtYP1w.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/sr/sr3hnK_P9HaS68zSw0GLhpPzpgEs9shxEe6J7ktfbcw.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/u_/u_y6q_eS56FrB6fbIcFt49Tw9exxHbWGGb9puLTTcnk.cache +3 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ub/ubraBOWW9z9uvIXTsIrgJ3kzPboMmsZcyeNsv7sMCnU.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/wi/win_v0ZNu-l7AoRx8w3ls1xcy0mUExLBVMCSr5oaJFc.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/xH/xHr1kqSt7XnOPWH1LDZY1-0rIpwoT4OM4g68Ts3A9a4.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/yM/yMJd-lz8flnlwt-j5DOGjhykEGnynSCv4I2YKpPfr0Y.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ys/ysn-zAA7CKGovpmCCejFwdSLV3RlH13Nc4cwac7BwL4.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/zT/zTQBjN2k1ltsiVOSJb4mqUhl4FvLQDM6cFRUtQLQ6Qw.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/zq/zqVwwFUvXqTxyX57DFJh5CY88HR0PEznhr-rLP6A5BQ.cache +2 -0
- data/spec/dummy/tmp/development_secret.txt +1 -0
- data/spec/examples.txt +19 -0
- data/spec/feature_spec_helper.rb +44 -0
- data/spec/features/nulogy_sso/sso_login_spec.rb +112 -0
- data/spec/integration/services/nulogy_sso/authenticator_spec.rb +95 -0
- data/spec/rails_helper.rb +28 -0
- data/spec/spec_helper.rb +43 -0
- data/spec/support/mock_auth0_verifier.rb +27 -0
- metadata +517 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails_helper"
|
|
4
|
+
require "capybara/rspec"
|
|
5
|
+
require "webmock/rspec"
|
|
6
|
+
require "resolv"
|
|
7
|
+
require "socket"
|
|
8
|
+
|
|
9
|
+
def configure_webmock(overrides: [])
|
|
10
|
+
allowed_hosts = (overrides + [ENV["NULOGY_SSO_MOCKSERVER_HOST"]]).compact
|
|
11
|
+
WebMock.disable_net_connect!(
|
|
12
|
+
allow_localhost: true,
|
|
13
|
+
allow: allowed_hosts
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
Capybara.server = :webrick
|
|
18
|
+
|
|
19
|
+
if ENV["REMOTE_SELENIUM_HOST"].present?
|
|
20
|
+
ip = Socket.ip_address_list.detect(&:ipv4_private?)
|
|
21
|
+
rails_server_host = ip.ip_address
|
|
22
|
+
remote_selenium_host = Resolv.getaddress(ENV.fetch("REMOTE_SELENIUM_HOST"))
|
|
23
|
+
remote_selenium_port = ENV.fetch("REMOTE_SELENIUM_PORT")
|
|
24
|
+
|
|
25
|
+
Capybara.register_driver :remote do |app|
|
|
26
|
+
Capybara.server_host = rails_server_host
|
|
27
|
+
Capybara::Selenium::Driver.new(
|
|
28
|
+
app,
|
|
29
|
+
browser: :remote,
|
|
30
|
+
url: "http://#{remote_selenium_host}:#{remote_selenium_port}/wd/hub",
|
|
31
|
+
desired_capabilities: :chrome
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
Capybara.javascript_driver = :remote
|
|
36
|
+
configure_webmock(overrides: [rails_server_host, remote_selenium_host])
|
|
37
|
+
else
|
|
38
|
+
Capybara.javascript_driver = :selenium_chrome
|
|
39
|
+
configure_webmock
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
RSpec.configure do |config|
|
|
43
|
+
config.use_transactional_fixtures = true
|
|
44
|
+
end
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "feature_spec_helper"
|
|
4
|
+
|
|
5
|
+
module NulogySSO
|
|
6
|
+
RSpec.describe "the SSO login process", type: :feature, js: true do
|
|
7
|
+
let(:email) { "test@nulogy.com" }
|
|
8
|
+
let(:auth_mock) { TestUtilities::AuthMock.new }
|
|
9
|
+
let(:test_helper) { TestUtilities::TestHelper.new }
|
|
10
|
+
|
|
11
|
+
describe "login flow" do
|
|
12
|
+
it "can successfully login" do
|
|
13
|
+
auth_mock.setup(email: email, redirect_path: "/hello_world")
|
|
14
|
+
create_active_user
|
|
15
|
+
|
|
16
|
+
visit "/hello_world"
|
|
17
|
+
|
|
18
|
+
expect(page).to have_content("Hello World")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "shows an error page when Auth0 authenticates the user but app validation fails" do
|
|
22
|
+
auth_mock.setup(email: email)
|
|
23
|
+
create_inactive_user
|
|
24
|
+
|
|
25
|
+
visit "/hello_world"
|
|
26
|
+
|
|
27
|
+
expect_error
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "shows an error page when the user can authorize with Auth0 but not the app itself" do
|
|
31
|
+
auth_mock.setup(email: email)
|
|
32
|
+
|
|
33
|
+
visit "/hello_world"
|
|
34
|
+
|
|
35
|
+
expect_error
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "shows an error page when Auth0 throws an error" do
|
|
39
|
+
auth_mock.setup(email: email, status_code: 403)
|
|
40
|
+
create_active_user
|
|
41
|
+
|
|
42
|
+
visit "/hello_world"
|
|
43
|
+
|
|
44
|
+
expect_error
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe "JWT authentication" do
|
|
49
|
+
let!(:user) { create_active_user }
|
|
50
|
+
|
|
51
|
+
before do
|
|
52
|
+
auth_mock.mockserver_reset
|
|
53
|
+
auth_mock.setup_jwks
|
|
54
|
+
|
|
55
|
+
# have to visit an unauthenticated endpoint in order for capybara to have something to have a tab to set the cookie on
|
|
56
|
+
visit "/robots.txt"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "allows a user with a valid JWT to visit a secured endpoint" do
|
|
60
|
+
set_access_token_cookie(test_helper.jwt(email))
|
|
61
|
+
|
|
62
|
+
visit "/hello_world"
|
|
63
|
+
|
|
64
|
+
expect(page).to have_content("Hello World")
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "prevents sessions with invalid JWTs from accessing secured endpoints" do
|
|
68
|
+
set_access_token_cookie(test_helper.jwt(email, "exp" => (Time.now - 1.day).to_i))
|
|
69
|
+
|
|
70
|
+
visit "/hello_world"
|
|
71
|
+
|
|
72
|
+
expect(current_path).to eq("/authorize")
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "prevents sessions with no JWT from accessing secured endpoints" do
|
|
76
|
+
visit "/hello_world"
|
|
77
|
+
|
|
78
|
+
expect(current_path).to eq("/authorize")
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it "shows the user an error page when they've been deactivated in CPI after they've logged in" do
|
|
82
|
+
set_access_token_cookie(test_helper.jwt(email))
|
|
83
|
+
|
|
84
|
+
visit "/hello_world"
|
|
85
|
+
|
|
86
|
+
expect(page).to have_content("Hello World")
|
|
87
|
+
|
|
88
|
+
user.update!(active: false)
|
|
89
|
+
|
|
90
|
+
visit "/hello_world"
|
|
91
|
+
|
|
92
|
+
expect_error
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def set_access_token_cookie(token)
|
|
96
|
+
page.driver.browser.manage.add_cookie(name: NulogySSO.auth_cookie_key, value: token)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def create_active_user
|
|
101
|
+
User.create!(email: email, active: true)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def create_inactive_user
|
|
105
|
+
User.create!(email: email, active: false)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def expect_error
|
|
109
|
+
expect(page).to have_content("You do not have permission to access Nulogy.")
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module NulogySSO
|
|
4
|
+
RSpec.describe Authenticator do
|
|
5
|
+
let(:auth_config) { NulogySSO.auth_config }
|
|
6
|
+
let(:verifier) do
|
|
7
|
+
MockAuth0Verifier.new(
|
|
8
|
+
issuer: "#{auth_config.base_uri}/",
|
|
9
|
+
audience: auth_config.audience,
|
|
10
|
+
jwks: TestUtilities::AuthMock.new.jwks_json
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
let(:default_authenticator) { Authenticator.new(verifier: verifier, find_user_by_email: find_a_user) }
|
|
14
|
+
let(:user) { User.new(email: email, active: true) }
|
|
15
|
+
let(:find_a_user) { proc { user } }
|
|
16
|
+
let(:find_no_user) { proc { nil } }
|
|
17
|
+
let(:on_success) { spy("on_success") }
|
|
18
|
+
let(:on_invalid_token) { spy("on_invalid_token") }
|
|
19
|
+
let(:email) { "sso_test@nulogy.com" }
|
|
20
|
+
let(:valid_signed_token) { test_helper.jwt(email) }
|
|
21
|
+
let(:invalid_signed_token) { test_helper.jwt(email, "exp" => 1.day.ago.to_i) }
|
|
22
|
+
let(:test_helper) { TestUtilities::TestHelper.new }
|
|
23
|
+
|
|
24
|
+
describe "#validate_token" do
|
|
25
|
+
it "calls on_invalid_token when the access token is blank" do
|
|
26
|
+
[nil, "", false].each(&method(:validate_token))
|
|
27
|
+
|
|
28
|
+
expect(on_invalid_token).to have_received(:call).exactly(3).times
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
context "JWT passes verification" do
|
|
32
|
+
it "calls the success handler when a user matching the access token email exists" do
|
|
33
|
+
validate_token(valid_signed_token)
|
|
34
|
+
|
|
35
|
+
expect(on_success).to have_received(:call).with(
|
|
36
|
+
a_hash_including(JWT_EMAIL_KEY => email)
|
|
37
|
+
).once
|
|
38
|
+
expect(on_invalid_token).not_to have_received(:call)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "calls the invalid token handler when there is no user matching the access token email" do
|
|
42
|
+
authenticator = Authenticator.new(verifier: verifier, find_user_by_email: find_no_user)
|
|
43
|
+
|
|
44
|
+
validate_token(valid_signed_token, authenticator: authenticator)
|
|
45
|
+
|
|
46
|
+
expect(on_invalid_token).to have_received(:call).once
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "calls the invalid token handler when there is an invalid user" do
|
|
50
|
+
authenticator = Authenticator.new(verifier: verifier, find_user_by_email: find_a_user, validate_user: proc { false })
|
|
51
|
+
|
|
52
|
+
validate_token(valid_signed_token, authenticator: authenticator)
|
|
53
|
+
|
|
54
|
+
expect(on_invalid_token).to have_received(:call).once
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
context "JWT fails verification" do
|
|
59
|
+
it "calls the invalid token handler" do
|
|
60
|
+
validate_token(invalid_signed_token)
|
|
61
|
+
|
|
62
|
+
expect(on_invalid_token).to have_received(:call).once
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def validate_token(raw_access_token, authenticator: default_authenticator)
|
|
67
|
+
authenticator.validate_token(
|
|
68
|
+
raw_access_token,
|
|
69
|
+
on_success: on_success,
|
|
70
|
+
on_invalid_token: on_invalid_token
|
|
71
|
+
)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
describe "#authenticated_user" do
|
|
76
|
+
it "returns the user that is associated to a valid JWT" do
|
|
77
|
+
expect(default_authenticator.authenticated_user(valid_signed_token)).to eq(user)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "returns nil when the JWT is invalid" do
|
|
81
|
+
expect(default_authenticator.authenticated_user(invalid_signed_token)).to be_nil
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "returns nil when the provided token is blank" do
|
|
85
|
+
expect(default_authenticator.authenticated_user("")).to be_nil
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it "returns nil when no user matching the JWT's email field exists" do
|
|
89
|
+
authenticator = Authenticator.new(verifier: verifier, find_user_by_email: find_no_user)
|
|
90
|
+
|
|
91
|
+
expect(authenticator.authenticated_user(valid_signed_token)).to be_nil
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
ENV["RAILS_ENV"] ||= "test"
|
|
5
|
+
require_relative "dummy/config/environment"
|
|
6
|
+
# Prevent database truncation if the environment is production
|
|
7
|
+
abort("The Rails environment is running in production mode!") if Rails.env.production?
|
|
8
|
+
require "rspec/rails"
|
|
9
|
+
# Add additional requires below this line. Rails is not loaded until this point!
|
|
10
|
+
|
|
11
|
+
Dir[NulogySSO::Engine.root.join("spec/support/**/*.rb")].each { |f| require f }
|
|
12
|
+
|
|
13
|
+
require "nulogy_sso/test_utilities/auth_mock"
|
|
14
|
+
require "nulogy_sso/test_utilities/test_helper"
|
|
15
|
+
|
|
16
|
+
begin
|
|
17
|
+
ActiveRecord::Migration.maintain_test_schema!
|
|
18
|
+
rescue ActiveRecord::PendingMigrationError => e
|
|
19
|
+
puts e.to_s.strip
|
|
20
|
+
exit 1
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
RSpec.configure do |config|
|
|
24
|
+
config.infer_spec_type_from_file_location!
|
|
25
|
+
|
|
26
|
+
# Filter lines from Rails gems in backtraces.
|
|
27
|
+
config.filter_rails_from_backtrace!
|
|
28
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
|
4
|
+
RSpec.configure do |config|
|
|
5
|
+
config.expect_with :rspec do |expectations|
|
|
6
|
+
# This option will default to `true` in RSpec 4
|
|
7
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
config.mock_with :rspec do |mocks|
|
|
11
|
+
# Prevents you from mocking or stubbing a method that does not exist on
|
|
12
|
+
# a real object. This is generally recommended, and will default to
|
|
13
|
+
# `true` in RSpec 4.
|
|
14
|
+
mocks.verify_partial_doubles = true
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# This option will default to `:apply_to_host_groups` in RSpec 4 (and will
|
|
18
|
+
# have no way to turn it off -- the option exists only for backwards
|
|
19
|
+
# compatibility in RSpec 3). It causes shared context metadata to be
|
|
20
|
+
# inherited by the metadata hash of host groups and examples, rather than
|
|
21
|
+
# triggering implicit auto-inclusion in groups with matching metadata.
|
|
22
|
+
config.shared_context_metadata_behavior = :apply_to_host_groups
|
|
23
|
+
|
|
24
|
+
# This allows you to limit a spec run to individual examples or groups
|
|
25
|
+
# you care about by tagging them with `:focus` metadata. When nothing
|
|
26
|
+
# is tagged with `:focus`, all examples get run. RSpec also provides
|
|
27
|
+
# aliases for `it`, `describe`, and `context` that include `:focus`
|
|
28
|
+
# metadata: `fit`, `fdescribe` and `fcontext`, respectively.
|
|
29
|
+
config.filter_run_when_matching :focus
|
|
30
|
+
|
|
31
|
+
config.example_status_persistence_file_path = "spec/examples.txt"
|
|
32
|
+
|
|
33
|
+
config.disable_monkey_patching!
|
|
34
|
+
|
|
35
|
+
if config.files_to_run.one?
|
|
36
|
+
config.default_formatter = "doc"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
config.order = :random
|
|
40
|
+
|
|
41
|
+
# Seed global randomization in this process using the `--seed` CLI option.
|
|
42
|
+
Kernel.srand config.seed
|
|
43
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This is a mock verifier that allows the auth0_rs256_jwt_verifier gem
|
|
4
|
+
# to still be used for verifying JWTs, but with a localhost JWKS specified.
|
|
5
|
+
# This code was adapted from the gem's test suite:
|
|
6
|
+
# https://github.com/DroidsOnRoids/auth0_rs256_jwt_verifier/blob/master/test/auth0_rs256_jwt_verifier_test.rb
|
|
7
|
+
|
|
8
|
+
class MockAuth0Verifier
|
|
9
|
+
def initialize(issuer:, audience:, jwks:)
|
|
10
|
+
@internal_verifier = Auth0RS256JWTVerifier.new(
|
|
11
|
+
issuer: issuer,
|
|
12
|
+
audience: audience,
|
|
13
|
+
jwks_url: "https://do.not.care",
|
|
14
|
+
http: http_stub(jwks)
|
|
15
|
+
)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
delegate :verify, to: :@internal_verifier
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def http_stub(jwks)
|
|
23
|
+
http_stub = Object.new
|
|
24
|
+
http_stub.define_singleton_method(:get) { |*_| jwks }
|
|
25
|
+
http_stub
|
|
26
|
+
end
|
|
27
|
+
end
|