Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
K
koko
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ops
koko
Commits
c489f6c4
Commit
c489f6c4
authored
May 09, 2019
by
Eric
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Update] MFA相关
parent
9aa34a44
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
81 additions
and
28 deletions
+81
-28
Gopkg.lock
Gopkg.lock
+2
-2
server.go
pkg/auth/server.go
+24
-9
context.go
pkg/cctx/context.go
+2
-0
session.go
pkg/handler/session.go
+4
-2
users.go
pkg/model/users.go
+7
-0
proxy.go
pkg/proxy/proxy.go
+1
-1
perms.go
pkg/service/perms.go
+2
-2
urls.go
pkg/service/urls.go
+2
-0
users.go
pkg/service/users.go
+27
-8
server.go
pkg/sshd/server.go
+10
-4
No files found.
Gopkg.lock
View file @
c489f6c4
...
@@ -154,7 +154,7 @@
...
@@ -154,7 +154,7 @@
[[projects]]
[[projects]]
branch = "master"
branch = "master"
digest = "1:
f8fa0c03fa1a9b220cd6e7984cd5ab923a83065f338a5fe2b2f61020d62f0991
"
digest = "1:
d275874accb1537f7bd7ac28985aeb1ddc32b22884e5f57b68c32591437f822b
"
name = "golang.org/x/crypto"
name = "golang.org/x/crypto"
packages = [
packages = [
"curve25519",
"curve25519",
...
@@ -167,7 +167,7 @@
...
@@ -167,7 +167,7 @@
"ssh/terminal",
"ssh/terminal",
]
]
pruneopts = "UT"
pruneopts = "UT"
revision = "
40738d426814df40c4d54d5e7017f7af7725da47
"
revision = "
ef0d1a6f5b87067803518089d4cbc349777a56bd
"
source = "github.com/ibuler/crypto"
source = "github.com/ibuler/crypto"
[[projects]]
[[projects]]
...
...
pkg/auth/server.go
View file @
c489f6c4
package
auth
package
auth
import
(
import
(
"cocogo/pkg/model"
"fmt"
"strings"
"strings"
"github.com/gliderlabs/ssh"
"github.com/gliderlabs/ssh"
...
@@ -17,7 +15,7 @@ import (
...
@@ -17,7 +15,7 @@ import (
func
checkAuth
(
ctx
ssh
.
Context
,
password
,
publicKey
string
)
(
res
ssh
.
AuthResult
)
{
func
checkAuth
(
ctx
ssh
.
Context
,
password
,
publicKey
string
)
(
res
ssh
.
AuthResult
)
{
username
:=
ctx
.
User
()
username
:=
ctx
.
User
()
remoteAddr
:=
strings
.
Split
(
ctx
.
RemoteAddr
()
.
String
(),
":"
)[
0
]
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"
authMethod
:=
"publickey"
action
:=
"Accepted"
action
:=
"Accepted"
res
=
ssh
.
AuthFailed
res
=
ssh
.
AuthFailed
...
@@ -26,10 +24,23 @@ func checkAuth(ctx ssh.Context, password, publicKey string) (res ssh.AuthResult)
...
@@ -26,10 +24,23 @@ func checkAuth(ctx ssh.Context, password, publicKey string) (res ssh.AuthResult)
}
}
if
err
!=
nil
{
if
err
!=
nil
{
action
=
"Failed"
action
=
"Failed"
}
else
{
res
=
ssh
.
AuthFailed
ctx
.
SetValue
(
cctx
.
ContextKeyUser
,
user
)
res
=
ssh
.
AuthPartiallySuccessful
}
}
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
)
logger
.
Infof
(
"%s %s for %s from %s"
,
action
,
authMethod
,
username
,
remoteAddr
)
return
res
return
res
}
}
...
@@ -46,13 +57,17 @@ func CheckUserPublicKey(ctx ssh.Context, key ssh.PublicKey) ssh.AuthResult {
...
@@ -46,13 +57,17 @@ func CheckUserPublicKey(ctx ssh.Context, key ssh.PublicKey) ssh.AuthResult {
}
}
func
CheckMFA
(
ctx
ssh
.
Context
,
challenger
gossh
.
KeyboardInteractiveChallenge
)
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
{
if
err
!=
nil
{
return
ssh
.
AuthFailed
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", "")
//ok := checkAuth(ctx, "admin", "")
ctx
.
SetValue
(
cctx
.
ContextKeyUser
,
&
model
.
User
{
Username
:
"admin"
,
Name
:
"admin"
})
return
ssh
.
AuthSuccessful
return
ssh
.
AuthSuccessful
}
}
pkg/cctx/context.go
View file @
c489f6c4
...
@@ -19,6 +19,8 @@ var (
...
@@ -19,6 +19,8 @@ var (
ContextKeySSHSession
=
&
contextKey
{
"sshSession"
}
ContextKeySSHSession
=
&
contextKey
{
"sshSession"
}
ContextKeyLocalAddr
=
&
contextKey
{
"localAddr"
}
ContextKeyLocalAddr
=
&
contextKey
{
"localAddr"
}
ContextKeySSHCtx
=
&
contextKey
{
"sshCtx"
}
ContextKeySSHCtx
=
&
contextKey
{
"sshCtx"
}
ContextKeySeed
=
&
contextKey
{
"seed"
}
ContextKeyToken
=
&
contextKey
{
"token"
}
)
)
type
Context
interface
{
type
Context
interface
{
...
...
pkg/handler/session.go
View file @
c489f6c4
...
@@ -29,6 +29,7 @@ func SessionHandler(sess ssh.Session) {
...
@@ -29,6 +29,7 @@ func SessionHandler(sess ssh.Session) {
_
,
_
,
ptyOk
:=
sess
.
Pty
()
_
,
_
,
ptyOk
:=
sess
.
Pty
()
if
ptyOk
{
if
ptyOk
{
ctx
,
cancel
:=
cctx
.
NewContext
(
sess
)
ctx
,
cancel
:=
cctx
.
NewContext
(
sess
)
fmt
.
Println
(
ctx
.
User
())
handler
:=
&
InteractiveHandler
{
handler
:=
&
InteractiveHandler
{
sess
:
sess
,
sess
:
sess
,
user
:
ctx
.
User
(),
user
:
ctx
.
User
(),
...
@@ -88,6 +89,7 @@ func (i *InteractiveHandler) watchWinSizeChange(winCh <-chan ssh.Window, done <-
...
@@ -88,6 +89,7 @@ func (i *InteractiveHandler) watchWinSizeChange(winCh <-chan ssh.Window, done <-
func
(
i
*
InteractiveHandler
)
Dispatch
(
ctx
cctx
.
Context
)
{
func
(
i
*
InteractiveHandler
)
Dispatch
(
ctx
cctx
.
Context
)
{
i
.
preDispatch
()
i
.
preDispatch
()
fmt
.
Println
(
i
.
user
)
_
,
winCh
,
_
:=
i
.
sess
.
Pty
()
_
,
winCh
,
_
:=
i
.
sess
.
Pty
()
for
{
for
{
doneChan
:=
make
(
chan
struct
{})
doneChan
:=
make
(
chan
struct
{})
...
@@ -323,8 +325,8 @@ func (i *InteractiveHandler) searchNodeAssets(num int) (assets []model.Asset) {
...
@@ -323,8 +325,8 @@ func (i *InteractiveHandler) searchNodeAssets(num int) (assets []model.Asset) {
}
}
func
(
i
*
InteractiveHandler
)
Proxy
(
ctx
context
.
Context
)
{
func
(
i
*
InteractiveHandler
)
Proxy
(
ctx
context
.
Context
)
{
i
.
assetSelect
=
&
model
.
Asset
{
Hostname
:
"centos"
,
Port
:
22
,
Ip
:
"192.168.244.185
"
}
i
.
assetSelect
=
&
model
.
Asset
{
Hostname
:
"centos"
,
Port
:
32768
,
Ip
:
"127.0.0.1
"
}
i
.
systemUserSelect
=
&
model
.
SystemUser
{
Name
:
"web"
,
UserName
:
"
web"
,
Password
:
"redha
t"
}
i
.
systemUserSelect
=
&
model
.
SystemUser
{
Name
:
"web"
,
UserName
:
"
root"
,
Password
:
"screencas
t"
}
p
:=
proxy
.
ProxyServer
{
p
:=
proxy
.
ProxyServer
{
Session
:
i
.
sess
,
Session
:
i
.
sess
,
User
:
i
.
user
,
User
:
i
.
user
,
...
...
pkg/model/users.go
View file @
c489f6c4
...
@@ -18,6 +18,12 @@ package model
...
@@ -18,6 +18,12 @@ package model
'date_expired': '2089-03-21 18:18:24 +0800'}
'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
{
type
User
struct
{
Id
string
`json:"id"`
Id
string
`json:"id"`
Username
string
`json:"username"`
Username
string
`json:"username"`
...
@@ -27,6 +33,7 @@ type User struct {
...
@@ -27,6 +33,7 @@ type User struct {
Role
string
`json:"role"`
Role
string
`json:"role"`
IsValid
bool
`json:"is_valid"`
IsValid
bool
`json:"is_valid"`
IsActive
bool
`json:"is_active"`
IsActive
bool
`json:"is_active"`
IsMFA
int
`json:"otp_level"`
}
}
type
TokenUser
struct
{
type
TokenUser
struct
{
...
...
pkg/proxy/proxy.go
View file @
c489f6c4
...
@@ -3,6 +3,7 @@ package proxy
...
@@ -3,6 +3,7 @@ package proxy
import
(
import
(
"fmt"
"fmt"
"io"
"io"
"strconv"
"strings"
"strings"
"time"
"time"
...
@@ -13,7 +14,6 @@ import (
...
@@ -13,7 +14,6 @@ import (
"cocogo/pkg/logger"
"cocogo/pkg/logger"
"cocogo/pkg/model"
"cocogo/pkg/model"
"cocogo/pkg/service"
"cocogo/pkg/service"
"strconv"
)
)
type
ProxyServer
struct
{
type
ProxyServer
struct
{
...
...
pkg/service/perms.go
View file @
c489f6c4
...
@@ -15,7 +15,7 @@ func GetUserAssets(userId, cachePolicy string) (assets model.AssetList) {
...
@@ -15,7 +15,7 @@ func GetUserAssets(userId, cachePolicy string) (assets model.AssetList) {
Url
:=
authClient
.
ParseUrlQuery
(
fmt
.
Sprintf
(
UserAssetsURL
,
userId
),
params
)
Url
:=
authClient
.
ParseUrlQuery
(
fmt
.
Sprintf
(
UserAssetsURL
,
userId
),
params
)
err
:=
authClient
.
Get
(
Url
,
&
assets
)
err
:=
authClient
.
Get
(
Url
,
&
assets
)
if
err
!=
nil
{
if
err
!=
nil
{
logger
.
Error
(
err
)
logger
.
Error
(
"GetUserAssets---err"
)
}
}
return
return
}
}
...
@@ -28,7 +28,7 @@ func GetUserNodes(userId, cachePolicy string) (nodes model.NodeList) {
...
@@ -28,7 +28,7 @@ func GetUserNodes(userId, cachePolicy string) (nodes model.NodeList) {
Url
:=
authClient
.
ParseUrlQuery
(
fmt
.
Sprintf
(
UserNodesAssetsURL
,
userId
),
params
)
Url
:=
authClient
.
ParseUrlQuery
(
fmt
.
Sprintf
(
UserNodesAssetsURL
,
userId
),
params
)
err
:=
authClient
.
Get
(
Url
,
&
nodes
)
err
:=
authClient
.
Get
(
Url
,
&
nodes
)
if
err
!=
nil
{
if
err
!=
nil
{
logger
.
Error
(
err
)
logger
.
Error
(
"GetUserNodes err"
)
}
}
return
return
}
}
...
...
pkg/service/urls.go
View file @
c489f6c4
...
@@ -5,6 +5,8 @@ const (
...
@@ -5,6 +5,8 @@ const (
UserProfileURL
=
"/api/users/v1/profile/"
// 获取当前用户的基本信息
UserProfileURL
=
"/api/users/v1/profile/"
// 获取当前用户的基本信息
UserUserURL
=
"/api/users/v1/users/%s/"
// 获取用户信息
UserUserURL
=
"/api/users/v1/users/%s/"
// 获取用户信息
AuthMFAURL
=
"/api/authentication/v1/otp/auth/"
// MFA 验证用户信息
SystemUserAssetAuthURL
=
"/api/assets/v1/system-user/%s/asset/%s/auth-info/"
// 该系统用户对某资产的授权
SystemUserAssetAuthURL
=
"/api/assets/v1/system-user/%s/asset/%s/auth-info/"
// 该系统用户对某资产的授权
SystemUserAuthInfoURL
=
"/api/assets/v1/system-user/%s/auth-info/"
// 该系统用户的授权
SystemUserAuthInfoURL
=
"/api/assets/v1/system-user/%s/auth-info/"
// 该系统用户的授权
SystemUserCmdFilterRules
=
"/api/assets/v1/system-user/%s/cmd-filter-rules/"
// 过滤规则url
SystemUserCmdFilterRules
=
"/api/assets/v1/system-user/%s/cmd-filter-rules/"
// 过滤规则url
...
...
pkg/service/users.go
View file @
c489f6c4
...
@@ -7,7 +7,7 @@ import (
...
@@ -7,7 +7,7 @@ import (
"cocogo/pkg/model"
"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
{
data
:=
map
[
string
]
string
{
"username"
:
username
,
"username"
:
username
,
"password"
:
password
,
"password"
:
password
,
...
@@ -15,20 +15,39 @@ func Authenticate(username, password, publicKey, remoteAddr, loginType string) (
...
@@ -15,20 +15,39 @@ func Authenticate(username, password, publicKey, remoteAddr, loginType string) (
"remote_addr"
:
remoteAddr
,
"remote_addr"
:
remoteAddr
,
"login_type"
:
loginType
,
"login_type"
:
loginType
,
}
}
var
resp
struct
{
Token
string
`json:"token"`
User
*
model
.
User
`json:"user"`
}
Url
:=
client
.
ParseUrlQuery
(
UserAuthURL
,
nil
)
Url
:=
client
.
ParseUrlQuery
(
UserAuthURL
,
nil
)
err
=
client
.
Post
(
Url
,
data
,
&
resp
)
err
=
client
.
Post
(
Url
,
data
,
resp
)
if
err
!=
nil
{
if
err
!=
nil
{
logger
.
Error
(
err
)
logger
.
Error
(
err
)
return
}
}
user
=
resp
.
User
return
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
)
{
func
GetUserProfile
(
userId
string
)
(
user
*
model
.
User
)
{
Url
:=
authClient
.
ParseUrlQuery
(
fmt
.
Sprintf
(
UserUserURL
,
userId
),
nil
)
Url
:=
authClient
.
ParseUrlQuery
(
fmt
.
Sprintf
(
UserUserURL
,
userId
),
nil
)
err
:=
authClient
.
Get
(
Url
,
&
user
)
err
:=
authClient
.
Get
(
Url
,
&
user
)
...
...
pkg/sshd/server.go
View file @
c489f6c4
...
@@ -18,12 +18,18 @@ const version = "v1.4.0"
...
@@ -18,12 +18,18 @@ const version = "v1.4.0"
func
defaultConfig
(
ctx
ssh
.
Context
)
(
conf
*
gossh
.
ServerConfig
)
{
func
defaultConfig
(
ctx
ssh
.
Context
)
(
conf
*
gossh
.
ServerConfig
)
{
conf
=
new
(
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
)
{
conf
.
NextAuthMethodsCallback
=
func
(
conn
gossh
.
ConnMetadata
)
(
methods
[]
string
)
{
fmt
.
Println
(
"Username: "
,
conn
.
User
())
fmt
.
Println
(
"Username: "
,
conn
.
User
())
if
conn
.
User
()
==
"ibuler"
{
return
[]
string
{
"keyboard-interactive"
}
return
[]
string
{
"keyboard-interactive"
}
}
return
}
}
return
conf
return
conf
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment