Files
EdgeAPI/internal/rpc/services/service_node_grant.go

327 lines
9.0 KiB
Go
Raw Normal View History

2020-07-29 19:02:28 +08:00
package services
import (
"context"
"errors"
2021-04-18 21:19:34 +08:00
"fmt"
2020-07-29 19:02:28 +08:00
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
2021-04-18 21:19:34 +08:00
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
2021-07-20 10:55:34 +08:00
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
2020-09-13 20:37:28 +08:00
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
2021-04-18 21:19:34 +08:00
"golang.org/x/crypto/ssh"
"net"
"regexp"
"strings"
2021-04-18 21:19:34 +08:00
"time"
2020-07-29 19:02:28 +08:00
)
type NodeGrantService struct {
2020-11-24 17:36:47 +08:00
BaseService
2020-07-29 19:02:28 +08:00
}
2021-04-18 21:19:34 +08:00
// CreateNodeGrant 创建认证
2020-07-29 19:02:28 +08:00
func (this *NodeGrantService) CreateNodeGrant(ctx context.Context, req *pb.CreateNodeGrantRequest) (*pb.CreateNodeGrantResponse, error) {
2022-07-22 14:35:17 +08:00
adminId, err := this.ValidateAdmin(ctx)
2020-07-29 19:02:28 +08:00
if err != nil {
return nil, err
}
2022-07-22 15:05:30 +08:00
var tx = this.NullTx()
2021-12-06 19:27:11 +08:00
grantId, err := models.SharedNodeGrantDAO.CreateGrant(tx, adminId, req.Name, req.Method, req.Username, req.Password, req.PrivateKey, req.Passphrase, req.Description, req.NodeId, req.Su)
2020-07-29 19:02:28 +08:00
if err != nil {
return nil, err
}
return &pb.CreateNodeGrantResponse{
2021-04-18 21:19:34 +08:00
NodeGrantId: grantId,
2020-07-29 19:02:28 +08:00
}, err
}
2021-04-18 21:19:34 +08:00
// UpdateNodeGrant 修改认证
func (this *NodeGrantService) UpdateNodeGrant(ctx context.Context, req *pb.UpdateNodeGrantRequest) (*pb.RPCSuccess, error) {
2022-07-22 14:35:17 +08:00
_, err := this.ValidateAdmin(ctx)
2020-07-29 19:02:28 +08:00
if err != nil {
return nil, err
}
2021-04-18 21:19:34 +08:00
if req.NodeGrantId <= 0 {
2020-07-29 19:02:28 +08:00
return nil, errors.New("wrong grantId")
}
2022-07-22 15:05:30 +08:00
var tx = this.NullTx()
// 从掩码中恢复密码和私钥
grant, err := models.SharedNodeGrantDAO.FindEnabledNodeGrant(tx, req.NodeGrantId)
if err != nil {
return nil, err
}
if grant == nil {
// do nothing here
return this.Success()
}
var maskReg = regexp.MustCompile(`^\*+$`)
if len(req.Password) > 0 && maskReg.MatchString(req.Password) {
req.Password = grant.Password
}
if len(req.PrivateKey) > 0 && strings.HasSuffix(req.PrivateKey, "********") {
req.PrivateKey = grant.PrivateKey
}
2021-12-06 19:27:11 +08:00
err = models.SharedNodeGrantDAO.UpdateGrant(tx, req.NodeGrantId, req.Name, req.Method, req.Username, req.Password, req.PrivateKey, req.Passphrase, req.Description, req.NodeId, req.Su)
2020-11-24 17:36:47 +08:00
return this.Success()
2020-07-29 19:02:28 +08:00
}
2021-04-18 21:19:34 +08:00
// DisableNodeGrant 禁用认证
2020-07-29 19:02:28 +08:00
func (this *NodeGrantService) DisableNodeGrant(ctx context.Context, req *pb.DisableNodeGrantRequest) (*pb.DisableNodeGrantResponse, error) {
2022-07-22 14:35:17 +08:00
_, err := this.ValidateAdmin(ctx)
2020-07-29 19:02:28 +08:00
if err != nil {
return nil, err
}
2022-07-22 15:05:30 +08:00
var tx = this.NullTx()
2021-04-18 21:19:34 +08:00
err = models.SharedNodeGrantDAO.DisableNodeGrant(tx, req.NodeGrantId)
2020-07-29 19:02:28 +08:00
return &pb.DisableNodeGrantResponse{}, err
}
2021-04-18 21:19:34 +08:00
// CountAllEnabledNodeGrants 计算认证的数量
2020-11-12 14:41:28 +08:00
func (this *NodeGrantService) CountAllEnabledNodeGrants(ctx context.Context, req *pb.CountAllEnabledNodeGrantsRequest) (*pb.RPCCountResponse, error) {
2022-07-22 14:35:17 +08:00
_, err := this.ValidateAdmin(ctx)
2020-07-29 19:02:28 +08:00
if err != nil {
return nil, err
}
2022-07-22 15:05:30 +08:00
var tx = this.NullTx()
count, err := models.SharedNodeGrantDAO.CountAllEnabledGrants(tx, req.Keyword)
2020-07-29 19:02:28 +08:00
if err != nil {
return nil, err
}
2020-11-24 17:36:47 +08:00
return this.SuccessCount(count)
2020-07-29 19:02:28 +08:00
}
2021-04-18 21:19:34 +08:00
// ListEnabledNodeGrants 列出单页认证
2020-07-29 19:02:28 +08:00
func (this *NodeGrantService) ListEnabledNodeGrants(ctx context.Context, req *pb.ListEnabledNodeGrantsRequest) (*pb.ListEnabledNodeGrantsResponse, error) {
2022-07-22 14:35:17 +08:00
_, err := this.ValidateAdmin(ctx)
2020-07-29 19:02:28 +08:00
if err != nil {
return nil, err
}
2022-07-22 15:05:30 +08:00
var tx = this.NullTx()
grants, err := models.SharedNodeGrantDAO.ListEnabledGrants(tx, req.Keyword, req.Offset, req.Size)
2020-07-29 19:02:28 +08:00
if err != nil {
return nil, err
}
result := []*pb.NodeGrant{}
for _, grant := range grants {
result = append(result, &pb.NodeGrant{
Id: int64(grant.Id),
Name: grant.Name,
Method: grant.Method,
Username: grant.Username,
2020-07-29 19:02:28 +08:00
Password: grant.Password,
Su: grant.Su == 1,
PrivateKey: grant.PrivateKey,
Description: grant.Description,
NodeId: int64(grant.NodeId),
})
}
2021-04-18 21:19:34 +08:00
return &pb.ListEnabledNodeGrantsResponse{NodeGrants: result}, nil
2020-07-29 19:02:28 +08:00
}
2020-07-30 22:41:49 +08:00
2021-04-18 21:19:34 +08:00
// FindAllEnabledNodeGrants 列出所有认证信息
2020-07-30 22:41:49 +08:00
func (this *NodeGrantService) FindAllEnabledNodeGrants(ctx context.Context, req *pb.FindAllEnabledNodeGrantsRequest) (*pb.FindAllEnabledNodeGrantsResponse, error) {
2022-07-22 14:35:17 +08:00
_, err := this.ValidateAdmin(ctx)
2020-07-30 22:41:49 +08:00
if err != nil {
return nil, err
}
grants, err := models.SharedNodeGrantDAO.FindAllEnabledGrants(this.NullTx())
2020-07-30 22:41:49 +08:00
if err != nil {
return nil, err
}
result := []*pb.NodeGrant{}
for _, grant := range grants {
result = append(result, &pb.NodeGrant{
Id: int64(grant.Id),
Name: grant.Name,
Method: grant.Method,
Username: grant.Username,
2020-07-30 22:41:49 +08:00
Password: grant.Password,
Su: grant.Su == 1,
PrivateKey: grant.PrivateKey,
Description: grant.Description,
NodeId: int64(grant.NodeId),
})
}
2021-04-18 21:19:34 +08:00
return &pb.FindAllEnabledNodeGrantsResponse{NodeGrants: result}, nil
2020-07-30 22:41:49 +08:00
}
2021-04-18 21:19:34 +08:00
// FindEnabledNodeGrant 获取单个认证信息
func (this *NodeGrantService) FindEnabledNodeGrant(ctx context.Context, req *pb.FindEnabledNodeGrantRequest) (*pb.FindEnabledNodeGrantResponse, error) {
2022-07-22 14:35:17 +08:00
_, err := this.ValidateAdmin(ctx)
2020-07-30 22:41:49 +08:00
if err != nil {
return nil, err
}
2021-04-18 21:19:34 +08:00
grant, err := models.SharedNodeGrantDAO.FindEnabledNodeGrant(this.NullTx(), req.NodeGrantId)
2020-07-30 22:41:49 +08:00
if err != nil {
return nil, err
}
if grant == nil {
2021-04-18 21:19:34 +08:00
return &pb.FindEnabledNodeGrantResponse{}, nil
2020-07-30 22:41:49 +08:00
}
2021-04-18 21:19:34 +08:00
return &pb.FindEnabledNodeGrantResponse{NodeGrant: &pb.NodeGrant{
2020-07-30 22:41:49 +08:00
Id: int64(grant.Id),
Name: grant.Name,
Method: grant.Method,
Username: grant.Username,
Password: grant.Password,
Su: grant.Su == 1,
PrivateKey: grant.PrivateKey,
2021-11-06 15:31:01 +08:00
Passphrase: grant.Passphrase,
2020-07-30 22:41:49 +08:00
Description: grant.Description,
NodeId: int64(grant.NodeId),
}}, nil
}
2021-04-18 21:19:34 +08:00
// TestNodeGrant 测试连接
func (this *NodeGrantService) TestNodeGrant(ctx context.Context, req *pb.TestNodeGrantRequest) (*pb.TestNodeGrantResponse, error) {
2022-07-22 14:35:17 +08:00
_, err := this.ValidateAdmin(ctx)
2021-04-18 21:19:34 +08:00
if err != nil {
return nil, err
}
var hostKeyCallback ssh.HostKeyCallback = nil
resp := &pb.TestNodeGrantResponse{
IsOk: false,
Error: "",
}
var tx = this.NullTx()
grant, err := models.SharedNodeGrantDAO.FindEnabledNodeGrant(tx, req.NodeGrantId)
if err != nil {
return nil, err
}
if grant == nil {
resp.Error = "can not find grant with id '" + numberutils.FormatInt64(req.NodeGrantId) + "'"
return resp, nil
}
// 检查参数
if len(req.Host) == 0 {
resp.Error = "'host' should not be empty"
return resp, nil
}
if req.Port <= 0 {
resp.Error = "'port' should be greater than 0"
return resp, nil
}
if len(grant.Password) == 0 && len(grant.PrivateKey) == 0 {
resp.Error = "require user 'password' or 'privateKey'"
return resp, nil
}
// 不使用known_hosts
if hostKeyCallback == nil {
hostKeyCallback = func(hostname string, remote net.Addr, key ssh.PublicKey) error {
return nil
}
}
// 认证
methods := []ssh.AuthMethod{}
if grant.Method == "user" {
2021-04-18 21:19:34 +08:00
{
authMethod := ssh.Password(grant.Password)
methods = append(methods, authMethod)
}
{
authMethod := ssh.KeyboardInteractive(func(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
if len(questions) == 0 {
return []string{}, nil
}
return []string{grant.Password}, nil
})
methods = append(methods, authMethod)
}
} else if grant.Method == "privateKey" {
2021-11-06 15:31:01 +08:00
var signer ssh.Signer
if len(grant.Passphrase) != 0 {
signer, err = ssh.ParsePrivateKeyWithPassphrase([]byte(grant.PrivateKey), []byte(grant.Passphrase))
} else {
signer, err = ssh.ParsePrivateKey([]byte(grant.PrivateKey))
}
2021-04-18 21:19:34 +08:00
if err != nil {
resp.Error = "parse private key: " + err.Error()
return resp, nil
}
authMethod := ssh.PublicKeys(signer)
methods = append(methods, authMethod)
} else {
return nil, errors.New("invalid method '" + grant.Method + "'")
2021-04-18 21:19:34 +08:00
}
// SSH客户端
if len(grant.Username) == 0 {
grant.Username = "root"
}
2021-04-18 21:19:34 +08:00
config := &ssh.ClientConfig{
User: grant.Username,
Auth: methods,
HostKeyCallback: hostKeyCallback,
Timeout: 5 * time.Second, // TODO 后期可以设置这个超时时间
}
2021-07-20 10:55:34 +08:00
sshClient, err := ssh.Dial("tcp", configutils.QuoteIP(req.Host)+":"+fmt.Sprintf("%d", req.Port), config)
2021-04-18 21:19:34 +08:00
if err != nil {
resp.Error = "connect failed: " + err.Error()
return resp, nil
}
defer func() {
_ = sshClient.Close()
}()
resp.IsOk = true
return resp, nil
}
2021-08-14 21:33:17 +08:00
// FindSuggestNodeGrants 查找集群推荐的认证
func (this *NodeGrantService) FindSuggestNodeGrants(ctx context.Context, req *pb.FindSuggestNodeGrantsRequest) (*pb.FindSuggestNodeGrantsResponse, error) {
2022-07-22 14:35:17 +08:00
_, err := this.ValidateAdmin(ctx)
2021-08-14 21:33:17 +08:00
if err != nil {
return nil, err
}
var pbGrants = []*pb.NodeGrant{}
var tx = this.NullTx()
grantIds, err := models.SharedNodeLoginDAO.FindFrequentGrantIds(tx, req.NodeClusterId, req.NsClusterId)
if err != nil {
return nil, err
}
for _, grantId := range grantIds {
grant, err := models.SharedNodeGrantDAO.FindEnabledNodeGrant(tx, grantId)
if err != nil {
return nil, err
}
if grant != nil {
pbGrants = append(pbGrants, &pb.NodeGrant{
Id: int64(grant.Id),
Name: grant.Name,
Method: grant.Method,
Username: grant.Username,
Su: grant.Su == 1,
Description: grant.Description,
})
}
}
return &pb.FindSuggestNodeGrantsResponse{NodeGrants: pbGrants}, nil
}