Skip to content

Add sshserver file transfer handlers#24580

Merged
avatus merged 1 commit intomasterfrom
michaelmyers/ssh_server_file_transfer_handlers
May 3, 2023
Merged

Add sshserver file transfer handlers#24580
avatus merged 1 commit intomasterfrom
michaelmyers/ssh_server_file_transfer_handlers

Conversation

@avatus
Copy link
Copy Markdown
Contributor

@avatus avatus commented Apr 13, 2023

Part of #23546

This PR will add the handlers to the sshserver to listen for File Transfer Request events. There is a bit of refactor as well from #24260, but the main thing being that file transfers over SFTP does not include an ssh.Request so I removed the comparison check.

partner PR (that also includes web) #24581

Comment thread lib/session/session.go Outdated
Comment thread lib/srv/sess.go Outdated
Comment thread lib/srv/sess.go Outdated
Comment thread lib/srv/termhandlers.go Outdated
Comment thread lib/session/session.go Outdated
@capnspacehook capnspacehook added the sftp Issues related to Teleport's SFTP implementation label Apr 14, 2023
Comment thread lib/srv/regular/sshserver.go Outdated
case teleport.ForceTerminateRequest:
return s.termHandlers.HandleForceTerminate(ch, req, serverContext)
case sshutils.EnvRequest, tracessh.EnvsRequest:
case sshutils.FileTransferRequestResponse:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure whether the lib/srv/forward SSH server needs to support this as well, probably not but for connections to agentless nodes it might.

Comment thread lib/session/session.go Outdated
Moderated bool `json:"moderated"`
}

// FileTransferParams contain parameters for requesting a file transfer
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit misleading, because it looks like this can be a request or a response based on the fields below.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. A comment on the other PR lead me to separate these from requests and responses so it will change (not sure outcome yet, but will update comment regardless)

Comment thread lib/session/session.go
// Direction is either upload or download
Direction string `json:"direction"`
// Location is location of file to download, or where to put an upload
Location string `json:"location"`
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would Path be a better name?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i was keeping it in line with the presentation on the frontend and current file transfer (not request) params. Path does seem like a better name but a change for all the other aspects that aren't in this PR might muddy it up. I'll double check, and if its too many small changed, I'll separate into another PR

Comment thread lib/session/session.go Outdated
// Filename is the name of the file to be uploaded
Filename string `json:"filename"`
// Size is the size of the file to be uploaded
Size string `json:"size"`
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would this look like? Why a string?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was vestigial from testing/tinkering. will remove as it's not used

Comment thread lib/session/session.go
// Requster is the authenticated Teleport user who requested the file transfer
Requester string `json:"requester"`
// Approvers is a list of teleport users who have approved the file transfer request
Approvers []Party `json:"approvers"`
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need an Approved field if you have approvers? Is it possible for Approved to be false but Approvers to be non-empty?

Copy link
Copy Markdown
Contributor Author

@avatus avatus Apr 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bad consequence of having the request/response in this single struct. What Approved actually meant was "is this response an approval or deny", which now that I've seen through the weeds is NOT very clear. Removing it from this and making a discrete Response struct will clear it up

Comment thread lib/session/session.go Outdated
Comment thread lib/srv/sess.go Outdated
)

// NotifyFileTransferRequest is called to notify all members of a party that a file transfer request has been created/approved/denied.
// The notification is a global ssh request and requires the client to update it's UI state accordingly.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// The notification is a global ssh request and requires the client to update it's UI state accordingly.
// The notification is a global ssh request and requires the client to update its UI state accordingly.

Comment thread lib/srv/sess.go Outdated
session := scx.getSession()
if session == nil {
s.log.Debugf("Unable to notify %s, no session found in context.", res)
return nil
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be an error or is it expected that there will sometimes not be a session?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be an error, thanks!

Comment thread lib/srv/sess.go Outdated
Comment thread lib/srv/sess.go
}

return sess.checkIfFileTransferApproved(req)
fileTransferEvent := &apievents.FileTransferRequestEvent{
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't the events in apievents for the audit log?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't added the audit event yet, but a similar pattern with Resize is to create the audit event and send it, and then reuse that to send to the client which I liked. It looks more weird since the audit event isn't happening yet.

Comment thread lib/srv/sess.go

// denyFileTransferRequest will deny a file transfer request and remove it from the current session's file transfer requests map.
// A file transfer request does not persist after deny, so there is no "denied" state. Deny in this case is synonymous with delete
// with the addition of checking for a valid denier.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So what happens in this scenario?

  • 2 moderator approvals are required for transfer
  • 3 moderators are watching the session
  • moderator A approves the transfer
  • moderator B denies the transfer

Does the request immediately get dropped, or does moderator C still have a chance to approve?

Copy link
Copy Markdown
Contributor Author

@avatus avatus Apr 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request will immediately be dropped. Similar to access requests, if moderated A approved and B denied, C won't be able to answer as the result is already in a denied state. (except there isn't a denied state here, its just gone, but you get the idea)

Comment thread lib/session/session.go Outdated
Approved bool `json:"approved"`
}

// UnmarshalFileTransferResponseParams takes a serialized string that contains the
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget to update the godoc to account for the rename (here and below)

Copy link
Copy Markdown
Contributor Author

@avatus avatus Apr 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't even think these methods are needed anymore. If i'm not checking/setting any defaults and just making a new struct, I'll just do it at the callsite and remove these all together. 6efdc11

Comment thread lib/session/session.go Outdated

