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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4758a2972294221b9dc3fc1bcc3e6cc6bd6b08fb62649c42473947733eac8a26
4
+ data.tar.gz: 3c367990340d32e800658cb5893e50b239e72b7e647b5e14e7d48eddf58ed50c
5
+ SHA512:
6
+ metadata.gz: d78af9ca9ae3db0346c647841a132fbcc49b07849934e84b205fa6742d1f7baffe8ae49c842715a9d327291577adcdd1eb3b8f835544798d27f685e6ce1f0fc0
7
+ data.tar.gz: '0927826539422b8428f4d5c2956b40dbc291d7e558dbe009579cb32468418bfaa24239228550c4d40aefd9b298edf5ac97a78c46d288d7d034849619e393bbe4'
data/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # NulogySSO
2
+
3
+ **This repo is still under heavy initial development and is not ready to be used by any other product besides CPI. This status will be changed very shortly.**
4
+
5
+ ## Installation
6
+
7
+ This gem is a Rails Engine. It follows best practices [documented here](https://guides.rubyonrails.org/engines.html).
8
+
9
+ To begin with, add the gem to your Gemfile:
10
+
11
+ ```ruby
12
+ gem "nulogy_sso"
13
+ ```
14
+
15
+ Install the gem:
16
+
17
+ ```sh
18
+ bundle
19
+ ```
20
+
21
+ Routes can now be mounted into your application in `routes.rb` and served up at a specific URI prefix:
22
+
23
+ ```ruby
24
+ mount NulogySSO::Engine, at: "/sso"
25
+
26
+ # Optional redirects
27
+ get "login", to: redirect("sso/login")
28
+ get "logout", to: redirect("sso/logout")
29
+ ```
30
+
31
+ The engine now needs to be configured. First create a YAML config file, perhaps named `config/auth_sso.yml`, to configure your app's Auth0 settings. This assumes that the necessary Auth0 applications have been created in the correct Auth0 tenants. The [CPI auth_sso.yml file](https://github.com/nulogy/Common-Platform-Interface/blob/master/config/auth_sso.yml) is a good starting place.
32
+
33
+ With that available, you can configure the engine with an initializer file. This is where _NulogySSO_ can be customized according to your application's needs. Put this code into `config/initializers/nulogy_sso.rb`, with the appropriate modifications implemented:
34
+
35
+ ```ruby
36
+ # Compiles config/auth_sso.yml into a Ruby object
37
+ NulogySSO.auth_config = Rails::Application.config_for(:auth_sso)
38
+ # Return the user matching the provided email
39
+ NulogySSO.find_user_by_email = ->(email) { nil }
40
+ # Return a boolean to indicate if the Auth0 user is valid for this app, or true if this step is not necessary
41
+ NulogySSO.validate_user = ->(user) { true }
42
+ ```
43
+
44
+ The app is now ready to authenticate a user with Auth0! With NulogyAuth and Auth0, the user's identity is maintained across requests (and apps!) via a [JWT](https://auth0.com/docs/jwt) stored as a browser cookie. Add this code to the `ApplicationController`:
45
+
46
+ ```ruby
47
+ class ApplicationController < ActionController::Base
48
+ include NulogySSO::ControllerHelper
49
+ before_action :authenticate_sso_user
50
+ # ...
51
+ end
52
+ ```
53
+
54
+ As an added bonus, NulogySSO also emulates the common Devise pattern of making the current User's user model object available via `current_user`. This is made available through inclusion of `ControllerHelper`.
55
+
56
+ ## Development
57
+
58
+ ### Setup
59
+
60
+ ```sh
61
+ # Setup Ruby
62
+ rvm install $(cat .ruby-version)
63
+ bundle
64
+
65
+ # Setup project files
66
+ cp .env.sample .env
67
+ rake app:db:test:prepare
68
+
69
+ # Launch Docker containers, required for testing
70
+ docker-compose up -d
71
+ ```
72
+
73
+ ### Testing
74
+
75
+ There are multiple helpers made available via the `NulogyAuth::TestUtilities` module. These are helpful for doing things such as grabbing test JWT values and interacting with a [Mockserver](https://github.com/jamesdbloom/mockserver) mock of the Auth0 API.
76
+
77
+ It is a common use case for a Rails app to switch from Devise-powered authentication to Auth0. Here's a pattern that could be applied around a feature flag (e.g. environment variable) to switch between Devise user authentication test helpers and NulogyAuth test helpers: _(TODO: insert link to CPI `ControllerIntegrationSpecMacros`)_
78
+
79
+ ### Contributing
80
+
81
+ Feel free to create a PR if you wish to add new functionality to this Engine or detect a bug. A developer on CN1 will review and merge.
82
+
83
+ This project follows [Semver Versioning](https://semver.org/). Please add an entry into [CHANGELOG.md](./CHANGELOG.md) in your PR. Deployments are done manually on an as-needed basis.
84
+
85
+ ## Roadmap
86
+
87
+ * Parameterize app name for error page
88
+ * Buildkite pipeline
89
+ * Rubocop
90
+ * Rake install task (ie, generate required files automatically, instead of requiring a heavy amount of manual work to integrate nulogy_sso into a Rails app)
data/Rakefile ADDED
@@ -0,0 +1,22 @@
1
+ begin
2
+ require "bundler/setup"
3
+ rescue LoadError
4
+ puts "You must `gem install bundler` and `bundle install` to run rake tasks"
5
+ end
6
+
7
+ require "rdoc/task"
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = "rdoc"
11
+ rdoc.title = "NulogySSO"
12
+ rdoc.options << "--line-numbers"
13
+ rdoc.rdoc_files.include("README.md")
14
+ rdoc.rdoc_files.include("lib/**/*.rb")
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
18
+ load "rails/tasks/engine.rake"
19
+
20
+ load "rails/tasks/statistics.rake"
21
+
22
+ require "bundler/gem_tasks"
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Do not edit directly
3
+ * Generated on Fri, 21 Jun 2019 19:45:11 GMT
4
+ */
5
+ /* -----------------------------------------
6
+ ## Default styles
7
+ ----------------------------------------- */
8
+ html,
9
+ body {
10
+ margin: 0;
11
+ }
12
+
13
+ * {
14
+ box-sizing: border-box;
15
+ }
16
+
17
+ body {
18
+ color: #011e38;
19
+ font-family: "IBM Plex Sans", sans-serif;
20
+ line-height: 1.5;
21
+ }
22
+
23
+ code {
24
+ font-family: "IBM Plex Mono", monospace;
25
+ }
26
+
27
+ img {
28
+ max-width: 100%;
29
+ height: auto;
30
+ display: block;
31
+ }
32
+
33
+ /* -----------------------------------------
34
+ ## Alerts
35
+ ----------------------------------------- */
36
+ .Alert {
37
+ border-radius: 4px;
38
+ border-left: 4px solid #216beb;
39
+ padding: 16px;
40
+ background: #e1ebfa;
41
+ display: flex;
42
+ max-width: 432px;
43
+ }
44
+ .Alert__icon {
45
+ fill: #216beb;
46
+ }
47
+ .Alert a {
48
+ color: #011e38;
49
+ }
50
+
51
+ .Alert__title {
52
+ margin: 0;
53
+ font-weight: 600;
54
+ }
55
+
56
+ .Alert__message {
57
+ margin-top: 0;
58
+ }
59
+ .Alert__message:last-child {
60
+ margin-bottom: 0;
61
+ }
62
+
63
+ .Alert--danger__icon,
64
+ .Alert--success__icon {
65
+ margin-right: 8px;
66
+ }
67
+
68
+ .Alert--danger {
69
+ border-radius: 4px;
70
+ border-left: 4px solid #cc1439;
71
+ padding: 16px;
72
+ background: #fae6ea;
73
+ }
74
+ .Alert--danger__icon {
75
+ fill: #cc1439;
76
+ }
77
+ .Alert--danger a {
78
+ color: #011e38;
79
+ }
80
+
81
+ .Alert--success {
82
+ border-radius: 4px;
83
+ border-left: 4px solid #008059;
84
+ padding: 16px;
85
+ background: #e9f7f2;
86
+ }
87
+ .Alert--success__icon {
88
+ fill: #008059;
89
+ }
90
+ .Alert--success a {
91
+ color: #011e38;
92
+ }
93
+
94
+ .Alert--warning {
95
+ border-radius: 4px;
96
+ border-left: 4px solid #ffbb00;
97
+ padding: 16px;
98
+ background: #fcf5e3;
99
+ }
100
+ .Alert--warning__icon {
101
+ fill: #ffbb00;
102
+ }
103
+ .Alert--warning a {
104
+ color: #011e38;
105
+ }
106
+
107
+ /* -----------------------------------------
108
+ ## Link
109
+ ----------------------------------------- */
110
+ .Link {
111
+ color: #216beb;
112
+ }
113
+ .Link:hover {
114
+ cursor: pointer;
115
+ color: #1254c7;
116
+ }
117
+ .Link:focus {
118
+ outline: none;
119
+ box-shadow: 0px 0px 5px 0px rgba(33, 107, 235, 0.9);
120
+ }
121
+
122
+ /* -----------------------------------------
123
+ ## Error page
124
+ ----------------------------------------- */
125
+ .ErrorPage {
126
+ height: 100vh;
127
+ display: flex;
128
+ flex-direction: column;
129
+ padding: 16px;
130
+ padding-top: 24px;
131
+ }
132
+
133
+ .ErrorPage__body {
134
+ display: flex;
135
+ flex-direction: column;
136
+ flex-grow: 1;
137
+ }
138
+
139
+ .ErrorPage__container {
140
+ max-width: 432px;
141
+ margin: 0 auto;
142
+ }
143
+
144
+ .ErrorPage__header {
145
+ text-align: center;
146
+ margin-top: 16px;
147
+ margin-bottom: 40px;
148
+ }
149
+
150
+ .ErrorPage__logout {
151
+ margin-right: auto;
152
+ margin-left: auto;
153
+ margin-top: 30px;
154
+ }
155
+ @media screen and (min-width: 768px) {
156
+ .ErrorPage__header {
157
+ margin-top: 80px;
158
+ }
159
+ }
160
+ @media screen and (min-width: 1360px) {
161
+ .ErrorPage__header {
162
+ margin: 0;
163
+ }
164
+ }
165
+
166
+ .ErrorPage__logo {
167
+ display: block;
168
+ margin: 0 auto;
169
+ }
170
+ @media screen and (min-width: 1360px) {
171
+ .ErrorPage__logo--with-homepage-link {
172
+ margin-top: -32px;
173
+ }
174
+ }
175
+
176
+ .ErrorPage__main {
177
+ max-width: 432px;
178
+ margin: 0 auto;
179
+ text-align: center;
180
+ }
181
+ @media screen and (min-width: 1360px) {
182
+ .ErrorPage__main {
183
+ text-align: left;
184
+ }
185
+ }
186
+ .ErrorPage__main .Alert {
187
+ text-align: left;
188
+ }
189
+
190
+ .ErrorPage__footer {
191
+ border-top: 1px solid #e4e7eb;
192
+ padding-top: 16px;
193
+ text-align: center;
194
+ font-size: 14px;
195
+ color: #434d59;
196
+ }
197
+
198
+ .Link--ErrorPage {
199
+ color: #00438f;
200
+ display: inline-block;
201
+ margin-top: 16px;
202
+ }
203
+
204
+ @media screen and (min-width: 1360px) {
205
+ .ErrorPage__body {
206
+ justify-content: center;
207
+ }
208
+ .ErrorPage__contents {
209
+ display: flex;
210
+ width: 672px;
211
+ margin: 0 auto;
212
+ align-items: center;
213
+ }
214
+ }
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "auth0"
4
+
5
+ module NulogySSO
6
+ class AuthController < ActionController::Base
7
+ include Auth0::Api::AuthenticationEndpoints
8
+ include Auth0::Mixins::HTTPProxy
9
+
10
+ def initialize
11
+ # These instance variables have to be set in order for the HTTPProxy mixin to work.
12
+ @base_uri = auth_config.base_uri
13
+ @headers = { content_type: "application/json" }
14
+ end
15
+
16
+ def login
17
+ raw_access_token = cookies[NulogySSO.auth_cookie_key]
18
+
19
+ authenticator.validate_token(
20
+ raw_access_token,
21
+ on_success: method(:on_authentication_success),
22
+ on_invalid_token: -> { redirect_to auth_path }
23
+ )
24
+ end
25
+
26
+ def code
27
+ code = params.require(:code)
28
+ begin
29
+ raw_access_token = token_response(code)["access_token"]
30
+ rescue Auth0::Exception => e
31
+ return sso_error
32
+ end
33
+
34
+ authenticator.validate_token(
35
+ raw_access_token,
36
+ on_success: method(:on_authentication_success),
37
+ on_invalid_token: -> { sso_error }
38
+ )
39
+ end
40
+
41
+ def logout
42
+ cookies.delete(NulogySSO.auth_cookie_key, domain: :all)
43
+
44
+ query_params = {
45
+ returnTo: auth_config.redirect_uri, # Yes, this must be camelCased
46
+ client_id: auth_config.client_id
47
+ }
48
+ redirect_to "#{auth_config.base_uri}/v2/logout?#{query_params.to_query}"
49
+ end
50
+
51
+ private
52
+
53
+ delegate :auth_config, to: :NulogySSO
54
+
55
+ def sso_error
56
+ render status: :forbidden, template: "sso_error"
57
+ end
58
+
59
+ def authenticator
60
+ @authenticator ||= Authenticator.new
61
+ end
62
+
63
+ def on_authentication_success(access_token)
64
+ respond_with_cookies(access_token)
65
+
66
+ redirect_to params["origin"].presence || auth_config.redirect_uri
67
+ end
68
+
69
+ def token_response(code)
70
+ exchange_auth_code_for_tokens(
71
+ code,
72
+ redirect_uri: auth_config.login_uri,
73
+ client_id: auth_config.client_id,
74
+ client_secret: auth_config.client_secret
75
+ )
76
+ end
77
+
78
+ def respond_with_cookies(access_token_value)
79
+ cookies[NulogySSO.auth_cookie_key] = {
80
+ value: access_token_value,
81
+ domain: :all,
82
+ expires: 36_000.seconds, # TODO: Fetch this value from the JWT
83
+ httponly: true,
84
+ secure: request.ssl?
85
+ }
86
+ end
87
+
88
+ def auth_path
89
+ query_params = {
90
+ audience: auth_config.audience,
91
+ client_id: auth_config.client_id,
92
+ response_type: "code",
93
+ scope: "openid email",
94
+ redirect_uri: "#{auth_config.login_uri}?origin=#{session[:previous_request_url]}"
95
+ }
96
+
97
+ "#{auth_config.base_uri}/authorize?#{query_params.to_query}"
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "auth0_rs256_jwt_verifier"
4
+
5
+ module NulogySSO
6
+ class Authenticator
7
+ ACCESS_TOKEN_VERIFIER = Auth0RS256JWTVerifier.new(
8
+ issuer: "#{NulogySSO.auth_config.base_uri}/", # Auth0 requires a backslash on the Issuer
9
+ audience: NulogySSO.auth_config.audience,
10
+ jwks_url: "#{NulogySSO.auth_config.base_uri}/.well-known/jwks.json"
11
+ )
12
+
13
+ def initialize(
14
+ verifier: ACCESS_TOKEN_VERIFIER,
15
+ find_user_by_email: NulogySSO.find_user_by_email,
16
+ validate_user: NulogySSO.validate_user
17
+ )
18
+ @verifier = verifier
19
+ @find_user_by_email = find_user_by_email
20
+ @validate_user = validate_user
21
+ end
22
+
23
+ # Authorizes the provided JWT, ensuring that a valid user can be associated to the token
24
+ def validate_token(raw_access_token, on_success:, on_invalid_token:)
25
+ access_token = decoded_validated_access_token(raw_access_token)
26
+
27
+ return on_invalid_token.call if access_token.nil?
28
+
29
+ user = fetch_user(access_token)
30
+ return on_invalid_token.call if user.blank? || !validate_user.call(user)
31
+
32
+ on_success.call(access_token)
33
+ end
34
+
35
+ # Returns the authenticated user that matches the provided JWT, or nil if the user cannot be authenticated
36
+ def authenticated_user(raw_access_token)
37
+ access_token = decoded_validated_access_token(raw_access_token)
38
+
39
+ return nil if access_token.nil?
40
+
41
+ fetch_user(access_token)
42
+ end
43
+
44
+ private
45
+
46
+ attr_reader :verifier, :find_user_by_email, :validate_user
47
+
48
+ def decoded_validated_access_token(raw_access_token)
49
+ if raw_access_token.present? && verifier.verify(raw_access_token).valid?
50
+ return JSON::JWT.decode(raw_access_token, :skip_verification)
51
+ end
52
+
53
+ nil
54
+ end
55
+
56
+ def fetch_user(access_token)
57
+ email = access_token.fetch(NulogySSO::JWT_EMAIL_KEY)
58
+ find_user_by_email.call(email)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,45 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
7
+ <title>Error</title>
8
+ <%= favicon_link_tag "nulogy_sso/favicon.png" %>
9
+ <%= stylesheet_link_tag "nulogy_sso/sso_error" %>
10
+ <link href="https://fonts.googleapis.com/css?family=IBM+Plex+Sans:300,400,500,600&display=swap" rel="stylesheet">
11
+ </head>
12
+
13
+ <body>
14
+ <div class="ErrorPage">
15
+ <div class="ErrorPage__body">
16
+ <div class="ErrorPage__contents">
17
+ <header class="ErrorPage__header">
18
+ <svg class="ErrorPage__logo" height="48px" width="200px" viewBox="0 0 133 32"><path fill="#F0B41C" d="M30.6967273,1.13648485 L36.3810909,3.40945455 L36.3810909,23.8758788 C36.3810909,28.2705455 30.9507879,29.0424242 27.2853333,29.5602424 C29.3818182,29.0424242 30.7083636,28.4606061 30.6967273,23.8758788 L30.6967273,5.68436364 L25.0123636,3.40945455 L30.6967273,1.13648485 Z M6.82084848,28.4237576 L6.82084848,15.9204848 C6.82084848,14.6618182 7.76533333,13.238303 8.91151515,12.7476364 L14.7801212,10.2264242 L14.7801212,18.1779394 L20.4644848,21.6048485 C21.6106667,22.1866667 23.8758788,22.2002424 23.8758788,20.4664242 L23.8758788,17.0550303 L21.5990303,15.9166061 L21.5990303,1.56319402e-13 L4.26666667,6.38642424 C1.91030303,7.25333333 3.55271368e-15,9.98593939 3.55271368e-15,12.5071515 L3.55271368e-15,31.2669091 L6.82084848,28.4237576 Z"></path><g transform="translate(43.000000, 0.000000)" fill="#1C68A5"><path d="M5.14521212,24.2224981 L1.33226763e-14,24.2224981 L1.33226763e-14,9.41134654 L4.75151515,9.41134654 L4.75151515,11.8937708 C5.43733518,11.0060378 6.29475204,10.2653615 7.27272727,9.71583139 C8.16188898,9.23817548 9.15699751,8.9920662 10.166303,9.00019502 C11.7333333,9.00019502 12.9221818,9.44948795 13.7328485,10.3480738 C14.5435152,11.2466597 14.9488485,12.5615688 14.9488485,14.2928011 L14.9488485,24.2224981 L9.83078788,24.2224981 L9.83078788,15.7376496 C9.83078788,14.961892 9.67175758,14.3755486 9.35369697,13.9786193 C9.03563636,13.58169 8.56436364,13.3877506 7.93987879,13.3968011 C7.04258586,13.3968011 6.35216162,13.6980536 5.86860606,14.3005587 C5.38505051,14.9030637 5.14391919,15.7803162 5.14521212,16.9323162 L5.14521212,24.2224981 Z"></path><path d="M27.8366061,9 L32.9507879,9 L32.9507879,22.6203636 L28.1992727,24.5190303 L28.1992727,21.6254545 C27.5124636,22.5143219 26.6553593,23.2573653 25.6780606,23.8111515 C24.7938668,24.2845189 23.8048332,24.5279425 22.8019394,24.5190303 C21.2323232,24.5190303 20.0402424,24.0665051 19.225697,23.1614545 C18.4111515,22.256404 18.0025859,20.9408485 18,19.2147879 L18,9 L23.1452121,9 L23.1452121,17.7796364 C23.1452121,18.5553939 23.3042424,19.1443232 23.622303,19.5464242 C23.9403636,19.9485253 24.4116364,20.1482828 25.0361212,20.145697 C25.9411717,20.145697 26.631596,19.8418586 27.1073939,19.2341818 C27.5831919,18.6265051 27.8243232,17.7524848 27.8307879,16.6121212 L27.8366061,9 Z"></path><polygon id="Path" points="38.7151515 24.5546667 36 24.5546667 36 1.088 38.7151515 1.15463195e-13"></polygon><path d="M41,17.0717576 C41,14.7263838 41.7453737,12.7947475 43.2361212,11.2768485 C44.7268687,9.75894949 46.6171313,9 48.9069091,9 C51.1966869,9 53.0869495,9.75894949 54.577697,11.2768485 C56.0684444,12.7947475 56.8138182,14.7263838 56.8138182,17.0717576 C56.8138182,19.4274747 56.0684444,21.3668687 54.577697,22.8899394 C53.0869495,24.4130101 51.1966869,25.1719596 48.9069091,25.1667879 C46.6261818,25.1667879 44.7385051,24.4078384 43.2438788,22.8899394 C41.7492525,21.3720404 41.0012929,19.4326465 41,17.0717576 Z M43.6957576,17.0717576 C43.6957576,18.9141818 44.172202,20.3965253 45.1250909,21.5187879 C46.0779798,22.6410505 47.327596,23.2028283 48.8739394,23.2041212 C50.4254545,23.2041212 51.6802424,22.6423434 52.638303,21.5187879 C53.5963636,20.3952323 54.0786263,18.9128889 54.0850909,17.0717576 C54.0850909,15.2422626 53.6028283,13.7657374 52.638303,12.6421818 C51.6737778,11.5186263 50.4189899,10.9574949 48.8739394,10.9587879 C47.3224242,10.9587879 46.0728081,11.5205657 45.1250909,12.6441212 C44.1773737,13.7676768 43.7009293,15.2435556 43.6957576,17.0717576 Z"></path><path d="M70.0824261,23.582303 C69.3285884,24.0285568 68.5220417,24.3790594 67.6814564,24.625697 C66.9065592,24.8487063 66.1042899,24.9622904 65.2979413,24.9631515 C63.1180625,24.9631515 61.3564463,24.2397576 60.0130928,22.7929697 C58.6697392,21.3461818 57.9987089,19.4449293 58.0000019,17.0892121 C58.0000019,14.6882424 58.7175776,12.739798 60.1527291,11.2438788 C61.5878807,9.7479596 63.4626281,9 65.7769716,9 C66.5067857,9.0106757 67.2345208,9.08072506 67.9529716,9.20945455 C68.7804463,9.34650505 69.737214,9.55725253 70.8232746,9.84169697 L72.745214,9.06593939 L72.745214,22.4283636 C72.745214,24.213899 72.6605271,25.520404 72.4911534,26.3478788 C72.3424597,27.1215145 72.0497022,27.860316 71.6281231,28.5258182 C70.9908577,29.4891385 70.0844202,30.2438287 69.0215776,30.696 C67.7834618,31.2231176 66.4474127,31.48094 65.1020625,31.4523636 C64.1335045,31.4523045 63.1689244,31.3284732 62.2317594,31.0838788 C61.252533,30.8239772 60.3068642,30.4510466 59.41382,29.9726061 L58.9696988,26.7512727 L60.9575776,28.0506667 C61.5573127,28.4240193 62.2116549,28.7014604 62.8969716,28.8729697 C63.6457641,29.0836796 64.4192481,29.1938978 65.1970928,29.2007273 C66.7486079,29.2007273 67.9516786,28.8128485 68.8063049,28.0370909 C69.6609312,27.2613333 70.0863049,26.1571717 70.0824261,24.7246061 L70.0824261,23.582303 Z M70.0824261,21.5595152 L70.0824261,12.0739394 C69.4432737,11.7542576 68.7741844,11.4983147 68.0848503,11.3098182 C67.4816476,11.1457578 66.859767,11.0603633 66.2346685,11.0557576 C64.581012,11.0557576 63.2499413,11.6117172 62.2414564,12.7236364 C61.2329716,13.8355556 60.7280827,15.3146667 60.7267897,17.1609697 C60.7267897,18.9348687 61.179315,20.3428687 62.0843655,21.3849697 C62.989416,22.4270707 64.2086483,22.9474747 65.7420625,22.9461818 C66.3845516,22.9385817 67.0221469,22.8332967 67.6329716,22.6339394 C68.4792669,22.3480186 69.2988853,21.9885027 70.0824261,21.5595152 L70.0824261,21.5595152 Z"></path><path d="M75,9 L77.8276364,9 L82.2649697,20.6363636 L87.1483636,9 L89.4504242,9 L82.3813333,25.3238788 L82.2649697,25.5546667 C81.1478788,28.0965657 80.2874343,29.9066667 79.6836364,30.9849697 L76.7415758,30.9849697 C77.3683498,30.3346009 77.9302011,29.6246546 78.4191515,28.8652121 C79.0313917,27.8817808 79.5750659,26.8572886 80.046303,25.7990303 L81.0004848,23.7452121 L75,9 Z"></path></g></svg>
19
+ </header>
20
+ <main class="ErrorPage__main">
21
+ <div class="Alert Alert--danger">
22
+ <div class="Alert--danger__icon">
23
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M11 15h2v2h-2zm0-8h2v6h-2zm.99-5C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/></svg>
24
+ </div>
25
+ <div class="Alert__content">
26
+ <p class="Alert__title">Not authorized.</p>
27
+ <%
28
+ # TODO: Parameterize the below message to be app specific, via NulogySSO engine config.
29
+ %>
30
+ <p class="Alert__message">You do not have permission to access Nulogy.</p>
31
+ </div>
32
+ </div>
33
+
34
+ </main>
35
+ </div>
36
+ <div class="ErrorPage__logout" >
37
+ <%= link_to("Logout", nulogy_sso.logout_path, class: "Link") %>
38
+ </div>
39
+ </div>
40
+ <footer class="ErrorPage__footer">
41
+ © 2007-<%= Date.today.year %> Nulogy Corporation
42
+ </footer>
43
+ </div>
44
+ </body>
45
+ </html>
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Inflections are used so that "SSO" can be used in the NulogySSO module name
4
+ # with this exact casing and still allow rails to evaluate directory paths as nulogy_sso
5
+ ActiveSupport::Inflector.inflections(:en) do |inflect|
6
+ inflect.acronym "SSO"
7
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,5 @@
1
+ NulogySSO::Engine.routes.draw do
2
+ get "login", to: "auth#login"
3
+ get "logout", to: "auth#logout"
4
+ get "code", to: "auth#code"
5
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NulogySSO
4
+
5
+ # A mix-in that is intended to enhance a controller with NulogySSO authentication code.
6
+ # It is recommended to `include NulogySSO::ControllerHelper` in your ApplicationController.
7
+ module ControllerHelper
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ # Makes the commonly used @current_user variable available to controllers and views.
12
+ # This emulates a code pattern popular in Rails apps using Devise.
13
+ attr_reader :current_user
14
+ helper_method :current_user
15
+ end
16
+
17
+ def authenticate_sso_user
18
+ raw_token = cookies[NulogySSO.auth_cookie_key]
19
+ return redirect_to nulogy_sso.login_path if raw_token.blank?
20
+
21
+ @current_user = Authenticator.new.authenticated_user(raw_token)
22
+ return redirect_to nulogy_sso.login_path if @current_user.blank?
23
+ return render status: :forbidden, template: "sso_error" unless valid_user?(@current_user)
24
+ end
25
+
26
+ private
27
+
28
+ def valid_user?(user)
29
+ NulogySSO.validate_user.call(user)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,29 @@
1
+ module NulogySSO
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace NulogySSO
4
+
5
+ # Load all gems in the gemspec, as opposed to explicit require calls
6
+ Bundler.require(*Rails.groups)
7
+
8
+ config.autoload_paths << File.expand_path("lib/nulogy_sso/controller_helper", __dir__)
9
+
10
+ # Instruct apps using Sprockets to include assets from NulogySSO
11
+ initializer "nulogy_sso.assets.precompile" do |app|
12
+ app.config.assets.precompile += ["nulogy_sso/sso_error.css", "nulogy_sso/favicon.png"]
13
+ end
14
+
15
+ config.after_initialize do
16
+ if NulogySSO.auth_config.blank?
17
+ raise "Missing auth_config config object. Consider using config_for() to load a YAML config file."
18
+ end
19
+
20
+ if NulogySSO.find_user_by_email.blank?
21
+ raise "Missing find_user_by_email config lambda."
22
+ end
23
+
24
+ if NulogySSO.validate_user.blank?
25
+ raise "Missing validate_user config lambda."
26
+ end
27
+ end
28
+ end
29
+ end