Skip to content

Commit 5b28d46

Browse files
committed
Server ack message propagates AC tokens to agent. Http knock api also set agent's cookie with tokens
1 parent 79ac584 commit 5b28d46

File tree

10 files changed

+133
-77
lines changed

10 files changed

+133
-77
lines changed

ac/httpac.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,8 @@ func (hs *HttpAC) IsRunning() bool {
134134
func (ha *HttpAC) initRouter() {
135135
g := ha.ginEngine
136136

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

201-
_, err = ha.ua.HandleAccessControl(entry.AgentUser, entry.SrcAddrs, entry.DstAddrs, entry.OpenTime, nil)
200+
_, err = ha.ua.HandleAccessControl(entry.User, entry.SrcAddrs, entry.DstAddrs, entry.OpenTime, nil)
202201
if err != nil {
203202
c.String(http.StatusOK, "{\"errMsg\": \"%s\"}", err)
204203
return

ac/msghandler.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func (a *UdpAC) HandleUdpACOperations(ppd *core.PacketParserData) (err error) {
4141
srcAddrs := dopMsg.SourceAddrs
4242
dstAddrs := dopMsg.DestinationAddrs
4343
openTimeSec := int(dopMsg.OpenTime)
44-
agentUser := &AgentUser{
44+
agentUser := &common.AgentUser{
4545
UserId: dopMsg.UserId,
4646
DeviceId: dopMsg.DeviceId,
4747
OrganizationId: dopMsg.OrganizationId,
@@ -54,10 +54,10 @@ func (a *UdpAC) HandleUdpACOperations(ppd *core.PacketParserData) (err error) {
5454

5555
// generate ac token and save user and access information
5656
entry := &AccessEntry{
57-
AgentUser: agentUser,
58-
SrcAddrs: srcAddrs,
59-
DstAddrs: dstAddrs,
60-
OpenTime: openTimeSec,
57+
User: agentUser,
58+
SrcAddrs: srcAddrs,
59+
DstAddrs: dstAddrs,
60+
OpenTime: openTimeSec,
6161
}
6262
artMsg.ACToken = a.GenerateAccessToken(entry)
6363

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

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

347347
tempEntry := &AccessEntry{
348-
AgentUser: au,
349-
SrcAddrs: srcAddrs,
350-
DstAddrs: dstAddrs,
351-
OpenTime: tempOpenTimeSec,
348+
User: au,
349+
SrcAddrs: srcAddrs,
350+
DstAddrs: dstAddrs,
351+
OpenTime: tempOpenTimeSec,
352352
}
353353
artMsg.PreAccessAction = &common.PreAccessInfo{
354354
AccessPort: strconv.Itoa(pickedPort),

ac/tokenstore.go

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,45 +11,38 @@ import (
1111
"github.com/OpenNHP/opennhp/log"
1212
)
1313

14-
type AgentUser struct {
15-
UserId string
16-
DeviceId string
17-
OrganizationId string
18-
AuthServiceId string
19-
}
20-
2114
type AccessEntry struct {
22-
AgentUser *AgentUser
15+
User *common.AgentUser
2316
SrcAddrs []*common.NetAddress
2417
DstAddrs []*common.NetAddress
2518
OpenTime int
2619
ExpireTime time.Time
2720
}
2821

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

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

3629
hash := sm3.New()
3730
binary.BigEndian.PutUint64(tsBytes[:], uint64(currTime))
38-
au := entry.AgentUser
31+
au := entry.User
3932
hash.Write([]byte(a.config.ACId + au.UserId + au.DeviceId + au.OrganizationId + au.AuthServiceId))
4033
hash.Write(tsBytes[:])
4134
token := base64.StdEncoding.EncodeToString(hash.Sum(nil))
4235
hash.Reset()
4336

44-
a.TokenStoreMutex.Lock()
45-
defer a.TokenStoreMutex.Unlock()
37+
a.tokenStoreMutex.Lock()
38+
defer a.tokenStoreMutex.Unlock()
4639

4740
entry.ExpireTime = time.Now().Add(time.Duration(entry.OpenTime) * time.Second)
4841
tokenMap, found := a.tokenStore[token[0:1]]
4942
if found {
5043
tokenMap[token] = entry
5144
} else {
52-
tokenMap := make(TokenAccessMap)
45+
tokenMap := make(TokenToAccessMap)
5346
tokenMap[token] = entry
5447
a.tokenStore[token[0:1]] = tokenMap
5548
}
@@ -58,8 +51,8 @@ func (a *UdpAC) GenerateAccessToken(entry *AccessEntry) string {
5851
}
5952

6053
func (a *UdpAC) VerifyAccessToken(token string) *AccessEntry {
61-
a.TokenStoreMutex.Lock()
62-
defer a.TokenStoreMutex.Unlock()
54+
a.tokenStoreMutex.Lock()
55+
defer a.tokenStoreMutex.Unlock()
6356

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

8679
case <-time.After(TokenStoreRefreshInterval * time.Second):
87-
a.TokenStoreMutex.Lock()
88-
defer a.TokenStoreMutex.Unlock()
80+
a.tokenStoreMutex.Lock()
81+
defer a.tokenStoreMutex.Unlock()
8982

9083
now := time.Now()
9184
for head, tokenMap := range a.tokenStore {
9285
for token, entry := range tokenMap {
9386
if now.After(entry.ExpireTime) {
94-
log.Info("[TokenStore] token %s expired", token)
87+
log.Info("[TokenStore] token %s expired, remove", token)
9588
delete(tokenMap, token)
9689
}
9790
}

ac/udpac.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ type UdpAC struct {
4040
serverPeerMutex sync.Mutex
4141
serverPeerMap map[string]*core.UdpPeer // indexed by server's public key
4242

43-
TokenStoreMutex sync.Mutex
43+
tokenStoreMutex sync.Mutex
4444
tokenStore TokenStore
4545

4646
device *core.Device

common/nhpmsg.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,15 @@ type PreAccessInfo struct {
7070
}
7171

7272
type ServerKnockAckMsg struct {
73-
ErrCode string `json:"errCode"`
74-
ErrMsg string `json:"errMsg,omitempty"`
75-
ResourceHost map[string]string `json:"resHost"`
76-
OpenTime uint32 `json:"opnTime"`
77-
AuthProviderToken string `json:"aspToken,omitempty"` // optional for ac backend validation
78-
AgentAddr string `json:"agentAddr"`
79-
PreAccessActions []*PreAccessInfo `json:"preActs,omitempty"` // optional for pre-access
80-
RedirectUrl string `json:"redirectUrl,omitempty"`
73+
ErrCode string `json:"errCode"`
74+
ErrMsg string `json:"errMsg,omitempty"`
75+
ResourceHost map[string]string `json:"resHost"`
76+
OpenTime uint32 `json:"opnTime"`
77+
AuthProviderToken string `json:"aspToken,omitempty"` // optional for ac backend validation
78+
AgentAddr string `json:"agentAddr"`
79+
ACTokens map[string]string `json:"acTokens"`
80+
PreAccessActions map[string]*PreAccessInfo `json:"preActions,omitempty"` // optional for pre-access
81+
RedirectUrl string `json:"redirectUrl,omitempty"`
8182
}
8283

8384
type AgentListMsg struct {

common/types.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@ package common
22

33
import "net/url"
44

5+
// an object contains represent knocking user information
6+
type AgentUser struct {
7+
UserId string
8+
DeviceId string
9+
OrganizationId string
10+
AuthServiceId string
11+
}
12+
513
// authsvcprovider and resource
614
type LoginPageContext struct {
715
Title string `json:"title,omitempty"`

server/constants.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const (
1818

1919
// knock
2020
const (
21-
DefaultIpOpenTime = 120 // second, align with ipset default timeout
22-
ACOpenCompensationTime = 5 // second
21+
DefaultIpOpenTime = 120 // second, align with ipset default timeout
22+
ACOpenCompensationTime = 5 // second
23+
TokenStoreRefreshInterval = 10 // second
2324
)

server/httpserver.go

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,30 @@ func (hs *HttpServer) initRouter() {
253253
}
254254
hs.legacyAuthWithAspPlugin(ctx, req)
255255
})
256+
257+
/*
258+
refreshGrp := g.Group("refresh")
259+
refreshGrp.GET("/:token", func(ctx *gin.Context) {
260+
var err error
261+
token := ctx.Param("token")
262+
log.Info("get refresh request. aspId: %s, query: %v", token, ctx.Request.URL.RawQuery)
263+
264+
if len(token) == 0 {
265+
err = common.ErrUrlPathInvalid
266+
log.Error("path error: %v", err)
267+
ctx.String(http.StatusOK, "{\"errMsg\": \"path error: %v\"}", err)
268+
return
269+
}
270+
271+
req := &common.HttpRefreshRequest{
272+
Token: token,
273+
SrcIp: ctx.Query("srcip"),
274+
}
275+
276+
hs.handleRefreshResource()
277+
})
278+
*/
279+
256280
}
257281

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

318342
acDstIpMap := make(map[string][]*common.NetAddress)
319-
for _, info := range res.Resources {
320-
addrs, exist := acDstIpMap[info.ACId]
343+
for resName, info := range res.Resources {
344+
addrs, exist := acDstIpMap[resName]
321345
if exist {
322346
addrs = append(addrs, info.Addr)
323-
acDstIpMap[info.ACId] = addrs
347+
acDstIpMap[resName] = addrs
324348
} else {
325-
acDstIpMap[info.ACId] = []*common.NetAddress{info.Addr}
349+
acDstIpMap[resName] = []*common.NetAddress{info.Addr}
326350
}
327351
}
328352

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

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

346373
acWg.Add(1)
347-
go func(acip string, dstAddrs []*common.NetAddress) {
374+
go func(name string, dstAddrs []*common.NetAddress) {
348375
defer acWg.Done()
349376

350377
artMsg, _ := s.processACOperation(knkMsg, acConn, srcAddr, dstAddrs, res.OpenTime)
351378
artMsgsMutex.Lock()
352-
artMsgs[acip] = artMsg
379+
artMsgs[name] = artMsg
380+
ackMsg.ACTokens[name] = artMsg.ACToken
381+
ackMsg.PreAccessActions[name] = artMsg.PreAccessAction
353382
artMsgsMutex.Unlock()
354-
}(acId, addrs)
383+
}(resName, addrs)
355384
}
356385
acWg.Wait()
357386

358387
var errCount int
359388
for _, artMsg := range artMsgs {
360389
if artMsg.ErrCode != common.ErrSuccess.ErrorCode() {
361390
errCount++
362-
break
391+
continue
363392
}
364393
}
365394

@@ -393,3 +422,8 @@ func (hs *HttpServer) NewHttpServerHelper() *plugins.HttpServerPluginHelper {
393422
func (hs *HttpServer) FindPluginHandler(aspId string) plugins.PluginHandler {
394423
return hs.udpServer.FindPluginHandler(aspId)
395424
}
425+
426+
func (hs *HttpServer) handleRefreshResource(token string) (err error) {
427+
// to do
428+
return nil
429+
}

server/plugins/example/main.go

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -244,14 +244,31 @@ func authRegular(ctx *gin.Context, req *common.HttpKnockRequest, res *common.Res
244244
log.Error("RedirectUrl is not provided.")
245245
} else {
246246
ackMsg.RedirectUrl = res.RedirectUrl
247-
ctx.SetCookie(
248-
"nhp-token", // Name
249-
"example-nhp-token-GUBdoVXpxt", // Value
250-
-1, // MaxAge
251-
"/", // Path
252-
res.CookieDomain, // Domain
253-
true, // Secure
254-
true) // HttpOnly
247+
}
248+
249+
// set cookies
250+
singleHost := len(ackMsg.ACTokens) == 1
251+
for resName, token := range ackMsg.ACTokens {
252+
if singleHost {
253+
ctx.SetCookie(
254+
"nhp-token", // Name
255+
token, // Value
256+
-1, // MaxAge
257+
"/", // Path
258+
res.CookieDomain, // Domain
259+
true, // Secure
260+
true) // HttpOnly
261+
} else {
262+
domain := strings.Split(ackMsg.ResourceHost[resName], ":")[0]
263+
ctx.SetCookie(
264+
"nhp-token"+"/"+resName, // Name
265+
token, // Value
266+
-1, // MaxAge
267+
"/", // Path
268+
domain, // Domain
269+
true, // Secure
270+
true) // HttpOnly
271+
}
255272
log.Info("ctx.SetCookie.")
256273
}
257274
}

0 commit comments

Comments
 (0)