// UnmarshalFileTransferResponseParams takes a serialized string that contains the
// file transfer request response parameters and returns a *FileTransferParams.
func NewFileTransferResponseParams(requestId string, approved bool) (*FileTransferResponseParams, error) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Fix the godoc. It should start with the name of the function you're documenting.
  • This never returns an error, so I would simplify the signature and remove the error return.

Comment thread lib/sshutils/req.go Outdated
Comment thread lib/srv/regular/sshserver.go Outdated
Comment on lines +1647 to +1650
case sshutils.FileTransferRequest:
return s.termHandlers.HandleFileTransferRequest(ctx, ch, req, serverContext)
case sshutils.FileTransferRequestResponse:
return s.termHandlers.HandleFileTransferRequestResponse(ctx, ch, req, serverContext)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to be careful when backporting these requests. Up until very recently unknown session requests would terminate the entire session instead of rejecting the request and keeping the session alive.

@codingllama codingllama removed their request for review April 17, 2023 15:04
Comment thread api/constants/constants.go
Comment thread lib/srv/sess.go
Comment thread lib/sshutils/req.go Outdated
Copy link
Copy Markdown
Contributor

@capnspacehook capnspacehook left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good assuming all other feedback is addressed

Comment thread lib/srv/regular/sshserver.go
Comment thread api/constants/constants.go Outdated
const (
// FileTransferRequest is used when creating a new file transfer request
FileTransferRequest string = "file-transfer-request@goteleport.com"
// FileTransferDecision is a request that will approve or deny an active file transfer
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a note indicating that this is one of possibly many decisions for a given FileTransferRequest if there are multiple approvers required?

Comment thread api/constants/constants.go Outdated

const (
// FileTransferRequest is used when creating a new file transfer request
FileTransferRequest string = "file-transfer-request@goteleport.com"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renaming this would allow you to use FileTransferReq for the name of the payload instead of FileTransferRequestReq

Suggested change
FileTransferRequest string = "file-transfer-request@goteleport.com"
InitiateFileTransfer string = "file-transfer@goteleport.com"

Comment on lines +632 to +633
// Download is true if the requested file transfer is a download, false if an upload
bool Download = 7 [(gogoproto.jsontag) = "download"];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it kosher to change this? Are there any compatibility concerns here?

Copy link
Copy Markdown
Contributor Author

@avatus avatus Apr 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this event was created by me to support this PR. so it's not consumed by anything yet. No compatibility concerns yet

Comment thread lib/srv/sess.go
return sess.checkIfFileTransferApproved(req)
}

type FileTransferRequestEvent string
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: missing go docs

Comment thread lib/srv/sess.go Outdated
session := scx.getSession()
if session == nil {
s.log.Debugf("Unable to notify %s, no session found in context.", res)
return trace.NotFound("No session found in context.")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error strings shouldn't be capitalized or end with punctuation: https://github.com/golang/go/wiki/CodeReviewComments#error-strings

Suggested change
return trace.NotFound("No session found in context.")
return trace.NotFound("no session found in context")

Comment thread lib/srv/sess.go Outdated
}
}
if approver == nil {
return nil, trace.AccessDenied("Cannot approve file transfer requests if not in the current moderated session")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return nil, trace.AccessDenied("Cannot approve file transfer requests if not in the current moderated session")
return nil, trace.AccessDenied("cannot approve file transfer requests if not in the current moderated session")

Comment thread lib/srv/sess.go Outdated
}
}
if denier == nil {
return nil, trace.AccessDenied("Cannot deny file transfer requests if not in the current moderated session")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return nil, trace.AccessDenied("Cannot deny file transfer requests if not in the current moderated session")
return nil, trace.AccessDenied("cannot deny file transfer requests if not in the current moderated session")

Comment thread lib/srv/termhandlers.go Outdated
Comment on lines +154 to +160
} else {
_, err := session.denyFileTransferRequest(params, scx)
if err != nil {
return trace.Wrap(err)
}
}
return nil
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: drop the else to unindent: https://github.com/golang/go/wiki/CodeReviewComments#indent-error-flow

Suggested change
} else {
_, err := session.denyFileTransferRequest(params, scx)
if err != nil {
return trace.Wrap(err)
}
}
return nil
}
_, err := session.denyFileTransferRequest(params, scx)
return trace.Wrap(err)

@avatus avatus requested a review from rosstimothy May 1, 2023 15:50
Comment thread lib/srv/sess.go
Comment on lines +437 to +448
for _, p := range session.parties {

// Send the message as a global request.
_, _, err = p.sconn.SendRequest(teleport.SessionEvent, false, eventPayload)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for _, p := range session.parties {
// Send the message as a global request.
_, _, err = p.sconn.SendRequest(teleport.SessionEvent, false, eventPayload)
for _, p := range session.parties {
// Send the message as a global request.
_, _, err = p.sconn.SendRequest(teleport.SessionEvent, false, eventPayload)

Add web terminal handlers for file transfer requests (#24581)
@avatus avatus force-pushed the michaelmyers/ssh_server_file_transfer_handlers branch from 8349a03 to 6021829 Compare May 3, 2023 20:37
@avatus avatus added this pull request to the merge queue May 3, 2023
Merged via the queue into master with commit f814b2d May 3, 2023
@avatus avatus deleted the michaelmyers/ssh_server_file_transfer_handlers branch May 3, 2023 21:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

sftp Issues related to Teleport's SFTP implementation size/md

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants