You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

151 lines
3.3 KiB

package identity
import (
"bytes"
"errors"
"io/ioutil"
"os/user"
"path/filepath"
"strconv"
"golang.org/x/crypto/ssh"
"maze.io/gate/pkg/core"
"maze.io/gate/pkg/core/logger"
"maze.io/gate/pkg/util/compact"
)
type systemIdentityProvider struct {
log *logger.Logger
}
func (idp *systemIdentityProvider) Setup(log *logger.Logger) error {
idp.log = log
return nil
}
func (idp *systemIdentityProvider) LookupUser(name string) (core.User, error) {
u, err := user.Lookup(name)
if err != nil {
return nil, err
}
return systemUser{idp, u}, nil
}
func (idp *systemIdentityProvider) LookupGroup(name string) (core.Group, error) {
if _, err := strconv.Atoi(name); err == nil {
g, err := user.LookupGroupId(name)
if err != nil {
return nil, err
}
return systemGroup{idp, g}, nil
}
g, err := user.LookupGroup(name)
if err != nil {
return nil, err
}
return systemGroup{idp, g}, nil
}
func (idp *systemIdentityProvider) PasswordCallback(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
user, err := idp.LookupUser(conn.User())
if err != nil {
return nil, err
}
_ = user
return nil, errors.New("password not implemented")
}
type systemKey struct {
ssh.PublicKey
Options []string
}
func (idp systemIdentityProvider) PublicKeyCallback(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
log := logger.Default.WithFields(logger.Fields{
logger.User: conn.User(),
"key": ssh.FingerprintSHA256(key),
"key_type": key.Type(),
}).WithSourceAddr(conn.RemoteAddr())
log.Debug("public key authentication")
user, err := idp.LookupUser(conn.User())
if err != nil {
return nil, err
}
name := filepath.Join(user.(systemUser).obj.HomeDir, ".ssh", "authorized_keys")
b, err := ioutil.ReadFile(name)
if err != nil {
return nil, err
}
marshaled := key.Marshal()
for len(b) > 0 {
var (
authorizedKey ssh.PublicKey
comment string
)
if authorizedKey, comment, _, b, err = ssh.ParseAuthorizedKey(b); err != nil {
break
}
log.WithFields(logger.Fields{
"authorized_key": ssh.FingerprintSHA256(authorizedKey),
"authorized_key_type": authorizedKey.Type(),
"authorized_key_comment": comment,
}).Debug("checking key")
if bytes.Equal(authorizedKey.Marshal(), marshaled) {
return &ssh.Permissions{
Extensions: map[string]string{
"gate-idp": "system",
"gate-obj": user.Login(),
},
}, nil
}
}
return nil, errors.New("key not found")
}
type systemUser struct {
idp core.IdentityProvider
obj *user.User
}
func (user systemUser) ID() compact.ID {
return compact.String(user.obj.Uid)
}
func (user systemUser) Login() string { return user.obj.Username }
func (user systemUser) Name() string { return user.obj.Name }
func (user systemUser) Groups() []core.Group {
var (
ids, _ = user.obj.GroupIds()
groups = make([]core.Group, 0, len(ids))
)
for _, id := range ids {
if group, err := user.idp.LookupGroup(id); err == nil {
groups = append(groups, group)
}
}
return groups
}
type systemGroup struct {
idp core.IdentityProvider
obj *user.Group
}
func (group systemGroup) ID() compact.ID {
return compact.String("gid=" + group.obj.Gid)
}
func (group systemGroup) Name() string {
return group.obj.Name
}
func (group systemGroup) Members() []core.User {
return nil
}