node-opcua-role-set-admin 2.174.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/LICENSE +22 -0
- package/README.md +87 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +52 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands.d.ts +21 -0
- package/dist/commands.js +176 -0
- package/dist/commands.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/package.json +53 -0
- package/source/cli.ts +66 -0
- package/source/commands.ts +184 -0
- package/source/index.ts +20 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022-2024 Sterfive SAS - 833264583 RCS ORLEANS - France (https://www.sterfive.com)
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2014-2022 Etienne Rossignon
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
8
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
9
|
+
the Software without restriction, including without limitation the rights to
|
|
10
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
11
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
12
|
+
subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
19
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
20
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
21
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
22
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# node-opcua-role-set-admin
|
|
2
|
+
|
|
3
|
+
A small command-line tool to administer the **RoleSet** and **User Management**
|
|
4
|
+
(OPC 10000-18) of any OPC UA server, built on
|
|
5
|
+
[`node-opcua-role-set-client`](../node-opcua-role-set-client). It connects over a
|
|
6
|
+
real session and drives the standard Methods, so it works against any compliant
|
|
7
|
+
server.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install -g node-opcua-role-set-admin
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
This installs the `role-set-admin` command.
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
role-set-admin -e opc.tcp://host:4840 -u admin -p *** list-roles
|
|
21
|
+
role-set-admin -e opc.tcp://host:4840 -u admin show-role Operator # password prompted
|
|
22
|
+
role-set-admin -e ... -u admin -p *** add-identity Operator joe
|
|
23
|
+
role-set-admin -e ... -u admin -p *** add-user alice s3cret -r Operator
|
|
24
|
+
role-set-admin -e ... -u admin -p *** remove-user alice
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
By default it connects with **SignAndEncrypt / Basic256Sha256** (most management
|
|
28
|
+
Methods require an encrypted channel and the `SecurityAdmin` Role). Use
|
|
29
|
+
`--insecure` for `None/None`.
|
|
30
|
+
|
|
31
|
+
If `--password` is omitted (but `--username` is given), the password is read from
|
|
32
|
+
the terminal with **hidden input** — so it never lands in your shell history or
|
|
33
|
+
the process list.
|
|
34
|
+
|
|
35
|
+
### Global options
|
|
36
|
+
|
|
37
|
+
| Option | Description |
|
|
38
|
+
|--------|-------------|
|
|
39
|
+
| `-e, --endpoint <url>` | OPC UA endpoint (required), e.g. `opc.tcp://host:4840`. |
|
|
40
|
+
| `-u, --username <name>` | User name (omit for anonymous). |
|
|
41
|
+
| `-p, --password <pw>` | Password (prompted with hidden input if omitted). |
|
|
42
|
+
| `--insecure` | Connect without security (`None/None`). |
|
|
43
|
+
|
|
44
|
+
### Commands
|
|
45
|
+
|
|
46
|
+
| Command | Description |
|
|
47
|
+
|---------|-------------|
|
|
48
|
+
| `list-roles` | List all Roles and their identities. |
|
|
49
|
+
| `show-role <name>` | Show one Role's identities. |
|
|
50
|
+
| `add-role <name>` | Add a custom Role. |
|
|
51
|
+
| `remove-role <name>` | Remove a custom Role. |
|
|
52
|
+
| `add-identity <role> <user>` | Map a UserName to a Role. |
|
|
53
|
+
| `remove-identity <role> <user>` | Unmap a UserName from a Role. |
|
|
54
|
+
| `list-users` | List managed users. |
|
|
55
|
+
| `add-user <user> <password> [-r <role...>]` | Add a user, optionally granting Roles. |
|
|
56
|
+
| `remove-user <user>` | Remove a user. |
|
|
57
|
+
| `change-password <old> <new>` | Change the connected user's password. |
|
|
58
|
+
|
|
59
|
+
## Programmatic API
|
|
60
|
+
|
|
61
|
+
The command actions are also exported, so you can script the same administration:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { addIdentity, listRoles } from "node-opcua-role-set-admin";
|
|
65
|
+
|
|
66
|
+
await listRoles({ endpoint: "opc.tcp://host:4840", username: "admin", password: "***" });
|
|
67
|
+
await addIdentity({ endpoint, username: "admin", password: "***" }, "Operator", "joe");
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Related packages
|
|
71
|
+
|
|
72
|
+
- [`node-opcua-role-set-client`](../node-opcua-role-set-client) — client-side RoleSet/UserManagement API.
|
|
73
|
+
- [`node-opcua-role-set-server`](../node-opcua-role-set-server) — server-side install & enforcement.
|
|
74
|
+
- [`node-opcua-role-set-common`](../node-opcua-role-set-common) — shared stores, persistence, matching.
|
|
75
|
+
- [Role-Based Security & User Management guide](https://github.com/node-opcua/node-opcua/blob/master/documentation/role_based_security.md) — cross-package overview & getting started.
|
|
76
|
+
|
|
77
|
+
# License
|
|
78
|
+
|
|
79
|
+
Node-OPCUA is made available to you under the MIT open source license.
|
|
80
|
+
|
|
81
|
+
See [LICENSE](./LICENSE) for details.
|
|
82
|
+
|
|
83
|
+
# Copyright
|
|
84
|
+
|
|
85
|
+
Copyright (c) 2022-2026 Sterfive SAS - https://www.sterfive.com
|
|
86
|
+
|
|
87
|
+
Copyright (c) 2014-2022 Etienne Rossignon
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
/**
|
|
5
|
+
* @module node-opcua-role-set-admin
|
|
6
|
+
*
|
|
7
|
+
* `role-set-admin` — administer the RoleSet & User Management (OPC 10000-18) of
|
|
8
|
+
* any OPC UA server over a real session.
|
|
9
|
+
*/
|
|
10
|
+
const commander_1 = require("commander");
|
|
11
|
+
const commands_js_1 = require("./commands.js");
|
|
12
|
+
const program = new commander_1.Command()
|
|
13
|
+
.name("role-set-admin")
|
|
14
|
+
.description("Administer the RoleSet & User Management of an OPC UA server (OPC 10000-18)")
|
|
15
|
+
.requiredOption("-e, --endpoint <url>", "OPC UA endpoint, e.g. opc.tcp://host:4840")
|
|
16
|
+
.option("-u, --username <name>", "user name (omit for anonymous)")
|
|
17
|
+
.option("-p, --password <password>", "password (prompted with hidden input if omitted)")
|
|
18
|
+
.option("--insecure", "connect without security (None/None) instead of SignAndEncrypt");
|
|
19
|
+
const fail = (err) => {
|
|
20
|
+
console.error(`error: ${err.message}`);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Adapt one of the {@link GlobalOpts}-first command actions to a commander
|
|
25
|
+
* handler. commander appends an options object (for commands with options) and
|
|
26
|
+
* the `Command` itself after the declared positionals — we keep only the leading
|
|
27
|
+
* string positionals and read the global options off the root program.
|
|
28
|
+
*/
|
|
29
|
+
function run(action) {
|
|
30
|
+
return (...args) => {
|
|
31
|
+
const positionals = args.filter((a) => typeof a === "string");
|
|
32
|
+
action(program.opts(), ...positionals).catch(fail);
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
program.command("list-roles").description("list all Roles and their identities").action(run(commands_js_1.listRoles));
|
|
36
|
+
program.command("show-role <name>").description("show one Role's identities").action(run(commands_js_1.showRole));
|
|
37
|
+
program.command("add-role <name>").description("add a custom Role").action(run(commands_js_1.addRole));
|
|
38
|
+
program.command("remove-role <name>").description("remove a custom Role").action(run(commands_js_1.removeRole));
|
|
39
|
+
program.command("add-identity <role> <user>").description("map a UserName to a Role").action(run(commands_js_1.addIdentity));
|
|
40
|
+
program.command("remove-identity <role> <user>").description("unmap a UserName from a Role").action(run(commands_js_1.removeIdentity));
|
|
41
|
+
program.command("list-users").description("list managed users").action(run(commands_js_1.listUsers));
|
|
42
|
+
program
|
|
43
|
+
.command("add-user <user> <password>")
|
|
44
|
+
.description("add a user, optionally granting Roles")
|
|
45
|
+
.option("-r, --role <name...>", "Role(s) to grant", [])
|
|
46
|
+
.action((user, password, cmdOpts) => {
|
|
47
|
+
(0, commands_js_1.addUser)(program.opts(), user, password, cmdOpts.role).catch(fail);
|
|
48
|
+
});
|
|
49
|
+
program.command("remove-user <user>").description("remove a user").action(run(commands_js_1.removeUser));
|
|
50
|
+
program.command("change-password <old> <new>").description("change the connected user's password").action(run(commands_js_1.changePassword));
|
|
51
|
+
program.parse(process.argv);
|
|
52
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../source/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type ClientSession } from "node-opcua-client";
|
|
2
|
+
/** Connection + identity options shared by every command. */
|
|
3
|
+
export interface GlobalOpts {
|
|
4
|
+
endpoint: string;
|
|
5
|
+
username?: string;
|
|
6
|
+
password?: string;
|
|
7
|
+
/** Connect without security (None/None) instead of SignAndEncrypt/Basic256Sha256. */
|
|
8
|
+
insecure?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/** Connect, run `fn` in a session, then tear everything down. */
|
|
11
|
+
export declare function withSession<T>(opts: GlobalOpts, fn: (session: ClientSession) => Promise<T>): Promise<T>;
|
|
12
|
+
export declare function listRoles(opts: GlobalOpts): Promise<void>;
|
|
13
|
+
export declare function showRole(opts: GlobalOpts, name: string): Promise<void>;
|
|
14
|
+
export declare function addRole(opts: GlobalOpts, name: string): Promise<void>;
|
|
15
|
+
export declare function removeRole(opts: GlobalOpts, name: string): Promise<void>;
|
|
16
|
+
export declare function addIdentity(opts: GlobalOpts, roleName: string, userName: string): Promise<void>;
|
|
17
|
+
export declare function removeIdentity(opts: GlobalOpts, roleName: string, userName: string): Promise<void>;
|
|
18
|
+
export declare function listUsers(opts: GlobalOpts): Promise<void>;
|
|
19
|
+
export declare function addUser(opts: GlobalOpts, userName: string, password: string, roles: string[]): Promise<void>;
|
|
20
|
+
export declare function removeUser(opts: GlobalOpts, userName: string): Promise<void>;
|
|
21
|
+
export declare function changePassword(opts: GlobalOpts, oldPassword: string, newPassword: string): Promise<void>;
|
package/dist/commands.js
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.withSession = withSession;
|
|
7
|
+
exports.listRoles = listRoles;
|
|
8
|
+
exports.showRole = showRole;
|
|
9
|
+
exports.addRole = addRole;
|
|
10
|
+
exports.removeRole = removeRole;
|
|
11
|
+
exports.addIdentity = addIdentity;
|
|
12
|
+
exports.removeIdentity = removeIdentity;
|
|
13
|
+
exports.listUsers = listUsers;
|
|
14
|
+
exports.addUser = addUser;
|
|
15
|
+
exports.removeUser = removeUser;
|
|
16
|
+
exports.changePassword = changePassword;
|
|
17
|
+
/**
|
|
18
|
+
* @module node-opcua-role-set-admin
|
|
19
|
+
*
|
|
20
|
+
* The connection helper and command actions behind the `role-set-admin` CLI,
|
|
21
|
+
* built on `ClientRoleSet` / `ClientUserManagement`. Exported so they can also be
|
|
22
|
+
* driven programmatically.
|
|
23
|
+
*/
|
|
24
|
+
const node_fs_1 = require("node:fs");
|
|
25
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
26
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
27
|
+
const node_opcua_certificate_manager_1 = require("node-opcua-certificate-manager");
|
|
28
|
+
const node_opcua_client_1 = require("node-opcua-client");
|
|
29
|
+
const node_opcua_role_set_client_1 = require("node-opcua-role-set-client");
|
|
30
|
+
const node_opcua_status_code_1 = require("node-opcua-status-code");
|
|
31
|
+
const node_opcua_types_1 = require("node-opcua-types");
|
|
32
|
+
const userNameRule = (userName) => new node_opcua_types_1.IdentityMappingRuleType({ criteriaType: node_opcua_types_1.IdentityCriteriaType.UserName, criteria: userName });
|
|
33
|
+
/**
|
|
34
|
+
* Resolve the password: use `--password` if given, otherwise prompt for it with
|
|
35
|
+
* hidden input (so it never lands in shell history or the process list). A
|
|
36
|
+
* non-interactive run without `--password` is an error.
|
|
37
|
+
*/
|
|
38
|
+
async function resolvePassword(opts) {
|
|
39
|
+
if (opts.username === undefined || opts.password !== undefined) {
|
|
40
|
+
return opts.password; // anonymous, or password already supplied
|
|
41
|
+
}
|
|
42
|
+
if (!process.stdin.isTTY) {
|
|
43
|
+
throw new Error(`password required for '${opts.username}': pass --password or run in an interactive terminal`);
|
|
44
|
+
}
|
|
45
|
+
// @inquirer/prompts is ESM-only; load it lazily so this CommonJS module can use it.
|
|
46
|
+
const { password } = await import("@inquirer/prompts");
|
|
47
|
+
return password({ message: `Password for ${opts.username}:`, mask: "*" });
|
|
48
|
+
}
|
|
49
|
+
/** Connect, run `fn` in a session, then tear everything down. */
|
|
50
|
+
async function withSession(opts, fn) {
|
|
51
|
+
const password = await resolvePassword(opts);
|
|
52
|
+
const secure = !opts.insecure;
|
|
53
|
+
const pkiRoot = node_path_1.default.join(node_os_1.default.tmpdir(), `role-set-admin-${process.pid}`);
|
|
54
|
+
const clientCertificateManager = new node_opcua_certificate_manager_1.OPCUACertificateManager({
|
|
55
|
+
rootFolder: pkiRoot,
|
|
56
|
+
automaticallyAcceptUnknownCertificate: true
|
|
57
|
+
});
|
|
58
|
+
await clientCertificateManager.initialize();
|
|
59
|
+
const client = node_opcua_client_1.OPCUAClient.create({
|
|
60
|
+
endpointMustExist: false,
|
|
61
|
+
securityMode: secure ? node_opcua_client_1.MessageSecurityMode.SignAndEncrypt : node_opcua_client_1.MessageSecurityMode.None,
|
|
62
|
+
securityPolicy: secure ? node_opcua_client_1.SecurityPolicy.Basic256Sha256 : node_opcua_client_1.SecurityPolicy.None,
|
|
63
|
+
clientCertificateManager
|
|
64
|
+
});
|
|
65
|
+
await client.connect(opts.endpoint);
|
|
66
|
+
try {
|
|
67
|
+
const userIdentity = opts.username !== undefined
|
|
68
|
+
? { type: node_opcua_client_1.UserTokenType.UserName, userName: opts.username, password: password ?? "" }
|
|
69
|
+
: undefined;
|
|
70
|
+
const session = await client.createSession(userIdentity);
|
|
71
|
+
try {
|
|
72
|
+
return await fn(session);
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
await session.close();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
await client.disconnect();
|
|
80
|
+
await clientCertificateManager.dispose();
|
|
81
|
+
await node_fs_1.promises.rm(pkiRoot, { recursive: true, force: true }).catch(() => undefined);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/** Print a StatusCode result and mark the process failed if it is not Good. */
|
|
85
|
+
function reportStatus(label, statusCode) {
|
|
86
|
+
const ok = statusCode === node_opcua_status_code_1.StatusCodes.Good;
|
|
87
|
+
console.log(`${ok ? "✓" : "✗"} ${label}: ${statusCode.name}`);
|
|
88
|
+
if (!ok)
|
|
89
|
+
process.exitCode = 1;
|
|
90
|
+
}
|
|
91
|
+
async function getRoleOrThrow(roleSet, name) {
|
|
92
|
+
const role = await roleSet.getRole(name);
|
|
93
|
+
if (!role)
|
|
94
|
+
throw new Error(`role '${name}' not found`);
|
|
95
|
+
return role;
|
|
96
|
+
}
|
|
97
|
+
async function listRoles(opts) {
|
|
98
|
+
await withSession(opts, async (session) => {
|
|
99
|
+
const roleSet = new node_opcua_role_set_client_1.ClientRoleSet(session);
|
|
100
|
+
for (const role of await roleSet.getRoles()) {
|
|
101
|
+
const identities = await role.readIdentities();
|
|
102
|
+
const who = identities.map((i) => i.criteria).join(", ") || "—";
|
|
103
|
+
console.log(`${role.roleName.padEnd(20)} ${role.roleNodeId.toString().padEnd(18)} identities: ${who}`);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
async function showRole(opts, name) {
|
|
108
|
+
await withSession(opts, async (session) => {
|
|
109
|
+
const role = await getRoleOrThrow(new node_opcua_role_set_client_1.ClientRoleSet(session), name);
|
|
110
|
+
console.log(`Role ${role.roleName} (${role.roleNodeId.toString()})`);
|
|
111
|
+
const identities = await role.readIdentities();
|
|
112
|
+
if (identities.length === 0) {
|
|
113
|
+
console.log(" (no identities)");
|
|
114
|
+
}
|
|
115
|
+
for (const i of identities) {
|
|
116
|
+
console.log(` - ${node_opcua_types_1.IdentityCriteriaType[i.criteriaType]}: ${i.criteria}`);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
async function addRole(opts, name) {
|
|
121
|
+
await withSession(opts, async (session) => {
|
|
122
|
+
const { statusCode, roleNodeId } = await new node_opcua_role_set_client_1.ClientRoleSet(session).addRole(name);
|
|
123
|
+
reportStatus(`AddRole '${name}'${roleNodeId ? ` -> ${roleNodeId.toString()}` : ""}`, statusCode);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
async function removeRole(opts, name) {
|
|
127
|
+
await withSession(opts, async (session) => {
|
|
128
|
+
const roleSet = new node_opcua_role_set_client_1.ClientRoleSet(session);
|
|
129
|
+
const role = await getRoleOrThrow(roleSet, name);
|
|
130
|
+
reportStatus(`RemoveRole '${name}'`, (await roleSet.removeRole(role.roleNodeId)).statusCode);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
async function addIdentity(opts, roleName, userName) {
|
|
134
|
+
await withSession(opts, async (session) => {
|
|
135
|
+
const role = await getRoleOrThrow(new node_opcua_role_set_client_1.ClientRoleSet(session), roleName);
|
|
136
|
+
reportStatus(`AddIdentity ${userName} -> ${roleName}`, (await role.addIdentity(userNameRule(userName))).statusCode);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
async function removeIdentity(opts, roleName, userName) {
|
|
140
|
+
await withSession(opts, async (session) => {
|
|
141
|
+
const role = await getRoleOrThrow(new node_opcua_role_set_client_1.ClientRoleSet(session), roleName);
|
|
142
|
+
reportStatus(`RemoveIdentity ${userName} from ${roleName}`, (await role.removeIdentity(userNameRule(userName))).statusCode);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
async function listUsers(opts) {
|
|
146
|
+
await withSession(opts, async (session) => {
|
|
147
|
+
for (const u of await new node_opcua_role_set_client_1.ClientUserManagement(session).readUsers()) {
|
|
148
|
+
console.log(`${(u.userName ?? "").padEnd(20)} config=${u.userConfiguration} ${u.description ?? ""}`);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
async function addUser(opts, userName, password, roles) {
|
|
153
|
+
await withSession(opts, async (session) => {
|
|
154
|
+
const um = new node_opcua_role_set_client_1.ClientUserManagement(session);
|
|
155
|
+
const addStatus = (await um.addUser(userName, password, node_opcua_types_1.UserConfigurationMask.None, "")).statusCode;
|
|
156
|
+
reportStatus(`AddUser '${userName}'`, addStatus);
|
|
157
|
+
if (addStatus !== node_opcua_status_code_1.StatusCodes.Good)
|
|
158
|
+
return;
|
|
159
|
+
const roleSet = new node_opcua_role_set_client_1.ClientRoleSet(session);
|
|
160
|
+
for (const roleName of roles) {
|
|
161
|
+
const role = await getRoleOrThrow(roleSet, roleName);
|
|
162
|
+
reportStatus(` + identity ${userName} -> ${roleName}`, (await role.addIdentity(userNameRule(userName))).statusCode);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
async function removeUser(opts, userName) {
|
|
167
|
+
await withSession(opts, async (session) => {
|
|
168
|
+
reportStatus(`RemoveUser '${userName}'`, (await new node_opcua_role_set_client_1.ClientUserManagement(session).removeUser(userName)).statusCode);
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
async function changePassword(opts, oldPassword, newPassword) {
|
|
172
|
+
await withSession(opts, async (session) => {
|
|
173
|
+
reportStatus("ChangePassword", (await new node_opcua_role_set_client_1.ClientUserManagement(session).changePassword(oldPassword, newPassword)).statusCode);
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../source/commands.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module node-opcua-role-set-admin
|
|
3
|
+
*
|
|
4
|
+
* Programmatic API behind the `role-set-admin` CLI. Import these to script the
|
|
5
|
+
* same RoleSet / User Management administration from your own code.
|
|
6
|
+
*/
|
|
7
|
+
export { addIdentity, addRole, addUser, changePassword, type GlobalOpts, listRoles, listUsers, removeIdentity, removeRole, removeUser, showRole, withSession } from "./commands.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withSession = exports.showRole = exports.removeUser = exports.removeRole = exports.removeIdentity = exports.listUsers = exports.listRoles = exports.changePassword = exports.addUser = exports.addRole = exports.addIdentity = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* @module node-opcua-role-set-admin
|
|
6
|
+
*
|
|
7
|
+
* Programmatic API behind the `role-set-admin` CLI. Import these to script the
|
|
8
|
+
* same RoleSet / User Management administration from your own code.
|
|
9
|
+
*/
|
|
10
|
+
var commands_js_1 = require("./commands.js");
|
|
11
|
+
Object.defineProperty(exports, "addIdentity", { enumerable: true, get: function () { return commands_js_1.addIdentity; } });
|
|
12
|
+
Object.defineProperty(exports, "addRole", { enumerable: true, get: function () { return commands_js_1.addRole; } });
|
|
13
|
+
Object.defineProperty(exports, "addUser", { enumerable: true, get: function () { return commands_js_1.addUser; } });
|
|
14
|
+
Object.defineProperty(exports, "changePassword", { enumerable: true, get: function () { return commands_js_1.changePassword; } });
|
|
15
|
+
Object.defineProperty(exports, "listRoles", { enumerable: true, get: function () { return commands_js_1.listRoles; } });
|
|
16
|
+
Object.defineProperty(exports, "listUsers", { enumerable: true, get: function () { return commands_js_1.listUsers; } });
|
|
17
|
+
Object.defineProperty(exports, "removeIdentity", { enumerable: true, get: function () { return commands_js_1.removeIdentity; } });
|
|
18
|
+
Object.defineProperty(exports, "removeRole", { enumerable: true, get: function () { return commands_js_1.removeRole; } });
|
|
19
|
+
Object.defineProperty(exports, "removeUser", { enumerable: true, get: function () { return commands_js_1.removeUser; } });
|
|
20
|
+
Object.defineProperty(exports, "showRole", { enumerable: true, get: function () { return commands_js_1.showRole; } });
|
|
21
|
+
Object.defineProperty(exports, "withSession", { enumerable: true, get: function () { return commands_js_1.withSession; } });
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../source/index.ts"],"names":[],"mappings":";;;AAAA;;;;;GAKG;AACH,6CAauB;AAZnB,0GAAA,WAAW,OAAA;AACX,sGAAA,OAAO,OAAA;AACP,sGAAA,OAAO,OAAA;AACP,6GAAA,cAAc,OAAA;AAEd,wGAAA,SAAS,OAAA;AACT,wGAAA,SAAS,OAAA;AACT,6GAAA,cAAc,OAAA;AACd,yGAAA,UAAU,OAAA;AACV,yGAAA,UAAU,OAAA;AACV,uGAAA,QAAQ,OAAA;AACR,0GAAA,WAAW,OAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "node-opcua-role-set-admin",
|
|
3
|
+
"version": "2.174.0",
|
|
4
|
+
"description": "pure nodejs OPCUA SDK - role-set-admin CLI to administer RoleSet & User Management (OPC 10000-18)",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "tsc -b",
|
|
7
|
+
"clean": "npx rimraf -g node_modules dist *.tsbuildinfo",
|
|
8
|
+
"role-set-admin": "tsx source/cli.ts"
|
|
9
|
+
},
|
|
10
|
+
"main": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"bin": {
|
|
13
|
+
"role-set-admin": "./dist/cli.js"
|
|
14
|
+
},
|
|
15
|
+
"devEngines": {
|
|
16
|
+
"node": ">=18.x",
|
|
17
|
+
"npm": ">=10.x"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@inquirer/prompts": "8.5.2",
|
|
21
|
+
"commander": "^12.1.0",
|
|
22
|
+
"node-opcua-certificate-manager": "2.174.0",
|
|
23
|
+
"node-opcua-client": "2.174.0",
|
|
24
|
+
"node-opcua-role-set-client": "2.174.0",
|
|
25
|
+
"node-opcua-status-code": "2.173.0",
|
|
26
|
+
"node-opcua-types": "2.174.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"tsx": "^4.22.4"
|
|
30
|
+
},
|
|
31
|
+
"author": "Etienne Rossignon",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git://github.com/node-opcua/node-opcua.git"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"OPCUA",
|
|
39
|
+
"opcua",
|
|
40
|
+
"m2m",
|
|
41
|
+
"iot",
|
|
42
|
+
"opc ua",
|
|
43
|
+
"internet of things",
|
|
44
|
+
"role",
|
|
45
|
+
"rbac",
|
|
46
|
+
"cli"
|
|
47
|
+
],
|
|
48
|
+
"homepage": "http://node-opcua.github.io/",
|
|
49
|
+
"files": [
|
|
50
|
+
"dist",
|
|
51
|
+
"source"
|
|
52
|
+
]
|
|
53
|
+
}
|
package/source/cli.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @module node-opcua-role-set-admin
|
|
4
|
+
*
|
|
5
|
+
* `role-set-admin` — administer the RoleSet & User Management (OPC 10000-18) of
|
|
6
|
+
* any OPC UA server over a real session.
|
|
7
|
+
*/
|
|
8
|
+
import { Command } from "commander";
|
|
9
|
+
import {
|
|
10
|
+
addIdentity,
|
|
11
|
+
addRole,
|
|
12
|
+
addUser,
|
|
13
|
+
changePassword,
|
|
14
|
+
type GlobalOpts,
|
|
15
|
+
listRoles,
|
|
16
|
+
listUsers,
|
|
17
|
+
removeIdentity,
|
|
18
|
+
removeRole,
|
|
19
|
+
removeUser,
|
|
20
|
+
showRole
|
|
21
|
+
} from "./commands.js";
|
|
22
|
+
|
|
23
|
+
const program = new Command()
|
|
24
|
+
.name("role-set-admin")
|
|
25
|
+
.description("Administer the RoleSet & User Management of an OPC UA server (OPC 10000-18)")
|
|
26
|
+
.requiredOption("-e, --endpoint <url>", "OPC UA endpoint, e.g. opc.tcp://host:4840")
|
|
27
|
+
.option("-u, --username <name>", "user name (omit for anonymous)")
|
|
28
|
+
.option("-p, --password <password>", "password (prompted with hidden input if omitted)")
|
|
29
|
+
.option("--insecure", "connect without security (None/None) instead of SignAndEncrypt");
|
|
30
|
+
|
|
31
|
+
const fail = (err: Error): never => {
|
|
32
|
+
console.error(`error: ${err.message}`);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Adapt one of the {@link GlobalOpts}-first command actions to a commander
|
|
38
|
+
* handler. commander appends an options object (for commands with options) and
|
|
39
|
+
* the `Command` itself after the declared positionals — we keep only the leading
|
|
40
|
+
* string positionals and read the global options off the root program.
|
|
41
|
+
*/
|
|
42
|
+
function run(action: (opts: GlobalOpts, ...args: string[]) => Promise<void>) {
|
|
43
|
+
return (...args: unknown[]) => {
|
|
44
|
+
const positionals = args.filter((a): a is string => typeof a === "string");
|
|
45
|
+
action(program.opts<GlobalOpts>(), ...positionals).catch(fail);
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
program.command("list-roles").description("list all Roles and their identities").action(run(listRoles));
|
|
50
|
+
program.command("show-role <name>").description("show one Role's identities").action(run(showRole));
|
|
51
|
+
program.command("add-role <name>").description("add a custom Role").action(run(addRole));
|
|
52
|
+
program.command("remove-role <name>").description("remove a custom Role").action(run(removeRole));
|
|
53
|
+
program.command("add-identity <role> <user>").description("map a UserName to a Role").action(run(addIdentity));
|
|
54
|
+
program.command("remove-identity <role> <user>").description("unmap a UserName from a Role").action(run(removeIdentity));
|
|
55
|
+
program.command("list-users").description("list managed users").action(run(listUsers));
|
|
56
|
+
program
|
|
57
|
+
.command("add-user <user> <password>")
|
|
58
|
+
.description("add a user, optionally granting Roles")
|
|
59
|
+
.option("-r, --role <name...>", "Role(s) to grant", [])
|
|
60
|
+
.action((user: string, password: string, cmdOpts: { role: string[] }) => {
|
|
61
|
+
addUser(program.opts<GlobalOpts>(), user, password, cmdOpts.role).catch(fail);
|
|
62
|
+
});
|
|
63
|
+
program.command("remove-user <user>").description("remove a user").action(run(removeUser));
|
|
64
|
+
program.command("change-password <old> <new>").description("change the connected user's password").action(run(changePassword));
|
|
65
|
+
|
|
66
|
+
program.parse(process.argv);
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module node-opcua-role-set-admin
|
|
3
|
+
*
|
|
4
|
+
* The connection helper and command actions behind the `role-set-admin` CLI,
|
|
5
|
+
* built on `ClientRoleSet` / `ClientUserManagement`. Exported so they can also be
|
|
6
|
+
* driven programmatically.
|
|
7
|
+
*/
|
|
8
|
+
import { promises as fs } from "node:fs";
|
|
9
|
+
import os from "node:os";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
import { OPCUACertificateManager } from "node-opcua-certificate-manager";
|
|
12
|
+
import { type ClientSession, MessageSecurityMode, OPCUAClient, SecurityPolicy, UserTokenType } from "node-opcua-client";
|
|
13
|
+
import { ClientRoleSet, ClientUserManagement } from "node-opcua-role-set-client";
|
|
14
|
+
import { type StatusCode, StatusCodes } from "node-opcua-status-code";
|
|
15
|
+
import { IdentityCriteriaType, IdentityMappingRuleType, UserConfigurationMask } from "node-opcua-types";
|
|
16
|
+
|
|
17
|
+
/** Connection + identity options shared by every command. */
|
|
18
|
+
export interface GlobalOpts {
|
|
19
|
+
endpoint: string;
|
|
20
|
+
username?: string;
|
|
21
|
+
password?: string;
|
|
22
|
+
/** Connect without security (None/None) instead of SignAndEncrypt/Basic256Sha256. */
|
|
23
|
+
insecure?: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const userNameRule = (userName: string) =>
|
|
27
|
+
new IdentityMappingRuleType({ criteriaType: IdentityCriteriaType.UserName, criteria: userName });
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Resolve the password: use `--password` if given, otherwise prompt for it with
|
|
31
|
+
* hidden input (so it never lands in shell history or the process list). A
|
|
32
|
+
* non-interactive run without `--password` is an error.
|
|
33
|
+
*/
|
|
34
|
+
async function resolvePassword(opts: GlobalOpts): Promise<string | undefined> {
|
|
35
|
+
if (opts.username === undefined || opts.password !== undefined) {
|
|
36
|
+
return opts.password; // anonymous, or password already supplied
|
|
37
|
+
}
|
|
38
|
+
if (!process.stdin.isTTY) {
|
|
39
|
+
throw new Error(`password required for '${opts.username}': pass --password or run in an interactive terminal`);
|
|
40
|
+
}
|
|
41
|
+
// @inquirer/prompts is ESM-only; load it lazily so this CommonJS module can use it.
|
|
42
|
+
const { password } = await import("@inquirer/prompts");
|
|
43
|
+
return password({ message: `Password for ${opts.username}:`, mask: "*" });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Connect, run `fn` in a session, then tear everything down. */
|
|
47
|
+
export async function withSession<T>(opts: GlobalOpts, fn: (session: ClientSession) => Promise<T>): Promise<T> {
|
|
48
|
+
const password = await resolvePassword(opts);
|
|
49
|
+
const secure = !opts.insecure;
|
|
50
|
+
const pkiRoot = path.join(os.tmpdir(), `role-set-admin-${process.pid}`);
|
|
51
|
+
const clientCertificateManager = new OPCUACertificateManager({
|
|
52
|
+
rootFolder: pkiRoot,
|
|
53
|
+
automaticallyAcceptUnknownCertificate: true
|
|
54
|
+
});
|
|
55
|
+
await clientCertificateManager.initialize();
|
|
56
|
+
|
|
57
|
+
const client = OPCUAClient.create({
|
|
58
|
+
endpointMustExist: false,
|
|
59
|
+
securityMode: secure ? MessageSecurityMode.SignAndEncrypt : MessageSecurityMode.None,
|
|
60
|
+
securityPolicy: secure ? SecurityPolicy.Basic256Sha256 : SecurityPolicy.None,
|
|
61
|
+
clientCertificateManager
|
|
62
|
+
});
|
|
63
|
+
await client.connect(opts.endpoint);
|
|
64
|
+
try {
|
|
65
|
+
const userIdentity =
|
|
66
|
+
opts.username !== undefined
|
|
67
|
+
? { type: UserTokenType.UserName as const, userName: opts.username, password: password ?? "" }
|
|
68
|
+
: undefined;
|
|
69
|
+
const session = await client.createSession(userIdentity);
|
|
70
|
+
try {
|
|
71
|
+
return await fn(session);
|
|
72
|
+
} finally {
|
|
73
|
+
await session.close();
|
|
74
|
+
}
|
|
75
|
+
} finally {
|
|
76
|
+
await client.disconnect();
|
|
77
|
+
await clientCertificateManager.dispose();
|
|
78
|
+
await fs.rm(pkiRoot, { recursive: true, force: true }).catch(() => undefined);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Print a StatusCode result and mark the process failed if it is not Good. */
|
|
83
|
+
function reportStatus(label: string, statusCode: StatusCode): void {
|
|
84
|
+
const ok = statusCode === StatusCodes.Good;
|
|
85
|
+
console.log(`${ok ? "✓" : "✗"} ${label}: ${statusCode.name}`);
|
|
86
|
+
if (!ok) process.exitCode = 1;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function getRoleOrThrow(roleSet: ClientRoleSet, name: string) {
|
|
90
|
+
const role = await roleSet.getRole(name);
|
|
91
|
+
if (!role) throw new Error(`role '${name}' not found`);
|
|
92
|
+
return role;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export async function listRoles(opts: GlobalOpts): Promise<void> {
|
|
96
|
+
await withSession(opts, async (session) => {
|
|
97
|
+
const roleSet = new ClientRoleSet(session);
|
|
98
|
+
for (const role of await roleSet.getRoles()) {
|
|
99
|
+
const identities = await role.readIdentities();
|
|
100
|
+
const who = identities.map((i) => i.criteria).join(", ") || "—";
|
|
101
|
+
console.log(`${role.roleName.padEnd(20)} ${role.roleNodeId.toString().padEnd(18)} identities: ${who}`);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export async function showRole(opts: GlobalOpts, name: string): Promise<void> {
|
|
107
|
+
await withSession(opts, async (session) => {
|
|
108
|
+
const role = await getRoleOrThrow(new ClientRoleSet(session), name);
|
|
109
|
+
console.log(`Role ${role.roleName} (${role.roleNodeId.toString()})`);
|
|
110
|
+
const identities = await role.readIdentities();
|
|
111
|
+
if (identities.length === 0) {
|
|
112
|
+
console.log(" (no identities)");
|
|
113
|
+
}
|
|
114
|
+
for (const i of identities) {
|
|
115
|
+
console.log(` - ${IdentityCriteriaType[i.criteriaType]}: ${i.criteria}`);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export async function addRole(opts: GlobalOpts, name: string): Promise<void> {
|
|
121
|
+
await withSession(opts, async (session) => {
|
|
122
|
+
const { statusCode, roleNodeId } = await new ClientRoleSet(session).addRole(name);
|
|
123
|
+
reportStatus(`AddRole '${name}'${roleNodeId ? ` -> ${roleNodeId.toString()}` : ""}`, statusCode);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export async function removeRole(opts: GlobalOpts, name: string): Promise<void> {
|
|
128
|
+
await withSession(opts, async (session) => {
|
|
129
|
+
const roleSet = new ClientRoleSet(session);
|
|
130
|
+
const role = await getRoleOrThrow(roleSet, name);
|
|
131
|
+
reportStatus(`RemoveRole '${name}'`, (await roleSet.removeRole(role.roleNodeId)).statusCode);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export async function addIdentity(opts: GlobalOpts, roleName: string, userName: string): Promise<void> {
|
|
136
|
+
await withSession(opts, async (session) => {
|
|
137
|
+
const role = await getRoleOrThrow(new ClientRoleSet(session), roleName);
|
|
138
|
+
reportStatus(`AddIdentity ${userName} -> ${roleName}`, (await role.addIdentity(userNameRule(userName))).statusCode);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export async function removeIdentity(opts: GlobalOpts, roleName: string, userName: string): Promise<void> {
|
|
143
|
+
await withSession(opts, async (session) => {
|
|
144
|
+
const role = await getRoleOrThrow(new ClientRoleSet(session), roleName);
|
|
145
|
+
reportStatus(`RemoveIdentity ${userName} from ${roleName}`, (await role.removeIdentity(userNameRule(userName))).statusCode);
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export async function listUsers(opts: GlobalOpts): Promise<void> {
|
|
150
|
+
await withSession(opts, async (session) => {
|
|
151
|
+
for (const u of await new ClientUserManagement(session).readUsers()) {
|
|
152
|
+
console.log(`${(u.userName ?? "").padEnd(20)} config=${u.userConfiguration} ${u.description ?? ""}`);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export async function addUser(opts: GlobalOpts, userName: string, password: string, roles: string[]): Promise<void> {
|
|
158
|
+
await withSession(opts, async (session) => {
|
|
159
|
+
const um = new ClientUserManagement(session);
|
|
160
|
+
const addStatus = (await um.addUser(userName, password, UserConfigurationMask.None, "")).statusCode;
|
|
161
|
+
reportStatus(`AddUser '${userName}'`, addStatus);
|
|
162
|
+
if (addStatus !== StatusCodes.Good) return;
|
|
163
|
+
const roleSet = new ClientRoleSet(session);
|
|
164
|
+
for (const roleName of roles) {
|
|
165
|
+
const role = await getRoleOrThrow(roleSet, roleName);
|
|
166
|
+
reportStatus(` + identity ${userName} -> ${roleName}`, (await role.addIdentity(userNameRule(userName))).statusCode);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export async function removeUser(opts: GlobalOpts, userName: string): Promise<void> {
|
|
172
|
+
await withSession(opts, async (session) => {
|
|
173
|
+
reportStatus(`RemoveUser '${userName}'`, (await new ClientUserManagement(session).removeUser(userName)).statusCode);
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export async function changePassword(opts: GlobalOpts, oldPassword: string, newPassword: string): Promise<void> {
|
|
178
|
+
await withSession(opts, async (session) => {
|
|
179
|
+
reportStatus(
|
|
180
|
+
"ChangePassword",
|
|
181
|
+
(await new ClientUserManagement(session).changePassword(oldPassword, newPassword)).statusCode
|
|
182
|
+
);
|
|
183
|
+
});
|
|
184
|
+
}
|
package/source/index.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module node-opcua-role-set-admin
|
|
3
|
+
*
|
|
4
|
+
* Programmatic API behind the `role-set-admin` CLI. Import these to script the
|
|
5
|
+
* same RoleSet / User Management administration from your own code.
|
|
6
|
+
*/
|
|
7
|
+
export {
|
|
8
|
+
addIdentity,
|
|
9
|
+
addRole,
|
|
10
|
+
addUser,
|
|
11
|
+
changePassword,
|
|
12
|
+
type GlobalOpts,
|
|
13
|
+
listRoles,
|
|
14
|
+
listUsers,
|
|
15
|
+
removeIdentity,
|
|
16
|
+
removeRole,
|
|
17
|
+
removeUser,
|
|
18
|
+
showRole,
|
|
19
|
+
withSession
|
|
20
|
+
} from "./commands.js";
|