sshsso

package module
v0.0.0-...-34e0cf6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 18, 2023 License: MIT Imports: 11 Imported by: 0

README

Go Reference

A GSSAPIServer and GSSAPIClient for crypto/ssh based on Kerberos and the Windows Security Support Provider Interface (so it only works on Windows). My only intention was that client implementation to be able to authenticate with this server implementation, so if it works with any other GSSAPI or Kerberos implementation it is just a happy accident. This makes it possible to do "Windows Single Sign On" without prompting the user for credentials, or to have AD computers authenticate using their computer account. You can also take advantage of the fact that kerberos does mutual authentication to eliminate the need for host key checking IF you use the GSSAPIClient.Success variable.

Check out the example program

Thanks to Alex Brainman's excellent SSPI library

Quick Start

Client

var usedKerberosAuth bool
sshConn, _ := ssh.Dial(
	// the host you specify here is what you will actually connect to
	"tcp", "localhost:2222",
	&ssh.ClientConfig{
		User: "MyUsername",
		Auth: []ssh.AuthMethod{
			// the host you specify here is the one we will ask for a
			// kerberos ticket to (the remote computer will have to
			// prove that it is this computer).
			ssh.GSSAPIWithMICAuthMethod(
				&sshsso.GSSAPIClient{Success: &usedKerberosAuth},
				"NetBIOSName",
			),
		},
		// we can safely ignore host key, since kerberos already forces
		// the remote computer to prove who it is **IF** we check that
		// we actually used Kerberos for authentication using the
		// usedKerberosAuth variable
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	},
)

// if this is false, it means the server accepted "none" auth and might
// not be who we think it is
if !usedKerberosAuth {
	sshConn.Close()
	panic("server accepted none auth")
}

Server

sshConfig := &ssh.ServerConfig{
	GSSAPIWithMICConfig: &ssh.GSSAPIWithMICConfig{
		// AllowLogin() decides if a user is allowed to
		// connect once we know who they are
		AllowLogin: func(_ ssh.ConnMetadata, user string) (*ssh.Permissions, error) {
			if user == "kidswatter@WAYSIDESCHOOL.LOCAL" {
				return nil, nil
			} else {
				return nil, errors.New("Not Authorized")
			}
		},
		Server: &sshsso.GSSAPIServer{},
	},
}

Gotchas

  • The server needs to have permission to validate tickets for the service principal name (SPN) "HOST/myhostname", which means you probably have to run as "SYSTEM" ("Network Service" might work too, I haven't tested)
  • If you are doing machine to machine authentication remember that AD computer accounts end with a "$"
  • I'm dumb and this is dangerously close to the classic blunder of "rolling your own key exchange". If it breaks, you get to keep both halves.
  • Thread safety: GSSAPIServer and GSSAPIClient are not thread safe. If you want to handle multiple authentication attempts at once (for example in a normal server) you will need to create a new copy for each connection which will be passed in via a new ssh.ServerConfig or ssh.ClientConfig
  • Neither the API nor the protocol should be considered stable

Documentation

Overview

Package sshsso implements gssapiServer and gssapiClient from crypto/ssh based on the Windows Security Support Provider Interface "negotiate" implimentation. This makes it possible to do authentication without prompting the user for credentials using AD. This package makes no attempt to be compatible with any other ssh server or client other than itself.

Index

Constants

This section is empty.

Variables

View Source
var Debug = false

Debug will cause each GAASPI call to be logged using the default logger

Functions

func NewClient

func NewClient() ssh.GSSAPIClient

NewClient returns a GSSAPIClient from crypto/ssh. It will always attempt to authenticate as the current Windows user. This is not thread safe. In normal client scenarios this is fine, but if you want to handle multiple authentication attempts at once you will need to create a new copy for each connection and pass that in via a new `ssh.ClientConfig`.

func NewServer

func NewServer() ssh.GSSAPIServer

NewServer returns a GSSAPIServer from crypto/ssh. It will authenticate as the SPN "HOST/foo" where foo is the hostname (not fqdn) of the current computer. This may necessitate running as "SYSTEM" or "Network Service". This is not thread safe. If you want to handle multiple authentication attempts at once (for example in a normal server) you will need to create a new copy for each connection, and pass that in via a new `ssh.ServerConfig`.

Types

This section is empty.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL