Skip to content
This repository was archived by the owner on Nov 8, 2024. It is now read-only.

Commit 11523ad

Browse files
committed
feat(oas3): finished oauth2 flow support
1 parent c74f87e commit 11523ad

File tree

4 files changed

+225
-13
lines changed

4 files changed

+225
-13
lines changed

packages/fury-adapter-oas3-parser/lib/parser/oas/parseOauthFlowObject.js

+14-3
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,22 @@ function parseOauthFlowObject(context, object) {
4040
return scope;
4141
}));
4242

43+
const parseUrl = pipeParseResult(namespace,
44+
parseString(context, name, false),
45+
(url) => {
46+
const transition = new namespace.elements.Transition();
47+
48+
transition.relation = url.key.toValue().slice(0, -3); // remove 'Url' from key
49+
transition.href = url.value.toValue();
50+
51+
return transition;
52+
});
53+
4354
const parseMember = R.cond([
4455
[hasKey('scopes'), R.compose(parseScopes, getValue)],
45-
[hasKey('refreshUrl'), parseString(context, name, false)],
46-
[hasKey('authorizationUrl'), parseString(context, name, false)],
47-
[hasKey('tokenUrl'), parseString(context, name, false)],
56+
[hasKey('refreshUrl'), parseUrl],
57+
[hasKey('authorizationUrl'), parseUrl],
58+
[hasKey('tokenUrl'), parseUrl],
4859

4960
// FIXME Support exposing extensions into parse result
5061
[isExtension, () => new namespace.elements.ParseResult()],

packages/fury-adapter-oas3-parser/lib/parser/oas/parseOauthFlowsObject.js

+10-5
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,18 @@ function parseOauthFlowsObject(context, object) {
6666
parseObject(context, name, parseMember),
6767
flows => new namespace.elements.Array(flows.content),
6868
R.map((member) => {
69-
const authScheme = new namespace.elements.AuthScheme();
69+
const authSchemeFlow = new namespace.elements.Array();
7070

71-
authScheme.element = 'Oauth2 Scheme';
72-
authScheme.push(new namespace.elements.Member('grantType', grantTypes[member.key.toValue()]));
73-
authScheme.push(member.value.getMember('scopes'));
71+
authSchemeFlow.push(new namespace.elements.Member('grantType', grantTypes[member.key.toValue()]));
72+
authSchemeFlow.push(member.value.getMember('scopes'));
7473

75-
return authScheme;
74+
['refreshUrl', 'authorizationUrl', 'tokenUrl'].forEach((item) => {
75+
if (member.value.get(item)) {
76+
authSchemeFlow.push(member.value.get(item));
77+
}
78+
});
79+
80+
return authSchemeFlow;
7681
}));
7782

7883
return parseOauthFlows(object);

packages/fury-adapter-oas3-parser/test/unit/parser/oas/parseOauthFlowObject-test.js

+54
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,24 @@ describe('Oauth Flow Object', () => {
9999
expect(parseResult.get(0).get('scopes')).to.be.instanceof(namespace.elements.Array);
100100
expect(parseResult.get(0).get('scopes').length).to.equal(0);
101101
});
102+
103+
it('parses it correctly', () => {
104+
const oauthFlow = new namespace.elements.Object({
105+
scopes: {},
106+
refreshUrl: '/refresh',
107+
});
108+
109+
const parseResult = parse(context, oauthFlow);
110+
111+
expect(parseResult.length).to.equal(1);
112+
expect(parseResult.get(0)).to.be.instanceof(namespace.elements.Object);
113+
114+
const refreshUrl = parseResult.get(0).get('refreshUrl');
115+
116+
expect(refreshUrl).to.be.instanceof(namespace.elements.Transition);
117+
expect(refreshUrl.relation.toValue()).to.equal('refresh');
118+
expect(refreshUrl.href.toValue()).to.equal('/refresh');
119+
});
102120
});
103121

104122
describe('#tokenUrl', () => {
@@ -117,6 +135,24 @@ describe('Oauth Flow Object', () => {
117135
expect(parseResult.get(0).get('scopes')).to.be.instanceof(namespace.elements.Array);
118136
expect(parseResult.get(0).get('scopes').length).to.equal(0);
119137
});
138+
139+
it('parses it correctly', () => {
140+
const oauthFlow = new namespace.elements.Object({
141+
scopes: {},
142+
tokenUrl: '/token',
143+
});
144+
145+
const parseResult = parse(context, oauthFlow);
146+
147+
expect(parseResult.length).to.equal(1);
148+
expect(parseResult.get(0)).to.be.instanceof(namespace.elements.Object);
149+
150+
const tokenUrl = parseResult.get(0).get('tokenUrl');
151+
152+
expect(tokenUrl).to.be.instanceof(namespace.elements.Transition);
153+
expect(tokenUrl.relation.toValue()).to.equal('token');
154+
expect(tokenUrl.href.toValue()).to.equal('/token');
155+
});
120156
});
121157

