Skip to content

Commit 5e85fae

Browse files
committed
feat(core): ensure combo resolution doesn't go into infinite loop #1416
1 parent 87877aa commit 5e85fae

File tree

2 files changed

+94
-77
lines changed

2 files changed

+94
-77
lines changed

packages/core/src/consumed-thing.ts

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -445,20 +445,29 @@ export default class ConsumedThing extends Thing implements IConsumedThing {
445445
}
446446

447447
getSecuritySchemes(security: Array<string>): Array<SecurityScheme> {
448+
const visited = new Set<string>();
449+
448450
const scs: Array<SecurityScheme> = [];
449-
for (const s of security) {
450-
const ws = this.securityDefinitions[s + ""]; // String vs. string (fix wot-typescript-definitions?)
451-
// also push nosec in case of proxy
452-
if (ws != null) {
453-
if (ws.scheme === "combo") {
454-
const combo = ws as ComboSecurityScheme;
455-
const schemes = this.getSecuritySchemes(combo.allOf as string[]);
456-
scs.push(...schemes);
457-
} else {
458-
scs.push(ws);
451+
const visitSchemes = (security: Array<string>) => {
452+
for (const s of security) {
453+
if (visited.has(s)) {
454+
continue;
455+
}
456+
visited.add(s);
457+
458+
const ws = this.securityDefinitions[s + ""]; // String vs. string (fix wot-typescript-definitions?)
459+
// also push nosec in case of proxy
460+
if (ws != null) {
461+
if (ws.scheme === "combo") {
462+
const combo = ws as ComboSecurityScheme;
463+
visitSchemes(combo.allOf as string[]);
464+
} else {
465+
scs.push(ws);
466+
}
459467
}
460468
}
461-
}
469+
};
470+
visitSchemes(security);
462471
return scs;
463472
}
464473

packages/core/test/ClientTest.ts

Lines changed: 74 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -806,71 +806,79 @@ class WoTClientTest {
806806
expect(WoTClientTest.servient.hasClientFor(tcf2.scheme)).to.be.not.true;
807807
}
808808

809-
@test "ensure combo security "(done: Mocha.Done) {
810-
try {
811-
const ct = new ConsumedThing(WoTClientTest.servient);
812-
ct.securityDefinitions = {
813-
basic_sc: {
814-
scheme: "basic",
815-
},
816-
opcua_secure_channel_sc: {
817-
scheme: "opcua-channel-security",
818-
},
819-
opcua_authetication_sc: {
820-
scheme: "opcua-authentication",
821-
},
822-
combo_sc: {
823-
scheme: "combo",
824-
allOf: ["opcua_secure_channel_sc", "opcua_authetication_sc"],
825-
},
826-
};
827-
ct.security = ["combo_sc"];
828-
const pc = new TestProtocolClient();
829-
const form: Form = {
830-
href: "https://example.com/",
831-
// security: ["apikey_sc"],
832-
};
833-
ct.ensureClientSecurity(pc, form);
834-
expect(pc.securitySchemes.length).equals(2);
835-
expect(pc.securitySchemes[0].scheme).equals("opcua-channel-security");
836-
expect(pc.securitySchemes[1].scheme).equals("opcua-authentication");
837-
done();
838-
} catch (err) {
839-
done(err);
840-
}
841-
}
842-
843-
@test "ensure combo security in form"(done: Mocha.Done) {
844-
try {
845-
const ct = new ConsumedThing(WoTClientTest.servient);
846-
ct.securityDefinitions = {
847-
basic_sc: {
848-
scheme: "basic",
849-
},
850-
opcua_secure_channel_sc: {
851-
scheme: "opcua-channel-security",
852-
},
853-
opcua_authetication_sc: {
854-
scheme: "opcua-authentication",
855-
},
856-
combo_sc: {
857-
scheme: "combo",
858-
allOf: ["opcua_secure_channel_sc", "opcua_authetication_sc"],
859-
},
860-
};
861-
ct.security = "basic";
862-
const pc = new TestProtocolClient();
863-
const form: Form = {
864-
href: "https://example.com/",
865-
security: ["combo_sc"],
866-
};
867-
ct.ensureClientSecurity(pc, form);
868-
expect(pc.securitySchemes.length).equals(2);
869-
expect(pc.securitySchemes[0].scheme).equals("opcua-channel-security");
870-
expect(pc.securitySchemes[1].scheme).equals("opcua-authentication");
871-
done();
872-
} catch (err) {
873-
done(err);
874-
}
809+
@test "ensure combo security"() {
810+
const ct = new ConsumedThing(WoTClientTest.servient);
811+
ct.securityDefinitions = {
812+
basic_sc: {
813+
scheme: "basic",
814+
},
815+
opcua_secure_channel_sc: {
816+
scheme: "opcua-channel-security",
817+
},
818+
opcua_authetication_sc: {
819+
scheme: "opcua-authentication",
820+
},
821+
combo_sc: {
822+
scheme: "combo",
823+
allOf: ["opcua_secure_channel_sc", "opcua_authetication_sc"],
824+
},
825+
};
826+
ct.security = ["combo_sc"];
827+
const pc = new TestProtocolClient();
828+
const form: Form = {
829+
href: "https://example.com/",
830+
};
831+
ct.ensureClientSecurity(pc, form);
832+
expect(pc.securitySchemes.length).equals(2);
833+
expect(pc.securitySchemes[0].scheme).equals("opcua-channel-security");
834+
expect(pc.securitySchemes[1].scheme).equals("opcua-authentication");
835+
}
836+
837+
@test "ensure combo security in form"() {
838+
const ct = new ConsumedThing(WoTClientTest.servient);
839+
ct.securityDefinitions = {
840+
basic_sc: {
841+
scheme: "basic",
842+
},
843+
opcua_secure_channel_sc: {
844+
scheme: "opcua-channel-security",
845+
},
846+
opcua_authetication_sc: {
847+
scheme: "opcua-authentication",
848+
},
849+
combo_sc: {
850+
scheme: "combo",
851+
allOf: ["opcua_secure_channel_sc", "opcua_authetication_sc"],
852+
},
853+
};
854+
ct.security = "basic";
855+
const pc = new TestProtocolClient();
856+
const form: Form = {
857+
href: "https://example.com/",
858+
security: ["combo_sc"],
859+
};
860+
ct.ensureClientSecurity(pc, form);
861+
expect(pc.securitySchemes.length).equals(2);
862+
expect(pc.securitySchemes[0].scheme).equals("opcua-channel-security");
863+
expect(pc.securitySchemes[1].scheme).equals("opcua-authentication");
864+
}
865+
866+
@test "ensure no infinite loop with recursive combo security"() {
867+
const ct = new ConsumedThing(WoTClientTest.servient);
868+
ct.securityDefinitions = {
869+
// a badly designed combo that goes into infinite loop
870+
combo_sc: {
871+
scheme: "combo",
872+
allOf: ["combo_sc", "combo_sc"],
873+
},
874+
};
875+
ct.security = "basic";
876+
const pc = new TestProtocolClient();
877+
const form: Form = {
878+
href: "https://example.com/",
879+
security: ["combo_sc"],
880+
};
881+
ct.ensureClientSecurity(pc, form);
882+
expect(pc.securitySchemes.length).equals(0);
875883
}
876884
}

0 commit comments

Comments
 (0)