nulogy_sso 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|