Skip to content

Commit 8f63462

Browse files
fkowaltim-lai
andauthoredMar 10, 2022
feat(oauth2): authActions.authPopup plugin accessible wrapper (#7699)
* enables win.open to be extensible by plugins Co-authored-by: Tim Lai <timothy.lai@gmail.com>
1 parent a5aca55 commit 8f63462

File tree

4 files changed

+65
-50
lines changed

4 files changed

+65
-50
lines changed
 

‎src/core/oauth2-authorize.js

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import parseUrl from "url-parse"
2-
import win from "core/window"
32
import Im from "immutable"
43
import { btoa, sanitizeUrl, generateCodeVerifier, createCodeChallenge } from "core/utils"
54

@@ -123,13 +122,11 @@ export default function authorize ( { auth, authActions, errActions, configs, au
123122
callback = authActions.authorizeAccessCodeWithFormParams
124123
}
125124

126-
win.swaggerUIRedirectOauth2 = {
125+
authActions.authPopup(url, {
127126
auth: auth,
128127
state: state,
129128
redirectUrl: redirectUrl,
130129
callback: callback,
131130
errCb: errActions.newAuthErr
132-
}
133-
134-
win.open(url)
131+
})
135132
}

‎src/core/plugins/auth/actions.js

+9-3
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export function authorize(payload) {
2929

3030
export const authorizeWithPersistOption = (payload) => ( { authActions } ) => {
3131
authActions.authorize(payload)
32-
authActions.persistAuthorizationIfNeeded()
32+
authActions.persistAuthorizationIfNeeded()
3333
}
3434

3535
export function logout(payload) {
@@ -41,7 +41,7 @@ export function logout(payload) {
4141

4242
export const logoutWithPersistOption = (payload) => ( { authActions } ) => {
4343
authActions.logout(payload)
44-
authActions.persistAuthorizationIfNeeded()
44+
authActions.persistAuthorizationIfNeeded()
4545
}
4646

4747
export const preAuthorizeImplicit = (payload) => ( { authActions, errActions } ) => {
@@ -85,7 +85,7 @@ export function authorizeOauth2(payload) {
8585

8686
export const authorizeOauth2WithPersistOption = (payload) => ( { authActions } ) => {
8787
authActions.authorizeOauth2(payload)
88-
authActions.persistAuthorizationIfNeeded()
88+
authActions.persistAuthorizationIfNeeded()
8989
}
9090

9191
export const authorizePassword = ( auth ) => ( { authActions } ) => {
@@ -279,3 +279,9 @@ export const persistAuthorizationIfNeeded = () => ( { authSelectors, getConfigs
279279
localStorage.setItem("authorized", JSON.stringify(authorized.toJS()))
280280
}
281281
}
282+
283+
export const authPopup = (url, swaggerUIRedirectOauth2) => ( ) => {
284+
win.swaggerUIRedirectOauth2 = swaggerUIRedirectOauth2
285+
286+
win.open(url)
287+
}

‎test/unit/core/oauth2-authorize.js

+38-41
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11

2-
import win from "core/window"
32
import Im from "immutable"
43
import oauth2Authorize from "core/oauth2-authorize"
54
import * as utils from "core/utils"
@@ -13,75 +12,76 @@ describe("oauth2", () => {
1312

1413
let authConfig = {
1514
auth: { schema: { get: (key)=> mockSchema[key] }, scopes: ["scope1", "scope2"] },
16-
authActions: {},
15+
authActions: {
16+
authPopup: jest.fn()
17+
},
1718
errActions: {},
1819
configs: { oauth2RedirectUrl: "" },
1920
authConfigs: {}
2021
}
2122

2223
let authConfig2 = {
2324
auth: { schema: { get: (key)=> mockSchema[key] }, scopes: Im.List(["scope2","scope3"]) },
24-
authActions: {},
25+
authActions: {
26+
authPopup: jest.fn()
27+
},
2528
errActions: {},
2629
configs: { oauth2RedirectUrl: "" },
2730
authConfigs: {}
2831
}
2932

3033
let authConfig3 = {
3134
auth: { schema: { get: (key)=> mockSchema[key] }, scopes: Im.List(["scope4","scope5"]) },
32-
authActions: {},
35+
authActions: {
36+
authPopup: jest.fn()
37+
},
3338
errActions: {},
3439
configs: { oauth2RedirectUrl: "" },
3540
authConfigs: {}
3641
}
3742

38-
beforeEach(() => {
39-
win.open = jest.fn()
40-
})
41-
4243
describe("authorize redirect", () => {
4344
it("should build authorize url", () => {
44-
const windowOpenSpy = jest.spyOn(win, "open")
4545
oauth2Authorize(authConfig)
46-
expect(windowOpenSpy.mock.calls.length).toEqual(1)
47-
expect(windowOpenSpy.mock.calls[0][0]).toMatch("https://testAuthorizationUrl?response_type=code&redirect_uri=&scope=scope1%20scope2&state=")
46+
expect(authConfig.authActions.authPopup.mock.calls.length).toEqual(1)
47+
expect(authConfig.authActions.authPopup.mock.calls[0][0]).toMatch("https://testAuthorizationUrl?response_type=code&redirect_uri=&scope=scope1%20scope2&state=")
4848

49-
windowOpenSpy.mockReset()
49+
authConfig.authActions.authPopup.mockReset()
5050
})
5151

5252
it("should build authorize url relative", function () {
53-
const windowOpenSpy = jest.spyOn(win, "open")
5453
let relativeMockSchema = {
5554
flow: "accessCode",
5655
authorizationUrl: "/testAuthorizationUrl"
5756
}
5857
let relativeAuthConfig = {
5958
auth: { schema: { get: (key) => relativeMockSchema[key] } },
60-
authActions: {},
59+
authActions: {
60+
authPopup: jest.fn()
61+
},
6162
errActions: {},
6263
configs: { oauth2RedirectUrl: "" },
6364
authConfigs: {},
6465
currentServer: "https://currentserver"
6566
}
6667
oauth2Authorize(relativeAuthConfig)
67-
expect(windowOpenSpy.mock.calls.length).toEqual(1)
68-
expect(windowOpenSpy.mock.calls[0][0]).toMatch("https://currentserver/testAuthorizationUrl?response_type=code&redirect_uri=&state=")
68+
expect(relativeAuthConfig.authActions.authPopup.mock.calls.length).toEqual(1)
69+
expect(relativeAuthConfig.authActions.authPopup.mock.calls[0][0]).toMatch("https://currentserver/testAuthorizationUrl?response_type=code&redirect_uri=&state=")
6970

70-
windowOpenSpy.mockReset()
71+
relativeAuthConfig.authActions.authPopup.mockReset()
7172
})
7273

7374
it("should append query parameters to authorizeUrl with query parameters", () => {
74-
const windowOpenSpy = jest.spyOn(win, "open")
7575
mockSchema.authorizationUrl = "https://testAuthorizationUrl?param=1"
7676
oauth2Authorize(authConfig)
77-
expect(windowOpenSpy.mock.calls.length).toEqual(1)
78-
expect(windowOpenSpy.mock.calls[0][0]).toMatch("https://testAuthorizationUrl?param=1&response_type=code&redirect_uri=&scope=scope1%20scope2&state=")
7977

80-
windowOpenSpy.mockReset()
78+
expect(authConfig.authActions.authPopup.mock.calls.length).toEqual(1)
79+
expect(authConfig.authActions.authPopup.mock.calls[0][0]).toMatch("https://testAuthorizationUrl?param=1&response_type=code&redirect_uri=&scope=scope1%20scope2&state=")
80+
81+
authConfig.authActions.authPopup.mockReset()
8182
})
8283

8384
it("should send code_challenge when using authorizationCode flow with usePkceWithAuthorizationCodeGrant enabled", () => {
84-
const windowOpenSpy = jest.spyOn(win, "open")
8585
mockSchema.flow = "authorizationCode"
8686

8787
const expectedCodeVerifier = "mock_code_verifier"
@@ -93,9 +93,9 @@ describe("oauth2", () => {
9393
authConfig.authConfigs.usePkceWithAuthorizationCodeGrant = true
9494

9595
oauth2Authorize(authConfig)
96-
expect(win.open.mock.calls.length).toEqual(1)
96+
expect(authConfig.authActions.authPopup.mock.calls.length).toEqual(1)
9797

98-
const actualUrl = new URLSearchParams(win.open.mock.calls[0][0])
98+
const actualUrl = new URLSearchParams(authConfig.authActions.authPopup.mock.calls[0][0])
9999
expect(actualUrl.get("code_challenge")).toBe(expectedCodeChallenge)
100100
expect(actualUrl.get("code_challenge_method")).toBe("S256")
101101

@@ -107,14 +107,13 @@ describe("oauth2", () => {
107107
expect(authConfig.auth.codeVerifier).toBe(expectedCodeVerifier)
108108

109109
// Restore spies
110-
windowOpenSpy.mockReset()
110+
authConfig.authActions.authPopup.mockReset()
111111
generateCodeVerifierSpy.mockReset()
112112
createCodeChallengeSpy.mockReset()
113113
})
114114

115115

116116
it("should send code_challenge when using accessCode flow with usePkceWithAuthorizationCodeGrant enabled", () => {
117-
const windowOpenSpy = jest.spyOn(win, "open")
118117
mockSchema.flow = "accessCode"
119118

120119
const expectedCodeVerifier = "mock_code_verifier"
@@ -127,9 +126,10 @@ describe("oauth2", () => {
127126
authConfig.authConfigs.usePkceWithAuthorizationCodeGrant = true
128127

129128
oauth2Authorize(authConfig)
130-
expect(win.open.mock.calls.length).toEqual(1)
131129

132-
const actualUrl = new URLSearchParams(win.open.mock.calls[0][0])
130+
expect(authConfig.authActions.authPopup.mock.calls.length).toEqual(1)
131+
132+
const actualUrl = new URLSearchParams(authConfig.authActions.authPopup.mock.calls[0][0])
133133
expect(actualUrl.get("code_challenge")).toBe(expectedCodeChallenge)
134134
expect(actualUrl.get("code_challenge_method")).toBe("S256")
135135

@@ -141,13 +141,12 @@ describe("oauth2", () => {
141141
expect(authConfig.auth.codeVerifier).toBe(expectedCodeVerifier)
142142

143143
// Restore spies
144-
windowOpenSpy.mockReset()
144+
authConfig.authActions.authPopup.mockReset()
145145
generateCodeVerifierSpy.mockReset()
146146
createCodeChallengeSpy.mockReset()
147147
})
148148

149149
it("should send code_challenge when using authorization_code flow with usePkceWithAuthorizationCodeGrant enabled", () => {
150-
const windowOpenSpy = jest.spyOn(win, "open")
151150
mockSchema.flow = "authorization_code"
152151

153152
const expectedCodeVerifier = "mock_code_verifier"
@@ -159,9 +158,9 @@ describe("oauth2", () => {
159158
authConfig.authConfigs.usePkceWithAuthorizationCodeGrant = true
160159

161160
oauth2Authorize(authConfig)
162-
expect(win.open.mock.calls.length).toEqual(1)
161+
expect(authConfig.authActions.authPopup.mock.calls.length).toEqual(1)
163162

164-
const actualUrl = new URLSearchParams(win.open.mock.calls[0][0])
163+
const actualUrl = new URLSearchParams(authConfig.authActions.authPopup.mock.calls[0][0])
165164
expect(actualUrl.get("code_challenge")).toBe(expectedCodeChallenge)
166165
expect(actualUrl.get("code_challenge_method")).toBe("S256")
167166

@@ -173,32 +172,30 @@ describe("oauth2", () => {
173172
expect(authConfig.auth.codeVerifier).toBe(expectedCodeVerifier)
174173

175174
// Restore spies
176-
windowOpenSpy.mockReset()
175+
authConfig.authActions.authPopup.mockReset()
177176
generateCodeVerifierSpy.mockReset()
178177
createCodeChallengeSpy.mockReset()
179178
})
180179

181180
it("should add list of scopes to authorizeUrl", () => {
182-
const windowOpenSpy = jest.spyOn(win, "open")
183181
mockSchema.authorizationUrl = "https://testAuthorizationUrl?param=1"
184182

185183
oauth2Authorize(authConfig2)
186-
expect(windowOpenSpy.mock.calls.length).toEqual(1)
187-
expect(windowOpenSpy.mock.calls[0][0]).toMatch("https://testAuthorizationUrl?param=1&response_type=code&redirect_uri=&scope=scope2%20scope3&state=")
184+
expect(authConfig2.authActions.authPopup.mock.calls.length).toEqual(1)
185+
expect(authConfig2.authActions.authPopup.mock.calls[0][0]).toMatch("https://testAuthorizationUrl?param=1&response_type=code&redirect_uri=&scope=scope2%20scope3&state=")
188186

189-
windowOpenSpy.mockReset()
187+
authConfig2.authActions.authPopup.mockReset()
190188
})
191189

192190
it("should build authorize url for authorization_code flow", () => {
193-
const windowOpenSpy = jest.spyOn(win, "open")
194191
mockSchema.authorizationUrl = "https://testAuthorizationUrl"
195192
mockSchema.flow = "authorization_code"
196193

197194
oauth2Authorize(authConfig3)
198-
expect(windowOpenSpy.mock.calls.length).toEqual(1)
199-
expect(windowOpenSpy.mock.calls[0][0]).toMatch("https://testAuthorizationUrl?response_type=code&redirect_uri=&scope=scope4%20scope5&state=")
195+
expect(authConfig3.authActions.authPopup.mock.calls.length).toEqual(1)
196+
expect(authConfig3.authActions.authPopup.mock.calls[0][0]).toMatch("https://testAuthorizationUrl?response_type=code&redirect_uri=&scope=scope4%20scope5&state=")
200197

201-
windowOpenSpy.mockReset()
198+
authConfig3.authActions.authPopup.mockReset()
202199
})
203200
})
204201
})

‎test/unit/core/plugins/auth/actions.js

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Map } from "immutable"
2+
import win from "core/window"
23
import {
34
authorizeRequest,
45
authorizeAccessCodeWithFormParams,
@@ -7,7 +8,7 @@ import {
78
logoutWithPersistOption,
89
persistAuthorizationIfNeeded
910
} from "corePlugins/auth/actions"
10-
import { authorizeAccessCodeWithBasicAuthentication } from "../../../../../src/core/plugins/auth/actions"
11+
import {authorizeAccessCodeWithBasicAuthentication, authPopup} from "../../../../../src/core/plugins/auth/actions"
1112

1213
describe("auth plugin - actions", () => {
1314

@@ -327,5 +328,19 @@ describe("auth plugin - actions", () => {
327328
})
328329
})
329330

331+
describe("authPopup", () => {
332+
beforeEach(() => {
333+
win.open = jest.fn()
334+
})
335+
it("should call win.open with url", () => {
336+
const windowOpenSpy = jest.spyOn(win, "open")
337+
338+
authPopup("http://swagger.ui", {})()
339+
340+
expect(windowOpenSpy.mock.calls.length).toEqual(1)
341+
windowOpenSpy.mockReset()
342+
})
343+
})
344+
330345
})
331346
})

0 commit comments

Comments
 (0)
Please sign in to comment.