Skip to content

Commit

Permalink
Allow upterm host to allowlist users on self-hosted versions of VCSes
Browse files Browse the repository at this point in the history
  • Loading branch information
debayande committed Jun 18, 2024
1 parent d520e3d commit aa6fefc
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 15 deletions.
8 changes: 4 additions & 4 deletions cmd/upterm/command/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ private key. To authorize client connections, specify a authorized_key file with
cmd.PersistentFlags().StringSliceVarP(&flagPrivateKeys, "private-key", "i", defaultPrivateKeys(homeDir), "Specify private key files for public key authentication with the upterm server (required).")
cmd.PersistentFlags().StringVarP(&flagKnownHostsFilename, "known-hosts", "", defaultKnownHost(homeDir), "Specify a file containing known keys for remote hosts (required).")
cmd.PersistentFlags().StringVar(&flagAuthorizedKeys, "authorized-keys", "", "Specify a authorize_keys file listing authorized public keys for connection.")
cmd.PersistentFlags().StringSliceVar(&flagCodebergUsers, "codeberg-user", nil, "Authorize specified Codeberg users by allowing their public keys to connect.")
cmd.PersistentFlags().StringSliceVar(&flagGitHubUsers, "github-user", nil, "Authorize specified GitHub users by allowing their public keys to connect. Configure GitHub CLI environment variables as needed; see https://cli.github.com/manual/gh_help_environment for details.")
cmd.PersistentFlags().StringSliceVar(&flagGitLabUsers, "gitlab-user", nil, "Authorize specified GitLab users by allowing their public keys to connect.")
cmd.PersistentFlags().StringSliceVar(&flagSourceHutUsers, "srht-user", nil, "Authorize specified SourceHut users by allowing their public keys to connect.")
cmd.PersistentFlags().StringSliceVar(&flagCodebergUsers, "codeberg-user", nil, "Authorize specified Codeberg users by allowing their public keys to connect. For self-hosted installations, set CODEBERG_HOST, along with the protocol prefix (e.g., https://git.example.com).")
cmd.PersistentFlags().StringSliceVar(&flagGitHubUsers, "github-user", nil, "Authorize specified GitHub users by allowing their public keys to connect. Configure GitHub CLI environment variables as needed; see https://cli.github.com/manual/gh_help_environment for details. For self-hosted installations, set GITHUB_HOST, along with the protocol prefix (e.g., https://git.example.com).")
cmd.PersistentFlags().StringSliceVar(&flagGitLabUsers, "gitlab-user", nil, "Authorize specified GitLab users by allowing their public keys to connect. For self-hosted installations, set GITLAB_HOST, along with the protocol prefix (e.g., https://git.example.com).")
cmd.PersistentFlags().StringSliceVar(&flagSourceHutUsers, "srht-user", nil, "Authorize specified SourceHut users by allowing their public keys to connect. For self-hosted installations, set SOURCEHUT_HOST, along with the protocol prefix (e.g., https://git.example.com).")
cmd.PersistentFlags().BoolVar(&flagAccept, "accept", false, "Automatically accept client connections without prompts.")
cmd.PersistentFlags().BoolVarP(&flagReadOnly, "read-only", "r", false, "Host a read-only session, preventing client interaction.")

Expand Down
33 changes: 22 additions & 11 deletions host/authorizedkeys.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,33 @@ import (
"time"

"github.com/cli/go-gh/v2/pkg/api"
"github.com/owenthereal/upterm/utils"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh"
)

const (
codebergKeysUrlFmt = "https://codeberg.org/%s"
gitHubKeysUrlFmt = "https://github.com/%s"
gitLabKeysUrlFmt = "https://gitlab.com/%s"
sourceHutKeysUrlFmt = "https://meta.sr.ht/~%s"
)

type AuthorizedKey struct {
PublicKeys []ssh.PublicKey
Comment string
}

func GetUrlFmt(service string) string {
serviceAttrsMap := map[string][]string{
"Codeberg": {"CODEBERG_HOST", "https://codeberg.org"},
"GitHub": {"GITHUB_HOST", "https://github.com"},
"GitLab": {"GITLAB_HOST", "https://gitlab.com"},
"SourceHut": {"SOURCEHUT_HOST", "https://meta.sr.ht"},
}

serviceUrl := utils.GetEnvWithDefault(serviceAttrsMap[service][0], serviceAttrsMap[service][1])

if service == "SourceHut" {
return (serviceUrl + "/~%s")
}

return (serviceUrl + "/%s")
}

func AuthorizedKeysFromFile(file string) (*AuthorizedKey, error) {
authorizedKeysBytes, err := os.ReadFile(file)
if err != nil {
Expand All @@ -36,7 +47,7 @@ func AuthorizedKeysFromFile(file string) (*AuthorizedKey, error) {
}

func CodebergUserAuthorizedKeys(usernames []string) ([]*AuthorizedKey, error) {
return usersPublicKeys(codebergKeysUrlFmt, usernames)
return usersPublicKeys(GetUrlFmt("Codeberg"), usernames)
}

func GitHubUserAuthorizedKeys(usernames []string, logger *logrus.Logger) ([]*AuthorizedKey, error) {
Expand Down Expand Up @@ -66,11 +77,11 @@ func GitHubUserAuthorizedKeys(usernames []string, logger *logrus.Logger) ([]*Aut
}

func GitLabUserAuthorizedKeys(usernames []string) ([]*AuthorizedKey, error) {
return usersPublicKeys(gitLabKeysUrlFmt, usernames)
return usersPublicKeys(GetUrlFmt("GitLab"), usernames)
}

func SourceHutUserAuthorizedKeys(usernames []string) ([]*AuthorizedKey, error) {
return usersPublicKeys(sourceHutKeysUrlFmt, usernames)
return usersPublicKeys(GetUrlFmt("SourceHut"), usernames)
}

func parseAuthorizedKeys(keysBytes []byte, comment string) (*AuthorizedKey, error) {
Expand All @@ -97,7 +108,7 @@ func githubUserPublicKeys(username string, logger *logrus.Logger) ([]byte, error
if strings.Contains(err.Error(), "authentication token not found for host") {
// fallback to use the public GH API
logger.WithError(err).Warn("no GitHub token found, falling back to public API")
return userPublicKeys(gitHubKeysUrlFmt, username)
return userPublicKeys(GetUrlFmt("GitHub"), username)
}

return nil, err
Expand Down
7 changes: 7 additions & 0 deletions utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ func UptermDir() (string, error) {
return filepath.Join(homedir, ".upterm"), nil
}

func GetEnvWithDefault(envVar, defaultValue string) string {
if v, ok := os.LookupEnv(envVar); ok && len(v) > 0 {
return v
}
return defaultValue
}

func CreateUptermDir() (string, error) {
dir, err := UptermDir()
if err != nil {
Expand Down

0 comments on commit aa6fefc

Please sign in to comment.