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.
Files changed (171) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +90 -0
  3. data/Rakefile +22 -0
  4. data/app/assets/images/nulogy_sso/favicon.png +0 -0
  5. data/app/assets/stylesheets/nulogy_sso/sso_error.css +214 -0
  6. data/app/controllers/nulogy_sso/auth_controller.rb +100 -0
  7. data/app/services/nulogy_sso/authenticator.rb +61 -0
  8. data/app/views/sso_error.html.erb +45 -0
  9. data/config/initializers/inflections.rb +7 -0
  10. data/config/routes.rb +5 -0
  11. data/lib/nulogy_sso/controller_helper.rb +32 -0
  12. data/lib/nulogy_sso/engine.rb +29 -0
  13. data/lib/nulogy_sso/test_utilities/auth_mock.rb +94 -0
  14. data/lib/nulogy_sso/test_utilities/cert.der +0 -0
  15. data/lib/nulogy_sso/test_utilities/key.pem +52 -0
  16. data/lib/nulogy_sso/test_utilities/test_helper.rb +55 -0
  17. data/lib/nulogy_sso/version.rb +3 -0
  18. data/lib/nulogy_sso.rb +39 -0
  19. data/spec/dummy/Rakefile +6 -0
  20. data/spec/dummy/app/assets/config/manifest.js +3 -0
  21. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  22. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  23. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  24. data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
  25. data/spec/dummy/app/controllers/application_controller.rb +12 -0
  26. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  27. data/spec/dummy/app/jobs/application_job.rb +2 -0
  28. data/spec/dummy/app/models/application_record.rb +3 -0
  29. data/spec/dummy/app/models/user.rb +5 -0
  30. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  31. data/spec/dummy/bin/bundle +3 -0
  32. data/spec/dummy/bin/rails +4 -0
  33. data/spec/dummy/bin/rake +4 -0
  34. data/spec/dummy/bin/setup +36 -0
  35. data/spec/dummy/bin/update +31 -0
  36. data/spec/dummy/bin/yarn +11 -0
  37. data/spec/dummy/config/application.rb +41 -0
  38. data/spec/dummy/config/auth_sso.yml +20 -0
  39. data/spec/dummy/config/boot.rb +5 -0
  40. data/spec/dummy/config/cable.yml +10 -0
  41. data/spec/dummy/config/database.yml +25 -0
  42. data/spec/dummy/config/environment.rb +5 -0
  43. data/spec/dummy/config/environments/development.rb +49 -0
  44. data/spec/dummy/config/environments/production.rb +79 -0
  45. data/spec/dummy/config/environments/test.rb +39 -0
  46. data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -0
  47. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  48. data/spec/dummy/config/initializers/content_security_policy.rb +25 -0
  49. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  50. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  51. data/spec/dummy/config/initializers/inflections.rb +16 -0
  52. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  53. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  54. data/spec/dummy/config/locales/en.yml +33 -0
  55. data/spec/dummy/config/puma.rb +34 -0
  56. data/spec/dummy/config/routes.rb +6 -0
  57. data/spec/dummy/config/spring.rb +6 -0
  58. data/spec/dummy/config/storage.yml +34 -0
  59. data/spec/dummy/config.ru +5 -0
  60. data/spec/dummy/db/migrate/20190912211120_create_users.rb +12 -0
  61. data/spec/dummy/db/schema.rb +22 -0
  62. data/spec/dummy/db/test.sqlite3 +0 -0
  63. data/spec/dummy/log/test.log +837 -0
  64. data/spec/dummy/package.json +5 -0
  65. data/spec/dummy/public/404.html +67 -0
  66. data/spec/dummy/public/422.html +67 -0
  67. data/spec/dummy/public/500.html +66 -0
  68. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  69. data/spec/dummy/public/apple-touch-icon.png +0 -0
  70. data/spec/dummy/public/favicon.ico +0 -0
  71. data/spec/dummy/public/robots.txt +5 -0
  72. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/-I/-IQzWZBVpyNJ9dwZO5AyzvfeT_L1FhLt_VKtEYstioM.cache +3 -0
  73. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/-w/-wQxmZSFnAYuueO3wv-SMcI6GpkF0zb93Bk-K1nh6-I.cache +0 -0
  74. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/03/03X-YlLKeQbKg9UgFMNeO-pNRjTrufgGcONruMJMhus.cache +1 -0
  75. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/0v/0vQlHhWsvfiQYmfJVne6KDdCTrM9Ct1ZBUv1wI12fXc.cache +1 -0
  76. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/1c/1cSa1S_Ik-wQeXi-Pb1sJX4_CC_Gu6CJ6THxM2ZxOTQ.cache +1 -0
  77. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/3A/3ACRNidm75IdG2lgWCRExd2yOtmLtKsdRrgsvML8gc4.cache +0 -0
  78. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/3o/3ogX5PjkplRXrsO2QZTSkbohBKS3xuy3yHXRf30Vsho.cache +0 -0
  79. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/4J/4J2ZSEfqkzjpNHLlEPvd-5laPYz8eA0Tm6lt04YfVc4.cache +2 -0
  80. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/4y/4ySQY2DeEDqx7mPwZF2m9dK9u5dtKOZj6PfLlWnRyEQ.cache +1 -0
  81. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/5J/5JVr1JuiYXAwKzD64wxtFHroGbE9K2aMWb6f67tfVDQ.cache +1 -0
  82. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/5u/5uuIL6SiWAHDNxQ63Bb-mEptuzUArLXyoTBDHJ5RTM4.cache +5 -0
  83. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/6b/6bIKFgIunI8QwnhOiCTyQOSHwPOCUNQbSzAVYhaqq8E.cache +1 -0
  84. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/8Q/8QavKcHzS_5D2q2DLfuAtFkJXKtNBAASd3oLAhmCNQs.cache +0 -0
  85. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/8a/8avIYxo88yDqslmUypali4ILLE-OVrryLchYsJuc9uE.cache +1 -0
  86. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/8i/8izW0a4Zw0ZIpyJ2h1olnHKpWoSj6Yu39_6iziqxvzc.cache +1 -0
  87. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/9J/9J6tFdjgXdjYE9Oc9ar9ti5spP_tdq-1_PiYhlD9t6I.cache +2 -0
  88. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/9q/9qxBVp_Ackolv-Ir9TIGtC3Jg4cbqj6mxxLcoimAilw.cache +0 -0
  89. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Ac/AccyOixh8iQFR7XBSzGVVKalgdg64T1yeAp7NBwDtTg.cache +3 -0
  90. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/An/An4y7wYtShMDQHwnRlEj4qcTQOlebrjVIrH-ZjRXlTw.cache +0 -0
  91. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/D2/D2kPITeQ0WkknzjDQuPSbkXklgS6LtKcdtgyC3pu50k.cache +1 -0
  92. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/DO/DOjY5JRYb7u9e6jD6doIfYt5nrvUEjacjyhiTjXal2M.cache +1 -0
  93. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/DU/DUMR4O60Nd02Z9uDvlfLbFUhubOiMbJnYrbJR_AKo4k.cache +1 -0
  94. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Dt/Dt8q0fkQgUXw6I6nWfcPb4ZYGY-_UebKwhNObSrdkT8.cache +0 -0
  95. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Ez/EzXtHEm-xBGVH72qLdvc7siqWebRocOJzp2iPwJm1TM.cache +0 -0
  96. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/FP/FPL9y7t_40uxIV9w2IGRZJnEh_5N6NmXaOWLgvn2wmI.cache +1 -0
  97. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/I-/I-aV6d9rIPlPNI2uOoWp7Il9fdzqpAmpJXcnd08TMxI.cache +0 -0
  98. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/J0/J030bfDTH7OJpzAVdkIlvcx8n0gY-en4t63QpRh83Yo.cache +2 -0
  99. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/KL/KLHTElxq3T60mK7oURgiZow2JiCXYvKCYEUdhhctZKM.cache +1 -0
  100. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/L2/L2uA8R_LKv75JnGXHF4Z-0J1AGG5VObLLPSObFUwov0.cache +0 -0
  101. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/M7/M7sD_tg1aMFHF-gHYiCM_ml6S44geHzvefKgdasAhz8.cache +1 -0
  102. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/M7/m7xag7aON7xLeWIpCQBJ70HcdFqJ1ZUZUg46oU89Zfw.cache +1 -0
  103. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/MA/MAsN3JftLnlWpSVqP84N8tvQ0c5DQ2AJBjL8nWVUINI.cache +0 -0
  104. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Mo/Mo6cKTdohqOXUaEUYOXwkpUewtRun6oC_arZQltPGZg.cache +0 -0
  105. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/OI/OIl8YRbsB6--l_CKIzlqpMNk31xMfPSe8IEGgNnNSQA.cache +2 -0
  106. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/OJ/OJjACgGreSmoal4FQO9QFdjAyRFG8y8Q6urqK9jarR0.cache +1 -0
  107. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/OS/OSjUgSyEOb3ZvdTPFeGkLQQzpdqEaIc_WDb9eOTANH8.cache +0 -0
  108. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/PJ/PJg5JJZQpAq56ZK4RlLkLk3EO_C_PfhhcQcgX155Q3Y.cache +3 -0
  109. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/QO/QO59HgQ2MIHck98-gaQqUM3ia4uzM138LlZsO5TsjLI.cache +1 -0
  110. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Qb/QblQL05XuRs4iHdx96hOHN5mI_37pNeik6NWB99iuxY.cache +0 -0
  111. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/R6/R678edDsoAWc6Bijbe0DN2gc--95iwiQo75-zILHS2Y.cache +0 -0
  112. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Rv/RvFFKTRBnfZgEO-gWwKl_MUeogSPgvYvqivJkjtHF1c.cache +1 -0
  113. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/St/StXiB3ZVbOvvg1eN7OMHH9g_uCljMP209iDbVkqVPaQ.cache +0 -0
  114. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Uj/UjohEpOjNl1G6DoHx_DiqYWORyFy_SIY-Z_3iTgvaNY.cache +2 -0
  115. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/W7/W7lea8dViN-zKiB0YDymngohwzY780_bafIrifdvdEU.cache +1 -0
  116. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Wv/Wv5smlMR8HZlVpUVszeSJC2Z3y9tNVOCXkBcRXb3PK0.cache +1 -0
  117. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/XZ/XZcPRDhkBL2jpJUwZciwFizBlxNz2CsMDBvM71F7Y6M.cache +1 -0
  118. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Y4/Y4XV3TFQk_FtIsIDm735D9Gxqs2n-nVssI7ItEbHlT4.cache +4 -0
  119. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/YU/YUZTikjrtYByH5K9PQpw9o9incNNYKhsjekDQLhPniE.cache +1 -0
  120. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Yp/YpMKz0G1Yf2acXo2K2vXpxKyND46cz69bF5q1zn5dWY.cache +1 -0
  121. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Zk/Zk5OwH10pLNWcgDncIB2KDdKjiMNtG7tzFnAiL4tITw.cache +2 -0
  122. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Zs/ZsxGMLE5q7daf8xX9wxiISEfgaSSkWQG13xtjs5oGvU.cache +1 -0
  123. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/_c/_c0OX2xSAUonHyl--ScIJdqu4dOIv5eWSiRCpsNIat4.cache +0 -0
  124. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/_v/_vB_dHVUtju7m6FGk-MvQutohQFkt58fsmuf3Y1EFgU.cache +1 -0
  125. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/aT/aTPoDhk5o9HqzSqn8VjurVSrWbYTbh3dAJmXhgLEZyc.cache +1 -0
  126. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/aZ/aZgVZIZURvHb9-rOh2SivDHU-aBn-Jn1nKOPuI7lF0U.cache +0 -0
  127. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/bB/bBrouo-AbmaOmmI5w0EatyvJIj6Zel6BDOqpXUub-YM.cache +2 -0
  128. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/bC/bCGetG10_IPS-4Lea1FrjonfYd1QJf5j7J23dBSgxMI.cache +3 -0
  129. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/bd/bde0sI4pua76cCQiJr5-4YPdoGOq7zUcE5JUFy10wEQ.cache +1 -0
  130. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/c3/c3MkD92XKFFo7SIHfkh3Zf3b7TTV7PPhLy04Ak1iOuY.cache +0 -0
  131. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/cI/cIXdHUyJ1umwlEmauLUx-whf_06eJvzlxEoPVPlG-4s.cache +1 -0
  132. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ck/ckZOTlrjGXnk3bJ7dEgh6ld9VFFg1rV7MGXqEv1Fb9I.cache +3 -0
  133. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/dC/dCxhpA2j6Pi1XDXa12EUmvdpLN_MJ3GPOZBqgg7GcVw.cache +0 -0
  134. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ej/ejwFH71RbcAzfpFyRxO8czavHqoOs9SzC10c-PwS60Y.cache +4 -0
  135. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/fl/flex8byqqPRlAhCuyDZsaMg2gOeDj3NHAIzid-OS2Hg.cache +0 -0
  136. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/gu/guEVVxdrH6uyyJ_m1VYsBVD566zTNeSBDgppqYGy-sk.cache +2 -0
  137. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/hV/hVXlJWvvr6NsDbr1qABWR3CFv36YU7970jmxU_L2NuY.cache +1 -0
  138. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ju/juWsFPPdDAbfJ4X3-dknffITj4HcW0Fu5U9UiaPn4b4.cache +1 -0
  139. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/kG/kG0KlJGmHu0kwLwZDKon08APGF3Z3GpbRt6BuyKJUf4.cache +0 -0
  140. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/kG/kGyYNYLbPlxoTk3K-8slRw-fuDznBFYnl-0y2jK6_cI.cache +0 -0
  141. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/lS/lStvx9Beg2l4s8L-QdTSKuc5_qQPQAZPnIcRI7JkpPE.cache +4 -1
  142. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/m9/m9S3GxTAovnGptmIbSxuSLVFWJCND5v6jetYN2IsHMQ.cache +1 -0
  143. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/mJ/mJ-X19ke9W8_XFBJqqn9Hd4LZNsntZzZjcGZUyStW3s.cache +1 -0
  144. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/n_/n_xYqQYhwEMQknb3jFQnjlxxBE9TzMNHCdJ-bEyZFIw.cache +0 -0
  145. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/nx/nxTv3sKVUQZADJyM3dPaVmUA78MIsMLD_K279yN_GsI.cache +0 -0
  146. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/pM/pM_tvcMleZAXoskYgAVEJ8IPTDCzNUrpHakxVWTZPNQ.cache +2 -0
  147. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/pt/ptleYqvprORReM2iFj-HW9O98Nhoy5qCF4iUWwtyve0.cache +0 -0
  148. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/q6/q6VE6KTZtyGRe8Cuj9izRDMuieCcGKOKzBUH2niWYpc.cache +2 -0
  149. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/q_/q_IgK4QolU1_5AK7pudGtHR2hiob-XkEZIMUgZY_iFM.cache +1 -0
  150. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/qj/qjq5Ug3S2i5pydfGSIfUa7Y0s8s0FwqXzt0kkFijToI.cache +2 -0
  151. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/rd/rd8rR4dvQJUvFyyzVHdNbHilCTfHWlGn6kEU65JL2Fw.cache +1 -0
  152. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/rx/rxqqFB2TXY1MQjq34u1hkkJgqenfyj2ZbYVtb2wEDvc.cache +1 -0
  153. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/sa/sab7V2jcUIn2nRakbXijIbvYmHyOOf6ShENXDRtYP1w.cache +1 -0
  154. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/sr/sr3hnK_P9HaS68zSw0GLhpPzpgEs9shxEe6J7ktfbcw.cache +1 -0
  155. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/u_/u_y6q_eS56FrB6fbIcFt49Tw9exxHbWGGb9puLTTcnk.cache +3 -0
  156. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ub/ubraBOWW9z9uvIXTsIrgJ3kzPboMmsZcyeNsv7sMCnU.cache +1 -0
  157. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/wi/win_v0ZNu-l7AoRx8w3ls1xcy0mUExLBVMCSr5oaJFc.cache +0 -0
  158. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/xH/xHr1kqSt7XnOPWH1LDZY1-0rIpwoT4OM4g68Ts3A9a4.cache +1 -0
  159. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/yM/yMJd-lz8flnlwt-j5DOGjhykEGnynSCv4I2YKpPfr0Y.cache +1 -0
  160. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ys/ysn-zAA7CKGovpmCCejFwdSLV3RlH13Nc4cwac7BwL4.cache +0 -0
  161. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/zT/zTQBjN2k1ltsiVOSJb4mqUhl4FvLQDM6cFRUtQLQ6Qw.cache +1 -0
  162. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/zq/zqVwwFUvXqTxyX57DFJh5CY88HR0PEznhr-rLP6A5BQ.cache +2 -0
  163. data/spec/dummy/tmp/development_secret.txt +1 -0
  164. data/spec/examples.txt +19 -0
  165. data/spec/feature_spec_helper.rb +44 -0
  166. data/spec/features/nulogy_sso/sso_login_spec.rb +112 -0
  167. data/spec/integration/services/nulogy_sso/authenticator_spec.rb +95 -0
  168. data/spec/rails_helper.rb +28 -0
  169. data/spec/spec_helper.rb +43 -0
  170. data/spec/support/mock_auth0_verifier.rb +27 -0
  171. 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
@@ -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