Skip to content

Commit

Permalink
Server ack message propagates AC tokens to agent. Http knock api also…
Browse files Browse the repository at this point in the history
… set agent's cookie with tokens
  • Loading branch information
craftleon committed Sep 29, 2024
1 parent 79ac584 commit 5b28d46
Show file tree
Hide file tree
Showing 10 changed files with 133 additions and 77 deletions.
7 changes: 3 additions & 4 deletions ac/httpac.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,8 @@ func (hs *HttpAC) IsRunning() bool {
func (ha *HttpAC) initRouter() {
g := ha.ginEngine

pluginGrp := g.Group("refresh")
// display login page with templates
pluginGrp.GET("/:token", func(ctx *gin.Context) {
refreshGrp := g.Group("refresh")
refreshGrp.GET("/:token", func(ctx *gin.Context) {
var err error
token := ctx.Param("token")
log.Info("get refresh request. aspId: %s, query: %v", token, ctx.Request.URL.RawQuery)
Expand Down Expand Up @@ -198,7 +197,7 @@ func (ha *HttpAC) HandleHttpRefreshOperations(c *gin.Context, req *common.HttpRe
entry.SrcAddrs = append(entry.SrcAddrs, newSrcAddr)
}

_, err = ha.ua.HandleAccessControl(entry.AgentUser, entry.SrcAddrs, entry.DstAddrs, entry.OpenTime, nil)
_, err = ha.ua.HandleAccessControl(entry.User, entry.SrcAddrs, entry.DstAddrs, entry.OpenTime, nil)
if err != nil {
c.String(http.StatusOK, "{\"errMsg\": \"%s\"}", err)
return
Expand Down
20 changes: 10 additions & 10 deletions ac/msghandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func (a *UdpAC) HandleUdpACOperations(ppd *core.PacketParserData) (err error) {
srcAddrs := dopMsg.SourceAddrs
dstAddrs := dopMsg.DestinationAddrs
openTimeSec := int(dopMsg.OpenTime)
agentUser := &AgentUser{
agentUser := &common.AgentUser{
UserId: dopMsg.UserId,
DeviceId: dopMsg.DeviceId,
OrganizationId: dopMsg.OrganizationId,
Expand All @@ -54,10 +54,10 @@ func (a *UdpAC) HandleUdpACOperations(ppd *core.PacketParserData) (err error) {

// generate ac token and save user and access information
entry := &AccessEntry{
AgentUser: agentUser,
SrcAddrs: srcAddrs,
DstAddrs: dstAddrs,
OpenTime: openTimeSec,
User: agentUser,
SrcAddrs: srcAddrs,
DstAddrs: dstAddrs,
OpenTime: openTimeSec,
}
artMsg.ACToken = a.GenerateAccessToken(entry)

Expand All @@ -84,7 +84,7 @@ func (a *UdpAC) HandleUdpACOperations(ppd *core.PacketParserData) (err error) {
return err
}

func (a *UdpAC) HandleAccessControl(au *AgentUser, srcAddrs []*common.NetAddress, dstAddrs []*common.NetAddress, openTimeSec int, artMsgIn *common.ACOpsResultMsg) (artMsg *common.ACOpsResultMsg, err error) {
func (a *UdpAC) HandleAccessControl(au *common.AgentUser, srcAddrs []*common.NetAddress, dstAddrs []*common.NetAddress, openTimeSec int, artMsgIn *common.ACOpsResultMsg) (artMsg *common.ACOpsResultMsg, err error) {
if artMsgIn == nil {
artMsg = &common.ACOpsResultMsg{}
} else {
Expand Down Expand Up @@ -345,10 +345,10 @@ func (a *UdpAC) HandleAccessControl(au *AgentUser, srcAddrs []*common.NetAddress
log.Info("[HandleAccessControl] open temporary udp port on %s", tladdr.String())

tempEntry := &AccessEntry{
AgentUser: au,
SrcAddrs: srcAddrs,
DstAddrs: dstAddrs,
OpenTime: tempOpenTimeSec,
User: au,
SrcAddrs: srcAddrs,
DstAddrs: dstAddrs,
OpenTime: tempOpenTimeSec,
}
artMsg.PreAccessAction = &common.PreAccessInfo{
AccessPort: strconv.Itoa(pickedPort),
Expand Down
31 changes: 12 additions & 19 deletions ac/tokenstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,45 +11,38 @@ import (
"github.com/OpenNHP/opennhp/log"
)

type AgentUser struct {
UserId string
DeviceId string
OrganizationId string
AuthServiceId string
}

type AccessEntry struct {
AgentUser *AgentUser
User *common.AgentUser
SrcAddrs []*common.NetAddress
DstAddrs []*common.NetAddress
OpenTime int
ExpireTime time.Time
}

type TokenAccessMap = map[string]*AccessEntry // access token mapped into user and access information
type TokenStore = map[string]TokenAccessMap // upper layer of tokens, indexed by first two characters
type TokenToAccessMap = map[string]*AccessEntry // access token mapped into user and access information
type TokenStore = map[string]TokenToAccessMap // upper layer of tokens, indexed by first two characters

func (a *UdpAC) GenerateAccessToken(entry *AccessEntry) string {
var tsBytes [8]byte
currTime := time.Now().UnixNano()

hash := sm3.New()
binary.BigEndian.PutUint64(tsBytes[:], uint64(currTime))
au := entry.AgentUser
au := entry.User
hash.Write([]byte(a.config.ACId + au.UserId + au.DeviceId + au.OrganizationId + au.AuthServiceId))
hash.Write(tsBytes[:])
token := base64.StdEncoding.EncodeToString(hash.Sum(nil))
hash.Reset()

a.TokenStoreMutex.Lock()
defer a.TokenStoreMutex.Unlock()
a.tokenStoreMutex.Lock()
defer a.tokenStoreMutex.Unlock()

entry.ExpireTime = time.Now().Add(time.Duration(entry.OpenTime) * time.Second)
tokenMap, found := a.tokenStore[token[0:1]]
if found {
tokenMap[token] = entry
} else {
tokenMap := make(TokenAccessMap)
tokenMap := make(TokenToAccessMap)
tokenMap[token] = entry
a.tokenStore[token[0:1]] = tokenMap
}
Expand All @@ -58,8 +51,8 @@ func (a *UdpAC) GenerateAccessToken(entry *AccessEntry) string {
}

func (a *UdpAC) VerifyAccessToken(token string) *AccessEntry {
a.TokenStoreMutex.Lock()
defer a.TokenStoreMutex.Unlock()
a.tokenStoreMutex.Lock()
defer a.tokenStoreMutex.Unlock()

tokenMap, found := a.tokenStore[token[0:1]]
if found {
Expand All @@ -84,14 +77,14 @@ func (a *UdpAC) tokenStoreRefreshRoutine() {
return

case <-time.After(TokenStoreRefreshInterval * time.Second):
a.TokenStoreMutex.Lock()
defer a.TokenStoreMutex.Unlock()
a.tokenStoreMutex.Lock()
defer a.tokenStoreMutex.Unlock()

now := time.Now()
for head, tokenMap := range a.tokenStore {
for token, entry := range tokenMap {
if now.After(entry.ExpireTime) {
log.Info("[TokenStore] token %s expired", token)
log.Info("[TokenStore] token %s expired, remove", token)
delete(tokenMap, token)
}
}
Expand Down
2 changes: 1 addition & 1 deletion ac/udpac.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ type UdpAC struct {
serverPeerMutex sync.Mutex
serverPeerMap map[string]*core.UdpPeer // indexed by server's public key

TokenStoreMutex sync.Mutex
tokenStoreMutex sync.Mutex
tokenStore TokenStore

device *core.Device
Expand Down
17 changes: 9 additions & 8 deletions common/nhpmsg.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,15 @@ type PreAccessInfo struct {
}

type ServerKnockAckMsg struct {
ErrCode string `json:"errCode"`
ErrMsg string `json:"errMsg,omitempty"`
ResourceHost map[string]string `json:"resHost"`
OpenTime uint32 `json:"opnTime"`
AuthProviderToken string `json:"aspToken,omitempty"` // optional for ac backend validation
AgentAddr string `json:"agentAddr"`
PreAccessActions []*PreAccessInfo `json:"preActs,omitempty"` // optional for pre-access
RedirectUrl string `json:"redirectUrl,omitempty"`
ErrCode string `json:"errCode"`
ErrMsg string `json:"errMsg,omitempty"`
ResourceHost map[string]string `json:"resHost"`
OpenTime uint32 `json:"opnTime"`
AuthProviderToken string `json:"aspToken,omitempty"` // optional for ac backend validation
AgentAddr string `json:"agentAddr"`
ACTokens map[string]string `json:"acTokens"`
PreAccessActions map[string]*PreAccessInfo `json:"preActions,omitempty"` // optional for pre-access
RedirectUrl string `json:"redirectUrl,omitempty"`
}

type AgentListMsg struct {
Expand Down
8 changes: 8 additions & 0 deletions common/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ package common

import "net/url"

// an object contains represent knocking user information
type AgentUser struct {
UserId string
DeviceId string
OrganizationId string
AuthServiceId string
}

// authsvcprovider and resource
type LoginPageContext struct {
Title string `json:"title,omitempty"`
Expand Down
5 changes: 3 additions & 2 deletions server/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const (

// knock
const (
DefaultIpOpenTime = 120 // second, align with ipset default timeout
ACOpenCompensationTime = 5 // second
DefaultIpOpenTime = 120 // second, align with ipset default timeout
ACOpenCompensationTime = 5 // second
TokenStoreRefreshInterval = 10 // second
)
52 changes: 43 additions & 9 deletions server/httpserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,30 @@ func (hs *HttpServer) initRouter() {
}
hs.legacyAuthWithAspPlugin(ctx, req)
})

/*
refreshGrp := g.Group("refresh")
refreshGrp.GET("/:token", func(ctx *gin.Context) {
var err error
token := ctx.Param("token")
log.Info("get refresh request. aspId: %s, query: %v", token, ctx.Request.URL.RawQuery)
if len(token) == 0 {
err = common.ErrUrlPathInvalid
log.Error("path error: %v", err)
ctx.String(http.StatusOK, "{\"errMsg\": \"path error: %v\"}", err)
return
}
req := &common.HttpRefreshRequest{
Token: token,
SrcIp: ctx.Query("srcip"),
}
hs.handleRefreshResource()
})
*/

}

// corsMiddleware is a middleware function that adds CORS headers to the HTTP response.
Expand Down Expand Up @@ -316,22 +340,25 @@ func (hs *HttpServer) handleHttpOpenResource(req *common.HttpKnockRequest, res *
srcAddr := &common.NetAddress{Ip: srcIp}

acDstIpMap := make(map[string][]*common.NetAddress)
for _, info := range res.Resources {
addrs, exist := acDstIpMap[info.ACId]
for resName, info := range res.Resources {
addrs, exist := acDstIpMap[resName]
if exist {
addrs = append(addrs, info.Addr)
acDstIpMap[info.ACId] = addrs
acDstIpMap[resName] = addrs
} else {
acDstIpMap[info.ACId] = []*common.NetAddress{info.Addr}
acDstIpMap[resName] = []*common.NetAddress{info.Addr}
}
}

// PART III: request ac operation for each resource and block for response
var acWg sync.WaitGroup
var artMsgsMutex sync.Mutex
artMsgs := make(map[string]*common.ACOpsResultMsg)
ackMsg.ACTokens = make(map[string]string)
ackMsg.PreAccessActions = make(map[string]*common.PreAccessInfo)

for acId, addrs := range acDstIpMap {
for resName, addrs := range acDstIpMap {
acId := res.Resources[resName].ACId
s.acConnectionMapMutex.Lock()
acConn, found := s.acConnectionMap[acId]
s.acConnectionMapMutex.Unlock()
Expand All @@ -344,22 +371,24 @@ func (hs *HttpServer) handleHttpOpenResource(req *common.HttpKnockRequest, res *
}

acWg.Add(1)
go func(acip string, dstAddrs []*common.NetAddress) {
go func(name string, dstAddrs []*common.NetAddress) {
defer acWg.Done()

artMsg, _ := s.processACOperation(knkMsg, acConn, srcAddr, dstAddrs, res.OpenTime)
artMsgsMutex.Lock()
artMsgs[acip] = artMsg
artMsgs[name] = artMsg
ackMsg.ACTokens[name] = artMsg.ACToken
ackMsg.PreAccessActions[name] = artMsg.PreAccessAction
artMsgsMutex.Unlock()
}(acId, addrs)
}(resName, addrs)
}
acWg.Wait()

var errCount int
for _, artMsg := range artMsgs {
if artMsg.ErrCode != common.ErrSuccess.ErrorCode() {
errCount++
break
continue
}
}

Expand Down Expand Up @@ -393,3 +422,8 @@ func (hs *HttpServer) NewHttpServerHelper() *plugins.HttpServerPluginHelper {
func (hs *HttpServer) FindPluginHandler(aspId string) plugins.PluginHandler {
return hs.udpServer.FindPluginHandler(aspId)
}

func (hs *HttpServer) handleRefreshResource(token string) (err error) {
// to do
return nil
}
33 changes: 25 additions & 8 deletions server/plugins/example/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,14 +244,31 @@ func authRegular(ctx *gin.Context, req *common.HttpKnockRequest, res *common.Res
log.Error("RedirectUrl is not provided.")
} else {
ackMsg.RedirectUrl = res.RedirectUrl
ctx.SetCookie(
"nhp-token", // Name
"example-nhp-token-GUBdoVXpxt", // Value
-1, // MaxAge
"/", // Path
res.CookieDomain, // Domain
true, // Secure
true) // HttpOnly
}

// set cookies
singleHost := len(ackMsg.ACTokens) == 1
for resName, token := range ackMsg.ACTokens {
if singleHost {
ctx.SetCookie(
"nhp-token", // Name
token, // Value
-1, // MaxAge
"/", // Path
res.CookieDomain, // Domain
true, // Secure
true) // HttpOnly
} else {
domain := strings.Split(ackMsg.ResourceHost[resName], ":")[0]
ctx.SetCookie(
"nhp-token"+"/"+resName, // Name
token, // Value
-1, // MaxAge
"/", // Path
domain, // Domain
true, // Secure
true) // HttpOnly
}
log.Info("ctx.SetCookie.")
}
}
Expand Down
Loading

0 comments on commit 5b28d46

Please sign in to comment.