Initial import
This commit is contained in:
96
auth/auth.go
Normal file
96
auth/auth.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
|
||||
"git.maze.io/maze/conduit/logger"
|
||||
)
|
||||
|
||||
var ErrUnauthorized = errors.New("unauthorized")
|
||||
|
||||
// Provider implements zero or more of the [Password], [PublicKey] interfaces.
|
||||
type Provider any
|
||||
|
||||
// Password authenticator.
|
||||
type Password interface {
|
||||
VerifyPassword(meta ssh.ConnMetadata, password string) (Principal, error)
|
||||
}
|
||||
|
||||
// Token authenticator.
|
||||
type Token interface {
|
||||
Instruction() string
|
||||
|
||||
Prompt() string
|
||||
|
||||
// Multiline accepts multiline input and wait for the user to supply
|
||||
// an empty line.
|
||||
Multiline() bool
|
||||
|
||||
VerifyToken(meta ssh.ConnMetadata, token string) (Principal, error)
|
||||
}
|
||||
|
||||
// PublicKey authenticator.
|
||||
type PublicKey interface {
|
||||
VerifyPublicKey(meta ssh.ConnMetadata, publicKey ssh.PublicKey) (Principal, error)
|
||||
}
|
||||
|
||||
type CertificateAuthority struct {
|
||||
checker *ssh.CertChecker
|
||||
keys []ssh.PublicKey
|
||||
blob [][]byte
|
||||
user bool
|
||||
host bool
|
||||
}
|
||||
|
||||
func NewUserCertificateAuthority(keys ...ssh.PublicKey) *CertificateAuthority {
|
||||
var blob [][]byte
|
||||
for _, key := range keys {
|
||||
blob = append(blob, key.Marshal())
|
||||
}
|
||||
auth := &CertificateAuthority{
|
||||
checker: &ssh.CertChecker{
|
||||
Clock: time.Now,
|
||||
},
|
||||
keys: keys,
|
||||
blob: blob,
|
||||
user: true,
|
||||
}
|
||||
auth.checker.IsUserAuthority = auth.isUserAuthority
|
||||
return auth
|
||||
}
|
||||
|
||||
func (auth *CertificateAuthority) isUserAuthority(key ssh.PublicKey) bool {
|
||||
if !auth.user {
|
||||
return false
|
||||
}
|
||||
blob := key.Marshal()
|
||||
for _, other := range auth.blob {
|
||||
if bytes.Equal(blob, other) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (auth *CertificateAuthority) VerifyPublicKey(meta ssh.ConnMetadata, publicKey ssh.PublicKey) (Principal, error) {
|
||||
log := logger.StandardLog.Values(logger.Values{
|
||||
"client": meta.RemoteAddr().String(),
|
||||
"key": strings.TrimSpace(string(ssh.MarshalAuthorizedKey(publicKey))),
|
||||
"user": meta.User(),
|
||||
"version": string(meta.ClientVersion()),
|
||||
})
|
||||
log.Debug("Verifying user certificate")
|
||||
|
||||
_, err := auth.checker.Authenticate(meta, publicKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cert := publicKey.(*ssh.Certificate)
|
||||
return UserCertificatePrincipal{cert}, nil
|
||||
}
|
Reference in New Issue
Block a user