From 94575666c3ae2431dc64c5f84d3b4ea2b8032834 Mon Sep 17 00:00:00 2001 From: kai-morich Date: Mon, 24 Oct 2022 22:37:49 +0200 Subject: [PATCH] fix(oauth2): only display scopes relevant for current endpoint (#8229) * 'available authorization' popup: only show oauth2 scopes relevant for current endpoint (issue #8219) * unit tests for oauth2 scope filter Co-authored-by: Kai Morich Co-authored-by: Tim Lai --- src/core/plugins/auth/selectors.js | 23 +++++- test/unit/core/plugins/auth/selectors.js | 96 ++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 2 deletions(-) diff --git a/src/core/plugins/auth/selectors.js b/src/core/plugins/auth/selectors.js index 53729449..61c52804 100644 --- a/src/core/plugins/auth/selectors.js +++ b/src/core/plugins/auth/selectors.js @@ -61,9 +61,28 @@ export const getDefinitionsByNames = ( state, securities ) => ( { specSelectors export const definitionsForRequirements = (state, securities = List()) => ({ authSelectors }) => { const allDefinitions = authSelectors.definitionsToAuthorize() || List() - return allDefinitions.filter((def) => { - return securities.some(sec => sec.get(def.keySeq().first())) + let result = List() + allDefinitions.forEach( (definition) => { + let security = securities.find(sec => sec.get(definition.keySeq().first())) + if ( security ) { + definition.forEach( (props, name) => { + if ( props.get("type") === "oauth2" ) { + const securityScopes = security.get(name) + let definitionScopes = props.get("scopes") + if( List.isList(securityScopes) && Map.isMap(definitionScopes) ) { + definitionScopes.keySeq().forEach( (key) => { + if ( !securityScopes.contains(key) ) { + definitionScopes = definitionScopes.delete(key) + } + }) + definition = definition.set(name, props.set("scopes", definitionScopes)) + } + } + }) + result = result.push(definition) + } }) + return result } export const authorized = createSelector( diff --git a/test/unit/core/plugins/auth/selectors.js b/test/unit/core/plugins/auth/selectors.js index bb8e5eac..2b6c1509 100644 --- a/test/unit/core/plugins/auth/selectors.js +++ b/test/unit/core/plugins/auth/selectors.js @@ -129,4 +129,100 @@ describe("auth plugin - selectors", () => { expect(res.toJS()).toEqual([]) }) }) + + it("should return only security definitions used by the endpoint", () => { + const securityDefinitions = { + "used": { + "type": "http", + "scheme": "basic", + }, + "unused": { + "type": "http", + "scheme": "basic", + } + } + + const system = { + authSelectors: { + definitionsToAuthorize() { + return fromJS([ + { + "used": securityDefinitions["used"] + }, + { + "unused": securityDefinitions["unused"] + }, + ]) + } + } + } + + const securities = fromJS([ + { + "used": [], + "undefined": [], + } + ]) + + const res = definitionsForRequirements({}, securities)(system) + + expect(res.toJS()).toEqual([ + { + "used": securityDefinitions["used"] + } + ]) + }) + + it("should return only oauth scopes used by the endpoint", () => { + const securityDefinitions = { + "oauth2": { + "type": "oauth2", + "flow": "clientCredentials", + "tokenUrl": "https://api.testserver.com/oauth2/token/", + "scopes": { + "used": "foo", + "unused": "bar" + } + }, + "other": { + "type": "apiKey", + "name": "api_key", + "in": "header" + } + + } + + const system = { + authSelectors: { + definitionsToAuthorize() { + return fromJS([ + { + "oauth2": securityDefinitions["oauth2"], + "other": securityDefinitions["other"], + }, + ]) + } + } + } + + const securities = fromJS([ + { + "oauth2": ["used", "undefined"], + "other": [], + } + ]) + + let expectedOauth2Definitions = {...securityDefinitions["oauth2"]} + expectedOauth2Definitions["scopes"] = {"used": "foo"} + + const res = definitionsForRequirements({}, securities)(system) + + expect(res.toJS()).toEqual([ + { + "oauth2": expectedOauth2Definitions, + "other": securityDefinitions["other"] + } + ]) + }) + })