node-opcua-server 2.66.3 → 2.67.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/opcua_server.d.ts +3 -10
- package/dist/opcua_server.js +8 -13
- package/dist/opcua_server.js.map +1 -1
- package/dist/server_engine.js.map +1 -1
- package/dist/server_session.js +6 -5
- package/dist/server_session.js.map +1 -1
- package/dist/server_subscription.js +1 -1
- package/dist/server_subscription.js.map +1 -1
- package/dist/user_manager.d.ts +32 -0
- package/dist/user_manager.js +72 -0
- package/dist/user_manager.js.map +1 -0
- package/dist/user_manager_ua.d.ts +3 -0
- package/dist/user_manager_ua.js +40 -0
- package/dist/user_manager_ua.js.map +1 -0
- package/package.json +44 -43
- package/source/index.ts +1 -0
- package/source/opcua_server.ts +30 -34
- package/source/server_engine.ts +5 -2
- package/source/server_session.ts +8 -6
- package/source/server_subscription.ts +1 -1
- package/source/user_manager.ts +81 -0
- package/source/user_manager_ua.ts +44 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { IUserManager, UARoleSet } from "node-opcua-address-space";
|
|
2
|
+
import { NodeId } from "node-opcua-nodeid";
|
|
3
|
+
import { IdentityMappingRuleType } from "node-opcua-types";
|
|
4
|
+
import { ServerSession } from "./server_session";
|
|
5
|
+
export declare type ValidUserFunc = (this: ServerSession, username: string, password: string) => boolean;
|
|
6
|
+
export declare type ValidUserAsyncFunc = (this: ServerSession, username: string, password: string, callback: (err: Error | null, isAuthorized?: boolean) => void) => void;
|
|
7
|
+
export interface IUserManagerEx extends IUserManager {
|
|
8
|
+
/** synchronous function to check the credentials - can be overruled by isValidUserAsync */
|
|
9
|
+
isValidUser?: ValidUserFunc;
|
|
10
|
+
/** asynchronous function to check if the credentials - overrules isValidUser */
|
|
11
|
+
isValidUserAsync?: ValidUserAsyncFunc;
|
|
12
|
+
}
|
|
13
|
+
export declare type UserManagerOptions = IUserManagerEx | UAUserManagerBase;
|
|
14
|
+
export interface IUAUserManager extends IUserManager {
|
|
15
|
+
getUserRoles(user: string): NodeId[];
|
|
16
|
+
isValidUser(session: ServerSession, username: string, password: string): Promise<boolean>;
|
|
17
|
+
getIdentitiesForRole(role: NodeId): IdentityMappingRuleType[];
|
|
18
|
+
}
|
|
19
|
+
export declare abstract class UAUserManagerBase implements IUAUserManager {
|
|
20
|
+
getUserRoles(user: string): NodeId[];
|
|
21
|
+
isValidUser(session: ServerSession, username: string, password: string): Promise<boolean>;
|
|
22
|
+
getIdentitiesForRole(role: NodeId): IdentityMappingRuleType[];
|
|
23
|
+
bind(roleSet: UARoleSet): void;
|
|
24
|
+
}
|
|
25
|
+
export declare class UAUserManager1 extends UAUserManagerBase {
|
|
26
|
+
private options;
|
|
27
|
+
constructor(options: IUserManagerEx);
|
|
28
|
+
getUserRoles(user: string): NodeId[];
|
|
29
|
+
isValidUser(session: ServerSession, username: string, password: string): Promise<boolean>;
|
|
30
|
+
getIdentitiesForRole(role: NodeId): IdentityMappingRuleType[];
|
|
31
|
+
}
|
|
32
|
+
export declare function makeUserManager(options?: UserManagerOptions): UAUserManagerBase;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.makeUserManager = exports.UAUserManager1 = exports.UAUserManagerBase = void 0;
|
|
13
|
+
class UAUserManagerBase {
|
|
14
|
+
getUserRoles(user) {
|
|
15
|
+
throw new Error("Method not implemented.");
|
|
16
|
+
}
|
|
17
|
+
isValidUser(session, username, password) {
|
|
18
|
+
throw new Error("Method not implemented.");
|
|
19
|
+
}
|
|
20
|
+
getIdentitiesForRole(role) {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
bind(roleSet) {
|
|
24
|
+
/** */
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.UAUserManagerBase = UAUserManagerBase;
|
|
28
|
+
class UAUserManager1 extends UAUserManagerBase {
|
|
29
|
+
constructor(options) {
|
|
30
|
+
super();
|
|
31
|
+
this.options = options;
|
|
32
|
+
}
|
|
33
|
+
getUserRoles(user) {
|
|
34
|
+
return this.options.getUserRoles(user);
|
|
35
|
+
}
|
|
36
|
+
isValidUser(session, username, password) {
|
|
37
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
38
|
+
if (typeof this.options.isValidUserAsync === "function") {
|
|
39
|
+
return new Promise((resolve, reject) => {
|
|
40
|
+
var _a;
|
|
41
|
+
(_a = this.options.isValidUserAsync) === null || _a === void 0 ? void 0 : _a.call(session, username, password, (err, isAuthorized) => {
|
|
42
|
+
if (err)
|
|
43
|
+
return reject();
|
|
44
|
+
resolve(isAuthorized);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
const authorized = this.options.isValidUser.call(session, username, password);
|
|
50
|
+
return authorized;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
getIdentitiesForRole(role) {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.UAUserManager1 = UAUserManager1;
|
|
59
|
+
function makeUserManager(options) {
|
|
60
|
+
if (options instanceof UAUserManagerBase) {
|
|
61
|
+
return options;
|
|
62
|
+
}
|
|
63
|
+
options = options || {};
|
|
64
|
+
if (typeof options.isValidUser !== "function") {
|
|
65
|
+
options.isValidUser = ( /*userName,password*/) => {
|
|
66
|
+
return false;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return new UAUserManager1(options);
|
|
70
|
+
}
|
|
71
|
+
exports.makeUserManager = makeUserManager;
|
|
72
|
+
//# sourceMappingURL=user_manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user_manager.js","sourceRoot":"","sources":["../source/user_manager.ts"],"names":[],"mappings":";;;;;;;;;;;;AA4BA,MAAsB,iBAAiB;IACnC,YAAY,CAAC,IAAY;QACrB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC/C,CAAC;IACD,WAAW,CAAC,OAAsB,EAAE,QAAgB,EAAE,QAAgB;QAClE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC/C,CAAC;IACD,oBAAoB,CAAC,IAAY;QAC7B,OAAO,EAAE,CAAC;IACd,CAAC;IACD,IAAI,CAAC,OAAkB;QACnB,OAAO;IACX,CAAC;CACJ;AAbD,8CAaC;AACD,MAAa,cAAe,SAAQ,iBAAiB;IACjD,YAAoB,OAAuB;QACvC,KAAK,EAAE,CAAC;QADQ,YAAO,GAAP,OAAO,CAAgB;IAE3C,CAAC;IACD,YAAY,CAAC,IAAY;QACrB,OAAO,IAAI,CAAC,OAAO,CAAC,YAAa,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC;IAEK,WAAW,CAAC,OAAsB,EAAE,QAAgB,EAAE,QAAgB;;YACxE,IAAI,OAAO,IAAI,CAAC,OAAO,CAAC,gBAAgB,KAAK,UAAU,EAAE;gBACrD,OAAO,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;;oBAC5C,MAAA,IAAI,CAAC,OAAO,CAAC,gBAAgB,0CAAE,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,YAAY,EAAE,EAAE;wBACnF,IAAI,GAAG;4BAAE,OAAO,MAAM,EAAE,CAAC;wBACzB,OAAO,CAAC,YAAa,CAAC,CAAC;oBAC3B,CAAC,CAAC,CAAC;gBACP,CAAC,CAAC,CAAC;aACN;iBAAM;gBACH,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,WAAY,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;gBAC/E,OAAO,UAAU,CAAC;aACrB;QACL,CAAC;KAAA;IACD,oBAAoB,CAAC,IAAY;QAC7B,OAAO,EAAE,CAAC;IACd,CAAC;CACJ;AAxBD,wCAwBC;AAED,SAAgB,eAAe,CAAC,OAA4B;IACxD,IAAI,OAAO,YAAY,iBAAiB,EAAE;QACtC,OAAO,OAAO,CAAC;KAClB;IACD,OAAO,GAAG,OAAO,IAAI,EAAE,CAAC;IAExB,IAAI,OAAO,OAAO,CAAC,WAAW,KAAK,UAAU,EAAE;QAC3C,OAAO,CAAC,WAAW,GAAG,EAAC,qBAAqB,EAAE,EAAE;YAC5C,OAAO,KAAK,CAAC;QACjB,CAAC,CAAC;KACL;IACD,OAAO,IAAI,cAAc,CAAC,OAAyB,CAAC,CAAC;AACzD,CAAC;AAZD,0CAYC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.bindRoleSet = void 0;
|
|
4
|
+
const node_opcua_constants_1 = require("node-opcua-constants");
|
|
5
|
+
const node_opcua_address_space_1 = require("node-opcua-address-space");
|
|
6
|
+
const node_opcua_variant_1 = require("node-opcua-variant");
|
|
7
|
+
const node_opcua_data_model_1 = require("node-opcua-data-model");
|
|
8
|
+
function bindRoleSet(userManager, addressSpace) {
|
|
9
|
+
var _a;
|
|
10
|
+
const roleSet = addressSpace.findNode(node_opcua_constants_1.ObjectIds.Server_ServerCapabilities_RoleSet);
|
|
11
|
+
if (!roleSet)
|
|
12
|
+
return;
|
|
13
|
+
const components = roleSet.getComponents();
|
|
14
|
+
for (const component of components) {
|
|
15
|
+
(0, node_opcua_address_space_1.ensureObjectIsSecure)(component);
|
|
16
|
+
if (component.nodeClass !== node_opcua_data_model_1.NodeClass.Object) {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
const o = component;
|
|
20
|
+
if (o.typeDefinitionObj.browseName.name !== "RoleType") {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const roleType = o;
|
|
24
|
+
const roleTypeProperties = roleType.findReferencesAsObject("HasChild", false);
|
|
25
|
+
for (const roleTypeProp of roleTypeProperties) {
|
|
26
|
+
(0, node_opcua_address_space_1.ensureObjectIsSecure)(roleTypeProp);
|
|
27
|
+
}
|
|
28
|
+
roleType.identities.setValueFromSource({ dataType: node_opcua_variant_1.DataType.ExtensionObject, value: [] });
|
|
29
|
+
(_a = roleType.endpoints) === null || _a === void 0 ? void 0 : _a.setValueFromSource({ dataType: node_opcua_variant_1.DataType.ExtensionObject, value: [] });
|
|
30
|
+
roleType.identities.bindVariable({
|
|
31
|
+
get: () => {
|
|
32
|
+
const identities = userManager.getIdentitiesForRole(roleType.nodeId);
|
|
33
|
+
return new node_opcua_variant_1.Variant({ dataType: node_opcua_variant_1.DataType.ExtensionObject, value: identities });
|
|
34
|
+
}
|
|
35
|
+
}, true);
|
|
36
|
+
}
|
|
37
|
+
userManager.bind(roleSet);
|
|
38
|
+
}
|
|
39
|
+
exports.bindRoleSet = bindRoleSet;
|
|
40
|
+
//# sourceMappingURL=user_manager_ua.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user_manager_ua.js","sourceRoot":"","sources":["../source/user_manager_ua.ts"],"names":[],"mappings":";;;AAAA,+DAAiD;AAEjD,uEAAgE;AAChE,2DAAuD;AACvD,iEAAkD;AAGlD,SAAgB,WAAW,CAAC,WAA8B,EAAE,YAA2B;;IACnF,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,CAAC,gCAAS,CAAC,iCAAiC,CAAc,CAAC;IAChG,IAAI,CAAC,OAAO;QAAE,OAAO;IAErB,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAC3C,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE;QAChC,IAAA,+CAAoB,EAAC,SAAS,CAAC,CAAC;QAChC,IAAI,SAAS,CAAC,SAAS,KAAK,iCAAS,CAAC,MAAM,EAAE;YAC1C,SAAS;SACZ;QACD,MAAM,CAAC,GAAG,SAAqB,CAAC;QAChC,IAAI,CAAC,CAAC,iBAAiB,CAAC,UAAU,CAAC,IAAI,KAAK,UAAU,EAAE;YACpD,SAAS;SACZ;QACD,MAAM,QAAQ,GAAG,CAAW,CAAC;QAC7B,MAAM,kBAAkB,GAAG,QAAQ,CAAC,sBAAsB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAC9E,KAAK,MAAM,YAAY,IAAI,kBAAkB,EAAE;YAC3C,IAAA,+CAAoB,EAAC,YAAY,CAAC,CAAC;SACtC;QACD,QAAQ,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,QAAQ,EAAE,6BAAQ,CAAC,eAAe,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAE1F,MAAA,QAAQ,CAAC,SAAS,0CAAE,kBAAkB,CAAC,EAAE,QAAQ,EAAE,6BAAQ,CAAC,eAAe,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAC1F,QAAQ,CAAC,UAAU,CAAC,YAAY,CAC5B;YACI,GAAG,EAAE,GAAG,EAAE;gBACN,MAAM,UAAU,GAAG,WAAW,CAAC,oBAAoB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;gBAErE,OAAO,IAAI,4BAAO,CAAC,EAAE,QAAQ,EAAE,6BAAQ,CAAC,eAAe,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;YAClF,CAAC;SACJ,EACD,IAAI,CACP,CAAC;KACL;IAED,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAE9B,CAAC;AApCD,kCAoCC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-opcua-server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.67.0",
|
|
4
4
|
"description": "pure nodejs OPCUA SDK - module -server",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "tsc -b",
|
|
@@ -18,53 +18,54 @@
|
|
|
18
18
|
"bonjour": "^3.5.0",
|
|
19
19
|
"dequeue": "^1.0.5",
|
|
20
20
|
"lodash": "4.17.21",
|
|
21
|
-
"node-opcua-address-space": "2.
|
|
21
|
+
"node-opcua-address-space": "2.67.0",
|
|
22
22
|
"node-opcua-assert": "2.66.0",
|
|
23
|
-
"node-opcua-basic-types": "2.
|
|
24
|
-
"node-opcua-certificate-manager": "2.
|
|
25
|
-
"node-opcua-client": "2.
|
|
26
|
-
"node-opcua-client-dynamic-extension-object": "2.
|
|
27
|
-
"node-opcua-common": "2.
|
|
28
|
-
"node-opcua-constants": "2.
|
|
23
|
+
"node-opcua-basic-types": "2.67.0",
|
|
24
|
+
"node-opcua-certificate-manager": "2.67.0",
|
|
25
|
+
"node-opcua-client": "2.67.0",
|
|
26
|
+
"node-opcua-client-dynamic-extension-object": "2.67.0",
|
|
27
|
+
"node-opcua-common": "2.67.0",
|
|
28
|
+
"node-opcua-constants": "2.67.0",
|
|
29
29
|
"node-opcua-crypto": "^1.10.0",
|
|
30
|
-
"node-opcua-data-access": "2.
|
|
31
|
-
"node-opcua-data-model": "2.
|
|
32
|
-
"node-opcua-data-value": "2.
|
|
33
|
-
"node-opcua-date-time": "2.
|
|
34
|
-
"node-opcua-debug": "2.
|
|
35
|
-
"node-opcua-enum": "2.
|
|
36
|
-
"node-opcua-extension-object": "2.
|
|
37
|
-
"node-opcua-factory": "2.
|
|
38
|
-
"node-opcua-hostname": "2.
|
|
39
|
-
"node-opcua-nodeid": "2.
|
|
30
|
+
"node-opcua-data-access": "2.67.0",
|
|
31
|
+
"node-opcua-data-model": "2.67.0",
|
|
32
|
+
"node-opcua-data-value": "2.67.0",
|
|
33
|
+
"node-opcua-date-time": "2.67.0",
|
|
34
|
+
"node-opcua-debug": "2.67.0",
|
|
35
|
+
"node-opcua-enum": "2.67.0",
|
|
36
|
+
"node-opcua-extension-object": "2.67.0",
|
|
37
|
+
"node-opcua-factory": "2.67.0",
|
|
38
|
+
"node-opcua-hostname": "2.67.0",
|
|
39
|
+
"node-opcua-nodeid": "2.67.0",
|
|
40
|
+
"node-opcua-nodeset-ua": "2.67.0",
|
|
40
41
|
"node-opcua-nodesets": "2.66.0",
|
|
41
|
-
"node-opcua-numeric-range": "2.
|
|
42
|
-
"node-opcua-object-registry": "2.
|
|
42
|
+
"node-opcua-numeric-range": "2.67.0",
|
|
43
|
+
"node-opcua-object-registry": "2.67.0",
|
|
43
44
|
"node-opcua-pki": "^2.15.4",
|
|
44
|
-
"node-opcua-secure-channel": "2.
|
|
45
|
-
"node-opcua-service-browse": "2.
|
|
46
|
-
"node-opcua-service-call": "2.
|
|
47
|
-
"node-opcua-service-discovery": "2.
|
|
48
|
-
"node-opcua-service-endpoints": "2.
|
|
49
|
-
"node-opcua-service-filter": "2.
|
|
50
|
-
"node-opcua-service-history": "2.
|
|
51
|
-
"node-opcua-service-node-management": "2.
|
|
52
|
-
"node-opcua-service-query": "2.
|
|
53
|
-
"node-opcua-service-read": "2.
|
|
54
|
-
"node-opcua-service-register-node": "2.
|
|
55
|
-
"node-opcua-service-secure-channel": "2.
|
|
56
|
-
"node-opcua-service-session": "2.
|
|
57
|
-
"node-opcua-service-subscription": "2.
|
|
58
|
-
"node-opcua-service-translate-browse-path": "2.
|
|
59
|
-
"node-opcua-service-write": "2.
|
|
60
|
-
"node-opcua-status-code": "2.
|
|
61
|
-
"node-opcua-transport": "2.
|
|
62
|
-
"node-opcua-types": "2.
|
|
63
|
-
"node-opcua-utils": "2.
|
|
64
|
-
"node-opcua-variant": "2.
|
|
45
|
+
"node-opcua-secure-channel": "2.67.0",
|
|
46
|
+
"node-opcua-service-browse": "2.67.0",
|
|
47
|
+
"node-opcua-service-call": "2.67.0",
|
|
48
|
+
"node-opcua-service-discovery": "2.67.0",
|
|
49
|
+
"node-opcua-service-endpoints": "2.67.0",
|
|
50
|
+
"node-opcua-service-filter": "2.67.0",
|
|
51
|
+
"node-opcua-service-history": "2.67.0",
|
|
52
|
+
"node-opcua-service-node-management": "2.67.0",
|
|
53
|
+
"node-opcua-service-query": "2.67.0",
|
|
54
|
+
"node-opcua-service-read": "2.67.0",
|
|
55
|
+
"node-opcua-service-register-node": "2.67.0",
|
|
56
|
+
"node-opcua-service-secure-channel": "2.67.0",
|
|
57
|
+
"node-opcua-service-session": "2.67.0",
|
|
58
|
+
"node-opcua-service-subscription": "2.67.0",
|
|
59
|
+
"node-opcua-service-translate-browse-path": "2.67.0",
|
|
60
|
+
"node-opcua-service-write": "2.67.0",
|
|
61
|
+
"node-opcua-status-code": "2.67.0",
|
|
62
|
+
"node-opcua-transport": "2.67.0",
|
|
63
|
+
"node-opcua-types": "2.67.0",
|
|
64
|
+
"node-opcua-utils": "2.67.0",
|
|
65
|
+
"node-opcua-variant": "2.67.0"
|
|
65
66
|
},
|
|
66
67
|
"devDependencies": {
|
|
67
|
-
"node-opcua-leak-detector": "2.
|
|
68
|
+
"node-opcua-leak-detector": "2.67.0",
|
|
68
69
|
"node-opcua-test-helpers": "2.66.0",
|
|
69
70
|
"should": "^13.2.3",
|
|
70
71
|
"sinon": "^13.0.1"
|
|
@@ -84,5 +85,5 @@
|
|
|
84
85
|
"internet of things"
|
|
85
86
|
],
|
|
86
87
|
"homepage": "http://node-opcua.github.io/",
|
|
87
|
-
"gitHead": "
|
|
88
|
+
"gitHead": "74c2fd7d4ce3eb48d25a911258bf90a64218ea0e"
|
|
88
89
|
}
|
package/source/index.ts
CHANGED
package/source/opcua_server.ts
CHANGED
|
@@ -42,9 +42,13 @@ import {
|
|
|
42
42
|
} from "node-opcua-address-space";
|
|
43
43
|
import { getDefaultCertificateManager, OPCUACertificateManager } from "node-opcua-certificate-manager";
|
|
44
44
|
import { ServerState } from "node-opcua-common";
|
|
45
|
-
import { Certificate, exploreCertificate,
|
|
45
|
+
import { Certificate, exploreCertificate, Nonce } from "node-opcua-crypto";
|
|
46
46
|
import {
|
|
47
|
-
AttributeIds,
|
|
47
|
+
AttributeIds,
|
|
48
|
+
filterDiagnosticOperationLevel,
|
|
49
|
+
filterDiagnosticServiceLevel,
|
|
50
|
+
NodeClass,
|
|
51
|
+
RESPONSE_DIAGNOSTICS_MASK_ALL
|
|
48
52
|
} from "node-opcua-data-model";
|
|
49
53
|
import { DataValue } from "node-opcua-data-value";
|
|
50
54
|
import { dump, make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
|
|
@@ -162,26 +166,14 @@ import { ServerSession } from "./server_session";
|
|
|
162
166
|
import { CreateMonitoredItemHook, DeleteMonitoredItemHook, Subscription } from "./server_subscription";
|
|
163
167
|
import { ISocketData } from "./i_socket_data";
|
|
164
168
|
import { IChannelData } from "./i_channel_data";
|
|
169
|
+
import { UAUserManagerBase, makeUserManager, UserManagerOptions } from "./user_manager";
|
|
170
|
+
import { bindRoleSet} from "./user_manager_ua";
|
|
171
|
+
|
|
165
172
|
|
|
166
173
|
function isSubscriptionIdInvalid(subscriptionId: number): boolean {
|
|
167
174
|
return subscriptionId < 0 || subscriptionId >= 0xffffffff;
|
|
168
175
|
}
|
|
169
176
|
|
|
170
|
-
export type ValidUserFunc = (this: ServerSession, username: string, password: string) => boolean;
|
|
171
|
-
export type ValidUserAsyncFunc = (
|
|
172
|
-
this: ServerSession,
|
|
173
|
-
username: string,
|
|
174
|
-
password: string,
|
|
175
|
-
callback: (err: Error | null, isAuthorized?: boolean) => void
|
|
176
|
-
) => void;
|
|
177
|
-
|
|
178
|
-
export interface UserManagerOptions extends IUserManager {
|
|
179
|
-
/** synchronous function to check the credentials - can be overruled by isValidUserAsync */
|
|
180
|
-
isValidUser?: ValidUserFunc;
|
|
181
|
-
/** asynchronous function to check if the credentials - overrules isValidUser */
|
|
182
|
-
isValidUserAsync?: ValidUserAsyncFunc;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
177
|
// tslint:disable-next-line:no-var-requires
|
|
186
178
|
const thenify = require("thenify");
|
|
187
179
|
// tslint:disable-next-line:no-var-requires
|
|
@@ -681,7 +673,10 @@ function validate_security_endpoint(
|
|
|
681
673
|
|
|
682
674
|
export function filterDiagnosticInfo(returnDiagnostics: number, response: CallResponse): void {
|
|
683
675
|
if (RESPONSE_DIAGNOSTICS_MASK_ALL & returnDiagnostics) {
|
|
684
|
-
response.responseHeader.serviceDiagnostics = filterDiagnosticServiceLevel(
|
|
676
|
+
response.responseHeader.serviceDiagnostics = filterDiagnosticServiceLevel(
|
|
677
|
+
returnDiagnostics,
|
|
678
|
+
response.responseHeader.serviceDiagnostics
|
|
679
|
+
);
|
|
685
680
|
|
|
686
681
|
if (response.diagnosticInfos && response.diagnosticInfos.length > 0) {
|
|
687
682
|
response.diagnosticInfos = response.diagnosticInfos.map((d) => filterDiagnosticOperationLevel(returnDiagnostics, d));
|
|
@@ -692,8 +687,8 @@ export function filterDiagnosticInfo(returnDiagnostics: number, response: CallRe
|
|
|
692
687
|
if (response.results) {
|
|
693
688
|
for (const entry of response.results) {
|
|
694
689
|
if (entry.inputArgumentDiagnosticInfos && entry.inputArgumentDiagnosticInfos.length > 0) {
|
|
695
|
-
entry.inputArgumentDiagnosticInfos = entry.inputArgumentDiagnosticInfos.map(
|
|
696
|
-
|
|
690
|
+
entry.inputArgumentDiagnosticInfos = entry.inputArgumentDiagnosticInfos.map((d) =>
|
|
691
|
+
filterDiagnosticOperationLevel(returnDiagnostics, d)
|
|
697
692
|
);
|
|
698
693
|
} else {
|
|
699
694
|
entry.inputArgumentDiagnosticInfos = [];
|
|
@@ -1059,7 +1054,8 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1059
1054
|
/**
|
|
1060
1055
|
* the user manager
|
|
1061
1056
|
*/
|
|
1062
|
-
public userManager:
|
|
1057
|
+
public userManager: UAUserManagerBase;
|
|
1058
|
+
|
|
1063
1059
|
public readonly options: OPCUAServerOptions;
|
|
1064
1060
|
|
|
1065
1061
|
private objectFactory?: Factory;
|
|
@@ -1093,12 +1089,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1093
1089
|
buildInfo.productUri = buildInfo.productUri || this.serverInfo.productUri;
|
|
1094
1090
|
this.serverInfo.productUri = this.serverInfo.productUri || buildInfo.productUri;
|
|
1095
1091
|
|
|
1096
|
-
this.userManager = options.userManager
|
|
1097
|
-
if (typeof this.userManager.isValidUser !== "function") {
|
|
1098
|
-
this.userManager.isValidUser = (/*userName,password*/) => {
|
|
1099
|
-
return false;
|
|
1100
|
-
};
|
|
1101
|
-
}
|
|
1092
|
+
this.userManager = makeUserManager(options.userManager);
|
|
1102
1093
|
|
|
1103
1094
|
options.allowAnonymous = options.allowAnonymous === undefined ? true : !!options.allowAnonymous;
|
|
1104
1095
|
/**
|
|
@@ -1212,6 +1203,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1212
1203
|
.then(() => {
|
|
1213
1204
|
OPCUAServer.registry.register(this);
|
|
1214
1205
|
this.engine.initialize(this.options, () => {
|
|
1206
|
+
bindRoleSet(this.userManager, this.engine.addressSpace!);
|
|
1215
1207
|
setImmediate(() => {
|
|
1216
1208
|
this.emit("post_initialize");
|
|
1217
1209
|
done();
|
|
@@ -1596,12 +1588,10 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1596
1588
|
password = buff.slice(4, 4 + length).toString("utf-8");
|
|
1597
1589
|
}
|
|
1598
1590
|
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
async.setImmediate(() => callback(null, authorized));
|
|
1604
|
-
}
|
|
1591
|
+
this.userManager
|
|
1592
|
+
.isValidUser(session, userName, password)
|
|
1593
|
+
.then((isValid) => callback(null, isValid))
|
|
1594
|
+
.catch((err) => callback(err));
|
|
1605
1595
|
}
|
|
1606
1596
|
|
|
1607
1597
|
/**
|
|
@@ -2185,7 +2175,13 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2185
2175
|
// --- check that provided session matches session attached to channel
|
|
2186
2176
|
if (channel.channelId !== session.channelId) {
|
|
2187
2177
|
if (!(request instanceof ActivateSessionRequest)) {
|
|
2188
|
-
errorLog(
|
|
2178
|
+
errorLog(
|
|
2179
|
+
chalk.red.bgWhite(
|
|
2180
|
+
"ERROR: channel.channelId !== session.channelId on processing request " + request.constructor.name
|
|
2181
|
+
),
|
|
2182
|
+
channel.channelId,
|
|
2183
|
+
session.channelId
|
|
2184
|
+
);
|
|
2189
2185
|
}
|
|
2190
2186
|
message.session_statusCode = StatusCodes.BadSecureChannelIdInvalid;
|
|
2191
2187
|
} else if (channel_has_session(channel, session)) {
|
package/source/server_engine.ts
CHANGED
|
@@ -28,7 +28,8 @@ import {
|
|
|
28
28
|
ISessionContext,
|
|
29
29
|
DTServerStatus,
|
|
30
30
|
resolveOpaqueOnAddressSpace,
|
|
31
|
-
ContinuationData
|
|
31
|
+
ContinuationData,
|
|
32
|
+
UARole
|
|
32
33
|
} from "node-opcua-address-space";
|
|
33
34
|
import { generateAddressSpace } from "node-opcua-address-space/nodeJS";
|
|
34
35
|
import { DataValue, coerceTimestampsToReturn, apply_timestamps_no_copy } from "node-opcua-data-value";
|
|
@@ -358,7 +359,7 @@ export class ServerEngine extends EventEmitter {
|
|
|
358
359
|
|
|
359
360
|
// "http://opcfoundation.org/UA-Profile/Server/ReverseConnect",
|
|
360
361
|
// "http://opcfoundation.org/UAProfile/Server/NodeManagement",
|
|
361
|
-
|
|
362
|
+
|
|
362
363
|
// "Embedded UA Server Profile",
|
|
363
364
|
// "Micro Embedded Device Server Profile",
|
|
364
365
|
// "Nano Embedded Device Server Profile"
|
|
@@ -1077,6 +1078,8 @@ export class ServerEngine extends EventEmitter {
|
|
|
1077
1078
|
});
|
|
1078
1079
|
};
|
|
1079
1080
|
|
|
1081
|
+
|
|
1082
|
+
|
|
1080
1083
|
bindServerDiagnostics();
|
|
1081
1084
|
|
|
1082
1085
|
bindServerStatus();
|
package/source/server_session.ts
CHANGED
|
@@ -26,7 +26,7 @@ import { assert } from "node-opcua-assert";
|
|
|
26
26
|
import { minOPCUADate, randomGuid } from "node-opcua-basic-types";
|
|
27
27
|
import { SessionDiagnosticsDataType, SessionSecurityDiagnosticsDataType, SubscriptionDiagnosticsDataType } from "node-opcua-common";
|
|
28
28
|
import { QualifiedName, NodeClass } from "node-opcua-data-model";
|
|
29
|
-
import { checkDebugFlag, make_debugLog } from "node-opcua-debug";
|
|
29
|
+
import { checkDebugFlag, make_debugLog, make_errorLog } from "node-opcua-debug";
|
|
30
30
|
import { makeNodeId, NodeId, NodeIdType, sameNodeId } from "node-opcua-nodeid";
|
|
31
31
|
import { ObjectRegistry } from "node-opcua-object-registry";
|
|
32
32
|
import { StatusCode, StatusCodes } from "node-opcua-status-code";
|
|
@@ -43,7 +43,9 @@ import { SubscriptionState } from "./server_subscription";
|
|
|
43
43
|
import { ServerEngine } from "./server_engine";
|
|
44
44
|
|
|
45
45
|
const debugLog = make_debugLog(__filename);
|
|
46
|
+
const errorLog = make_errorLog(__filename);
|
|
46
47
|
const doDebug = checkDebugFlag(__filename);
|
|
48
|
+
|
|
47
49
|
const theWatchDog = new WatchDog();
|
|
48
50
|
|
|
49
51
|
const registeredNodeNameSpace = 9999;
|
|
@@ -299,11 +301,11 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
299
301
|
public incrementRequestTotalCounter(counterName: string): void {
|
|
300
302
|
if (this._sessionDiagnostics) {
|
|
301
303
|
const propName = lowerFirstLetter(counterName + "Count");
|
|
304
|
+
// istanbul ignore next
|
|
302
305
|
if (!Object.prototype.hasOwnProperty.call(this._sessionDiagnostics, propName)) {
|
|
303
|
-
|
|
306
|
+
errorLog("incrementRequestTotalCounter: cannot find", propName);
|
|
304
307
|
// xx return;
|
|
305
308
|
} else {
|
|
306
|
-
// console.log(self._sessionDiagnostics.toString());
|
|
307
309
|
(this._sessionDiagnostics as any)[propName].totalCount += 1;
|
|
308
310
|
}
|
|
309
311
|
}
|
|
@@ -313,8 +315,9 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
313
315
|
this.parent?.incrementRejectedRequestsCount();
|
|
314
316
|
if (this._sessionDiagnostics) {
|
|
315
317
|
const propName = lowerFirstLetter(counterName + "Count");
|
|
318
|
+
// istanbul ignore next
|
|
316
319
|
if (!Object.prototype.hasOwnProperty.call(this._sessionDiagnostics, propName)) {
|
|
317
|
-
|
|
320
|
+
errorLog("incrementRequestErrorCounter: cannot find", propName);
|
|
318
321
|
// xx return;
|
|
319
322
|
} else {
|
|
320
323
|
(this._sessionDiagnostics as any)[propName].errorCount += 1;
|
|
@@ -428,7 +431,7 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
428
431
|
|
|
429
432
|
if (!deleteSubscriptions && this.currentSubscriptionCount !== 0) {
|
|
430
433
|
// I don't know what to do yet if deleteSubscriptions is false
|
|
431
|
-
|
|
434
|
+
errorLog("TO DO : Closing session without deleting subscription not yet implemented");
|
|
432
435
|
// to do: Put subscriptions in safe place for future transfer if any
|
|
433
436
|
}
|
|
434
437
|
|
|
@@ -593,7 +596,6 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
593
596
|
const subscriptionDiagnostics = subscription.subscriptionDiagnostics;
|
|
594
597
|
assert(subscriptionDiagnostics instanceof SubscriptionDiagnosticsDataType);
|
|
595
598
|
if (subscriptionDiagnostics && subscriptionDiagnosticsArray) {
|
|
596
|
-
// console.log("GG => ServerSession **Unexposing** subscription diagnostics =>",
|
|
597
599
|
// subscription.id,"on session", session.nodeId.toString());
|
|
598
600
|
removeElement(subscriptionDiagnosticsArray, subscriptionDiagnostics);
|
|
599
601
|
}
|
|
@@ -123,7 +123,7 @@ function _adjust_maxNotificationsPerPublish(maxNotificationsPerPublish?: number)
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
function w(s: string | number, length: number): string {
|
|
126
|
-
return ("000" + s).
|
|
126
|
+
return ("000" + s).padStart(length);
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
function t(d: Date): string {
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { IUserManager, UARoleSet } from "node-opcua-address-space";
|
|
2
|
+
import { NodeId } from "node-opcua-nodeid";
|
|
3
|
+
import { IdentityMappingRuleType } from "node-opcua-types";
|
|
4
|
+
import { ServerSession } from "./server_session";
|
|
5
|
+
|
|
6
|
+
export type ValidUserFunc = (this: ServerSession, username: string, password: string) => boolean;
|
|
7
|
+
export type ValidUserAsyncFunc = (
|
|
8
|
+
this: ServerSession,
|
|
9
|
+
username: string,
|
|
10
|
+
password: string,
|
|
11
|
+
callback: (err: Error | null, isAuthorized?: boolean) => void
|
|
12
|
+
) => void;
|
|
13
|
+
|
|
14
|
+
export interface IUserManagerEx extends IUserManager {
|
|
15
|
+
/** synchronous function to check the credentials - can be overruled by isValidUserAsync */
|
|
16
|
+
isValidUser?: ValidUserFunc;
|
|
17
|
+
/** asynchronous function to check if the credentials - overrules isValidUser */
|
|
18
|
+
isValidUserAsync?: ValidUserAsyncFunc;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type UserManagerOptions = IUserManagerEx | UAUserManagerBase;
|
|
22
|
+
|
|
23
|
+
export interface IUAUserManager extends IUserManager {
|
|
24
|
+
getUserRoles(user: string): NodeId[];
|
|
25
|
+
isValidUser(session: ServerSession, username: string, password: string): Promise<boolean>;
|
|
26
|
+
getIdentitiesForRole(role: NodeId): IdentityMappingRuleType[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export abstract class UAUserManagerBase implements IUAUserManager {
|
|
30
|
+
getUserRoles(user: string): NodeId[] {
|
|
31
|
+
throw new Error("Method not implemented.");
|
|
32
|
+
}
|
|
33
|
+
isValidUser(session: ServerSession, username: string, password: string): Promise<boolean> {
|
|
34
|
+
throw new Error("Method not implemented.");
|
|
35
|
+
}
|
|
36
|
+
getIdentitiesForRole(role: NodeId): IdentityMappingRuleType[] {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
bind(roleSet: UARoleSet): void {
|
|
40
|
+
/** */
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export class UAUserManager1 extends UAUserManagerBase {
|
|
44
|
+
constructor(private options: IUserManagerEx) {
|
|
45
|
+
super();
|
|
46
|
+
}
|
|
47
|
+
getUserRoles(user: string): NodeId[] {
|
|
48
|
+
return this.options.getUserRoles!(user);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async isValidUser(session: ServerSession, username: string, password: string): Promise<boolean> {
|
|
52
|
+
if (typeof this.options.isValidUserAsync === "function") {
|
|
53
|
+
return new Promise<boolean>((resolve, reject) => {
|
|
54
|
+
this.options.isValidUserAsync?.call(session, username, password, (err, isAuthorized) => {
|
|
55
|
+
if (err) return reject();
|
|
56
|
+
resolve(isAuthorized!);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
} else {
|
|
60
|
+
const authorized = this.options.isValidUser!.call(session, username, password);
|
|
61
|
+
return authorized;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
getIdentitiesForRole(role: NodeId): IdentityMappingRuleType[] {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function makeUserManager(options?: UserManagerOptions): UAUserManagerBase {
|
|
70
|
+
if (options instanceof UAUserManagerBase) {
|
|
71
|
+
return options;
|
|
72
|
+
}
|
|
73
|
+
options = options || {};
|
|
74
|
+
|
|
75
|
+
if (typeof options.isValidUser !== "function") {
|
|
76
|
+
options.isValidUser = (/*userName,password*/) => {
|
|
77
|
+
return false;
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
return new UAUserManager1(options as IUserManagerEx);
|
|
81
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ObjectIds } from "node-opcua-constants";
|
|
2
|
+
import { IAddressSpace, UAObject, UARole , UARoleSet} from "node-opcua-address-space";
|
|
3
|
+
import { ensureObjectIsSecure } from "node-opcua-address-space";
|
|
4
|
+
import { Variant, DataType } from "node-opcua-variant";
|
|
5
|
+
import { NodeClass } from "node-opcua-data-model";
|
|
6
|
+
import { UAUserManagerBase } from "./user_manager";
|
|
7
|
+
|
|
8
|
+
export function bindRoleSet(userManager: UAUserManagerBase, addressSpace: IAddressSpace) {
|
|
9
|
+
const roleSet = addressSpace.findNode(ObjectIds.Server_ServerCapabilities_RoleSet) as UARoleSet;
|
|
10
|
+
if (!roleSet) return;
|
|
11
|
+
|
|
12
|
+
const components = roleSet.getComponents();
|
|
13
|
+
for (const component of components) {
|
|
14
|
+
ensureObjectIsSecure(component);
|
|
15
|
+
if (component.nodeClass !== NodeClass.Object) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
const o = component as UAObject;
|
|
19
|
+
if (o.typeDefinitionObj.browseName.name !== "RoleType") {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const roleType = o as UARole;
|
|
23
|
+
const roleTypeProperties = roleType.findReferencesAsObject("HasChild", false);
|
|
24
|
+
for (const roleTypeProp of roleTypeProperties) {
|
|
25
|
+
ensureObjectIsSecure(roleTypeProp);
|
|
26
|
+
}
|
|
27
|
+
roleType.identities.setValueFromSource({ dataType: DataType.ExtensionObject, value: [] });
|
|
28
|
+
|
|
29
|
+
roleType.endpoints?.setValueFromSource({ dataType: DataType.ExtensionObject, value: [] });
|
|
30
|
+
roleType.identities.bindVariable(
|
|
31
|
+
{
|
|
32
|
+
get: () => {
|
|
33
|
+
const identities = userManager.getIdentitiesForRole(roleType.nodeId);
|
|
34
|
+
|
|
35
|
+
return new Variant({ dataType: DataType.ExtensionObject, value: identities });
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
true
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
userManager.bind(roleSet);
|
|
43
|
+
|
|
44
|
+
}
|