122158
describe('#authorizationUrl', () => {
@@ -135,6 +171,24 @@ describe('Oauth Flow Object', () => {
135171
expect(parseResult.get(0).get('scopes')).to.be.instanceof(namespace.elements.Array);
136172
expect(parseResult.get(0).get('scopes').length).to.equal(0);
137173
});
174+
175+
it('parses it correctly', () => {
176+
const oauthFlow = new namespace.elements.Object({
177+
scopes: {},
178+
authorizationUrl: '/authorization',
179+
});
180+
181+
const parseResult = parse(context, oauthFlow);
182+
183+
expect(parseResult.length).to.equal(1);
184+
expect(parseResult.get(0)).to.be.instanceof(namespace.elements.Object);
185+
186+
const authorizationUrl = parseResult.get(0).get('authorizationUrl');
187+
188+
expect(authorizationUrl).to.be.instanceof(namespace.elements.Transition);
189+
expect(authorizationUrl.relation.toValue()).to.equal('authorization');
190+
expect(authorizationUrl.href.toValue()).to.equal('/authorization');
191+
});
138192
});
139193

140194
it('provides warning for invalid keys', () => {

packages/fury-adapter-oas3-parser/test/unit/parser/oas/parseOauthFlowsObject-test.js

+147-5
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,35 @@ describe('Oauth Flows Object', () => {
3636
expect(parseResult).to.contain.warning("'Oauth Flows Object' 'implicit' is missing required property 'authorizationUrl'");
3737
});
3838

39-
it.skip('parses correctly', () => {
39+
it('parses correctly', () => {
4040
const oauthFlows = new namespace.elements.Object({
4141
implicit: {
42-
authorizationUrl: '/authorize',
42+
authorizationUrl: '/authorization',
4343
scopes: {},
4444
},
4545
});
4646

4747
const parseResult = parse(context, oauthFlows);
48-
console.log(JSON.stringify(parseResult, null, 2));
48+
4949
expect(parseResult.length).to.equal(1);
50+
expect(parseResult.get(0)).to.be.instanceof(namespace.elements.Array);
51+
expect(parseResult.get(0).length).to.equal(1);
52+
53+
const flow = parseResult.get(0).get(0);
54+
55+
expect(flow).to.be.instanceof(namespace.elements.Array);
56+
expect(flow.length).to.equal(3);
57+
58+
expect(flow.get(0)).to.be.instanceof(namespace.elements.Member);
59+
expect(flow.get(0).key.toValue()).to.equal('grantType');
60+
expect(flow.get(0).value.toValue()).to.equal('implicit');
61+
62+
expect(flow.get(1)).to.be.instanceof(namespace.elements.Member);
63+
expect(flow.get(1).key.toValue()).to.equal('scopes');
64+
expect(flow.get(1).value).to.be.instanceof(namespace.elements.Array);
65+
66+
expect(flow.get(2)).to.be.instanceof(namespace.elements.Transition);
67+
expect(flow.get(2).href.toValue()).to.equal('/authorization');
5068
});
5169
});
5270

@@ -65,6 +83,37 @@ describe('Oauth Flows Object', () => {
6583
expect(parseResult.get(0).length).to.equal(0);
6684
expect(parseResult).to.contain.warning("'Oauth Flows Object' 'password' is missing required property 'tokenUrl'");
6785
});
86+
87+
it('parses correctly', () => {
88+
const oauthFlows = new namespace.elements.Object({
89+
password: {
90+
tokenUrl: '/token',
91+
scopes: {},
92+
},
93+
});
94+
95+
const parseResult = parse(context, oauthFlows);
96+
97+
expect(parseResult.length).to.equal(1);
98+
expect(parseResult.get(0)).to.be.instanceof(namespace.elements.Array);
99+
expect(parseResult.get(0).length).to.equal(1);
100+
101+
const flow = parseResult.get(0).get(0);
102+
103+
expect(flow).to.be.instanceof(namespace.elements.Array);
104+
expect(flow.length).to.equal(3);
105+
106+
expect(flow.get(0)).to.be.instanceof(namespace.elements.Member);
107+
expect(flow.get(0).key.toValue()).to.equal('grantType');
108+
expect(flow.get(0).value.toValue()).to.equal('resource owner password credentials');
109+
110+
expect(flow.get(1)).to.be.instanceof(namespace.elements.Member);
111+
expect(flow.get(1).key.toValue()).to.equal('scopes');
112+
expect(flow.get(1).value).to.be.instanceof(namespace.elements.Array);
113+
114+
expect(flow.get(2)).to.be.instanceof(namespace.elements.Transition);
115+
expect(flow.get(2).href.toValue()).to.equal('/token');
116+
});
68117
});
69118

