nulogy_sso 0.2.0

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