Skip to content

Commit 9efc831

Browse files
committed
feat(core): refine combo security scheme implementation
This commit refines the implementation of combo security schemes by introducing explicit AllOfSecurityScheme and OneOfSecurityScheme types. The getSecuritySchemes method in ConsumedThing has been updated to recursively resolve these schemes, and the tests have been expanded to cover nested allOf and oneOf scenarios.
1 parent ab42852 commit 9efc831

File tree

3 files changed

+105
-18
lines changed

3 files changed

+105
-18
lines changed

packages/core/src/consumed-thing.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import {
2424
ThingAction,
2525
ThingEvent,
2626
SecurityScheme,
27+
AllOfSecurityScheme,
28+
OneOfSecurityScheme,
2729
} from "./thing-description";
2830

2931
import { ThingModel } from "wot-thing-model-types";
@@ -447,27 +449,40 @@ export default class ConsumedThing extends Thing implements IConsumedThing {
447449
getSecuritySchemes(security: Array<string>): Array<SecurityScheme> {
448450
const visited = new Set<string>();
449451

450-
const scs: Array<SecurityScheme> = [];
451-
const visitSchemes = (security: Array<string>) => {
452+
const visitSchemes = (security: Array<string>, visitedScheme: Array<SecurityScheme>) => {
452453
for (const s of security) {
453454
if (visited.has(s)) {
454455
continue;
455456
}
456457
visited.add(s);
457-
458458
const ws = this.securityDefinitions[s + ""]; // String vs. string (fix wot-typescript-definitions?)
459459
// also push nosec in case of proxy
460460
if (ws != null) {
461461
if (ws.scheme === "combo") {
462462
const combo = ws as ComboSecurityScheme;
463-
visitSchemes(combo.allOf as string[]);
463+
const comboScheme: SecurityScheme[] = [];
464+
if (combo.allOf) {
465+
visitSchemes(combo.allOf as string[], comboScheme);
466+
visitedScheme.push(<AllOfSecurityScheme>{
467+
scheme: "combo",
468+
allOf: comboScheme,
469+
});
470+
}
471+
if (combo.oneOf) {
472+
visitSchemes(combo.oneOf as string[], comboScheme);
473+
visitedScheme.push(<OneOfSecurityScheme>{
474+
scheme: "combo",
475+
oneOf: comboScheme,
476+
});
477+
}
464478
} else {
465-
scs.push(ws);
479+
visitedScheme.push(ws);
466480
}
467481
}
468482
}
469483
};
470-
visitSchemes(security);
484+
const scs: SecurityScheme[] = [];
485+
visitSchemes(security, scs);
471486
return scs;
472487
}
473488

packages/core/src/thing-description.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,15 +135,16 @@ export interface NullSchema extends BaseSchema {
135135
}
136136

137137
// TODO AutoSecurityScheme
138-
// TODO ComboSecurityScheme
139138
export type SecurityType =
140139
| NoSecurityScheme
141140
| BasicSecurityScheme
142141
| DigestSecurityScheme
143142
| BearerSecurityScheme
144143
| APIKeySecurityScheme
145144
| OAuth2SecurityScheme
146-
| PSKSecurityScheme;
145+
| PSKSecurityScheme
146+
| AllOfSecurityScheme
147+
| OneOfSecurityScheme;
147148

148149
export interface SecurityScheme {
149150
scheme: string;
@@ -180,6 +181,17 @@ export interface PSKSecurityScheme extends SecurityScheme, TDT.PskSecurityScheme
180181
export interface OAuth2SecurityScheme extends SecurityScheme, TDT.OAuth2SecurityScheme {
181182
scheme: "oauth2";
182183
}
184+
export interface OneOfSecurityScheme extends SecurityScheme {
185+
scheme: "combo";
186+
oneOf: SecurityScheme[];
187+
allOf: never;
188+
}
189+
export interface AllOfSecurityScheme extends SecurityScheme {
190+
scheme: "combo";
191+
allOf: SecurityScheme[];
192+
oneOf: never;
193+
}
194+
export type ComboSecurityScheme = AllOfSecurityScheme | OneOfSecurityScheme;
183195

184196
/** Implements the Thing Property description */
185197
export abstract class ThingProperty extends BaseSchema {

packages/core/test/ClientTest.ts

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import { Subscription } from "rxjs/Subscription";
2727

2828
import Servient from "../src/servient";
2929
import ConsumedThing from "../src/consumed-thing";
30-
import { Form, SecurityScheme } from "../src/thing-description";
30+
import { AllOfSecurityScheme, Form, OneOfSecurityScheme, SecurityScheme } from "../src/thing-description";
3131
import { ProtocolClient, ProtocolClientFactory } from "../src/protocol-interfaces";
3232
import { Content } from "../src/content";
3333
import { ContentSerdes } from "../src/content-serdes";
@@ -37,6 +37,7 @@ import { createLoggers, ProtocolHelpers } from "../src/core";
3737
import { ThingDescription } from "wot-typescript-definitions";
3838
import chaiAsPromised from "chai-as-promised";
3939
import { fail } from "assert";
40+
import { ComboSecurityScheme } from "wot-thing-description-types";
4041

4142
const { debug } = createLoggers("core", "ClientTest");
4243

@@ -806,7 +807,7 @@ class WoTClientTest {
806807
expect(WoTClientTest.servient.hasClientFor(tcf2.scheme)).to.be.not.true;
807808
}
808809

809-
@test "ensure combo security"() {
810+
@test "ensure combo security - allOf"() {
810811
const ct = new ConsumedThing(WoTClientTest.servient);
811812
ct.securityDefinitions = {
812813
basic_sc: {
@@ -829,12 +830,69 @@ class WoTClientTest {
829830
href: "https://example.com/",
830831
};
831832
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");
833+
expect(pc.securitySchemes.length).equals(1);
834+
expect(pc.securitySchemes[0].scheme).equals("combo");
835+
836+
const comboScheme = pc.securitySchemes[0] as AllOfSecurityScheme;
837+
expect(comboScheme.allOf).instanceOf(Array);
838+
expect(comboScheme.allOf.length).equal(2);
839+
expect(comboScheme.allOf[0].scheme).equals("opcua-channel-security");
840+
expect(comboScheme.allOf[1].scheme).equals("opcua-authentication");
841+
}
842+
843+
@test "ensure combo security - oneOf"() {
844+
const ct = new ConsumedThing(WoTClientTest.servient);
845+
ct.securityDefinitions = {
846+
basic_sc: {
847+
scheme: "basic",
848+
},
849+
opcua_secure_channel_encrypt_sc: {
850+
scheme: "opcua-channel-security",
851+
mode: "encrypt",
852+
},
853+
opcua_secure_channel_sign_sc: {
854+
scheme: "opcua-channel-security",
855+
mode: "sign",
856+
},
857+
opcua_authetication_sc: {
858+
scheme: "opcua-authentication",
859+
},
860+
comob_opcua_secure_channel: {
861+
scheme: "combo",
862+
oneOf: ["opcua_secure_channel_encrypt_sc", "opcua_secure_channel_sign_sc"],
863+
},
864+
combo_sc: {
865+
scheme: "combo",
866+
allOf: ["comob_opcua_secure_channel", "opcua_authetication_sc"],
867+
},
868+
};
869+
ct.security = ["combo_sc"];
870+
const pc = new TestProtocolClient();
871+
const form: Form = {
872+
href: "https://example.com/",
873+
};
874+
ct.ensureClientSecurity(pc, form);
875+
expect(pc.securitySchemes.length).equals(1);
876+
expect(pc.securitySchemes[0].scheme).equals("combo");
877+
878+
const comboScheme = pc.securitySchemes[0] as AllOfSecurityScheme;
879+
880+
expect(comboScheme.allOf).instanceOf(Array);
881+
expect(comboScheme.allOf.length).equal(2);
882+
expect(comboScheme.allOf[0].scheme).equals("combo");
883+
expect(comboScheme.allOf[1].scheme).equals("opcua-authentication");
884+
885+
//
886+
const comob_opcua_secure_channel = comboScheme.allOf[0] as OneOfSecurityScheme;
887+
expect(comob_opcua_secure_channel.scheme).equal("combo");
888+
expect(comob_opcua_secure_channel.oneOf).instanceOf(Array);
889+
890+
expect(comob_opcua_secure_channel.oneOf.length).equal(2);
891+
expect(comob_opcua_secure_channel.oneOf[0].scheme).equal("opcua-channel-security");
892+
expect(comob_opcua_secure_channel.oneOf[0].scheme).equal("opcua-channel-security");
835893
}
836894

837-
@test "ensure combo security in form"() {
895+
@test "ensure combo security in form - allOf"() {
838896
const ct = new ConsumedThing(WoTClientTest.servient);
839897
ct.securityDefinitions = {
840898
basic_sc: {
@@ -858,9 +916,11 @@ class WoTClientTest {
858916
security: ["combo_sc"],
859917
};
860918
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");
919+
expect(pc.securitySchemes.length).equals(1);
920+
const comboScheme = pc.securitySchemes[0] as AllOfSecurityScheme;
921+
922+
expect(comboScheme.allOf[0].scheme).equals("opcua-channel-security");
923+
expect(comboScheme.allOf[1].scheme).equals("opcua-authentication");
864924
}
865925

866926
@test "ensure no infinite loop with recursive combo security"() {
@@ -879,6 +939,6 @@ class WoTClientTest {
879939
security: ["combo_sc"],
880940
};
881941
ct.ensureClientSecurity(pc, form);
882-
expect(pc.securitySchemes.length).equals(0);
942+
expect(pc.securitySchemes.length).equals(1);
883943
}
884944
}

0 commit comments

Comments
 (0)