70119
describe('#clientCredentials', () => {
@@ -82,6 +131,37 @@ describe('Oauth Flows Object', () => {
82131
expect(parseResult.get(0).length).to.equal(0);
83132
expect(parseResult).to.contain.warning("'Oauth Flows Object' 'clientCredentials' is missing required property 'tokenUrl'");
84133
});
134+
135+
it('parses correctly', () => {
136+
const oauthFlows = new namespace.elements.Object({
137+
clientCredentials: {
138+
tokenUrl: '/token',
139+
scopes: {},
140+
},
141+
});
142+
143+
const parseResult = parse(context, oauthFlows);
144+
145+
expect(parseResult.length).to.equal(1);
146+
expect(parseResult.get(0)).to.be.instanceof(namespace.elements.Array);
147+
expect(parseResult.get(0).length).to.equal(1);
148+
149+
const flow = parseResult.get(0).get(0);
150+
151+
expect(flow).to.be.instanceof(namespace.elements.Array);
152+
expect(flow.length).to.equal(3);
153+
154+
expect(flow.get(0)).to.be.instanceof(namespace.elements.Member);
155+
expect(flow.get(0).key.toValue()).to.equal('grantType');
156+
expect(flow.get(0).value.toValue()).to.equal('client credentials');
157+
158+
expect(flow.get(1)).to.be.instanceof(namespace.elements.Member);
159+
expect(flow.get(1).key.toValue()).to.equal('scopes');
160+
expect(flow.get(1).value).to.be.instanceof(namespace.elements.Array);
161+
162+
expect(flow.get(2)).to.be.instanceof(namespace.elements.Transition);
163+
expect(flow.get(2).href.toValue()).to.equal('/token');
164+
});
85165
});
86166

87167
describe('#authorizationCode', () => {
@@ -103,7 +183,7 @@ describe('Oauth Flows Object', () => {
103183
it('provides warning when no tokenUrl', () => {
104184
const oauthFlows = new namespace.elements.Object({
105185
authorizationCode: {
106-
authorizationUrl: '/authorize',
186+
authorizationUrl: '/authorization',
107187
scopes: {},
108188
},
109189
});
@@ -115,9 +195,71 @@ describe('Oauth Flows Object', () => {
115195
expect(parseResult.get(0).length).to.equal(0);
116196
expect(parseResult).to.contain.warning("'Oauth Flows Object' 'authorizationCode' is missing required property 'tokenUrl'");
117197
});
198+
199+
it('parses correctly', () => {
200+
const oauthFlows = new namespace.elements.Object({
201+
authorizationCode: {
202+
authorizationUrl: '/authorization',
203+
tokenUrl: '/token',
204+
scopes: {},
205+
},
206+
});
207+
208+
const parseResult = parse(context, oauthFlows);
209+
210+
expect(parseResult.length).to.equal(1);
211+
expect(parseResult.get(0)).to.be.instanceof(namespace.elements.Array);
212+
expect(parseResult.get(0).length).to.equal(1);
213+
214+
const flow = parseResult.get(0).get(0);
215+
216+
expect(flow).to.be.instanceof(namespace.elements.Array);
217+
expect(flow.length).to.equal(4);
218+
219+
expect(flow.get(0)).to.be.instanceof(namespace.elements.Member);
220+
expect(flow.get(0).key.toValue()).to.equal('grantType');
221+
expect(flow.get(0).value.toValue()).to.equal('authorization code');
222+
223+
expect(flow.get(1)).to.be.instanceof(namespace.elements.Member);
224+
expect(flow.get(1).key.toValue()).to.equal('scopes');
225+
expect(flow.get(1).value).to.be.instanceof(namespace.elements.Array);
226+
227+
expect(flow.get(2)).to.be.instanceof(namespace.elements.Transition);
228+
expect(flow.get(2).href.toValue()).to.equal('/authorization');
229+
230+
expect(flow.get(3)).to.be.instanceof(namespace.elements.Transition);
231+
expect(flow.get(3).href.toValue()).to.equal('/token');
232+
});
118233
});
119234

120-
// TODO: Multiple flows
235+
it('parses multiple flows correctly', () => {
236+
const oauthFlows = new namespace.elements.Object({
237+
implicit: {
238+
authorizationUrl: '/authorization',
239+
scopes: {},
240+
},
241+
password: {
242+
tokenUrl: '/token',
243+
scopes: {},
244+
},
245+
});
246+
247+
const parseResult = parse(context, oauthFlows);
248+
249+
expect(parseResult.length).to.equal(1);
250+
expect(parseResult.get(0)).to.be.instanceof(namespace.elements.Array);
251+
expect(parseResult.get(0).length).to.equal(2);
252+
253+
const implicitFlow = parseResult.get(0).get(0);
254+
255+
expect(implicitFlow).to.be.instanceof(namespace.elements.Array);
256+
expect(implicitFlow.length).to.equal(3);
257+
258+
const passwordFlow = parseResult.get(0).get(1);
259+
260+
expect(passwordFlow).to.be.instanceof(namespace.elements.Array);
261+
expect(passwordFlow.length).to.equal(3);
262+
});
121263

122264
it('provides warning for invalid keys', () => {
123265
const oauthFlows = new namespace.elements.Object({

0 commit comments

Comments
 (0)