mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Merge CoA into ReAuthorize logic
Also updated the integration test.
This commit is contained in:
committed by
Dan Christian Bogos
parent
02c8ed11c1
commit
7129d349a1
@@ -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
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -61,7 +61,8 @@
|
||||
"acct_address": "127.0.0.1:1813"
|
||||
}
|
||||
],
|
||||
"dmr_template": "*dmr"
|
||||
"dmr_template": "*dmr",
|
||||
"coa_template": "*coa"
|
||||
},
|
||||
|
||||
"apiers": {
|
||||
Reference in New Issue
Block a user