Commit c489f6c4 authored by Eric's avatar Eric

[Update] MFA相关

parent 9aa34a44
......@@ -154,7 +154,7 @@
[[projects]]
branch = "master"
digest = "1:f8fa0c03fa1a9b220cd6e7984cd5ab923a83065f338a5fe2b2f61020d62f0991"
digest = "1:d275874accb1537f7bd7ac28985aeb1ddc32b22884e5f57b68c32591437f822b"
name = "golang.org/x/crypto"
packages = [
"curve25519",
......@@ -167,7 +167,7 @@
"ssh/terminal",
]
pruneopts = "UT"
revision = "40738d426814df40c4d54d5e7017f7af7725da47"
revision = "ef0d1a6f5b87067803518089d4cbc349777a56bd"
source = "github.com/ibuler/crypto"
[[projects]]
......
package auth
import (
"cocogo/pkg/model"
"fmt"
"strings"
"github.com/gliderlabs/ssh"
......@@ -17,7 +15,7 @@ import (
func checkAuth(ctx ssh.Context, password, publicKey string) (res ssh.AuthResult) {
username := ctx.User()
remoteAddr := strings.Split(ctx.RemoteAddr().String(), ":")[0]
user, err := service.Authenticate(username, password, publicKey, remoteAddr, "T")
resp, err := service.Authenticate(username, password, publicKey, remoteAddr, "T")
authMethod := "publickey"
action := "Accepted"
res = ssh.AuthFailed
......@@ -26,10 +24,23 @@ func checkAuth(ctx ssh.Context, password, publicKey string) (res ssh.AuthResult)
}
if err != nil {
action = "Failed"
} else {
ctx.SetValue(cctx.ContextKeyUser, user)
res = ssh.AuthPartiallySuccessful
res = ssh.AuthFailed
}
if resp != nil {
switch resp.User.IsMFA {
case 0:
res = ssh.AuthSuccessful
case 1:
res = ssh.AuthPartiallySuccessful
case 2:
res = ssh.AuthPartiallySuccessful
default:
}
ctx.SetValue(cctx.ContextKeyUser, resp.User)
ctx.SetValue(cctx.ContextKeySeed, resp.Seed)
ctx.SetValue(cctx.ContextKeyToken, resp.Token)
}
logger.Infof("%s %s for %s from %s", action, authMethod, username, remoteAddr)
return res
}
......@@ -46,13 +57,17 @@ func CheckUserPublicKey(ctx ssh.Context, key ssh.PublicKey) ssh.AuthResult {
}
func CheckMFA(ctx ssh.Context, challenger gossh.KeyboardInteractiveChallenge) ssh.AuthResult {
answers, err := challenger("admin", "> ", []string{"MFA"}, []bool{true})
answers, err := challenger(ctx.User(), "Please enter 6 digits.", []string{"[MFA auth]: "}, []bool{true})
if err != nil {
return ssh.AuthFailed
}
fmt.Println(answers)
seed := ctx.Value(cctx.ContextKeySeed).(string)
code := answers[0]
res, err := service.AuthenticateMFA(seed, code, "T")
if err != nil || res != nil {
return ssh.AuthFailed
}
//ok := checkAuth(ctx, "admin", "")
ctx.SetValue(cctx.ContextKeyUser, &model.User{Username: "admin", Name: "admin"})
return ssh.AuthSuccessful
}
......@@ -19,6 +19,8 @@ var (
ContextKeySSHSession = &contextKey{"sshSession"}
ContextKeyLocalAddr = &contextKey{"localAddr"}
ContextKeySSHCtx = &contextKey{"sshCtx"}
ContextKeySeed = &contextKey{"seed"}
ContextKeyToken = &contextKey{"token"}
)
type Context interface {
......
......@@ -29,6 +29,7 @@ func SessionHandler(sess ssh.Session) {
_, _, ptyOk := sess.Pty()
if ptyOk {
ctx, cancel := cctx.NewContext(sess)
fmt.Println(ctx.User())
handler := &InteractiveHandler{
sess: sess,
user: ctx.User(),
......@@ -88,6 +89,7 @@ func (i *InteractiveHandler) watchWinSizeChange(winCh <-chan ssh.Window, done <-
func (i *InteractiveHandler) Dispatch(ctx cctx.Context) {
i.preDispatch()
fmt.Println(i.user)
_, winCh, _ := i.sess.Pty()
for {
doneChan := make(chan struct{})
......@@ -323,8 +325,8 @@ func (i *InteractiveHandler) searchNodeAssets(num int) (assets []model.Asset) {
}
func (i *InteractiveHandler) Proxy(ctx context.Context) {
i.assetSelect = &model.Asset{Hostname: "centos", Port: 22, Ip: "192.168.244.185"}
i.systemUserSelect = &model.SystemUser{Name: "web", UserName: "web", Password: "redhat"}
i.assetSelect = &model.Asset{Hostname: "centos", Port: 32768, Ip: "127.0.0.1"}
i.systemUserSelect = &model.SystemUser{Name: "web", UserName: "root", Password: "screencast"}
p := proxy.ProxyServer{
Session: i.sess,
User: i.user,
......
......@@ -18,6 +18,12 @@ package model
'date_expired': '2089-03-21 18:18:24 +0800'}
*/
type AuthResponse struct {
Token string `json:"token"`
Seed string `json:"seed"`
User *User `json:"user"`
}
type User struct {
Id string `json:"id"`
Username string `json:"username"`
......@@ -27,6 +33,7 @@ type User struct {
Role string `json:"role"`
IsValid bool `json:"is_valid"`
IsActive bool `json:"is_active"`
IsMFA int `json:"otp_level"`
}
type TokenUser struct {
......
......@@ -3,6 +3,7 @@ package proxy
import (
"fmt"
"io"
"strconv"
"strings"
"time"
......@@ -13,7 +14,6 @@ import (
"cocogo/pkg/logger"
"cocogo/pkg/model"
"cocogo/pkg/service"
"strconv"
)
type ProxyServer struct {
......
......@@ -15,7 +15,7 @@ func GetUserAssets(userId, cachePolicy string) (assets model.AssetList) {
Url := authClient.ParseUrlQuery(fmt.Sprintf(UserAssetsURL, userId), params)
err := authClient.Get(Url, &assets)
if err != nil {
logger.Error(err)
logger.Error("GetUserAssets---err")
}
return
}
......@@ -28,7 +28,7 @@ func GetUserNodes(userId, cachePolicy string) (nodes model.NodeList) {
Url := authClient.ParseUrlQuery(fmt.Sprintf(UserNodesAssetsURL, userId), params)
err := authClient.Get(Url, &nodes)
if err != nil {
logger.Error(err)
logger.Error("GetUserNodes err")
}
return
}
......
......@@ -5,6 +5,8 @@ const (
UserProfileURL = "/api/users/v1/profile/" // 获取当前用户的基本信息
UserUserURL = "/api/users/v1/users/%s/" // 获取用户信息
AuthMFAURL = "/api/authentication/v1/otp/auth/" // MFA 验证用户信息
SystemUserAssetAuthURL = "/api/assets/v1/system-user/%s/asset/%s/auth-info/" // 该系统用户对某资产的授权
SystemUserAuthInfoURL = "/api/assets/v1/system-user/%s/auth-info/" // 该系统用户的授权
SystemUserCmdFilterRules = "/api/assets/v1/system-user/%s/cmd-filter-rules/" // 过滤规则url
......
......@@ -7,7 +7,7 @@ import (
"cocogo/pkg/model"
)
func Authenticate(username, password, publicKey, remoteAddr, loginType string) (user *model.User, err error) {
func Authenticate(username, password, publicKey, remoteAddr, loginType string) (resp *model.AuthResponse, err error) {
data := map[string]string{
"username": username,
"password": password,
......@@ -15,20 +15,39 @@ func Authenticate(username, password, publicKey, remoteAddr, loginType string) (
"remote_addr": remoteAddr,
"login_type": loginType,
}
var resp struct {
Token string `json:"token"`
User *model.User `json:"user"`
}
Url := client.ParseUrlQuery(UserAuthURL, nil)
err = client.Post(Url, data, &resp)
err = client.Post(Url, data, resp)
if err != nil {
logger.Error(err)
return
}
user = resp.User
return
}
func AuthenticateMFA(seed, code, loginType string) (resp *model.AuthResponse, err error) {
/*
data = {
'seed': seed,
'otp_code': otp_code,
'login_type': login_type,
}
*/
data := map[string]string{
"seed": seed,
"otp_code": code,
"login_type": loginType,
}
Url := client.ParseUrlQuery(AuthMFAURL, nil)
err = client.Post(Url, data, resp)
if err != nil {
logger.Error(err)
}
return
}
func GetUserProfile(userId string) (user *model.User) {
Url := authClient.ParseUrlQuery(fmt.Sprintf(UserUserURL, userId), nil)
err := authClient.Get(Url, &user)
......
......@@ -18,12 +18,18 @@ const version = "v1.4.0"
func defaultConfig(ctx ssh.Context) (conf *gossh.ServerConfig) {
conf = new(gossh.ServerConfig)
conf.AuthLogCallback = func(conn gossh.ConnMetadata, method string, err error) {
fmt.Println(err)
fmt.Println(method)
result := "failed"
if err == nil {
result = "success"
}
logger.Debugf("%s use AuthMethod %s %s\n", conn.User(), method, result)
}
conf.NextAuthMethodsCallback = func(conn gossh.ConnMetadata) (methods []string) {
fmt.Println("Username: ", conn.User())
if conn.User() == "ibuler" {
return []string{"keyboard-interactive"}
}
return
return []string{"keyboard-interactive"}
}
return conf
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment