Merge CoA into ReAuthorize logic

Also updated the integration test.
This commit is contained in:
ionutboangiu
2024-02-08 06:59:22 -05:00
committed by Dan Christian Bogos
parent 02c8ed11c1
commit 7129d349a1
7 changed files with 64 additions and 34 deletions

View File

@@ -518,11 +518,11 @@ func (ra *RadiusAgent) V1DisconnectSession(_ *context.Context, attr utils.AttrDi
return nil
}
// V1ChangeAuthorization updates session authorization using RADIUS CoA functionality.
func (ra *RadiusAgent) V1ChangeOfAuthorization(ctx *context.Context, sessionID string, reply *string) error {
replyCode, err := ra.sendRadDaReq(radigo.CoARequest, ra.cgrCfg.RadiusAgentCfg().CoATemplate, sessionID, nil)
// V1ReAuthorize updates session authorization using RADIUS CoA functionality.
func (ra *RadiusAgent) V1ReAuthorize(_ *context.Context, originID string, reply *string) error {
replyCode, err := ra.sendRadDaReq(radigo.CoARequest, ra.cgrCfg.RadiusAgentCfg().CoATemplate, originID, nil)
if err != nil {
return fmt.Errorf("change of authorization failed: %w", err)
return err
}
switch replyCode {
case radigo.CoAACK:
@@ -566,7 +566,7 @@ func (ra *RadiusAgent) sendRadDaReq(requestType radigo.PacketCode, requestTempla
}
dynAuthReq := dynAuthClient.NewRequest(requestType, 1)
if err = radAppendAttributes(dynAuthReq, agReq.radDAReq); err != nil {
return 0, errors.New("could not append attributes to the request packet")
return 0, fmt.Errorf("could not append attributes to the request packet: %w", err)
}
dynAuthReply, err := dynAuthClient.SendRequest(dynAuthReq)
if err != nil {
@@ -593,11 +593,6 @@ func dmRemoteAddr(remoteAddr string, dynAuthAddresses map[string]string) (string
return "", "", utils.ErrNotFound
}
// V1ReAuthorize is needed to satisfy the sessions.BiRPClient interface
func (*RadiusAgent) V1ReAuthorize(_ *context.Context, _ string, _ *string) error {
return utils.ErrNotImplemented
}
// V1WarnDisconnect is needed to satisfy the sessions.BiRPClient interface
func (*RadiusAgent) V1WarnDisconnect(_ *context.Context, _ map[string]any, _ *string) error {
return utils.ErrNotImplemented

View File

@@ -25,6 +25,7 @@ import (
"bytes"
"encoding/base64"
"path"
"sync"
"testing"
"time"
@@ -36,26 +37,28 @@ import (
)
/*
TestRadiusDisconnect scenario:
TestRadiusCoADisconnect scenario:
1. Configure a radius_agent with:
- a bidirectional connection to sessions
- dmr_template field pointing to the predefined *dmr template
- coa_template field pointing to the predefined *coa template
- localhost:3799 inside client_da_addresses
- an auth request processor
- an accounting request processor
2. Set up a 'client' (acting as a server) that will handle incoming Disconnect Requests.
2. Set up a 'client' (acting as a server) that will handle incoming CoA/Disconnect Requests.
3. Send an AccessRequest to cgr-engine's RADIUS server in order to register the packet.
4. Send an AccountingRequest to initialize a session.
5. Send a SessionSv1ForceDisconnect request, that will attempt to remotely disconnect the
session created previously.
5. Send a SessionSv1ReAuthorize request, that will send a CoA request to the client. The
client will then verify that the packet was populated correctly.
6. Verify that the request fields from the 'client' handler are correctly sent.
6. Send a SessionSv1ForceDisconnect request, that will attempt to remotely disconnect the
session created previously and verify the request packet fields.
*/
func TestRadiusDisconnect(t *testing.T) {
func TestRadiusCoADisconnect(t *testing.T) {
switch *dbType {
case utils.MetaInternal:
case utils.MetaMySQL, utils.MetaMongo, utils.MetaPostgres:
@@ -65,7 +68,7 @@ func TestRadiusDisconnect(t *testing.T) {
}
// Set up test environment.
cfgPath := path.Join(*dataDir, "conf", "samples", "radius_disconnect")
cfgPath := path.Join(*dataDir, "conf", "samples", "radius_coa_disconnect")
raDiscCfg, err := config.NewCGRConfigFromPath(cfgPath)
if err != nil {
t.Fatal(err)
@@ -92,9 +95,15 @@ func TestRadiusDisconnect(t *testing.T) {
time.Sleep(time.Duration(*waitRater) * time.Millisecond)
// Testing the functionality itself starts here.
done := make(chan struct{}) // signal to end the test when the handler has finished processing
var wg sync.WaitGroup
done := make(chan struct{}) // signal to end the test when the handlers have finished processing
go func() {
wg.Wait()
close(done)
}()
wg.Add(2)
handleDisconnect := func(request *radigo.Packet) (*radigo.Packet, error) {
defer close(done)
defer wg.Done()
encodedNasIPAddr := "fwAAAQ=="
decodedNasIPAddr, err := base64.StdEncoding.DecodeString(encodedNasIPAddr)
if err != nil {
@@ -112,6 +121,25 @@ func TestRadiusDisconnect(t *testing.T) {
}
return reply, nil
}
handleCoA := func(request *radigo.Packet) (*radigo.Packet, error) {
defer wg.Done()
encodedNasIPAddr := "fwAAAQ=="
decodedNasIPAddr, err := base64.StdEncoding.DecodeString(encodedNasIPAddr)
if err != nil {
t.Error("error decoding base64 NAS-IP-Address:", err)
}
reply := request.Reply()
if string(request.AVPs[0].RawValue) != "1001" ||
!bytes.Equal(request.AVPs[1].RawValue, decodedNasIPAddr) ||
string(request.AVPs[2].RawValue) != "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0" ||
string(request.AVPs[3].RawValue) != "custom_filter" {
t.Errorf("unexpected request received: %v", utils.ToJSON(request))
reply.Code = radigo.CoANAK
} else {
reply.Code = radigo.CoAACK
}
return reply, nil
}
type testNAS struct {
clientAuth *radigo.Client
clientAcct *radigo.Client
@@ -123,6 +151,7 @@ func TestRadiusDisconnect(t *testing.T) {
testRadClient.server = radigo.NewServer("udp", "127.0.0.1:3799", secrets, dicts,
map[radigo.PacketCode]func(*radigo.Packet) (*radigo.Packet, error){
radigo.DisconnectRequest: handleDisconnect,
radigo.CoARequest: handleCoA,
}, nil, utils.Logger)
stopChan := make(chan struct{})
defer close(stopChan)
@@ -203,14 +232,18 @@ func TestRadiusDisconnect(t *testing.T) {
t.Errorf("unexpected reply received to AccountingRequest: %+v", replyPacket)
}
var replyFD string
if err = raDiscRPC.Call(context.Background(), utils.SessionSv1ForceDisconnect, nil, &replyFD); err != nil {
var reply string
if err := raDiscRPC.Call(context.Background(), utils.SessionSv1ReAuthorize, &utils.SessionFilter{}, &reply); err != nil {
t.Error(err)
}
if err = raDiscRPC.Call(context.Background(), utils.SessionSv1ForceDisconnect, nil, &reply); err != nil {
t.Error(err)
}
select {
case <-done:
case <-time.After(time.Second):
t.Error("client did not receive a DisconnectRequest in time")
t.Error("client did not receive a the expected requests in time")
}
}

View File

@@ -1226,16 +1226,16 @@ const CGRATES_CFG_JSON = `
{"tag": "Reply-Message", "path": "*radDAReq.Reply-Message", "type": "*variable",
"value": "~*vars.DisconnectCause"},
],
// "*coa": [
// {"tag": "User-Name", "path": "*radDAReq.User-Name", "type": "*variable",
// "value": "~*req.User-Name"},
// {"tag": "NAS-IP-Address", "path": "*radDAReq.NAS-IP-Address", "type": "*variable",
// "value": "~*req.NAS-IP-Address"},
// {"tag": "Acct-Session-Id", "path": "*radDAReq.Acct-Session-Id", "type": "*variable",
// "value": "~*req.Acct-Session-Id"},
// {"tag": "Filter-ID", "path": "*radDAReq.Filter-ID", "type": "*constant",
// "value": "custom_filter"},
// ],
"*coa": [
{"tag": "User-Name", "path": "*radDAReq.User-Name", "type": "*variable",
"value": "~*req.User-Name"},
{"tag": "NAS-IP-Address", "path": "*radDAReq.NAS-IP-Address", "type": "*variable",
"value": "~*req.NAS-IP-Address"},
{"tag": "Acct-Session-Id", "path": "*radDAReq.Acct-Session-Id", "type": "*variable",
"value": "~*req.Acct-Session-Id"},
{"tag": "Filter-Id", "path": "*radDAReq.Filter-Id", "type": "*constant",
"value": "custom_filter"},
],
"*errSip": [
{"tag": "Request", "path": "*rep.Request", "type": "*constant",
"value": "SIP/2.0 500 Internal Server Error", "mandatory": true},

View File

@@ -56,9 +56,10 @@
"diameter_agent": {
"enabled": true,
"sessions_conns": ["*bijson_localhost"],
"asr_template": "*asr",
"rar_template": "*rar",
"forced_disconnect": "*asr", // the request to send to diameter on DisconnectSession <*none|*asr|*rar>
"forced_disconnect": "*asr" // the request to send to diameter on DisconnectSession <*none|*asr|*rar>
},
"apiers": {

View File

@@ -61,7 +61,8 @@
"acct_address": "127.0.0.1:1813"
}
],
"dmr_template": "*dmr"
"dmr_template": "*dmr",
"coa_template": "*coa"
},
"apiers": {