From aabf41945d28a18cbaa0e9c947e32f9c491786cf Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Sun, 24 May 2026 15:25:21 +0200 Subject: [PATCH] pam: remove token auth --- e2e/auth_test.go | 28 ---- ee/psso/Bridge/Generated/ic_ssh.grpc.swift | 11 -- ee/psso/Bridge/Generated/ic_ssh.pb.swift | 75 ----------- pam/src/auth.rs | 45 ++----- pam/src/auth/token.rs | 45 ------- pkg/cli/auth/device/device.go | 57 --------- pkg/cli/ssh.go | 39 ------ pkg/cli/ssh/client.go | 141 --------------------- pkg/cli/ssh/command.go | 16 --- pkg/cli/ssh/config.go | 126 ------------------ pkg/cli/ssh/shell.go | 86 ------------- pkg/cli/ssh/socket.go | 71 ----------- pkg/cli/ssh/token.go | 22 ---- pkg/pb/ic_ssh.pb.go | 132 ------------------- protobuf/ic_ssh.proto | 11 -- src/generated/ic_ssh/ic_ssh.rs | 11 -- src/generated/mod.rs | 5 - 17 files changed, 9 insertions(+), 912 deletions(-) delete mode 100644 ee/psso/Bridge/Generated/ic_ssh.grpc.swift delete mode 100644 ee/psso/Bridge/Generated/ic_ssh.pb.swift delete mode 100644 pam/src/auth/token.rs delete mode 100644 pkg/cli/auth/device/device.go delete mode 100644 pkg/cli/ssh.go delete mode 100644 pkg/cli/ssh/client.go delete mode 100644 pkg/cli/ssh/command.go delete mode 100644 pkg/cli/ssh/config.go delete mode 100644 pkg/cli/ssh/shell.go delete mode 100644 pkg/cli/ssh/socket.go delete mode 100644 pkg/cli/ssh/token.go delete mode 100644 pkg/pb/ic_ssh.pb.go delete mode 100644 protobuf/ic_ssh.proto delete mode 100644 src/generated/ic_ssh/ic_ssh.rs diff --git a/e2e/auth_test.go b/e2e/auth_test.go index 069c97d9..e7332125 100644 --- a/e2e/auth_test.go +++ b/e2e/auth_test.go @@ -41,31 +41,3 @@ func Test_Auth_IdentityAgent(t *testing.T) { }, }) } - -func Test_Auth_Legacy(t *testing.T) { - net, err := network.New(t.Context(), network.WithAttachable()) - defer testcontainers.CleanupNetwork(t, net) - assert.NoError(t, err) - - tc := testMachine(t) - - assert.NoError(t, tc.Start(t.Context())) - JoinDomain(t, tc) - AgentSetup(t, tc) - - MustExec(t, tc, "sed -i 's/KbdInteractiveAuthentication no/KbdInteractiveAuthentication yes/g' /etc/ssh/sshd_config") - MustExec(t, tc, "systemctl restart ssh") - - cmdTest(t, tc, []cmdTestCase{ - { - name: "ssh_env", - cmd: "ak ssh -i akadmin@$(hostname) env", - expects: []string{"AUTHENTIK_CLI_SOCKET", "SSH_CONNECTION"}, - }, - { - name: "ssh_ak_whoami", - cmd: "ak ssh -i akadmin@$(hostname) ak whoami", - expects: []string{"akadmin"}, - }, - }) -} diff --git a/ee/psso/Bridge/Generated/ic_ssh.grpc.swift b/ee/psso/Bridge/Generated/ic_ssh.grpc.swift deleted file mode 100644 index 8615c0e7..00000000 --- a/ee/psso/Bridge/Generated/ic_ssh.grpc.swift +++ /dev/null @@ -1,11 +0,0 @@ -// DO NOT EDIT. -// swift-format-ignore-file -// swiftlint:disable all -// -// Generated by the gRPC Swift generator plugin for the protocol buffer compiler. -// Source: ic_ssh.proto -// -// For information on using the generated types, please see the documentation: -// https://github.com/grpc/grpc-swift - -// This file contained no services. \ No newline at end of file diff --git a/ee/psso/Bridge/Generated/ic_ssh.pb.swift b/ee/psso/Bridge/Generated/ic_ssh.pb.swift deleted file mode 100644 index b77ec1a6..00000000 --- a/ee/psso/Bridge/Generated/ic_ssh.pb.swift +++ /dev/null @@ -1,75 +0,0 @@ -// DO NOT EDIT. -// swift-format-ignore-file -// swiftlint:disable all -// -// Generated by the Swift generator plugin for the protocol buffer compiler. -// Source: ic_ssh.proto -// -// For information on using the generated types, please see the documentation: -// https://github.com/apple/swift-protobuf/ - -internal import SwiftProtobuf - -// If the compiler emits an error on this type, it is because this file -// was generated by a version of the `protoc` Swift plug-in that is -// incompatible with the version of SwiftProtobuf to which you are linking. -// Please ensure that you are building against the same version of the API -// that was used to generate this file. -fileprivate nonisolated struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck { - struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {} - typealias Version = _2 -} - -/// Message to encode token for SSH authenticaiton with CLI -nonisolated struct SSHTokenAuthentication: Sendable { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var token: String = String() - - var localSocket: String = String() - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} -} - -// MARK: - Code below here is support for the SwiftProtobuf runtime. - -fileprivate nonisolated let _protobuf_package = "ic_ssh" - -nonisolated extension SSHTokenAuthentication: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".SSHTokenAuthentication" - static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}token\0\u{3}local_socket\0") - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.token) }() - case 2: try { try decoder.decodeSingularStringField(value: &self.localSocket) }() - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if !self.token.isEmpty { - try visitor.visitSingularStringField(value: self.token, fieldNumber: 1) - } - if !self.localSocket.isEmpty { - try visitor.visitSingularStringField(value: self.localSocket, fieldNumber: 2) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SSHTokenAuthentication, rhs: SSHTokenAuthentication) -> Bool { - if lhs.token != rhs.token {return false} - if lhs.localSocket != rhs.localSocket {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} diff --git a/pam/src/auth.rs b/pam/src/auth.rs index 8eb46eb1..ec6a66c1 100644 --- a/pam/src/auth.rs +++ b/pam/src/auth.rs @@ -1,7 +1,4 @@ -use authentik_sys::{ - generated::ic_ssh::SshTokenAuthentication, - grpc::{Bridge, decode_pb}, -}; +use authentik_sys::grpc::Bridge; use pam::{ constants::{PAM_PROMPT_ECHO_OFF, PamFlag, PamResultCode}, conv::Conv, @@ -12,7 +9,7 @@ use std::ffi::CStr; use crate::{ ENV_SESSION_ID, - auth::{interactive::auth_interactive, token::auth_token}, + auth::interactive::auth_interactive, pam_env::pam_put_env, pam_try_log, session_data::{_write_session_data, SessionData}, @@ -21,9 +18,7 @@ use crate::{ pub mod authorize; pub mod fido; pub mod interactive; -pub mod token; -pub const PW_PREFIX: &str = "\u{200b}"; pub const PW_PROMPT: &str = "authentik Password: "; pub fn authenticate_impl( @@ -79,11 +74,10 @@ pub fn authenticate_impl( } }; - let mut session_data = SessionData { + let session_data = SessionData { username: username.to_string(), local_socket: "".to_owned(), }; - let session_id: String; let bridge = match Bridge::new() { Ok(b) => b, @@ -93,33 +87,12 @@ pub fn authenticate_impl( } }; - if password.starts_with(PW_PREFIX) { - log::debug!("Token authentication"); - let raw_token = password - .strip_prefix(PW_PREFIX) - .unwrap_or(password) - .to_string(); - let decoded = match decode_pb::(raw_token) { - Ok(t) => t, - Err(e) => { - log::warn!("failed to decode token: {}", e); - return PamResultCode::PAM_ABORT; - } - }; - let token_res = match auth_token(username, decoded.token.to_owned(), bridge) { - Ok(t) => t, - Err(e) => return e, - }; - session_data.local_socket = decoded.local_socket; - session_id = token_res.session_id; - } else { - log::debug!("Interactive authentication"); - let int_res = match auth_interactive(username, password.to_owned(), &conv, bridge) { - Ok(ss) => ss, - Err(code) => return code, - }; - session_id = int_res.session_id; - } + log::debug!("Interactive authentication"); + let int_res = match auth_interactive(username, password.to_owned(), &conv, bridge) { + Ok(ss) => ss, + Err(code) => return code, + }; + let session_id: String = int_res.session_id; if !session_data.local_socket.is_empty() { pam_try_log!( pam_put_env( diff --git a/pam/src/auth/token.rs b/pam/src/auth/token.rs deleted file mode 100644 index f3417ec0..00000000 --- a/pam/src/auth/token.rs +++ /dev/null @@ -1,45 +0,0 @@ -use authentik_sys::generated::sys_auth::system_auth_token_client::SystemAuthTokenClient; -use authentik_sys::generated::sys_auth::{TokenAuthRequest, TokenAuthResponse}; -use authentik_sys::grpc::SysdBridge; -use pam::constants::PamResultCode; - -pub fn auth_token( - username: String, - token: String, - bridge: impl SysdBridge, -) -> Result { - let response = match bridge.grpc_request(async |ch| { - return Ok(SystemAuthTokenClient::new(ch) - .token_auth(TokenAuthRequest { - username: username.to_owned(), - token: token.to_owned(), - }) - .await?); - }) { - Ok(t) => t.into_inner(), - Err(e) => { - log::warn!("failed to validate token: {e}"); - return Err(PamResultCode::PAM_AUTH_ERR); - } - }; - - if !response.successful { - return Err(PamResultCode::PAM_AUTH_ERR); - } - - log::debug!("Got valid token: {response:#?}"); - let token_username = response - .token - .clone() - .ok_or(PamResultCode::PAM_AUTH_ERR)? - .preferred_username; - if username != token_username { - log::warn!( - "User mismatch: token={:#?}, expected={:#?}", - token_username, - username - ); - return Err(PamResultCode::PAM_USER_UNKNOWN); - } - Ok(response) -} diff --git a/pkg/cli/auth/device/device.go b/pkg/cli/auth/device/device.go deleted file mode 100644 index 0fe4459b..00000000 --- a/pkg/cli/auth/device/device.go +++ /dev/null @@ -1,57 +0,0 @@ -package device - -import ( - "context" - "time" - - log "github.com/sirupsen/logrus" - "goauthentik.io/platform/pkg/agent_local/client" - "goauthentik.io/platform/pkg/pb" -) - -type CredentialsOpts struct { - Profile string - DeviceName string -} - -type DeviceCredentialOutput struct { - AccessToken string - Expiration time.Time -} - -func (dco DeviceCredentialOutput) Expiry() time.Time { - return dco.Expiration -} - -func GetCredentials(c *client.AgentClient, ctx context.Context, opts CredentialsOpts) *DeviceCredentialOutput { - log := log.WithField("logger", "auth.device") - - cc := client.NewCache[DeviceCredentialOutput](c, &pb.RequestHeader{ - Profile: opts.Profile, - }, "auth-device-cache", opts.DeviceName) - if v, err := cc.Get(ctx); err == nil { - log.Debug("Got Device Credentials from cache") - return &v - } - - dt, err := c.DeviceTokenExchange(ctx, &pb.DeviceTokenExchangeRequest{ - Header: &pb.RequestHeader{ - Profile: opts.Profile, - }, - DeviceName: opts.DeviceName, - }) - if err != nil { - log.WithError(err).Warning("failed to get device token") - return nil - } - - o := DeviceCredentialOutput{ - AccessToken: dt.AccessToken, - Expiration: time.Now().Add(time.Duration(dt.ExpiresIn) * time.Second), - } - err = cc.Set(ctx, o) - if err != nil { - log.WithError(err).Warning("failed to cache device token") - } - return &o -} diff --git a/pkg/cli/ssh.go b/pkg/cli/ssh.go deleted file mode 100644 index dae4c61f..00000000 --- a/pkg/cli/ssh.go +++ /dev/null @@ -1,39 +0,0 @@ -package cli - -import ( - "github.com/spf13/cobra" - "goauthentik.io/platform/pkg/agent_local/client" - "goauthentik.io/platform/pkg/cli/ssh" -) - -var insecure = false - -var sshCmd = &cobra.Command{ - Use: "ssh", - Short: "Establish an SSH connection with `host`.", - Args: cobra.MinimumNArgs(1), - SilenceUsage: true, - Deprecated: "`ak ssh` is deprecated, migrate to the authentik SSH Agent.", - RunE: func(cmd *cobra.Command, args []string) error { - profile := mustFlag(cmd.Flags().GetString("profile")) - agentClient, err := client.New(socketPath) - if err != nil { - return err - } - - client, err := ssh.ParseArgs(args) - if err != nil { - return err - } - - client.AgentClient = agentClient - client.AgentProfile = profile - client.Insecure = insecure - return client.Connect() - }, -} - -func init() { - sshCmd.Flags().BoolVarP(&insecure, "insecure", "i", false, "Insecure host-key checking, use with caution!") - rootCmd.AddCommand(sshCmd) -} diff --git a/pkg/cli/ssh/client.go b/pkg/cli/ssh/client.go deleted file mode 100644 index 5e811766..00000000 --- a/pkg/cli/ssh/client.go +++ /dev/null @@ -1,141 +0,0 @@ -package ssh - -import ( - "fmt" - "io" - "net" - "os" - "os/user" - "strconv" - "strings" - - "github.com/google/uuid" - "github.com/pkg/errors" - log "github.com/sirupsen/logrus" - "github.com/skeema/knownhosts" - "goauthentik.io/platform/pkg/agent_local/client" - "golang.org/x/crypto/ssh" -) - -type SSHClient struct { - host string - port int - user string - - Command string - Insecure bool - AgentClient *client.AgentClient - AgentProfile string - - agentToken string - - knownHosts *knownhosts.HostKeyDB - knownHostsFile string - remoteSocketPath string - - log *log.Entry -} - -func New(host string, port int, user string) (*SSHClient, error) { - c := &SSHClient{ - log: log.WithField("component", "ssh"), - host: host, - port: port, - user: user, - } - - khf, err := DefaultKnownHostsPath() - if err != nil { - return nil, errors.Wrap(err, "failed to locate known_hosts") - } - if _, err := os.Stat(khf); os.IsNotExist(err) { - _, err := os.OpenFile(khf, os.O_CREATE, 0600) - if err != nil { - return nil, errors.Wrap(err, "failed to create known_hosts file") - } - } - c.knownHostsFile = khf - kh, err := knownhosts.NewDB(khf) - if err != nil { - return nil, errors.Wrap(err, "failed to read known_hosts") - } - c.knownHosts = kh - - uid := uuid.New().String() - c.remoteSocketPath = fmt.Sprintf("/var/run/authentik/agent-%s.sock", uid) - - return c, nil -} - -func ParseArgs(args []string) (*SSHClient, error) { - u, err := user.Current() - if err != nil { - return nil, err - } - if len(args) < 1 { - return nil, errors.New("missing host") - } - host := args[0] - user := u.Username - port := "22" - if strings.Contains(host, "@") { - _parts := strings.Split(host, "@") - user = _parts[0] - host = _parts[1] - } - if strings.Contains(host, ":") { - _parts := strings.Split(host, ":") - host = _parts[0] - port = _parts[1] - } - nport, err := strconv.Atoi(port) - if err != nil { - return nil, err - } - cmd := "" - if len(args) > 1 { - cmd = args[1] - } - c, err := New(host, nport, user) - if err != nil { - return nil, err - } - c.Command = cmd - return c, nil -} - -func (c *SSHClient) Connect() error { - client, err := ssh.Dial("tcp", net.JoinHostPort(c.host, strconv.Itoa(c.port)), c.getConfig()) - if err != nil { - return err - } - defer func() { - err := client.Close() - if err != nil && !errors.Is(err, net.ErrClosed) { - c.log.WithError(err).Warning("Failed to close client") - } - }() - - go func() { - err := c.ForwardAgentSocket(c.remoteSocketPath, client) - if err != nil { - c.log.WithError(err).Warning("failed to forward local agent") - } - }() - - session, err := client.NewSession() - if err != nil { - return err - } - defer func() { - err := session.Close() - if err != nil && !errors.Is(err, io.EOF) { - c.log.WithError(err).Warning("Failed to close session") - } - }() - - if c.Command != "" { - return c.command(session) - } - return c.shell(session) -} diff --git a/pkg/cli/ssh/command.go b/pkg/cli/ssh/command.go deleted file mode 100644 index b916d728..00000000 --- a/pkg/cli/ssh/command.go +++ /dev/null @@ -1,16 +0,0 @@ -package ssh - -import ( - "os" - - "golang.org/x/crypto/ssh" -) - -func (c *SSHClient) command(session *ssh.Session) error { - // Set up terminal - session.Stdout = os.Stdout - session.Stderr = os.Stderr - session.Stdin = os.Stdin - - return session.Run(c.Command) -} diff --git a/pkg/cli/ssh/config.go b/pkg/cli/ssh/config.go deleted file mode 100644 index d9af29b2..00000000 --- a/pkg/cli/ssh/config.go +++ /dev/null @@ -1,126 +0,0 @@ -package ssh - -import ( - "bufio" - "context" - "errors" - "fmt" - "net" - "os" - "path" - "strings" - "time" - - progress "github.com/ankddev/conemu-progressbar-go" - "github.com/skeema/knownhosts" - "goauthentik.io/platform/pkg/cli/auth/device" - "goauthentik.io/platform/pkg/meta" - "goauthentik.io/platform/pkg/shared/tui" - "golang.org/x/crypto/ssh" - "golang.org/x/term" -) - -const PAMPrompt = "authentik Password: " - -func (c *SSHClient) getTokenIfNeeded() (string, error) { - progress.SetIndeterminateProgress() - defer progress.ClearProgress() - fmt.Println(tui.InlineStyle().Render(fmt.Sprintf("authentik: Getting token to access '%s'...", c.host))) - cc := device.GetCredentials(c.AgentClient, context.Background(), device.CredentialsOpts{ - Profile: c.AgentProfile, - DeviceName: c.host, - }) - if cc == nil { - return "", errors.New("failed to exchange token") - } - ft := FormatToken(cc, c.remoteSocketPath) - return ft, nil -} - -func (c *SSHClient) auth(name, instruction string, questions []string, echos []bool) ([]string, error) { - c.log.Debugf("name '%s' instruction '%s' questions '%+v' echos '%+v'\n", name, instruction, questions, echos) - if len(questions) > 0 && questions[0] == PAMPrompt { - if c.agentToken == "" { - token, err := c.getTokenIfNeeded() - if err != nil { - return []string{}, err - } - c.agentToken = token - } - return []string{c.agentToken}, nil - } - ans := []string{} - for _, q := range questions { - l, err := c.ReadPassword(q) - fmt.Println("") - if err != nil { - return ans, err - } - ans = append(ans, l) - } - return ans, nil -} - -func (c *SSHClient) getConfig() *ssh.ClientConfig { - config := &ssh.ClientConfig{ - User: c.user, - Auth: []ssh.AuthMethod{ - ssh.KeyboardInteractive(c.auth), - }, - HostKeyCallback: ssh.HostKeyCallback(func(hostname string, remote net.Addr, key ssh.PublicKey) error { - innerCallback := c.knownHosts.HostKeyCallback() - err := innerCallback(hostname, remote, key) - if knownhosts.IsHostKeyChanged(err) { - fmt.Printf("REMOTE HOST IDENTIFICATION HAS CHANGED for host %s! This may indicate a MitM attack.\n", hostname) - return errors.New("hostkey changed") - } else if knownhosts.IsHostUnknown(err) { - if !term.IsTerminal(int(os.Stdin.Fd())) { - return errors.New("host key verification failed: unknown host and stdin is not a terminal") - } - fmt.Printf("The authenticity of host '%s (%s)' can't be established.\n", hostname, remote.String()) - fmt.Printf("%s key fingerprint is %s.\n", key.Type(), ssh.FingerprintSHA256(key)) - fmt.Print("Are you sure you want to continue connecting (yes/no)? ") - answer, rerr := bufio.NewReader(os.Stdin).ReadString('\n') - if rerr != nil { - return fmt.Errorf("failed to read user input: %w", rerr) - } - if strings.TrimSpace(strings.ToLower(answer)) != "yes" { - return errors.New("host key verification rejected by user") - } - f, ferr := os.OpenFile(c.knownHostsFile, os.O_APPEND|os.O_WRONLY, 0600) - if ferr == nil { - defer func() { - err := f.Close() - if err != nil { - c.log.WithError(err).Warning("failed to close known_hosts file") - } - }() - ferr = knownhosts.WriteKnownHost(f, hostname, remote, key) - } - if ferr != nil { - c.log.Infof("Failed to add host %s to known_hosts: %v\n", hostname, ferr) - return ferr - } - fmt.Printf("Warning: Permanently added '%s' (%s) to the list of known hosts.\n", hostname, key.Type()) - c.log.Infof("Added host %s to known_hosts\n", hostname) - return nil - } - return err - }), - HostKeyAlgorithms: c.knownHosts.HostKeyAlgorithms(c.host), - ClientVersion: fmt.Sprintf("SSH-2.0-authentik-cli/%s", meta.FullVersion()), - Timeout: 5 * time.Second, - } - if c.Insecure { - config.HostKeyCallback = ssh.InsecureIgnoreHostKey() - } - return config -} - -func DefaultKnownHostsPath() (string, error) { - home, err := os.UserHomeDir() - if err != nil { - return "", err - } - return path.Join(home, ".ssh/known_hosts"), err -} diff --git a/pkg/cli/ssh/shell.go b/pkg/cli/ssh/shell.go deleted file mode 100644 index b17785d8..00000000 --- a/pkg/cli/ssh/shell.go +++ /dev/null @@ -1,86 +0,0 @@ -package ssh - -import ( - "fmt" - "os" - "os/signal" - "syscall" - - "golang.org/x/crypto/ssh" - "golang.org/x/term" -) - -func (c *SSHClient) shell(session *ssh.Session) error { - // Set up terminal - session.Stdout = os.Stdout - session.Stderr = os.Stderr - session.Stdin = os.Stdin - - // Request a pseudo terminal - if term.IsTerminal(int(os.Stdin.Fd())) { - originalState, err := term.MakeRaw(int(os.Stdin.Fd())) - if err != nil { - c.log.WithError(err).Fatal("Failed to set raw mode") - } - defer func() { - err := term.Restore(int(os.Stdin.Fd()), originalState) - if err != nil { - c.log.WithError(err).Warn("Failed to restore terminal state") - } - }() - - width, height, err := term.GetSize(int(os.Stdin.Fd())) - if err != nil { - width, height = 80, 24 - } - term := os.Getenv("TERM") - if term == "" { - term = "xterm" - } - if err := session.RequestPty(term, height, width, ssh.TerminalModes{}); err != nil { - c.log.Fatalf("Failed to request pty: %v", err) - } - } - - // Start shell - if err := session.Shell(); err != nil { - c.log.Fatalf("Failed to start shell: %v", err) - } - - // Wait for session to end - _ = session.Wait() - return nil -} - -func (c *SSHClient) ReadPassword(prompt string) (string, error) { - stdin := int(syscall.Stdin) - oldState, err := term.GetState(stdin) - if err != nil { - return "", err - } - defer func() { - err := term.Restore(stdin, oldState) - if err != nil { - c.log.WithError(err).Warning("failed to restore terminal") - } - }() - - sigch := make(chan os.Signal, 1) - signal.Notify(sigch, os.Interrupt) - go func() { - for range sigch { - err := term.Restore(stdin, oldState) - if err != nil { - c.log.WithError(err).Warning("failed to restore terminal state") - } - os.Exit(1) - } - }() - - fmt.Print(prompt) - password, err := term.ReadPassword(stdin) - if err != nil { - return "", err - } - return string(password), nil -} diff --git a/pkg/cli/ssh/socket.go b/pkg/cli/ssh/socket.go deleted file mode 100644 index bf02d7b4..00000000 --- a/pkg/cli/ssh/socket.go +++ /dev/null @@ -1,71 +0,0 @@ -package ssh - -import ( - "io" - "net" - "strings" - - "goauthentik.io/platform/pkg/agent_local/types" - "goauthentik.io/platform/pkg/platform/socket" - "golang.org/x/crypto/ssh" -) - -func (c *SSHClient) ForwardAgentSocket(remoteSocket string, client *ssh.Client) error { - localSocket := types.GetAgentSocketPath(types.SocketIDDefault) - remoteListener, err := client.Listen("unix", remoteSocket) - if err != nil { - return err - } - defer func() { - err := remoteListener.Close() - if err != nil { - c.log.WithError(err).Warning("Failed to close remote listener") - } - }() - c.log.Debugf("remote listening %s → local %s", remoteSocket, localSocket.ForCurrent()) - - for { - remoteConn, err := remoteListener.Accept() - if err != nil { - c.log.WithError(err).Debug("remote Accept error") - continue - } - go func(rc net.Conn) { - defer func() { - err := rc.Close() - if err != nil { - c.log.WithError(err).Warning("failed to close remote connection") - } - }() - // Dial the local unix socket - lc, err := socket.Connect(localSocket) - if err != nil { - c.log.WithError(err).Debugf("local dial %s failed", localSocket.ForCurrent()) - return - } - defer func() { - err := lc.Close() - if err != nil { - c.log.WithError(err).Warning("failed to close local connection") - } - }() - - done := make(chan struct{}, 2) - go func() { - _, err := io.Copy(rc, lc) - if err != nil && !strings.Contains(err.Error(), "use of closed network connection") { - c.log.WithError(err).Warning("failed to copy from remote to local") - } - done <- struct{}{} - }() - go func() { - _, err := io.Copy(lc, rc) - if err != nil { - c.log.WithError(err).Warning("failed to copy from local to remote") - } - done <- struct{}{} - }() - <-done - }(remoteConn) - } -} diff --git a/pkg/cli/ssh/token.go b/pkg/cli/ssh/token.go deleted file mode 100644 index 048fc18a..00000000 --- a/pkg/cli/ssh/token.go +++ /dev/null @@ -1,22 +0,0 @@ -package ssh - -import ( - "encoding/base64" - "fmt" - - "goauthentik.io/platform/pkg/cli/auth/device" - "goauthentik.io/platform/pkg/pb" - "google.golang.org/protobuf/proto" -) - -func FormatToken(cc *device.DeviceCredentialOutput, rtp string) string { - msg := pb.SSHTokenAuthentication{ - Token: cc.AccessToken, - LocalSocket: rtp, - } - rv, err := proto.Marshal(&msg) - if err != nil { - panic(err) - } - return fmt.Sprintf("\u200b%s", base64.StdEncoding.EncodeToString(rv)) -} diff --git a/pkg/pb/ic_ssh.pb.go b/pkg/pb/ic_ssh.pb.go deleted file mode 100644 index 8aefbe32..00000000 --- a/pkg/pb/ic_ssh.pb.go +++ /dev/null @@ -1,132 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.36.11 -// protoc v7.34.1 -// source: ic_ssh.proto - -package pb - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" - unsafe "unsafe" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// Message to encode token for SSH authenticaiton with CLI -type SSHTokenAuthentication struct { - state protoimpl.MessageState `protogen:"open.v1"` - Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` - LocalSocket string `protobuf:"bytes,2,opt,name=local_socket,json=localSocket,proto3" json:"local_socket,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *SSHTokenAuthentication) Reset() { - *x = SSHTokenAuthentication{} - mi := &file_ic_ssh_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *SSHTokenAuthentication) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SSHTokenAuthentication) ProtoMessage() {} - -func (x *SSHTokenAuthentication) ProtoReflect() protoreflect.Message { - mi := &file_ic_ssh_proto_msgTypes[0] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SSHTokenAuthentication.ProtoReflect.Descriptor instead. -func (*SSHTokenAuthentication) Descriptor() ([]byte, []int) { - return file_ic_ssh_proto_rawDescGZIP(), []int{0} -} - -func (x *SSHTokenAuthentication) GetToken() string { - if x != nil { - return x.Token - } - return "" -} - -func (x *SSHTokenAuthentication) GetLocalSocket() string { - if x != nil { - return x.LocalSocket - } - return "" -} - -var File_ic_ssh_proto protoreflect.FileDescriptor - -const file_ic_ssh_proto_rawDesc = "" + - "\n" + - "\fic_ssh.proto\x12\x06ic_ssh\"Q\n" + - "\x16SSHTokenAuthentication\x12\x14\n" + - "\x05token\x18\x01 \x01(\tR\x05token\x12!\n" + - "\flocal_socket\x18\x02 \x01(\tR\vlocalSocketB\vZ\x06pkg/pb\xba\x02\x00b\x06proto3" - -var ( - file_ic_ssh_proto_rawDescOnce sync.Once - file_ic_ssh_proto_rawDescData []byte -) - -func file_ic_ssh_proto_rawDescGZIP() []byte { - file_ic_ssh_proto_rawDescOnce.Do(func() { - file_ic_ssh_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ic_ssh_proto_rawDesc), len(file_ic_ssh_proto_rawDesc))) - }) - return file_ic_ssh_proto_rawDescData -} - -var file_ic_ssh_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_ic_ssh_proto_goTypes = []any{ - (*SSHTokenAuthentication)(nil), // 0: ic_ssh.SSHTokenAuthentication -} -var file_ic_ssh_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_ic_ssh_proto_init() } -func file_ic_ssh_proto_init() { - if File_ic_ssh_proto != nil { - return - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: unsafe.Slice(unsafe.StringData(file_ic_ssh_proto_rawDesc), len(file_ic_ssh_proto_rawDesc)), - NumEnums: 0, - NumMessages: 1, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_ic_ssh_proto_goTypes, - DependencyIndexes: file_ic_ssh_proto_depIdxs, - MessageInfos: file_ic_ssh_proto_msgTypes, - }.Build() - File_ic_ssh_proto = out.File - file_ic_ssh_proto_goTypes = nil - file_ic_ssh_proto_depIdxs = nil -} diff --git a/protobuf/ic_ssh.proto b/protobuf/ic_ssh.proto deleted file mode 100644 index a9ddbb29..00000000 --- a/protobuf/ic_ssh.proto +++ /dev/null @@ -1,11 +0,0 @@ -syntax = "proto3"; - -package ic_ssh; -option go_package = "pkg/pb"; -option swift_prefix = ""; - -// Message to encode token for SSH authenticaiton with CLI -message SSHTokenAuthentication { - string token = 1; - string local_socket = 2; -} diff --git a/src/generated/ic_ssh/ic_ssh.rs b/src/generated/ic_ssh/ic_ssh.rs deleted file mode 100644 index 719da268..00000000 --- a/src/generated/ic_ssh/ic_ssh.rs +++ /dev/null @@ -1,11 +0,0 @@ -// @generated -// This file is @generated by prost-build. -/// Message to encode token for SSH authenticaiton with CLI -#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] -pub struct SshTokenAuthentication { - #[prost(string, tag="1")] - pub token: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub local_socket: ::prost::alloc::string::String, -} -// @@protoc_insertion_point(module) diff --git a/src/generated/mod.rs b/src/generated/mod.rs index 406eb384..27cef4bd 100644 --- a/src/generated/mod.rs +++ b/src/generated/mod.rs @@ -29,11 +29,6 @@ pub mod ic_pam_fido { include!("ic_pam_fido/ic_pam_fido.rs"); // @@protoc_insertion_point(ic_pam_fido) } -// @@protoc_insertion_point(attribute:ic_ssh) -pub mod ic_ssh { - include!("ic_ssh/ic_ssh.rs"); - // @@protoc_insertion_point(ic_ssh) -} // @@protoc_insertion_point(attribute:ping) pub mod ping { include!("ping/ping.rs");