actions.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. import { Map } from "immutable"
  2. import {
  3. authorizeRequest,
  4. authorizeAccessCodeWithFormParams,
  5. authorizeWithPersistOption,
  6. authorizeOauth2WithPersistOption,
  7. logoutWithPersistOption,
  8. persistAuthorizationIfNeeded
  9. } from "corePlugins/auth/actions"
  10. describe("auth plugin - actions", () => {
  11. describe("authorizeRequest", () => {
  12. [
  13. [
  14. {
  15. oas3: true,
  16. server: "https://host/resource",
  17. effectiveServer: "https://host/resource",
  18. scheme: "http",
  19. host: null,
  20. url: "http://specs/file",
  21. },
  22. "https://host/authorize"
  23. ],
  24. [
  25. {
  26. oas3: true,
  27. server: "https://{selected_host}/resource",
  28. effectiveServer: "https://host/resource",
  29. scheme: "http",
  30. host: null,
  31. url: "http://specs/file",
  32. },
  33. "https://host/authorize"
  34. ],
  35. [
  36. {
  37. oas3: false,
  38. server: null,
  39. effectiveServer: null,
  40. scheme: "https",
  41. host: undefined,
  42. url: "https://specs/file",
  43. },
  44. "https://specs/authorize"
  45. ],
  46. [
  47. {
  48. oas3: false,
  49. server: null,
  50. effectiveServer: null,
  51. scheme: "https",
  52. host: "host",
  53. url: "http://specs/file",
  54. },
  55. "http://specs/authorize"
  56. ],
  57. ].forEach(([{ oas3, server, effectiveServer, scheme, host, url }, expectedFetchUrl]) => {
  58. it("should resolve authorization endpoint against the server URL", () => {
  59. // Given
  60. const data = {
  61. url: "/authorize"
  62. }
  63. const system = {
  64. fn: {
  65. fetch: jest.fn().mockImplementation(() => Promise.resolve())
  66. },
  67. getConfigs: () => ({}),
  68. authSelectors: {
  69. getConfigs: () => ({})
  70. },
  71. errActions: {
  72. newAuthErr: () => ({})
  73. },
  74. oas3Selectors: {
  75. selectedServer: () => server,
  76. serverEffectiveValue: () => effectiveServer || server
  77. },
  78. specSelectors: {
  79. isOAS3: () => oas3,
  80. operationScheme: () => scheme,
  81. host: () => host,
  82. url: () => url
  83. }
  84. }
  85. // When
  86. authorizeRequest(data)(system)
  87. // Then
  88. expect(system.fn.fetch.mock.calls.length).toEqual(1)
  89. expect(system.fn.fetch.mock.calls[0][0]).toEqual(expect.objectContaining({ url: expectedFetchUrl }))
  90. })
  91. })
  92. it("should add additionalQueryStringParams to Swagger 2.0 authorization and token URLs", () => {
  93. // Given
  94. const data = {
  95. url: "/authorize?q=1"
  96. }
  97. const system = {
  98. fn: {
  99. fetch: jest.fn().mockImplementation(() => Promise.resolve())
  100. },
  101. getConfigs: () => ({}),
  102. authSelectors: {
  103. getConfigs: () => ({
  104. additionalQueryStringParams: {
  105. myCustomParam: "abc123"
  106. }
  107. })
  108. },
  109. errActions: {
  110. newAuthErr: () => ({})
  111. },
  112. specSelectors: {
  113. isOAS3: () => false,
  114. operationScheme: () => "https",
  115. host: () => "http://google.com",
  116. url: () => "http://google.com/swagger.json"
  117. }
  118. }
  119. // When
  120. authorizeRequest(data)(system)
  121. // Then
  122. expect(system.fn.fetch.mock.calls.length).toEqual(1)
  123. expect(system.fn.fetch.mock.calls[0][0].url)
  124. .toEqual("http://google.com/authorize?q=1&myCustomParam=abc123")
  125. })
  126. it("should add additionalQueryStringParams to OpenAPI 3.0 authorization and token URLs", () => {
  127. // Given
  128. const data = {
  129. url: "/authorize?q=1"
  130. }
  131. const system = {
  132. fn: {
  133. fetch: jest.fn().mockImplementation(() => Promise.resolve())
  134. },
  135. errActions: {
  136. newAuthErr: () => ({})
  137. },
  138. getConfigs: () => ({}),
  139. authSelectors: {
  140. getConfigs: () => ({
  141. additionalQueryStringParams: {
  142. myCustomParam: "abc123"
  143. }
  144. })
  145. },
  146. oas3Selectors: {
  147. selectedServer: () => "http://google.com",
  148. serverEffectiveValue: () => "http://google.com"
  149. },
  150. specSelectors: {
  151. isOAS3: () => true,
  152. }
  153. }
  154. // When
  155. authorizeRequest(data)(system)
  156. // Then
  157. expect(system.fn.fetch.mock.calls.length).toEqual(1)
  158. expect(system.fn.fetch.mock.calls[0][0].url)
  159. .toEqual("http://google.com/authorize?q=1&myCustomParam=abc123")
  160. })
  161. })
  162. describe("tokenRequest", function () {
  163. it("should send the code verifier when set", () => {
  164. const data = {
  165. auth: {
  166. schema: {
  167. get: () => "http://tokenUrl"
  168. },
  169. codeVerifier: "mock_code_verifier"
  170. },
  171. redirectUrl: "http://google.com"
  172. }
  173. const authActions = {
  174. authorizeRequest: jest.fn()
  175. }
  176. authorizeAccessCodeWithFormParams(data)({ authActions })
  177. expect(authActions.authorizeRequest.mock.calls.length).toEqual(1)
  178. const actualArgument = authActions.authorizeRequest.mock.calls[0][0]
  179. expect(actualArgument.body).toContain("code_verifier=" + data.auth.codeVerifier)
  180. expect(actualArgument.body).toContain("grant_type=authorization_code")
  181. })
  182. })
  183. describe("persistAuthorization", () => {
  184. describe("wrapped functions with persist option", () => {
  185. it("should wrap `authorize` action and persist data if needed", () => {
  186. // Given
  187. const data = {
  188. "api_key": {}
  189. }
  190. const system = {
  191. getConfigs: () => ({}),
  192. authActions: {
  193. authorize: jest.fn(() => { }),
  194. persistAuthorizationIfNeeded: jest.fn(() => { })
  195. }
  196. }
  197. // When
  198. authorizeWithPersistOption(data)(system)
  199. // Then
  200. expect(system.authActions.authorize).toHaveBeenCalled()
  201. expect(system.authActions.authorize).toHaveBeenCalledWith(data)
  202. expect(system.authActions.persistAuthorizationIfNeeded).toHaveBeenCalled()
  203. })
  204. it("should wrap `oauth2Authorize` action and persist data if needed", () => {
  205. // Given
  206. const data = {
  207. "api_key": {}
  208. }
  209. const system = {
  210. getConfigs: () => ({}),
  211. authActions: {
  212. authorizeOauth2: jest.fn(() => { }),
  213. persistAuthorizationIfNeeded: jest.fn(() => { })
  214. }
  215. }
  216. // When
  217. authorizeOauth2WithPersistOption(data)(system)
  218. // Then
  219. expect(system.authActions.authorizeOauth2).toHaveBeenCalled()
  220. expect(system.authActions.authorizeOauth2).toHaveBeenCalledWith(data)
  221. expect(system.authActions.persistAuthorizationIfNeeded).toHaveBeenCalled()
  222. })
  223. it("should wrap `logout` action and persist data if needed", () => {
  224. // Given
  225. const data = {
  226. "api_key": {}
  227. }
  228. const system = {
  229. getConfigs: () => ({}),
  230. authActions: {
  231. logout: jest.fn(() => { }),
  232. persistAuthorizationIfNeeded: jest.fn(() => { })
  233. }
  234. }
  235. // When
  236. logoutWithPersistOption(data)(system)
  237. // Then
  238. expect(system.authActions.logout).toHaveBeenCalled()
  239. expect(system.authActions.logout).toHaveBeenCalledWith(data)
  240. expect(system.authActions.persistAuthorizationIfNeeded).toHaveBeenCalled()
  241. })
  242. })
  243. describe("persistAuthorizationIfNeeded", () => {
  244. beforeEach(() => {
  245. localStorage.clear()
  246. })
  247. it("should skip if `persistAuthorization` is turned off", () => {
  248. // Given
  249. const system = {
  250. getConfigs: () => ({
  251. persistAuthorization: false
  252. }),
  253. authSelectors: {
  254. authorized: jest.fn(() => { })
  255. }
  256. }
  257. // When
  258. persistAuthorizationIfNeeded()(system)
  259. // Then
  260. expect(system.authSelectors.authorized).not.toHaveBeenCalled()
  261. })
  262. it("should persist authorization data to localStorage", () => {
  263. // Given
  264. const data = {
  265. "api_key": {}
  266. }
  267. const system = {
  268. getConfigs: () => ({
  269. persistAuthorization: true
  270. }),
  271. errActions: {
  272. newAuthErr: () => ({})
  273. },
  274. authSelectors: {
  275. authorized: jest.fn(() => Map(data))
  276. }
  277. }
  278. jest.spyOn(Object.getPrototypeOf(window.localStorage), "setItem")
  279. // When
  280. persistAuthorizationIfNeeded()(system)
  281. expect(localStorage.setItem).toHaveBeenCalled()
  282. expect(localStorage.setItem).toHaveBeenCalledWith("authorized", JSON.stringify(data))
  283. })
  284. })
  285. })
  286. })