* [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell
@ 2025-11-11 8:29 Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH pve-xtermjs 1/2] xtermjs: add support for remote node shells via PDM Fabian Grünbichler
` (26 more replies)
0 siblings, 27 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
there's a lot of inter-dependencies here, unfortunately.
proxmox-auth-api breaks (building) PBS and PDM, and PBS requires bumped
proxmox-auth-api for this series to work.
PBS and PVE require new termproxy
pve-manager requires new pve-access-control (via termproxy)
PBS requires new pbs-api-types
PDM requires new pbs-api-types, pve-api-types, proxmox-yew-comp and pve-xtermjs
suggested build-order:
- pve-xtermjs / proxmox-termproxy
- pve-access-control
- pve-manager
- pve-api-types
- pbs-api-types
- proxmox-auth-api
- PBS
- proxmox-yew-comp
- PDM
the remote shell only works if remotes have new enough PVE/PBS packages.
pve-xtermjs:
Fabian Grünbichler (2):
xtermjs: add support for remote node shells via PDM
termproxy: allow using new vncticket endpoint
termproxy/src/cli.rs | 5 +++++
termproxy/src/main.rs | 31 ++++++++++++++++++++++---------
xterm.js/src/main.js | 13 +++++++++++--
3 files changed, 38 insertions(+), 11 deletions(-)
pve-access-control:
Fabian Grünbichler (1):
api: ticket: allow token-owned VNC ticket verification
src/PVE/API2/AccessControl.pm | 60 +++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
pve-manager:
Fabian Grünbichler (3):
api: termproxy/vncwebsocket: allow tokens
api: termproxy: add description to return schema
http server: allow unauthenticated access to /access/vncticket
PVE/API2/Nodes.pm | 17 ++++++++++-------
PVE/HTTPServer.pm | 1 +
2 files changed, 11 insertions(+), 7 deletions(-)
proxmox:
Fabian Grünbichler (3):
pbs-api-types: add NodeShellTicket
auth-api: use Authid for path ticket validation
auth-api: add vncticket verification endpoint and type
pbs-api-types/src/node.rs | 36 +++++++++++++++++++++++++++++-
proxmox-auth-api/src/api/access.rs | 34 ++++++++++++++++++++++++++--
proxmox-auth-api/src/api/mod.rs | 8 +++----
proxmox-auth-api/src/types.rs | 22 ++++++++++++++++++
4 files changed, 93 insertions(+), 7 deletions(-)
proxmox-backup:
Fabian Grünbichler (4):
tree-wide: user Userid::root_user() instead of hard-coded root@pam
api: access: add vncticket verification endpoint
api: node shell: allow access for tokens
api: termproxy: use NodeShellTicket type from pbs-api-types
pbs-config/src/acl.rs | 2 +-
pbs-config/src/cached_user_info.rs | 4 +-
pbs-config/src/user.rs | 5 ++-
src/api2/access/mod.rs | 6 ++-
src/api2/node/mod.rs | 66 +++++++++---------------------
src/auth.rs | 5 +--
src/tools/ticket.rs | 6 +--
7 files changed, 36 insertions(+), 58 deletions(-)
proxmox-yew-comp:
Fabian Grünbichler (3):
xtermjs: add remote PVE support
xtermjs: merge ConsoleType to parameters conversion
xtermjs: add remote PBS console type
src/xtermjs.rs | 41 ++++++++++++++++++++++++++---------------
1 file changed, 26 insertions(+), 15 deletions(-)
proxmox-datacenter-manager:
Fabian Grünbichler (9):
auth: allow tokens in term tickets
connection: add access to "raw" client
pbs client: add termproxy wrapper
api: add remote_shell module with termproxy endpoint
api: remote shell: add websocket endpoint
api: pve: wire up remote shell support
ui: pve: node: add shell tab
api: pbs: wire up node shell endpoints
ui: add PBS remote shell button
Cargo.toml | 2 +-
debian/control | 12 +-
server/src/api/mod.rs | 1 +
server/src/api/pbs/node.rs | 12 +-
server/src/api/pve/node.rs | 8 +
server/src/api/remote_shell.rs | 261 ++++++++++++++++++
server/src/auth/mod.rs | 5 +-
server/src/connection.rs | 11 +
.../src/metric_collection/collection_task.rs | 5 +
server/src/pbs_client.rs | 6 +
server/src/test_support/fake_remote.rs | 5 +
ui/src/pbs/mod.rs | 18 +-
ui/src/pve/node/mod.rs | 18 +-
13 files changed, 351 insertions(+), 13 deletions(-)
create mode 100644 server/src/api/remote_shell.rs
Summary over all repositories:
31 files changed, 615 insertions(+), 111 deletions(-)
--
Generated by git-murpp 0.8.1
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH pve-xtermjs 1/2] xtermjs: add support for remote node shells via PDM
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH pve-xtermjs 2/2] termproxy: allow using new vncticket endpoint Fabian Grünbichler
` (25 subsequent siblings)
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
if a remote name and type is specified, adapt the API endpoint base url
accordingly, and do not send the authentication line, since there is no PDM
termproxy that handles it. instead, PDM will generate and inject the
authentication line when proxying the websocket connection to the termproxy on
the remote.
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
v1: adapt to nits/style
xterm.js/src/main.js | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/xterm.js/src/main.js b/xterm.js/src/main.js
index 902a1c3..01c7786 100644
--- a/xterm.js/src/main.js
+++ b/xterm.js/src/main.js
@@ -19,6 +19,8 @@ var term,
state = states.start,
starttime = new Date();
+const remote = getQueryParameter('remote');
+const remote_type = getQueryParameter('remote-type');
var type = getQueryParameter('console');
var vmid = getQueryParameter('vmid');
var vmname = getQueryParameter('vmname');
@@ -175,7 +177,11 @@ function createTerminal() {
protocol = (location.protocol === 'https:') ? 'wss://' : 'ws://';
var params = {};
- var url = '/nodes/' + nodename;
+ var url = '';
+ if (remote) {
+ url += `/${remote_type}/remotes/${remote}/`;
+ }
+ url += `/nodes/${nodename}`;
switch (type) {
case 'kvm':
url += '/qemu/' + vmid;
@@ -252,7 +258,10 @@ function runTerminal() {
}, 250);
});
- socket.send(PVE.UserName + ':' + ticket + "\n");
+ // for remote sessions, this line needs to be sent by PDM
+ if (!remote) {
+ socket.send(`${PVE.UserName}:${ticket}\n`);
+ }
}
function getLxcStatus(callback) {
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH pve-xtermjs 2/2] termproxy: allow using new vncticket endpoint
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH pve-xtermjs 1/2] xtermjs: add support for remote node shells via PDM Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH access-control 1/1] api: ticket: allow token-owned VNC ticket verification Fabian Grünbichler
` (24 subsequent siblings)
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
that supports tokens in addition to users, needed for remote shell invocations
from PDM.
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
new in v1
termproxy/src/cli.rs | 5 +++++
termproxy/src/main.rs | 31 ++++++++++++++++++++++---------
2 files changed, 27 insertions(+), 9 deletions(-)
diff --git a/termproxy/src/cli.rs b/termproxy/src/cli.rs
index 94b9c4b..63fbbb8 100644
--- a/termproxy/src/cli.rs
+++ b/termproxy/src/cli.rs
@@ -60,6 +60,8 @@ pub struct Options {
pub acl_path: String,
/// The ACL permission that the ticket, read from the stream, is required to have on 'acl_path'
pub acl_permission: Option<String>,
+ /// User new-style 'vncticket' auth endpoint
+ pub vncticket_endpoint: bool,
}
impl Options {
@@ -108,6 +110,8 @@ impl Options {
}
};
+ let vncticket_endpoint = args.contains("--vncticket-endpoint");
+
// NOTE: free-form arguments are literally the next unused argument, so only get them after
// all options got parsed
let auth_port_or_fd = args.free_from_str()?;
@@ -118,6 +122,7 @@ impl Options {
api_daemon_address,
acl_path,
acl_permission,
+ vncticket_endpoint,
};
if !args.finish().is_empty() {
diff --git a/termproxy/src/main.rs b/termproxy/src/main.rs
index 98275ef..135468d 100644
--- a/termproxy/src/main.rs
+++ b/termproxy/src/main.rs
@@ -147,7 +147,11 @@ fn read_ticket_line(
}
}
-fn simple_auth_request<S: Read + Write>(mut stream: S, params: &[(&str, &str)]) -> Result<()> {
+fn simple_auth_request<S: Read + Write>(
+ mut stream: S,
+ endpoint: &str,
+ params: &[(&str, &str)],
+) -> Result<()> {
let mut form = form_urlencoded::Serializer::new(String::new());
for (name, value) in params {
@@ -158,13 +162,14 @@ fn simple_auth_request<S: Read + Write>(mut stream: S, params: &[(&str, &str)])
let raw_request = format!(
concat!(
- "POST /api2/json/access/ticket HTTP/1.1\r\n",
+ "POST /api2/json/access/{} HTTP/1.1\r\n",
"Connection: close\r\n",
"User-Agent: termproxy/1.0\r\n",
"Content-Type: application/x-www-form-urlencoded;charset=UTF-8\r\n",
"Content-Length: {}\r\n",
"\r\n"
),
+ endpoint,
raw_body.len()
);
@@ -184,10 +189,18 @@ fn simple_auth_request<S: Read + Write>(mut stream: S, params: &[(&str, &str)])
}
}
-fn authenticate(username: &[u8], ticket: &[u8], options: &Options, listen_port: u16) -> Result<()> {
+fn authenticate(authid: &[u8], ticket: &[u8], options: &Options, listen_port: u16) -> Result<()> {
let mut post_fields: Vec<(&str, &str)> = Vec::with_capacity(5);
- post_fields.push(("username", std::str::from_utf8(username)?));
- post_fields.push(("password", std::str::from_utf8(ticket)?));
+
+ let endpoint = if options.vncticket_endpoint {
+ post_fields.push(("authid", std::str::from_utf8(authid)?));
+ post_fields.push(("vncticket", std::str::from_utf8(ticket)?));
+ "vncticket"
+ } else {
+ post_fields.push(("username", std::str::from_utf8(authid)?));
+ post_fields.push(("password", std::str::from_utf8(ticket)?));
+ "ticket"
+ };
post_fields.push(("path", &options.acl_path));
if let Some(perm) = options.acl_permission.as_ref() {
post_fields.push(("privs", perm));
@@ -205,11 +218,11 @@ fn authenticate(username: &[u8], ticket: &[u8], options: &Options, listen_port:
let stream =
std::net::TcpStream::connect(std::net::SocketAddr::from(([127, 0, 0, 1], port)))?;
stream.set_nodelay(true)?;
- simple_auth_request(stream, &post_fields)
+ simple_auth_request(stream, endpoint, &post_fields)
}
cli::DaemonAddress::UnixSocket(ref path) => {
let stream = UnixStream::connect(path)?;
- simple_auth_request(stream, &post_fields)
+ simple_auth_request(stream, endpoint, &post_fields)
}
}
}
@@ -298,10 +311,10 @@ fn do_main() -> Result<()> {
let mut pty_buf = ByteBuffer::new();
let mut tcp_buf = ByteBuffer::new();
- let (username, ticket) = read_ticket_line(&mut tcp_handle, &mut pty_buf, Duration::new(10, 0))
+ let (authid, ticket) = read_ticket_line(&mut tcp_handle, &mut pty_buf, Duration::new(10, 0))
.map_err(|err| format_err!("failed reading ticket: {err}"))?;
- authenticate(&username, &ticket, &options, listen_port)?;
+ authenticate(&authid, &ticket, &options, listen_port)?;
tcp_handle.write_all(b"OK").expect("error writing response");
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH access-control 1/1] api: ticket: allow token-owned VNC ticket verification
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH pve-xtermjs 1/2] xtermjs: add support for remote node shells via PDM Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH pve-xtermjs 2/2] termproxy: allow using new vncticket endpoint Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH manager 1/3] api: termproxy/vncwebsocket: allow tokens Fabian Grünbichler
` (23 subsequent siblings)
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
our termproxy will issue a call to this endpoint on pvedaemon to verify the VNC
ticket passed by a client. with PDM, the shell client is actually using a PVE
token to authenticate, and the VNC ticket is owned by this token as well.
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
v1: replaces modifying the existing ticket call, since that is not really an
option for PBS/PDM
src/PVE/API2/AccessControl.pm | 60 +++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
diff --git a/src/PVE/API2/AccessControl.pm b/src/PVE/API2/AccessControl.pm
index 457a0a6..23d03cd 100644
--- a/src/PVE/API2/AccessControl.pm
+++ b/src/PVE/API2/AccessControl.pm
@@ -322,6 +322,66 @@ __PACKAGE__->register_method({
},
});
+__PACKAGE__->register_method({
+ name => 'verify_vnc_ticket',
+ path => 'vncticket',
+ method => 'POST',
+ permissions => {
+ description => "You need to pass valid credientials.",
+ user => 'world',
+ },
+ protected => 1, # else we can't access authkey files
+ description => "verify VNC authentication ticket.",
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ authid => {
+ description => "UserId or token",
+ type => 'string',
+ maxLength => 64,
+ },
+ vncticket => {
+ description => "The VNC ticket.",
+ type => 'string',
+ },
+ path => {
+ description => "Verify ticket, and check if user have access 'privs' on 'path'",
+ type => 'string',
+ maxLength => 64,
+ },
+ privs => {
+ description => "Verify ticket, and check if user have access 'privs' on 'path'",
+ type => 'string',
+ format => 'pve-priv-list',
+ maxLength => 64,
+ },
+ },
+ },
+ returns => { type => "null" },
+ code => sub {
+ my ($param) = @_;
+
+ my $auth_id = $param->{authid};
+
+ my $rpcenv = PVE::RPCEnvironment::get();
+
+ my $res = eval {
+ my $normpath = PVE::AccessControl::normalize_path($param->{path});
+ PVE::AccessControl::verify_vnc_ticket($param->{vncticket}, $auth_id, $normpath);
+ };
+ if (my $err = $@) {
+ my $clientip = $rpcenv->get_client_ip() || '';
+ syslog('err', "authentication failure; rhost=$clientip user=$auth_id msg=$err");
+ # do not return any info to prevent user enumeration attacks
+ die PVE::Exception->new("authentication failure\n", code => 401);
+ }
+
+ PVE::Cluster::log_msg('info', 'root@pam', "successful auth for user '$auth_id'");
+
+ return undef;
+ },
+});
+
__PACKAGE__->register_method({
name => 'change_password',
path => 'password',
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH manager 1/3] api: termproxy/vncwebsocket: allow tokens
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (2 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH access-control 1/1] api: ticket: allow token-owned VNC ticket verification Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH manager 2/3] api: termproxy: add description to return schema Fabian Grünbichler
` (22 subsequent siblings)
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
this is required for PDM to access a PVE node shell, since the PVE client uses
tokens for authentication. the user still needs a local PAM login to use the
shell.
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
v1: use new termproxy option to switch to new auth endpoint
PVE/API2/Nodes.pm | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/PVE/API2/Nodes.pm b/PVE/API2/Nodes.pm
index 4590b6186..459e0ed0a 100644
--- a/PVE/API2/Nodes.pm
+++ b/PVE/API2/Nodes.pm
@@ -1338,7 +1338,7 @@ __PACKAGE__->register_method({
my ($param) = @_;
my $rpcenv = PVE::RPCEnvironment::get();
- my ($user, undef, $realm) = PVE::AccessControl::verify_username($rpcenv->get_user());
+ my $user = $rpcenv->get_user();
my $node = $param->{node};
my $authpath = "/nodes/$node";
@@ -1354,7 +1354,7 @@ __PACKAGE__->register_method({
syslog('info', "starting termproxy $upid\n");
my $cmd = [
- '/usr/bin/termproxy', $port, '--path', $authpath, '--perm', 'Sys.Console', '--',
+ '/usr/bin/termproxy', $port, '--path', $authpath, '--perm', 'Sys.Console', '--vncticket-endpoint', '--',
];
push @$cmd, @$shcmd;
@@ -1410,7 +1410,7 @@ __PACKAGE__->register_method({
my $rpcenv = PVE::RPCEnvironment::get();
- my ($user, undef, $realm) = PVE::AccessControl::verify_username($rpcenv->get_user());
+ my $user = $rpcenv->get_user();
my $authpath = "/nodes/$param->{node}";
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH manager 2/3] api: termproxy: add description to return schema
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (3 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH manager 1/3] api: termproxy/vncwebsocket: allow tokens Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-13 10:38 ` Stefan Hanreich
2025-11-11 8:29 ` [pdm-devel] [PATCH manager 3/3] http server: allow unauthenticated access to /access/vncticket Fabian Grünbichler
` (21 subsequent siblings)
26 siblings, 1 reply; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
needed to call this endpoint from PDM.
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
PVE/API2/Nodes.pm | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/PVE/API2/Nodes.pm b/PVE/API2/Nodes.pm
index 459e0ed0a..53e3af08f 100644
--- a/PVE/API2/Nodes.pm
+++ b/PVE/API2/Nodes.pm
@@ -1328,10 +1328,13 @@ __PACKAGE__->register_method({
returns => {
additionalProperties => 0,
properties => {
- user => { type => 'string' },
- ticket => { type => 'string' },
- port => { type => 'integer' },
- upid => { type => 'string' },
+ user => {
+ type => 'string',
+ description => 'user/token that generated the VNC ticket in `ticket`',
+ },
+ ticket => { type => 'string', description => 'VNC ticket used to verifiy websocket connection' },
+ port => { type => 'integer', description => 'port used to bind termproxy to' },
+ upid => { type => 'string', description => 'UPID for termproxy worker task' },
},
},
code => sub {
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH manager 3/3] http server: allow unauthenticated access to /access/vncticket
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (4 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH manager 2/3] api: termproxy: add description to return schema Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox 1/3] pbs-api-types: add NodeShellTicket Fabian Grünbichler
` (20 subsequent siblings)
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
requests there are authenticated via the parameters, it only allows validating
a VNC ticket..
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
new in v1
PVE/HTTPServer.pm | 1 +
1 file changed, 1 insertion(+)
diff --git a/PVE/HTTPServer.pm b/PVE/HTTPServer.pm
index 62b53fc74..660d87e84 100755
--- a/PVE/HTTPServer.pm
+++ b/PVE/HTTPServer.pm
@@ -70,6 +70,7 @@ sub auth_handler {
if (
($rel_uri eq '/access/domains' && $method eq 'GET')
|| ($rel_uri eq '/access/ticket' && ($method eq 'GET' || $method eq 'POST'))
+ || ($rel_uri eq '/access/vncticket' && $method eq 'POST')
|| ($rel_uri eq '/access/openid/login' && $method eq 'POST')
|| ($rel_uri eq '/access/openid/auth-url' && $method eq 'POST')
) {
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH proxmox 1/3] pbs-api-types: add NodeShellTicket
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (5 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH manager 3/3] http server: allow unauthenticated access to /access/vncticket Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox 2/3] auth-api: use Authid for path ticket validation Fabian Grünbichler
` (19 subsequent siblings)
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
used for termproxy endpoint calls
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
new in v1, used by PBS and PDM
pbs-api-types/src/node.rs | 36 +++++++++++++++++++++++++++++++++++-
1 file changed, 35 insertions(+), 1 deletion(-)
diff --git a/pbs-api-types/src/node.rs b/pbs-api-types/src/node.rs
index c4e9a179..4231f312 100644
--- a/pbs-api-types/src/node.rs
+++ b/pbs-api-types/src/node.rs
@@ -1,8 +1,10 @@
use std::ffi::OsStr;
-use proxmox_schema::*;
use serde::{Deserialize, Serialize};
+use proxmox_auth_api::types::Authid;
+use proxmox_schema::*;
+
use crate::StorageStatus;
#[api]
@@ -160,3 +162,35 @@ pub struct NodeStatus {
/// Current boot mode
pub boot_info: BootModeInformation,
}
+
+#[api(
+ properties: {
+ port: {
+ type: Integer,
+ },
+ ticket: {
+ type: String,
+ },
+ upid: {
+ type: String,
+ },
+ user: {
+ type: String,
+ },
+ },
+)]
+/// Ticket used for authenticating a VNC websocket upgrade request.
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct NodeShellTicket {
+ /// port used to bind termproxy to
+ pub port: u16,
+
+ /// ticket used to verifiy websocket connection
+ pub ticket: String,
+
+ /// UPID for termproxy worker task
+ pub upid: String,
+
+ /// user or authid encoded in the ticket
+ pub user: Authid,
+}
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH proxmox 2/3] auth-api: use Authid for path ticket validation
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (6 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox 1/3] pbs-api-types: add NodeShellTicket Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox 3/3] auth-api: add vncticket verification endpoint and type Fabian Grünbichler
` (18 subsequent siblings)
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
instead of Userid. technically a breaking change, callers that pass in a Userid
at the moment and want to restrict it as such need to add an extra check.
in practice, PDM already has such a check, and PBS drops it after this change.
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
breaking change, needed by PBS
proxmox-auth-api/src/api/access.rs | 2 +-
proxmox-auth-api/src/api/mod.rs | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/proxmox-auth-api/src/api/access.rs b/proxmox-auth-api/src/api/access.rs
index a32739af..6921ea29 100644
--- a/proxmox-auth-api/src/api/access.rs
+++ b/proxmox-auth-api/src/api/access.rs
@@ -290,7 +290,7 @@ async fn authenticate_user(
bail!("ticket login failed - wrong userid");
}
} else if let Some(((path, privs), port)) = path.zip(privs).zip(port) {
- match auth_context.check_path_ticket(userid, password, path, privs, port)? {
+ match auth_context.check_path_ticket(&auth_id, password, path, privs, port)? {
None => (), // no path based tickets supported, just fall through.
Some(true) => return Ok(AuthResult::Success),
Some(false) => bail!("No such privilege"),
diff --git a/proxmox-auth-api/src/api/mod.rs b/proxmox-auth-api/src/api/mod.rs
index e176ea01..3c07ead3 100644
--- a/proxmox-auth-api/src/api/mod.rs
+++ b/proxmox-auth-api/src/api/mod.rs
@@ -78,13 +78,13 @@ pub trait AuthContext: Send + Sync {
/// Check path based tickets. (Used for terminal tickets).
fn check_path_ticket(
&self,
- userid: &Userid,
+ auth_id: &Authid,
password: &str,
path: String,
privs: String,
port: u16,
) -> Result<Option<bool>, Error> {
- let _ = (userid, password, path, privs, port);
+ let _ = (auth_id, password, path, privs, port);
Ok(None)
}
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH proxmox 3/3] auth-api: add vncticket verification endpoint and type
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (7 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox 2/3] auth-api: use Authid for path ticket validation Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-backup 1/4] tree-wide: user Userid::root_user() instead of hard-coded root@pam Fabian Grünbichler
` (17 subsequent siblings)
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
needed to allow token-based shells in PBS/PDM.
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
new in v1, required for PBS
proxmox-auth-api/src/api/access.rs | 32 +++++++++++++++++++++++++++++-
proxmox-auth-api/src/api/mod.rs | 4 ++--
proxmox-auth-api/src/types.rs | 22 ++++++++++++++++++++
3 files changed, 55 insertions(+), 3 deletions(-)
diff --git a/proxmox-auth-api/src/api/access.rs b/proxmox-auth-api/src/api/access.rs
index 6921ea29..3ff1d0e8 100644
--- a/proxmox-auth-api/src/api/access.rs
+++ b/proxmox-auth-api/src/api/access.rs
@@ -16,7 +16,7 @@ use proxmox_tfa::api::TfaChallenge;
use super::ApiTicket;
use super::{auth_context, HMACKey};
use crate::ticket::Ticket;
-use crate::types::{Authid, CreateTicket, CreateTicketResponse, Userid};
+use crate::types::{Authid, CreateTicket, CreateTicketResponse, Userid, VerifyVNCTicket};
#[allow(clippy::large_enum_variant)]
enum AuthResult {
@@ -68,6 +68,36 @@ pub async fn create_ticket(
})
}
+#[api(
+ input: {
+ properties: {
+ verify_params: {
+ type: VerifyVNCTicket,
+ flatten: true,
+ }
+ },
+ },
+ protected: true,
+ access: {
+ permission: &Permission::World,
+ },
+)]
+/// Verify that a VNC ticket is valid for a given Authid, path and privilege(s).
+pub async fn verify_vnc_ticket(verify_params: VerifyVNCTicket) -> Result<(), Error> {
+ let auth_context = auth_context()?;
+ match auth_context.check_path_ticket(
+ &verify_params.authid,
+ &verify_params.vncticket,
+ verify_params.path,
+ verify_params.privs,
+ verify_params.port.unwrap_or_default(),
+ )? {
+ None => bail!("Checking VNC ticket failed"), // no path based tickets supported, just fall through.
+ Some(true) => return Ok(()),
+ Some(false) => bail!("No such privilege"),
+ }
+}
+
pub const API_METHOD_LOGOUT: ApiMethod = ApiMethod::new(
&ApiHandler::AsyncHttpBodyParameters(&logout_handler),
&ObjectSchema::new("", &[]),
diff --git a/proxmox-auth-api/src/api/mod.rs b/proxmox-auth-api/src/api/mod.rs
index 3c07ead3..98cf77e9 100644
--- a/proxmox-auth-api/src/api/mod.rs
+++ b/proxmox-auth-api/src/api/mod.rs
@@ -19,8 +19,8 @@ use crate::ticket::Ticket;
use access::verify_csrf_prevention_token;
pub use access::{
- assemble_csrf_prevention_token, create_ticket, API_METHOD_CREATE_TICKET,
- API_METHOD_CREATE_TICKET_HTTP_ONLY, API_METHOD_LOGOUT,
+ assemble_csrf_prevention_token, create_ticket, verify_vnc_ticket, API_METHOD_CREATE_TICKET,
+ API_METHOD_CREATE_TICKET_HTTP_ONLY, API_METHOD_LOGOUT, API_METHOD_VERIFY_VNC_TICKET,
};
pub use ticket::{ApiTicket, PartialTicket};
diff --git a/proxmox-auth-api/src/types.rs b/proxmox-auth-api/src/types.rs
index 9bde661c..86b79d70 100644
--- a/proxmox-auth-api/src/types.rs
+++ b/proxmox-auth-api/src/types.rs
@@ -706,6 +706,28 @@ pub struct CreateTicket {
pub tfa_challenge: Option<String>,
}
+#[api]
+/// The parameter object for verifying a VNC ticket.
+#[derive(Debug, Clone, Deserialize, Serialize)]
+pub struct VerifyVNCTicket {
+ /// Userid or Token
+ pub authid: Authid,
+
+ /// The VNC ticket
+ #[serde(default)]
+ pub vncticket: String,
+
+ /// Verify ticket, and check if user have access 'privs' on 'path'.
+ pub path: String,
+
+ /// Verify ticket, and check if user have access 'privs' on 'path'.
+ pub privs: String,
+
+ /// Port for verifying terminal tickets.
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub port: Option<u16>,
+}
+
#[api]
/// The API response for a ticket call.
#[derive(Debug, Deserialize, Serialize)]
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH proxmox-backup 1/4] tree-wide: user Userid::root_user() instead of hard-coded root@pam
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (8 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox 3/3] auth-api: add vncticket verification endpoint and type Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-backup 2/4] api: access: add vncticket verification endpoint Fabian Grünbichler
` (16 subsequent siblings)
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
we were not super consistent here, and this might be a nice first step towards
later on replacing these call sites with calls to is_superuser(), if we go down
that route..
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
pbs-config/src/acl.rs | 2 +-
pbs-config/src/cached_user_info.rs | 4 ++--
pbs-config/src/user.rs | 5 +++--
src/api2/node/mod.rs | 10 ++++++----
4 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/pbs-config/src/acl.rs b/pbs-config/src/acl.rs
index fb3863b8f..2abbf5802 100644
--- a/pbs-config/src/acl.rs
+++ b/pbs-config/src/acl.rs
@@ -449,7 +449,7 @@ impl AclTree {
for (auth_id, roles) in &node.users {
// no need to save, because root is always 'Administrator'
- if !auth_id.is_token() && auth_id.user() == "root@pam" {
+ if !auth_id.is_token() && auth_id.user() == Userid::root_userid() {
continue;
}
for (role, propagate) in roles {
diff --git a/pbs-config/src/cached_user_info.rs b/pbs-config/src/cached_user_info.rs
index e1cd2d68a..0bba542b2 100644
--- a/pbs-config/src/cached_user_info.rs
+++ b/pbs-config/src/cached_user_info.rs
@@ -137,7 +137,7 @@ impl CachedUserInfo {
}
pub fn is_superuser(&self, auth_id: &Authid) -> bool {
- !auth_id.is_token() && auth_id.user() == "root@pam"
+ !auth_id.is_token() && auth_id.user() == Userid::root_userid()
}
pub fn is_group_member(&self, _userid: &Userid, _group: &str) -> bool {
@@ -208,7 +208,7 @@ impl CachedUserInfo {
impl UserInformation for CachedUserInfo {
fn is_superuser(&self, userid: &str) -> bool {
- userid == "root@pam"
+ userid == Userid::root_userid().as_str()
}
fn is_group_member(&self, _userid: &str, _group: &str) -> bool {
diff --git a/pbs-config/src/user.rs b/pbs-config/src/user.rs
index 08d141e66..87e3bfb2d 100644
--- a/pbs-config/src/user.rs
+++ b/pbs-config/src/user.rs
@@ -53,8 +53,9 @@ pub fn config() -> Result<(SectionConfigData, [u8; 32]), Error> {
let digest = openssl::sha::sha256(content.as_bytes());
let mut data = CONFIG.parse(USER_CFG_FILENAME, &content)?;
+ let root_user = Userid::root_userid().as_str();
- if !data.sections.contains_key("root@pam") {
+ if !data.sections.contains_key(root_user) {
let user: User = User {
userid: Userid::root_userid().clone(),
comment: Some("Superuser".to_string()),
@@ -64,7 +65,7 @@ pub fn config() -> Result<(SectionConfigData, [u8; 32]), Error> {
lastname: None,
email: None,
};
- data.set_data("root@pam", "user", &user).unwrap();
+ data.set_data(root_user, "user", &user).unwrap();
}
Ok((data, digest))
diff --git a/src/api2/node/mod.rs b/src/api2/node/mod.rs
index 83367bd09..72df9ea72 100644
--- a/src/api2/node/mod.rs
+++ b/src/api2/node/mod.rs
@@ -25,7 +25,7 @@ use proxmox_schema::*;
use proxmox_sortable_macro::sortable;
use proxmox_sys::fd::fd_change_cloexec;
-use pbs_api_types::{NODE_SCHEMA, PRIV_SYS_CONSOLE};
+use pbs_api_types::{Userid, NODE_SCHEMA, PRIV_SYS_CONSOLE};
use tracing::{info, warn};
use crate::auth::{private_auth_keyring, public_auth_keyring};
@@ -98,6 +98,8 @@ pub const SHELL_CMD_SCHEMA: Schema = StringSchema::new("The command to run.")
)]
/// Call termproxy and return shell ticket
async fn termproxy(cmd: Option<String>, rpcenv: &mut dyn RpcEnvironment) -> Result<Value, Error> {
+ let root_user = Userid::root_userid();
+
// intentionally user only for now
let auth_id: Authid = rpcenv
.get_auth_id()
@@ -125,14 +127,14 @@ async fn termproxy(cmd: Option<String>, rpcenv: &mut dyn RpcEnvironment) -> Resu
match cmd.as_deref() {
Some("login") | None => {
command.push("login");
- if userid == "root@pam" {
+ if userid == root_user {
command.push("-f");
command.push("root");
}
}
Some("upgrade") => {
- if userid != "root@pam" {
- bail!("only root@pam can upgrade");
+ if userid != root_user {
+ bail!("only {root_user} can upgrade");
}
// TODO: add nicer/safer wrapper like in PVE instead
command.push("sh");
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH proxmox-backup 2/4] api: access: add vncticket verification endpoint
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (9 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-backup 1/4] tree-wide: user Userid::root_user() instead of hard-coded root@pam Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-backup 3/4] api: node shell: allow access for tokens Fabian Grünbichler
` (15 subsequent siblings)
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
via proxmox-auth-api, needed for new termproxy auth call to work.
the existing ticket verification is user-only, the vncticket one allows tokens
as well.
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
new in v1, requires bumped proxmox-auth-api
src/api2/access/mod.rs | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/api2/access/mod.rs b/src/api2/access/mod.rs
index b356c842d..9e23db278 100644
--- a/src/api2/access/mod.rs
+++ b/src/api2/access/mod.rs
@@ -10,7 +10,7 @@ use serde_json::{json, Value};
use std::collections::HashMap;
use std::collections::HashSet;
-use proxmox_auth_api::api::API_METHOD_CREATE_TICKET_HTTP_ONLY;
+use proxmox_auth_api::api::{API_METHOD_CREATE_TICKET_HTTP_ONLY, API_METHOD_VERIFY_VNC_TICKET};
use proxmox_auth_api::types::{CreateTicket, CreateTicketResponse};
use proxmox_router::{
http_bail, http_err, list_subdirs_api_method, ApiHandler, ApiMethod, ApiResponseFuture,
@@ -281,6 +281,10 @@ const SUBDIRS: SubdirMap = &sorted!([
.post(&API_METHOD_CREATE_TICKET_TOGGLE)
.delete(&proxmox_auth_api::api::API_METHOD_LOGOUT)
),
+ (
+ "vncticket",
+ &Router::new().post(&API_METHOD_VERIFY_VNC_TICKET)
+ ),
("openid", &openid::ROUTER),
("domains", &domain::ROUTER),
("roles", &role::ROUTER),
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH proxmox-backup 3/4] api: node shell: allow access for tokens
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (10 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-backup 2/4] api: access: add vncticket verification endpoint Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-backup 4/4] api: termproxy: use NodeShellTicket type from pbs-api-types Fabian Grünbichler
` (14 subsequent siblings)
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
needed for PDM, but backwards compatible for existing user-based usage.
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
new in v1, requires bumped termproxy
src/api2/node/mod.rs | 28 ++++++++--------------------
src/auth.rs | 5 ++---
src/tools/ticket.rs | 6 +++---
3 files changed, 13 insertions(+), 26 deletions(-)
diff --git a/src/api2/node/mod.rs b/src/api2/node/mod.rs
index 72df9ea72..a5ec903a7 100644
--- a/src/api2/node/mod.rs
+++ b/src/api2/node/mod.rs
@@ -98,7 +98,7 @@ pub const SHELL_CMD_SCHEMA: Schema = StringSchema::new("The command to run.")
)]
/// Call termproxy and return shell ticket
async fn termproxy(cmd: Option<String>, rpcenv: &mut dyn RpcEnvironment) -> Result<Value, Error> {
- let root_user = Userid::root_userid();
+ let root_auth_id = Authid::root_auth_id();
// intentionally user only for now
let auth_id: Authid = rpcenv
@@ -106,12 +106,6 @@ async fn termproxy(cmd: Option<String>, rpcenv: &mut dyn RpcEnvironment) -> Resu
.ok_or_else(|| format_err!("no authid available"))?
.parse()?;
- if auth_id.is_token() {
- bail!("API tokens cannot access this API endpoint");
- }
-
- let userid = auth_id.user();
-
let path = "/system";
// use port 0 and let the kernel decide which port is free
@@ -120,21 +114,21 @@ async fn termproxy(cmd: Option<String>, rpcenv: &mut dyn RpcEnvironment) -> Resu
let ticket = Ticket::new(crate::auth::TERM_PREFIX, &Empty)?.sign(
private_auth_keyring(),
- Some(&tools::ticket::term_aad(userid, path, port)),
+ Some(&tools::ticket::term_aad(&auth_id, path, port)),
)?;
let mut command = Vec::new();
match cmd.as_deref() {
Some("login") | None => {
command.push("login");
- if userid == root_user {
+ if auth_id == *root_auth_id {
command.push("-f");
command.push("root");
}
}
Some("upgrade") => {
- if userid != root_user {
- bail!("only {root_user} can upgrade");
+ if auth_id != *root_auth_id {
+ bail!("only {root_auth_id} can upgrade");
}
// TODO: add nicer/safer wrapper like in PVE instead
command.push("sh");
@@ -144,7 +138,6 @@ async fn termproxy(cmd: Option<String>, rpcenv: &mut dyn RpcEnvironment) -> Resu
_ => bail!("invalid command"),
};
- let username = userid.name().to_owned();
let upid = WorkerTask::spawn(
"termproxy",
None,
@@ -166,6 +159,7 @@ async fn termproxy(cmd: Option<String>, rpcenv: &mut dyn RpcEnvironment) -> Resu
"--authport",
"82",
"--port-as-fd",
+ "--vncticket-endpoint",
"--",
]);
arguments.extend_from_slice(&command);
@@ -234,9 +228,8 @@ async fn termproxy(cmd: Option<String>, rpcenv: &mut dyn RpcEnvironment) -> Resu
},
)?;
- // FIXME: We're returning the user NAME only?
Ok(json!({
- "user": username,
+ "user": auth_id,
"ticket": ticket,
"port": port,
"upid": upid,
@@ -278,11 +271,6 @@ fn upgrade_to_websocket(
.ok_or_else(|| format_err!("no authid available"))?
.parse()?;
- if auth_id.is_token() {
- bail!("API tokens cannot access this API endpoint");
- }
-
- let userid = auth_id.user();
let ticket = pbs_tools::json::required_string_param(¶m, "vncticket")?;
let port: u16 = pbs_tools::json::required_integer_param(¶m, "port")? as u16;
@@ -290,7 +278,7 @@ fn upgrade_to_websocket(
Ticket::<Empty>::parse(ticket)?.verify(
public_auth_keyring(),
crate::auth::TERM_PREFIX,
- Some(&tools::ticket::term_aad(userid, "/system", port)),
+ Some(&tools::ticket::term_aad(&auth_id, "/system", port)),
)?;
let (ws, response) = WebSocket::new(parts.headers.clone())?;
diff --git a/src/auth.rs b/src/auth.rs
index ac24c8cac..a930d8cd9 100644
--- a/src/auth.rs
+++ b/src/auth.rs
@@ -449,7 +449,7 @@ impl proxmox_auth_api::api::AuthContext for PbsAuthContext {
/// Check path based tickets. (Used for terminal tickets).
fn check_path_ticket(
&self,
- userid: &Userid,
+ auth_id: &Authid,
password: &str,
path: String,
privs: String,
@@ -463,11 +463,10 @@ impl proxmox_auth_api::api::AuthContext for PbsAuthContext {
ticket.verify(
self.keyring,
TERM_PREFIX,
- Some(&crate::tools::ticket::term_aad(userid, &path, port)),
+ Some(&crate::tools::ticket::term_aad(auth_id, &path, port)),
)
}) {
let user_info = pbs_config::CachedUserInfo::new()?;
- let auth_id = Authid::from(userid.clone());
for (name, privilege) in pbs_api_types::PRIVILEGES {
if *name == privs {
let mut path_vec = Vec::new();
diff --git a/src/tools/ticket.rs b/src/tools/ticket.rs
index 8dd3c968a..f086d2d82 100644
--- a/src/tools/ticket.rs
+++ b/src/tools/ticket.rs
@@ -1,5 +1,5 @@
-use pbs_api_types::Userid;
+use pbs_api_types::Authid;
-pub fn term_aad(userid: &Userid, path: &str, port: u16) -> String {
- format!("{userid}{path}{port}")
+pub fn term_aad(auth_id: &Authid, path: &str, port: u16) -> String {
+ format!("{auth_id}{path}{port}")
}
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH proxmox-backup 4/4] api: termproxy: use NodeShellTicket type from pbs-api-types
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (11 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-backup 3/4] api: node shell: allow access for tokens Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-yew-comp 1/3] xtermjs: add remote PVE support Fabian Grünbichler
` (13 subsequent siblings)
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
new in v1, requires bumped pbs-api-types
src/api2/node/mod.rs | 40 ++++++++++++----------------------------
1 file changed, 12 insertions(+), 28 deletions(-)
diff --git a/src/api2/node/mod.rs b/src/api2/node/mod.rs
index a5ec903a7..42e1dbaa2 100644
--- a/src/api2/node/mod.rs
+++ b/src/api2/node/mod.rs
@@ -25,7 +25,7 @@ use proxmox_schema::*;
use proxmox_sortable_macro::sortable;
use proxmox_sys::fd::fd_change_cloexec;
-use pbs_api_types::{Userid, NODE_SCHEMA, PRIV_SYS_CONSOLE};
+use pbs_api_types::{NodeShellTicket, NODE_SCHEMA, PRIV_SYS_CONSOLE};
use tracing::{info, warn};
use crate::auth::{private_auth_keyring, public_auth_keyring};
@@ -70,26 +70,7 @@ pub const SHELL_CMD_SCHEMA: Schema = StringSchema::new("The command to run.")
},
},
returns: {
- type: Object,
- description: "Object with the user, ticket, port and upid",
- properties: {
- user: {
- description: "",
- type: String,
- },
- ticket: {
- description: "",
- type: String,
- },
- port: {
- description: "",
- type: String,
- },
- upid: {
- description: "",
- type: String,
- },
- }
+ type: NodeShellTicket,
},
access: {
description: "The user needs Sys.Console on /system.",
@@ -97,7 +78,10 @@ pub const SHELL_CMD_SCHEMA: Schema = StringSchema::new("The command to run.")
}
)]
/// Call termproxy and return shell ticket
-async fn termproxy(cmd: Option<String>, rpcenv: &mut dyn RpcEnvironment) -> Result<Value, Error> {
+async fn termproxy(
+ cmd: Option<String>,
+ rpcenv: &mut dyn RpcEnvironment,
+) -> Result<NodeShellTicket, Error> {
let root_auth_id = Authid::root_auth_id();
// intentionally user only for now
@@ -228,12 +212,12 @@ async fn termproxy(cmd: Option<String>, rpcenv: &mut dyn RpcEnvironment) -> Resu
},
)?;
- Ok(json!({
- "user": auth_id,
- "ticket": ticket,
- "port": port,
- "upid": upid,
- }))
+ Ok(NodeShellTicket {
+ user: auth_id,
+ ticket,
+ port,
+ upid,
+ })
}
#[sortable]
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH proxmox-yew-comp 1/3] xtermjs: add remote PVE support
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (12 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-backup 4/4] api: termproxy: use NodeShellTicket type from pbs-api-types Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-yew-comp 2/3] xtermjs: merge ConsoleType to parameters conversion Fabian Grünbichler
` (12 subsequent siblings)
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
by defining a new ConsoleType containing the remote type and name.
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
v1:
- encode remote name in ConsoleType variant, drop Copy, drop additional
parameters (Thanks Dominik!)
src/xtermjs.rs | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/src/xtermjs.rs b/src/xtermjs.rs
index 4eb464d..9656516 100644
--- a/src/xtermjs.rs
+++ b/src/xtermjs.rs
@@ -47,7 +47,7 @@ impl XTermJs {
// FIXME: separate noVNC and xterm.js, this is not a nice interface!
/// Open a new terminal window.
pub fn open_xterm_js_viewer(console_type: ConsoleType, node_name: &str, vnc: bool) {
- let url = xtermjs_url(console_type, node_name, vnc);
+ let url = xtermjs_url(&console_type, node_name, vnc);
let target = "_blank";
let features =
"toolbar=no,location=no,status=no,menubar=no,resizable=yes,width=800,height=420";
@@ -66,20 +66,21 @@ impl XTermJs {
}
}
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Clone, PartialEq)]
pub enum ConsoleType {
KVM(u64),
LXC(u64),
UpgradeShell,
LoginShell,
+ RemotePveLoginShell(String),
}
-fn xtermjs_url(console_type: ConsoleType, node_name: &str, vnc: bool) -> String {
+fn xtermjs_url(console_type: &ConsoleType, node_name: &str, vnc: bool) -> String {
let console = match console_type {
ConsoleType::KVM(_vmid) => "kvm",
ConsoleType::LXC(_vmid) => "lxc",
ConsoleType::UpgradeShell => "upgrade",
- ConsoleType::LoginShell => "shell",
+ ConsoleType::LoginShell | ConsoleType::RemotePveLoginShell(_) => "shell",
};
let mut param = json!({
@@ -96,15 +97,20 @@ fn xtermjs_url(console_type: ConsoleType, node_name: &str, vnc: bool) -> String
match console_type {
ConsoleType::KVM(vmid) => {
- param["vmid"] = vmid.into();
+ param["vmid"] = (*vmid).into();
}
ConsoleType::LXC(vmid) => {
- param["vmid"] = vmid.into();
+ param["vmid"] = (*vmid).into();
}
ConsoleType::UpgradeShell => { /* no additional parameters required */ }
ConsoleType::LoginShell => {
param["cmd"] = "login".into();
}
+ ConsoleType::RemotePveLoginShell(remote_name) => {
+ param["cmd"] = "login".into();
+ param["remote-type"] = "pve".into();
+ param["remote"] = remote_name.as_str().into();
+ }
}
format!("?{}", json_object_to_query(param).unwrap())
@@ -122,7 +128,7 @@ impl Component for ProxmoxXTermJs {
fn view(&self, ctx: &Context<Self>) -> Html {
let props = ctx.props();
- let url = xtermjs_url(props.console_type, &props.node_name, props.vnc);
+ let url = xtermjs_url(&props.console_type, &props.node_name, props.vnc);
html! {<iframe class="pwt-flex-fit" src={format!("/{url}")}/>}
}
}
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH proxmox-yew-comp 2/3] xtermjs: merge ConsoleType to parameters conversion
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (13 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-yew-comp 1/3] xtermjs: add remote PVE support Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-yew-comp 3/3] xtermjs: add remote PBS console type Fabian Grünbichler
` (11 subsequent siblings)
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
new in v1
src/xtermjs.rs | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/src/xtermjs.rs b/src/xtermjs.rs
index 9656516..4d83a73 100644
--- a/src/xtermjs.rs
+++ b/src/xtermjs.rs
@@ -76,15 +76,7 @@ pub enum ConsoleType {
}
fn xtermjs_url(console_type: &ConsoleType, node_name: &str, vnc: bool) -> String {
- let console = match console_type {
- ConsoleType::KVM(_vmid) => "kvm",
- ConsoleType::LXC(_vmid) => "lxc",
- ConsoleType::UpgradeShell => "upgrade",
- ConsoleType::LoginShell | ConsoleType::RemotePveLoginShell(_) => "shell",
- };
-
let mut param = json!({
- "console": console,
"node": node_name,
});
@@ -97,16 +89,22 @@ fn xtermjs_url(console_type: &ConsoleType, node_name: &str, vnc: bool) -> String
match console_type {
ConsoleType::KVM(vmid) => {
+ param["console"] = "kvm".into();
param["vmid"] = (*vmid).into();
}
ConsoleType::LXC(vmid) => {
+ param["console"] = "lxc".into();
param["vmid"] = (*vmid).into();
}
- ConsoleType::UpgradeShell => { /* no additional parameters required */ }
+ ConsoleType::UpgradeShell => {
+ param["console"] = "upgrade".into();
+ }
ConsoleType::LoginShell => {
+ param["console"] = "shell".into();
param["cmd"] = "login".into();
}
ConsoleType::RemotePveLoginShell(remote_name) => {
+ param["console"] = "shell".into();
param["cmd"] = "login".into();
param["remote-type"] = "pve".into();
param["remote"] = remote_name.as_str().into();
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH proxmox-yew-comp 3/3] xtermjs: add remote PBS console type
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (14 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-yew-comp 2/3] xtermjs: merge ConsoleType to parameters conversion Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 1/9] auth: allow tokens in term tickets Fabian Grünbichler
` (10 subsequent siblings)
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
new in v1
src/xtermjs.rs | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/xtermjs.rs b/src/xtermjs.rs
index 4d83a73..c2c080c 100644
--- a/src/xtermjs.rs
+++ b/src/xtermjs.rs
@@ -73,6 +73,7 @@ pub enum ConsoleType {
UpgradeShell,
LoginShell,
RemotePveLoginShell(String),
+ RemotePbsLoginShell(String),
}
fn xtermjs_url(console_type: &ConsoleType, node_name: &str, vnc: bool) -> String {
@@ -103,6 +104,12 @@ fn xtermjs_url(console_type: &ConsoleType, node_name: &str, vnc: bool) -> String
param["console"] = "shell".into();
param["cmd"] = "login".into();
}
+ ConsoleType::RemotePbsLoginShell(remote_name) => {
+ param["console"] = "shell".into();
+ param["cmd"] = "login".into();
+ param["remote-type"] = "pbs".into();
+ param["remote"] = remote_name.as_str().into();
+ }
ConsoleType::RemotePveLoginShell(remote_name) => {
param["console"] = "shell".into();
param["cmd"] = "login".into();
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH proxmox-datacenter-manager 1/9] auth: allow tokens in term tickets
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (15 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-yew-comp 3/3] xtermjs: add remote PBS console type Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 2/9] connection: add access to "raw" client Fabian Grünbichler
` (9 subsequent siblings)
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
adapting to proxmox-auth-api change required for PBS support for remote shells.
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
new in v1
server/src/auth/mod.rs | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/server/src/auth/mod.rs b/server/src/auth/mod.rs
index 9413a83..0d6bcdd 100644
--- a/server/src/auth/mod.rs
+++ b/server/src/auth/mod.rs
@@ -141,7 +141,7 @@ impl proxmox_auth_api::api::AuthContext for PdmAuthContext {
/// Check path based tickets. (Used for terminal tickets).
fn check_path_ticket(
&self,
- userid: &Userid,
+ auth_id: &Authid,
password: &str,
path: String,
privs: String,
@@ -155,11 +155,10 @@ impl proxmox_auth_api::api::AuthContext for PdmAuthContext {
ticket.verify(
&self.keyring,
TERM_PREFIX,
- Some(&format!("{}{}{}", userid, path, port)),
+ Some(&format!("{}{}{}", auth_id, path, port)),
)
}) {
let user_info = CachedUserInfo::new()?;
- let auth_id = Authid::from(userid.clone());
for (name, privilege) in pdm_api_types::PRIVILEGES {
if *name == privs {
let mut path_vec = Vec::new();
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH proxmox-datacenter-manager 2/9] connection: add access to "raw" client
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (16 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 1/9] auth: allow tokens in term tickets Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-13 10:39 ` Stefan Hanreich
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 3/9] pbs client: add termproxy wrapper Fabian Grünbichler
` (8 subsequent siblings)
26 siblings, 1 reply; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
needed for websocket connections and similar lower level access.
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
unchanged
server/src/connection.rs | 11 +++++++++++
server/src/metric_collection/collection_task.rs | 5 +++++
server/src/test_support/fake_remote.rs | 5 +++++
3 files changed, 21 insertions(+)
diff --git a/server/src/connection.rs b/server/src/connection.rs
index e749c1a..1c0069e 100644
--- a/server/src/connection.rs
+++ b/server/src/connection.rs
@@ -252,6 +252,9 @@ pub trait ClientFactory {
///
/// Note: currently does not support two factor authentication.
async fn make_pbs_client_and_login(&self, remote: &Remote) -> Result<Box<PbsClient>, Error>;
+
+ /// Create a new API client for raw acess to the given remote
+ fn make_raw_client(&self, remote: &Remote) -> Result<Box<Client>, Error>;
}
/// Default production client factory
@@ -346,6 +349,10 @@ impl ClientFactory for DefaultClientFactory {
ConnectionCache::get().make_pve_client(remote)
}
+ fn make_raw_client(&self, remote: &Remote) -> Result<Box<Client>, Error> {
+ Ok(Box::new(crate::connection::connect(remote, None)?))
+ }
+
fn make_pbs_client(&self, remote: &Remote) -> Result<Box<PbsClient>, Error> {
let client = crate::connection::connect(remote, None)?;
Ok(Box::new(PbsClient(client)))
@@ -418,6 +425,10 @@ pub fn make_pbs_client(remote: &Remote) -> Result<Box<PbsClient>, Error> {
instance().make_pbs_client(remote)
}
+pub fn make_raw_client(remote: &Remote) -> Result<Box<Client>, Error> {
+ instance().make_raw_client(remote)
+}
+
/// Create a new API client for PVE remotes.
///
/// In case the remote has a user configured (instead of an API token), it will connect and get a
diff --git a/server/src/metric_collection/collection_task.rs b/server/src/metric_collection/collection_task.rs
index a6c8443..cc1a460 100644
--- a/server/src/metric_collection/collection_task.rs
+++ b/server/src/metric_collection/collection_task.rs
@@ -387,6 +387,7 @@ pub(super) mod tests {
use http::StatusCode;
use pdm_api_types::Authid;
+ use proxmox_client::Client;
use pve_api_types::{ClusterMetrics, ClusterMetricsData};
use crate::{
@@ -430,6 +431,10 @@ pub(super) mod tests {
bail!("not implemented")
}
+ fn make_raw_client(&self, _remote: &Remote) -> Result<Box<Client>, Error> {
+ bail!("not implemented")
+ }
+
async fn make_pve_client_and_login(
&self,
_remote: &Remote,
diff --git a/server/src/test_support/fake_remote.rs b/server/src/test_support/fake_remote.rs
index cd2ccf6..62dd869 100644
--- a/server/src/test_support/fake_remote.rs
+++ b/server/src/test_support/fake_remote.rs
@@ -5,6 +5,7 @@ use serde::Deserialize;
use pdm_api_types::{remotes::Remote, Authid, ConfigDigest};
use pdm_config::remotes::RemoteConfig;
+use proxmox_client::Client;
use proxmox_product_config::ApiLockGuard;
use proxmox_section_config::typed::SectionConfigData;
use pve_api_types::{
@@ -100,6 +101,10 @@ impl ClientFactory for FakeClientFactory {
bail!("not implemented")
}
+ fn make_raw_client(&self, _remote: &Remote) -> Result<Box<Client>, Error> {
+ bail!("not implemented")
+ }
+
async fn make_pve_client_and_login(&self, _remote: &Remote) -> Result<Arc<PveClient>, Error> {
bail!("not implemented")
}
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH proxmox-datacenter-manager 3/9] pbs client: add termproxy wrapper
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (17 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 2/9] connection: add access to "raw" client Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 4/9] api: add remote_shell module with termproxy endpoint Fabian Grünbichler
` (7 subsequent siblings)
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
new in v1, requires bumped pbs-api-types
server/src/pbs_client.rs | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/server/src/pbs_client.rs b/server/src/pbs_client.rs
index 4908736..f2b4838 100644
--- a/server/src/pbs_client.rs
+++ b/server/src/pbs_client.rs
@@ -238,6 +238,12 @@ impl PbsClient {
Ok(self.0.get(path).await?.expect_json()?.data)
}
+ /// Return a term ticket for calling the vncwebsocket endpoint
+ pub async fn node_shell_termproxy(&self) -> Result<pbs_api_types::NodeShellTicket, Error> {
+ let path = "/api2/extjs/nodes/localhost/termproxy";
+ Ok(self.0.post_without_body(path).await?.expect_json()?.data)
+ }
+
/// Return the datastore status
pub async fn datastore_status(
&self,
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH proxmox-datacenter-manager 4/9] api: add remote_shell module with termproxy endpoint
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (18 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 3/9] pbs client: add termproxy wrapper Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 5/9] api: remote shell: add websocket endpoint Fabian Grünbichler
` (6 subsequent siblings)
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
contrary to the PDM node one or the PVE/PBS ones, this doesn't spawn a
termproxy instance, but just generates the ticket used for authenticating the
websocket upgrade on the PDM side.
the returned port is hard-coded as 0 to be compatible with the rest of the
stack that expects one.
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
replaces previous patch which was PVE only
server/src/api/mod.rs | 1 +
server/src/api/remote_shell.rs | 80 ++++++++++++++++++++++++++++++++++
2 files changed, 81 insertions(+)
create mode 100644 server/src/api/remote_shell.rs
diff --git a/server/src/api/mod.rs b/server/src/api/mod.rs
index 6a7a65a..dca597f 100644
--- a/server/src/api/mod.rs
+++ b/server/src/api/mod.rs
@@ -13,6 +13,7 @@ pub mod metric_collection;
pub mod nodes;
pub mod pbs;
pub mod pve;
+pub mod remote_shell;
pub mod remote_tasks;
pub mod remote_updates;
pub mod remotes;
diff --git a/server/src/api/remote_shell.rs b/server/src/api/remote_shell.rs
new file mode 100644
index 0000000..380bbba
--- /dev/null
+++ b/server/src/api/remote_shell.rs
@@ -0,0 +1,80 @@
+use anyhow::{bail, format_err, Error};
+use serde_json::{json, Value};
+
+use proxmox_auth_api::{
+ ticket::{Empty, Ticket},
+ Keyring,
+};
+use proxmox_router::{Permission, RpcEnvironment};
+use proxmox_schema::api;
+
+use pdm_api_types::{remotes::REMOTE_ID_SCHEMA, Authid, NODE_SCHEMA, PRIV_SYS_CONSOLE};
+
+fn encode_term_ticket_path(remote: &str, node: &str) -> String {
+ format!("/shell/{remote}/{node}")
+}
+
+#[api(
+ protected: true,
+ input: {
+ properties: {
+ remote: { schema: REMOTE_ID_SCHEMA },
+ node: {
+ schema: NODE_SCHEMA,
+ },
+ },
+ },
+ returns: {
+ type: Object,
+ description: "Object with the user and ticket",
+ properties: {
+ user: {
+ description: "User that obtained the VNC ticket.",
+ type: String,
+ },
+ ticket: {
+ description: "VNC ticket used to authenticate websocket upgrade.",
+ type: String,
+ },
+ port: {
+ description: "Always '0'.",
+ type: Integer,
+ }
+ }
+ },
+ access: {
+ description: "Restricted to users",
+ permission: &Permission::Privilege(&["resource", "{remote}", "node", "{node}"], PRIV_SYS_CONSOLE, false),
+ }
+)]
+/// Call termproxy and return shell ticket
+pub(crate) async fn shell_ticket(
+ remote: String,
+ node: String,
+ rpcenv: &mut dyn RpcEnvironment,
+) -> Result<Value, Error> {
+ // intentionally user only for now
+ let auth_id: Authid = rpcenv
+ .get_auth_id()
+ .ok_or_else(|| format_err!("no authid available"))?
+ .parse()?;
+
+ if auth_id.is_token() {
+ bail!("API tokens cannot access this API endpoint");
+ }
+
+ let userid = auth_id.user();
+ let path = encode_term_ticket_path(&remote, &node);
+
+ let private_auth_keyring =
+ Keyring::with_private_key(crate::auth::key::private_auth_key().clone());
+
+ let ticket = Ticket::new(crate::auth::TERM_PREFIX, &Empty)?
+ .sign(&private_auth_keyring, Some(&format!("{}{}", userid, path)))?;
+
+ Ok(json!({
+ "user": userid,
+ "ticket": ticket,
+ "port": 0,
+ }))
+}
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH proxmox-datacenter-manager 5/9] api: remote shell: add websocket endpoint
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (19 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 4/9] api: add remote_shell module with termproxy endpoint Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 6/9] api: pve: wire up remote shell support Fabian Grünbichler
` (5 subsequent siblings)
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
instead of directly forwarding to a running termproxy instance, PDM needs to
authenticate the incoming connection, create a new VNC ticket (and spawn a
termproxy instance) on the remote side, and forward the incoming connection to
the remote.
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
replaces previous patch which was PVE only
Cargo.toml | 2 +-
debian/control | 12 +--
server/src/api/remote_shell.rs | 187 ++++++++++++++++++++++++++++++++-
3 files changed, 191 insertions(+), 10 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
index 3252ccb..4328402 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -40,7 +40,7 @@ proxmox-auth-api = "1"
proxmox-base64 = "1"
proxmox-client = "1"
proxmox-daemon = "1"
-proxmox-http = { version = "1", features = [ "client", "http-helpers", "websocket" ] } # see below
+proxmox-http = { version = "1.0.4", features = [ "client", "http-helpers", "websocket" ] } # see below
proxmox-human-byte = "1"
proxmox-io = "1.0.1" # tools and client use "tokio" feature
proxmox-ldap = { version = "1.1", features = ["sync"] }
diff --git a/debian/control b/debian/control
index 19b13c8..e1e8c8f 100644
--- a/debian/control
+++ b/debian/control
@@ -47,12 +47,12 @@ Build-Depends: cargo:native,
librust-proxmox-daemon-1+default-dev,
librust-proxmox-dns-api-1+default-dev,
librust-proxmox-dns-api-1+impl-dev,
- librust-proxmox-http-1+client-dev,
- librust-proxmox-http-1+client-trait-dev,
- librust-proxmox-http-1+default-dev,
- librust-proxmox-http-1+http-helpers-dev,
- librust-proxmox-http-1+proxmox-async-dev,
- librust-proxmox-http-1+websocket-dev,
+ librust-proxmox-http-1+client-dev (>= 1.0.4-~~),
+ librust-proxmox-http-1+client-trait-dev (>= 1.0.4-~~),
+ librust-proxmox-http-1+default-dev (>= 1.0.4-~~),
+ librust-proxmox-http-1+http-helpers-dev (>= 1.0.4-~~),
+ librust-proxmox-http-1+proxmox-async-dev (>= 1.0.4-~~),
+ librust-proxmox-http-1+websocket-dev (>= 1.0.4-~~),
librust-proxmox-human-byte-1+default-dev,
librust-proxmox-lang-1+default-dev (>= 1.1-~~),
librust-proxmox-ldap-1+default-dev (>= 1.1-~~),
diff --git a/server/src/api/remote_shell.rs b/server/src/api/remote_shell.rs
index 380bbba..c617b4d 100644
--- a/server/src/api/remote_shell.rs
+++ b/server/src/api/remote_shell.rs
@@ -1,14 +1,30 @@
use anyhow::{bail, format_err, Error};
+use futures::{FutureExt, TryFutureExt};
+use http::{
+ header::{SEC_WEBSOCKET_KEY, SEC_WEBSOCKET_VERSION, UPGRADE},
+ request::Parts,
+ Method, Request, StatusCode,
+};
+use hyper::upgrade::Upgraded;
+use hyper_util::rt::TokioIo;
use serde_json::{json, Value};
use proxmox_auth_api::{
ticket::{Empty, Ticket},
Keyring,
};
-use proxmox_router::{Permission, RpcEnvironment};
-use proxmox_schema::api;
+use proxmox_client::ApiPathBuilder;
+use proxmox_http::{websocket::WebSocket, Body};
+use proxmox_router::{ApiHandler, ApiMethod, ApiResponseFuture, Permission, RpcEnvironment};
+use proxmox_schema::{api, IntegerSchema, ObjectSchema, StringSchema};
+use proxmox_sortable_macro::sortable;
-use pdm_api_types::{remotes::REMOTE_ID_SCHEMA, Authid, NODE_SCHEMA, PRIV_SYS_CONSOLE};
+use pdm_api_types::{
+ remotes::{RemoteType, REMOTE_ID_SCHEMA},
+ Authid, NODE_SCHEMA, PRIV_SYS_CONSOLE,
+};
+
+use crate::api::{nodes::vncwebsocket::required_string_param, remotes::get_remote};
fn encode_term_ticket_path(remote: &str, node: &str) -> String {
format!("/shell/{remote}/{node}")
@@ -78,3 +94,168 @@ pub(crate) async fn shell_ticket(
"port": 0,
}))
}
+
+#[sortable]
+pub const API_METHOD_SHELL_WEBSOCKET: ApiMethod = ApiMethod::new(
+ &ApiHandler::AsyncHttp(&upgrade_to_websocket),
+ &ObjectSchema::new(
+ "Upgraded to websocket",
+ &sorted!([
+ ("remote", false, &REMOTE_ID_SCHEMA),
+ ("node", false, &NODE_SCHEMA),
+ (
+ "vncticket",
+ false,
+ &StringSchema::new("Terminal ticket").schema()
+ ),
+ ("port", false, &IntegerSchema::new("Terminal port").schema()),
+ ]),
+ ),
+)
+.access(
+ Some("The user needs Sys.Console on /resource/{remote}/node/{node}."),
+ &Permission::Privilege(
+ &["resource", "{remote}", "node", "{node}"],
+ PRIV_SYS_CONSOLE,
+ false,
+ ),
+);
+
+fn upgrade_to_websocket(
+ parts: Parts,
+ req_body: hyper::body::Incoming,
+ param: Value,
+ _info: &ApiMethod,
+ rpcenv: Box<dyn RpcEnvironment>,
+) -> ApiResponseFuture {
+ async move {
+ // intentionally user only for now
+ let auth_id: Authid = rpcenv
+ .get_auth_id()
+ .ok_or_else(|| format_err!("no authid available"))?
+ .parse()?;
+
+ if auth_id.is_token() {
+ bail!("API tokens cannot access this API endpoint");
+ }
+
+ let userid = auth_id.user();
+ let ticket = required_string_param(¶m, "vncticket")?;
+
+ let public_auth_keyring =
+ Keyring::with_public_key(crate::auth::key::public_auth_key().clone());
+
+ let remote = required_string_param(¶m, "remote")?.to_owned();
+ let node = required_string_param(¶m, "node")?.to_owned();
+ let ticket_path = encode_term_ticket_path(&remote, &node);
+
+ Ticket::<Empty>::parse(ticket)?.verify(
+ &public_auth_keyring,
+ crate::auth::TERM_PREFIX,
+ Some(&format!("{}{}", userid, ticket_path)),
+ )?;
+
+ let (mut ws, response) = WebSocket::new(parts.headers.clone())?;
+
+ proxmox_rest_server::spawn_internal_task(async move {
+ let incoming_ws: Upgraded =
+ match hyper::upgrade::on(Request::from_parts(parts, req_body))
+ .map_err(Error::from)
+ .await
+ {
+ Ok(upgraded) => upgraded,
+ _ => bail!("error"),
+ };
+
+ let (remotes, _digest) = pdm_config::remotes::config()?;
+ let remote = get_remote(&remotes, &remote)?;
+ let (ticket, port) = match remote.ty {
+ RemoteType::Pve => {
+ let pve = crate::connection::make_pve_client(&remote)?;
+ let pve_term_ticket = pve
+ .node_shell_termproxy(
+ &node,
+ pve_api_types::NodeShellTermproxy {
+ cmd: None,
+ cmd_opts: None,
+ },
+ )
+ .await?;
+ (pve_term_ticket.ticket, pve_term_ticket.port)
+ }
+ RemoteType::Pbs => {
+ let pbs = crate::connection::make_pbs_client(&remote)?;
+ let pbs_term_ticket = pbs.node_shell_termproxy().await?;
+ (pbs_term_ticket.ticket, pbs_term_ticket.port as i64)
+ }
+ };
+
+ let raw_client = crate::connection::make_raw_client(remote)?;
+
+ let ws_key = proxmox_sys::linux::random_data(16)?;
+ let ws_key = proxmox_base64::encode(&ws_key);
+
+ let api_url = raw_client.api_url().clone().into_parts();
+
+ let mut builder = http::uri::Builder::new();
+ if let Some(scheme) = api_url.scheme {
+ builder = builder.scheme(scheme);
+ }
+ if let Some(authority) = api_url.authority {
+ builder = builder.authority(authority)
+ }
+ let api_path = ApiPathBuilder::new(format!("/api2/json/nodes/{node}/vncwebsocket"))
+ .arg("vncticket", ticket.clone())
+ .arg("port", port)
+ .build();
+ let uri = builder
+ .path_and_query(api_path)
+ .build()
+ .map_err(|err| format_err!("failed to build Uri - {err}"))?;
+
+ let auth = raw_client.login_auth()?;
+ let req = Request::builder()
+ .method(Method::GET)
+ .uri(uri)
+ .header(UPGRADE, "websocket")
+ .header(SEC_WEBSOCKET_VERSION, "13")
+ .header(SEC_WEBSOCKET_KEY, ws_key);
+
+ let req = auth.set_auth_headers(req).body(Body::empty())?;
+
+ let res = raw_client.http_client().request(req).await?;
+ if res.status() != StatusCode::SWITCHING_PROTOCOLS {
+ bail!("server didn't upgrade: {}", res.status());
+ }
+
+ let pve_ws = hyper::upgrade::on(res)
+ .await
+ .map_err(|err| format_err!("failed to upgrade - {}", err))?;
+
+ let username = if let proxmox_client::AuthenticationKind::Token(ref token) = *auth {
+ token.userid.clone()
+ } else {
+ bail!("shell not supported with ticket-based authentication")
+ };
+
+ let preamble = format!("{username}:{ticket}\n", ticket = ticket);
+ ws.mask = Some([0, 0, 0, 0]);
+
+ if let Err(err) = ws
+ .proxy_connection(
+ TokioIo::new(incoming_ws),
+ TokioIo::new(pve_ws),
+ preamble.as_bytes(),
+ )
+ .await
+ {
+ log::warn!("error while copying between websockets: {err:?}");
+ }
+
+ Ok(())
+ });
+
+ Ok(response)
+ }
+ .boxed()
+}
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH proxmox-datacenter-manager 6/9] api: pve: wire up remote shell support
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (20 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 5/9] api: remote shell: add websocket endpoint Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 7/9] ui: pve: node: add shell tab Fabian Grünbichler
` (4 subsequent siblings)
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
new in v1
server/src/api/pve/node.rs | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/server/src/api/pve/node.rs b/server/src/api/pve/node.rs
index 301c0b1..8828243 100644
--- a/server/src/api/pve/node.rs
+++ b/server/src/api/pve/node.rs
@@ -18,6 +18,14 @@ const SUBDIRS: SubdirMap = &sorted!([
("apt", &crate::api::remote_updates::APT_ROUTER),
("rrddata", &super::rrddata::NODE_RRD_ROUTER),
("network", &Router::new().get(&API_METHOD_GET_NETWORK)),
+ (
+ "termproxy",
+ &Router::new().post(&crate::api::remote_shell::API_METHOD_SHELL_TICKET)
+ ),
+ (
+ "vncwebsocket",
+ &Router::new().upgrade(&crate::api::remote_shell::API_METHOD_SHELL_WEBSOCKET)
+ ),
("storage", &STORAGE_ROUTER),
("status", &Router::new().get(&API_METHOD_GET_STATUS)),
]);
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH proxmox-datacenter-manager 7/9] ui: pve: node: add shell tab
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (21 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 6/9] api: pve: wire up remote shell support Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 8/9] api: pbs: wire up node shell endpoints Fabian Grünbichler
` (3 subsequent siblings)
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
could also spawn a new window instead, which might be more ergonomic - see PBS
for an example ;)
v1: adapt to proxmox-yew-comp changes
ui/src/pve/node/mod.rs | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/ui/src/pve/node/mod.rs b/ui/src/pve/node/mod.rs
index d89bcde..aba5d32 100644
--- a/ui/src/pve/node/mod.rs
+++ b/ui/src/pve/node/mod.rs
@@ -1,7 +1,7 @@
use std::rc::Rc;
use gloo_utils::window;
-use proxmox_yew_comp::AptPackageManager;
+use proxmox_yew_comp::{AptPackageManager, ConsoleType, XTermJs};
use yew::{
virtual_dom::{VComp, VNode},
Context,
@@ -113,6 +113,22 @@ impl yew::Component for NodePanelComp {
}
},
)
+ .with_item_builder(
+ TabBarItem::new()
+ .key("shell_view")
+ .label(tr!("Shell"))
+ .icon_class("fa fa-terminal"),
+ {
+ let remote = props.remote.clone();
+ let node = props.node.clone();
+ move |_| {
+ let mut xtermjs = XTermJs::new();
+ xtermjs.set_node_name(node.clone());
+ xtermjs.set_console_type(ConsoleType::RemotePveLoginShell(remote.clone()));
+ xtermjs.into()
+ }
+ },
+ )
.into()
}
}
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH proxmox-datacenter-manager 8/9] api: pbs: wire up node shell endpoints
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (22 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 7/9] ui: pve: node: add shell tab Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 9/9] ui: add PBS remote shell button Fabian Grünbichler
` (2 subsequent siblings)
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
new in v1
server/src/api/pbs/node.rs | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/server/src/api/pbs/node.rs b/server/src/api/pbs/node.rs
index 286e1a1..cf8cbea 100644
--- a/server/src/api/pbs/node.rs
+++ b/server/src/api/pbs/node.rs
@@ -6,4 +6,14 @@ pub const ROUTER: Router = Router::new()
.subdirs(SUBDIRS);
#[sortable]
-const SUBDIRS: SubdirMap = &sorted!([("apt", &crate::api::remote_updates::APT_ROUTER),]);
+const SUBDIRS: SubdirMap = &sorted!([
+ ("apt", &crate::api::remote_updates::APT_ROUTER),
+ (
+ "termproxy",
+ &Router::new().post(&crate::api::remote_shell::API_METHOD_SHELL_TICKET)
+ ),
+ (
+ "vncwebsocket",
+ &Router::new().upgrade(&crate::api::remote_shell::API_METHOD_SHELL_WEBSOCKET)
+ ),
+]);
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] [PATCH proxmox-datacenter-manager 9/9] ui: add PBS remote shell button
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (23 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 8/9] api: pbs: wire up node shell endpoints Fabian Grünbichler
@ 2025-11-11 8:29 ` Fabian Grünbichler
2025-11-13 10:40 ` [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Stefan Hanreich
2025-11-14 11:04 ` [pdm-devel] partially-applied: " Fabian Grünbichler
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-11 8:29 UTC (permalink / raw)
To: pdm-devel
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
new in v1, PVE could also use this if desired
ui/src/pbs/mod.rs | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/ui/src/pbs/mod.rs b/ui/src/pbs/mod.rs
index d57e12b..f36128c 100644
--- a/ui/src/pbs/mod.rs
+++ b/ui/src/pbs/mod.rs
@@ -8,7 +8,9 @@ use pwt::props::ExtractPrimaryKey;
use yew::virtual_dom::{VComp, VNode};
use yew::{Html, Properties};
-use proxmox_yew_comp::{LoadableComponent, LoadableComponentContext, LoadableComponentMaster};
+use proxmox_yew_comp::{
+ ConsoleType, LoadableComponent, LoadableComponentContext, LoadableComponentMaster, XTermJs,
+};
use pwt::css::{AlignItems, FlexFit};
use pwt::prelude::*;
use pwt::state::NavigationContainer;
@@ -149,6 +151,20 @@ impl LoadableComponent for PbsRemoteComp {
}
}),
)
+ .with_tool(
+ Button::new(tr!("Open Shell"))
+ .icon_class("fa fa-terminal")
+ .on_activate({
+ let remote = ctx.props().remote.clone();
+ move |_| {
+ XTermJs::open_xterm_js_viewer(
+ ConsoleType::RemotePbsLoginShell(remote.clone()),
+ "localhost",
+ false,
+ )
+ }
+ }),
+ )
.with_child(Column::new().padding(4).class(FlexFit).with_child(
PbsTree::new(
props.remote.clone(),
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [pdm-devel] [PATCH manager 2/3] api: termproxy: add description to return schema
2025-11-11 8:29 ` [pdm-devel] [PATCH manager 2/3] api: termproxy: add description to return schema Fabian Grünbichler
@ 2025-11-13 10:38 ` Stefan Hanreich
0 siblings, 0 replies; 30+ messages in thread
From: Stefan Hanreich @ 2025-11-13 10:38 UTC (permalink / raw)
To: Proxmox Datacenter Manager development discussion,
Fabian Grünbichler
On 11/11/25 9:29 AM, Fabian Grünbichler wrote:
> needed to call this endpoint from PDM.
>
> Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
> ---
> PVE/API2/Nodes.pm | 11 +++++++----
> 1 file changed, 7 insertions(+), 4 deletions(-)
>
> diff --git a/PVE/API2/Nodes.pm b/PVE/API2/Nodes.pm
> index 459e0ed0a..53e3af08f 100644
> --- a/PVE/API2/Nodes.pm
> +++ b/PVE/API2/Nodes.pm
> @@ -1328,10 +1328,13 @@ __PACKAGE__->register_method({
> returns => {
> additionalProperties => 0,
> properties => {
> - user => { type => 'string' },
> - ticket => { type => 'string' },
> - port => { type => 'integer' },
> - upid => { type => 'string' },
> + user => {
> + type => 'string',
> + description => 'user/token that generated the VNC ticket in `ticket`',
> + },
> + ticket => { type => 'string', description => 'VNC ticket used to verifiy websocket connection' },
nit: typo + needs make tidy
> + port => { type => 'integer', description => 'port used to bind termproxy to' },
> + upid => { type => 'string', description => 'UPID for termproxy worker task' },
> },
> },
> code => sub {
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [pdm-devel] [PATCH proxmox-datacenter-manager 2/9] connection: add access to "raw" client
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 2/9] connection: add access to "raw" client Fabian Grünbichler
@ 2025-11-13 10:39 ` Stefan Hanreich
0 siblings, 0 replies; 30+ messages in thread
From: Stefan Hanreich @ 2025-11-13 10:39 UTC (permalink / raw)
To: Proxmox Datacenter Manager development discussion,
Fabian Grünbichler
since both PveClient and PbsClient wrap a Client afaict, would it be
better to add a method to them that allows for obtaining a reference to
that one? But I assume it's simply easier for this feature to be able to
obtain a raw client for a remote, without having to distinguish remote
types everywhere?
On 11/11/25 9:29 AM, Fabian Grünbichler wrote:
> needed for websocket connections and similar lower level access.
>
> Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
> ---
>
> Notes:
> unchanged
>
> server/src/connection.rs | 11 +++++++++++
> server/src/metric_collection/collection_task.rs | 5 +++++
> server/src/test_support/fake_remote.rs | 5 +++++
> 3 files changed, 21 insertions(+)
>
> diff --git a/server/src/connection.rs b/server/src/connection.rs
> index e749c1a..1c0069e 100644
> --- a/server/src/connection.rs
> +++ b/server/src/connection.rs
> @@ -252,6 +252,9 @@ pub trait ClientFactory {
> ///
> /// Note: currently does not support two factor authentication.
> async fn make_pbs_client_and_login(&self, remote: &Remote) -> Result<Box<PbsClient>, Error>;
> +
> + /// Create a new API client for raw acess to the given remote
> + fn make_raw_client(&self, remote: &Remote) -> Result<Box<Client>, Error>;
> }
>
> /// Default production client factory
> @@ -346,6 +349,10 @@ impl ClientFactory for DefaultClientFactory {
> ConnectionCache::get().make_pve_client(remote)
> }
>
> + fn make_raw_client(&self, remote: &Remote) -> Result<Box<Client>, Error> {
> + Ok(Box::new(crate::connection::connect(remote, None)?))
> + }
> +
> fn make_pbs_client(&self, remote: &Remote) -> Result<Box<PbsClient>, Error> {
> let client = crate::connection::connect(remote, None)?;
> Ok(Box::new(PbsClient(client)))
> @@ -418,6 +425,10 @@ pub fn make_pbs_client(remote: &Remote) -> Result<Box<PbsClient>, Error> {
> instance().make_pbs_client(remote)
> }
>
> +pub fn make_raw_client(remote: &Remote) -> Result<Box<Client>, Error> {
> + instance().make_raw_client(remote)
> +}
> +
> /// Create a new API client for PVE remotes.
> ///
> /// In case the remote has a user configured (instead of an API token), it will connect and get a
> diff --git a/server/src/metric_collection/collection_task.rs b/server/src/metric_collection/collection_task.rs
> index a6c8443..cc1a460 100644
> --- a/server/src/metric_collection/collection_task.rs
> +++ b/server/src/metric_collection/collection_task.rs
> @@ -387,6 +387,7 @@ pub(super) mod tests {
> use http::StatusCode;
>
> use pdm_api_types::Authid;
> + use proxmox_client::Client;
> use pve_api_types::{ClusterMetrics, ClusterMetricsData};
>
> use crate::{
> @@ -430,6 +431,10 @@ pub(super) mod tests {
> bail!("not implemented")
> }
>
> + fn make_raw_client(&self, _remote: &Remote) -> Result<Box<Client>, Error> {
> + bail!("not implemented")
> + }
> +
> async fn make_pve_client_and_login(
> &self,
> _remote: &Remote,
> diff --git a/server/src/test_support/fake_remote.rs b/server/src/test_support/fake_remote.rs
> index cd2ccf6..62dd869 100644
> --- a/server/src/test_support/fake_remote.rs
> +++ b/server/src/test_support/fake_remote.rs
> @@ -5,6 +5,7 @@ use serde::Deserialize;
>
> use pdm_api_types::{remotes::Remote, Authid, ConfigDigest};
> use pdm_config::remotes::RemoteConfig;
> +use proxmox_client::Client;
> use proxmox_product_config::ApiLockGuard;
> use proxmox_section_config::typed::SectionConfigData;
> use pve_api_types::{
> @@ -100,6 +101,10 @@ impl ClientFactory for FakeClientFactory {
> bail!("not implemented")
> }
>
> + fn make_raw_client(&self, _remote: &Remote) -> Result<Box<Client>, Error> {
> + bail!("not implemented")
> + }
> +
> async fn make_pve_client_and_login(&self, _remote: &Remote) -> Result<Arc<PveClient>, Error> {
> bail!("not implemented")
> }
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (24 preceding siblings ...)
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 9/9] ui: add PBS remote shell button Fabian Grünbichler
@ 2025-11-13 10:40 ` Stefan Hanreich
2025-11-14 11:04 ` [pdm-devel] partially-applied: " Fabian Grünbichler
26 siblings, 0 replies; 30+ messages in thread
From: Stefan Hanreich @ 2025-11-13 10:40 UTC (permalink / raw)
To: Proxmox Datacenter Manager development discussion,
Fabian Grünbichler
Tested this on my local PDM with both PVE / PBS and also quickly checked
that the local shell there still works as well. Worked great, couldn't
find an issue so far. Error messages for non-supported remotes could be
improved.
W.r.t the code only very minor issues stood out (see the responses),
everything lgtm. Some API descriptions could be improved (casing,
periods at the end...).
Consider this:
Tested-by: Stefan Hanreich <s.hanreich@proxmox.com>
Reviewed-by: Stefan Hanreich <s.hanreich@proxmox.com>
Has nothing to do with this patch series per-se, but PDM also has the
termproxy endpoint for its local shell which we could refactor in a
similar manner as the PBS one (e.g. return type changes, root_id, ...).
On 11/11/25 9:29 AM, Fabian Grünbichler wrote:
> there's a lot of inter-dependencies here, unfortunately.
>
> proxmox-auth-api breaks (building) PBS and PDM, and PBS requires bumped
> proxmox-auth-api for this series to work.
> PBS and PVE require new termproxy
> pve-manager requires new pve-access-control (via termproxy)
> PBS requires new pbs-api-types
> PDM requires new pbs-api-types, pve-api-types, proxmox-yew-comp and pve-xtermjs
>
> suggested build-order:
> - pve-xtermjs / proxmox-termproxy
> - pve-access-control
> - pve-manager
> - pve-api-types
> - pbs-api-types
> - proxmox-auth-api
> - PBS
> - proxmox-yew-comp
> - PDM
>
> the remote shell only works if remotes have new enough PVE/PBS packages.
>
> pve-xtermjs:
>
> Fabian Grünbichler (2):
> xtermjs: add support for remote node shells via PDM
> termproxy: allow using new vncticket endpoint
>
> termproxy/src/cli.rs | 5 +++++
> termproxy/src/main.rs | 31 ++++++++++++++++++++++---------
> xterm.js/src/main.js | 13 +++++++++++--
> 3 files changed, 38 insertions(+), 11 deletions(-)
>
>
> pve-access-control:
>
> Fabian Grünbichler (1):
> api: ticket: allow token-owned VNC ticket verification
>
> src/PVE/API2/AccessControl.pm | 60 +++++++++++++++++++++++++++++++++++
> 1 file changed, 60 insertions(+)
>
>
> pve-manager:
>
> Fabian Grünbichler (3):
> api: termproxy/vncwebsocket: allow tokens
> api: termproxy: add description to return schema
> http server: allow unauthenticated access to /access/vncticket
>
> PVE/API2/Nodes.pm | 17 ++++++++++-------
> PVE/HTTPServer.pm | 1 +
> 2 files changed, 11 insertions(+), 7 deletions(-)
>
>
> proxmox:
>
> Fabian Grünbichler (3):
> pbs-api-types: add NodeShellTicket
> auth-api: use Authid for path ticket validation
> auth-api: add vncticket verification endpoint and type
>
> pbs-api-types/src/node.rs | 36 +++++++++++++++++++++++++++++-
> proxmox-auth-api/src/api/access.rs | 34 ++++++++++++++++++++++++++--
> proxmox-auth-api/src/api/mod.rs | 8 +++----
> proxmox-auth-api/src/types.rs | 22 ++++++++++++++++++
> 4 files changed, 93 insertions(+), 7 deletions(-)
>
>
> proxmox-backup:
>
> Fabian Grünbichler (4):
> tree-wide: user Userid::root_user() instead of hard-coded root@pam
> api: access: add vncticket verification endpoint
> api: node shell: allow access for tokens
> api: termproxy: use NodeShellTicket type from pbs-api-types
>
> pbs-config/src/acl.rs | 2 +-
> pbs-config/src/cached_user_info.rs | 4 +-
> pbs-config/src/user.rs | 5 ++-
> src/api2/access/mod.rs | 6 ++-
> src/api2/node/mod.rs | 66 +++++++++---------------------
> src/auth.rs | 5 +--
> src/tools/ticket.rs | 6 +--
> 7 files changed, 36 insertions(+), 58 deletions(-)
>
>
> proxmox-yew-comp:
>
> Fabian Grünbichler (3):
> xtermjs: add remote PVE support
> xtermjs: merge ConsoleType to parameters conversion
> xtermjs: add remote PBS console type
>
> src/xtermjs.rs | 41 ++++++++++++++++++++++++++---------------
> 1 file changed, 26 insertions(+), 15 deletions(-)
>
>
> proxmox-datacenter-manager:
>
> Fabian Grünbichler (9):
> auth: allow tokens in term tickets
> connection: add access to "raw" client
> pbs client: add termproxy wrapper
> api: add remote_shell module with termproxy endpoint
> api: remote shell: add websocket endpoint
> api: pve: wire up remote shell support
> ui: pve: node: add shell tab
> api: pbs: wire up node shell endpoints
> ui: add PBS remote shell button
>
> Cargo.toml | 2 +-
> debian/control | 12 +-
> server/src/api/mod.rs | 1 +
> server/src/api/pbs/node.rs | 12 +-
> server/src/api/pve/node.rs | 8 +
> server/src/api/remote_shell.rs | 261 ++++++++++++++++++
> server/src/auth/mod.rs | 5 +-
> server/src/connection.rs | 11 +
> .../src/metric_collection/collection_task.rs | 5 +
> server/src/pbs_client.rs | 6 +
> server/src/test_support/fake_remote.rs | 5 +
> ui/src/pbs/mod.rs | 18 +-
> ui/src/pve/node/mod.rs | 18 +-
> 13 files changed, 351 insertions(+), 13 deletions(-)
> create mode 100644 server/src/api/remote_shell.rs
>
>
> Summary over all repositories:
> 31 files changed, 615 insertions(+), 111 deletions(-)
>
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
* [pdm-devel] partially-applied: [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
` (25 preceding siblings ...)
2025-11-13 10:40 ` [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Stefan Hanreich
@ 2025-11-14 11:04 ` Fabian Grünbichler
26 siblings, 0 replies; 30+ messages in thread
From: Fabian Grünbichler @ 2025-11-14 11:04 UTC (permalink / raw)
To: pdm-devel, Stefan Hanreich, Thomas Lamprecht
applied all but the UI part of PDM, and bumped everything except for
pve-manager, PBS, PDM and yew-comp.
after yew-comp has been bumped, PDM ui patches can be applied as well.
bumping PVE, PBS and PDM is not blocked on anything, but I assumed there are
enough other open things that doing a bump that has no user-visible effect yet
anyway is moot ;)
Quoting Fabian Grünbichler (2025-11-11 09:29:07)
> there's a lot of inter-dependencies here, unfortunately.
>
> proxmox-auth-api breaks (building) PBS and PDM, and PBS requires bumped
> proxmox-auth-api for this series to work.
> PBS and PVE require new termproxy
> pve-manager requires new pve-access-control (via termproxy)
> PBS requires new pbs-api-types
> PDM requires new pbs-api-types, pve-api-types, proxmox-yew-comp and pve-xtermjs
>
> suggested build-order:
> - pve-xtermjs / proxmox-termproxy
> - pve-access-control
> - pve-manager
> - pve-api-types
> - pbs-api-types
> - proxmox-auth-api
> - PBS
> - proxmox-yew-comp
> - PDM
>
> the remote shell only works if remotes have new enough PVE/PBS packages.
>
> pve-xtermjs:
>
> Fabian Grünbichler (2):
> xtermjs: add support for remote node shells via PDM
> termproxy: allow using new vncticket endpoint
>
> termproxy/src/cli.rs | 5 +++++
> termproxy/src/main.rs | 31 ++++++++++++++++++++++---------
> xterm.js/src/main.js | 13 +++++++++++--
> 3 files changed, 38 insertions(+), 11 deletions(-)
>
>
> pve-access-control:
>
> Fabian Grünbichler (1):
> api: ticket: allow token-owned VNC ticket verification
>
> src/PVE/API2/AccessControl.pm | 60 +++++++++++++++++++++++++++++++++++
> 1 file changed, 60 insertions(+)
>
>
> pve-manager:
>
> Fabian Grünbichler (3):
> api: termproxy/vncwebsocket: allow tokens
> api: termproxy: add description to return schema
> http server: allow unauthenticated access to /access/vncticket
>
> PVE/API2/Nodes.pm | 17 ++++++++++-------
> PVE/HTTPServer.pm | 1 +
> 2 files changed, 11 insertions(+), 7 deletions(-)
>
>
> proxmox:
>
> Fabian Grünbichler (3):
> pbs-api-types: add NodeShellTicket
> auth-api: use Authid for path ticket validation
> auth-api: add vncticket verification endpoint and type
>
> pbs-api-types/src/node.rs | 36 +++++++++++++++++++++++++++++-
> proxmox-auth-api/src/api/access.rs | 34 ++++++++++++++++++++++++++--
> proxmox-auth-api/src/api/mod.rs | 8 +++----
> proxmox-auth-api/src/types.rs | 22 ++++++++++++++++++
> 4 files changed, 93 insertions(+), 7 deletions(-)
>
>
> proxmox-backup:
>
> Fabian Grünbichler (4):
> tree-wide: user Userid::root_user() instead of hard-coded root@pam
> api: access: add vncticket verification endpoint
> api: node shell: allow access for tokens
> api: termproxy: use NodeShellTicket type from pbs-api-types
>
> pbs-config/src/acl.rs | 2 +-
> pbs-config/src/cached_user_info.rs | 4 +-
> pbs-config/src/user.rs | 5 ++-
> src/api2/access/mod.rs | 6 ++-
> src/api2/node/mod.rs | 66 +++++++++---------------------
> src/auth.rs | 5 +--
> src/tools/ticket.rs | 6 +--
> 7 files changed, 36 insertions(+), 58 deletions(-)
>
>
> proxmox-yew-comp:
>
> Fabian Grünbichler (3):
> xtermjs: add remote PVE support
> xtermjs: merge ConsoleType to parameters conversion
> xtermjs: add remote PBS console type
>
> src/xtermjs.rs | 41 ++++++++++++++++++++++++++---------------
> 1 file changed, 26 insertions(+), 15 deletions(-)
>
>
> proxmox-datacenter-manager:
>
> Fabian Grünbichler (9):
> auth: allow tokens in term tickets
> connection: add access to "raw" client
> pbs client: add termproxy wrapper
> api: add remote_shell module with termproxy endpoint
> api: remote shell: add websocket endpoint
> api: pve: wire up remote shell support
> ui: pve: node: add shell tab
> api: pbs: wire up node shell endpoints
> ui: add PBS remote shell button
>
> Cargo.toml | 2 +-
> debian/control | 12 +-
> server/src/api/mod.rs | 1 +
> server/src/api/pbs/node.rs | 12 +-
> server/src/api/pve/node.rs | 8 +
> server/src/api/remote_shell.rs | 261 ++++++++++++++++++
> server/src/auth/mod.rs | 5 +-
> server/src/connection.rs | 11 +
> .../src/metric_collection/collection_task.rs | 5 +
> server/src/pbs_client.rs | 6 +
> server/src/test_support/fake_remote.rs | 5 +
> ui/src/pbs/mod.rs | 18 +-
> ui/src/pve/node/mod.rs | 18 +-
> 13 files changed, 351 insertions(+), 13 deletions(-)
> create mode 100644 server/src/api/remote_shell.rs
>
>
> Summary over all repositories:
> 31 files changed, 615 insertions(+), 111 deletions(-)
>
> --
> Generated by git-murpp 0.8.1
>
>
> _______________________________________________
> pdm-devel mailing list
> pdm-devel@lists.proxmox.com
> https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2025-11-14 11:04 UTC | newest]
Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-11-11 8:29 [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH pve-xtermjs 1/2] xtermjs: add support for remote node shells via PDM Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH pve-xtermjs 2/2] termproxy: allow using new vncticket endpoint Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH access-control 1/1] api: ticket: allow token-owned VNC ticket verification Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH manager 1/3] api: termproxy/vncwebsocket: allow tokens Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH manager 2/3] api: termproxy: add description to return schema Fabian Grünbichler
2025-11-13 10:38 ` Stefan Hanreich
2025-11-11 8:29 ` [pdm-devel] [PATCH manager 3/3] http server: allow unauthenticated access to /access/vncticket Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox 1/3] pbs-api-types: add NodeShellTicket Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox 2/3] auth-api: use Authid for path ticket validation Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox 3/3] auth-api: add vncticket verification endpoint and type Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-backup 1/4] tree-wide: user Userid::root_user() instead of hard-coded root@pam Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-backup 2/4] api: access: add vncticket verification endpoint Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-backup 3/4] api: node shell: allow access for tokens Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-backup 4/4] api: termproxy: use NodeShellTicket type from pbs-api-types Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-yew-comp 1/3] xtermjs: add remote PVE support Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-yew-comp 2/3] xtermjs: merge ConsoleType to parameters conversion Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-yew-comp 3/3] xtermjs: add remote PBS console type Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 1/9] auth: allow tokens in term tickets Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 2/9] connection: add access to "raw" client Fabian Grünbichler
2025-11-13 10:39 ` Stefan Hanreich
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 3/9] pbs client: add termproxy wrapper Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 4/9] api: add remote_shell module with termproxy endpoint Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 5/9] api: remote shell: add websocket endpoint Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 6/9] api: pve: wire up remote shell support Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 7/9] ui: pve: node: add shell tab Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 8/9] api: pbs: wire up node shell endpoints Fabian Grünbichler
2025-11-11 8:29 ` [pdm-devel] [PATCH proxmox-datacenter-manager 9/9] ui: add PBS remote shell button Fabian Grünbichler
2025-11-13 10:40 ` [pdm-devel] [PATCH access-control/manager/proxmox{, -backup, -yew-comp, -datacenter-manager}/xtermjs 00/25] add remote node shell Stefan Hanreich
2025-11-14 11:04 ` [pdm-devel] partially-applied: " Fabian Grünbichler
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox