node-opcua-server 2.66.1 → 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.
@@ -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,3 @@
1
+ import { IAddressSpace } from "node-opcua-address-space";
2
+ import { UAUserManagerBase } from "./user_manager";
3
+ export declare function bindRoleSet(userManager: UAUserManagerBase, addressSpace: IAddressSpace): void;
@@ -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.66.1",
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.66.1",
21
+ "node-opcua-address-space": "2.67.0",
22
22
  "node-opcua-assert": "2.66.0",
23
- "node-opcua-basic-types": "2.66.0",
24
- "node-opcua-certificate-manager": "2.66.1",
25
- "node-opcua-client": "2.66.1",
26
- "node-opcua-client-dynamic-extension-object": "2.66.1",
27
- "node-opcua-common": "2.66.0",
28
- "node-opcua-constants": "2.66.0",
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.66.0",
31
- "node-opcua-data-model": "2.66.0",
32
- "node-opcua-data-value": "2.66.0",
33
- "node-opcua-date-time": "2.66.0",
34
- "node-opcua-debug": "2.66.0",
35
- "node-opcua-enum": "2.66.0",
36
- "node-opcua-extension-object": "2.66.0",
37
- "node-opcua-factory": "2.66.0",
38
- "node-opcua-hostname": "2.66.0",
39
- "node-opcua-nodeid": "2.66.0",
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.66.0",
42
- "node-opcua-object-registry": "2.66.0",
43
- "node-opcua-pki": "^2.15.1",
44
- "node-opcua-secure-channel": "2.66.1",
45
- "node-opcua-service-browse": "2.66.0",
46
- "node-opcua-service-call": "2.66.0",
47
- "node-opcua-service-discovery": "2.66.0",
48
- "node-opcua-service-endpoints": "2.66.0",
49
- "node-opcua-service-filter": "2.66.0",
50
- "node-opcua-service-history": "2.66.0",
51
- "node-opcua-service-node-management": "2.66.0",
52
- "node-opcua-service-query": "2.66.1",
53
- "node-opcua-service-read": "2.66.0",
54
- "node-opcua-service-register-node": "2.66.0",
55
- "node-opcua-service-secure-channel": "2.66.0",
56
- "node-opcua-service-session": "2.66.0",
57
- "node-opcua-service-subscription": "2.66.1",
58
- "node-opcua-service-translate-browse-path": "2.66.0",
59
- "node-opcua-service-write": "2.66.0",
60
- "node-opcua-status-code": "2.66.0",
61
- "node-opcua-transport": "2.66.0",
62
- "node-opcua-types": "2.66.0",
63
- "node-opcua-utils": "2.66.0",
64
- "node-opcua-variant": "2.66.0"
42
+ "node-opcua-numeric-range": "2.67.0",
43
+ "node-opcua-object-registry": "2.67.0",
44
+ "node-opcua-pki": "^2.15.4",
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.66.0",
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": "1a6c8ca803eb794dcdd3af58ab34d1b48dcd7c18"
88
+ "gitHead": "74c2fd7d4ce3eb48d25a911258bf90a64218ea0e"
88
89
  }
package/source/index.ts CHANGED
@@ -12,3 +12,4 @@ export * from "./server_capabilities";
12
12
  export * from "./server_engine";
13
13
  export * from "./opcua_server";
14
14
  export * from "./monitored_item";
15
+ export * from "./user_manager";
@@ -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, makeSHA1Thumbprint, Nonce, toPem } from "node-opcua-crypto";
45
+ import { Certificate, exploreCertificate, Nonce } from "node-opcua-crypto";
46
46
  import {
47
- AttributeIds, DiagnosticInfo, filterDiagnosticInfoLevel, filterDiagnosticOperationLevel, filterDiagnosticServiceLevel, LocalizedText, NodeClass, RESPONSE_DIAGNOSTICS_MASK_ALL
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(returnDiagnostics, response.responseHeader.serviceDiagnostics);
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
- (d) => filterDiagnosticOperationLevel(returnDiagnostics, d)
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: UserManagerOptions;
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
- if (typeof this.userManager.isValidUserAsync === "function") {
1600
- this.userManager.isValidUserAsync.call(session, userName, password, callback);
1601
- } else {
1602
- const authorized = this.userManager.isValidUser!.call(session, userName, password);
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(chalk.red.bgWhite("ERROR: channel.channelId !== session.channelId on processing request " + request.constructor.name), channel.channelId, session.channelId);
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)) {
@@ -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();
@@ -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
- console.log(" cannot find", propName);
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
- console.log(" cannot find", propName);
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
- console.log("TO DO : Closing session without deleting subscription not yet implemented");
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).substr(-length);
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
+ }