diff --git a/agents/radagent.go b/agents/radagent.go index 1a84251f5..c5a84bc76 100644 --- a/agents/radagent.go +++ b/agents/radagent.go @@ -527,7 +527,12 @@ func (ra *RadiusAgent) V1ReAuthorize(_ *context.Context, cgrEv utils.CGREvent, r if originID == "" { return utils.NewErrMandatoryIeMissing(utils.OriginID) } - replyCode, err := ra.sendRadDaReq(radigo.CoARequest, ra.cgrCfg.RadiusAgentCfg().CoATemplate, + coaTpl := ra.cgrCfg.RadiusAgentCfg().CoATemplate + if optTpl, err := cgrEv.OptAsString(utils.MetaRadCoATemplate); err == nil { + coaTpl = optTpl + } + + replyCode, err := ra.sendRadDaReq(radigo.CoARequest, coaTpl, originID, utils.MapStorage(cgrEv.Event), nil) if err != nil { return err diff --git a/agents/radius_coa_it_test.go b/agents/radius_coa_it_test.go index 3058fe21f..a862b613c 100644 --- a/agents/radius_coa_it_test.go +++ b/agents/radius_coa_it_test.go @@ -132,7 +132,7 @@ func TestRadiusCoADisconnect(t *testing.T) { 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" { + string(request.AVPs[3].RawValue) != "mycustomvalue" { t.Errorf("unexpected request received: %v", utils.ToJSON(request)) reply.Code = radigo.CoANAK } else { @@ -233,11 +233,16 @@ func TestRadiusCoADisconnect(t *testing.T) { } var reply string - if err := raDiscRPC.Call(context.Background(), utils.SessionSv1ReAuthorize, utils.SessionFilterWithEvent{ - Event: map[string]any{ - "CustomFilter": "custom_filter", - }, - }, &reply); err != nil { + if err := raDiscRPC.Call(context.Background(), utils.SessionSv1ReAuthorize, + utils.SessionFilterWithEvent{ + SessionFilter: &utils.SessionFilter{ + APIOpts: map[string]any{ + utils.MetaRadCoATemplate: "mycoa", + }}, + Event: map[string]any{ + "CustomFilter": "custom_filter", + }, + }, &reply); err != nil { t.Error(err) } diff --git a/config/config_defaults.go b/config/config_defaults.go index 1484a1391..304d15d1f 100644 --- a/config/config_defaults.go +++ b/config/config_defaults.go @@ -1163,42 +1163,42 @@ const CGRATES_CFG_JSON = ` "templates": { "*err": [ - {"tag": "SessionId", "path": "*rep.Session-Id", "type": "*variable", - "value": "~*req.Session-Id", "mandatory": true}, - {"tag": "OriginHost", "path": "*rep.Origin-Host", "type": "*variable", - "value": "~*vars.OriginHost", "mandatory": true}, - {"tag": "OriginRealm", "path": "*rep.Origin-Realm", "type": "*variable", + {"tag": "SessionId", "path": "*rep.Session-Id", "type": "*variable", + "value": "~*req.Session-Id", "mandatory": true}, + {"tag": "OriginHost", "path": "*rep.Origin-Host", "type": "*variable", + "value": "~*vars.OriginHost", "mandatory": true}, + {"tag": "OriginRealm", "path": "*rep.Origin-Realm", "type": "*variable", "value": "~*vars.OriginRealm", "mandatory": true}, ], "*cca": [ - {"tag": "SessionId", "path": "*rep.Session-Id", "type": "*variable", - "value": "~*req.Session-Id", "mandatory": true}, - {"tag": "ResultCode", "path": "*rep.Result-Code", "type": "*constant", - "value": "2001"}, - {"tag": "OriginHost", "path": "*rep.Origin-Host", "type": "*variable", - "value": "~*vars.OriginHost", "mandatory": true}, - {"tag": "OriginRealm", "path": "*rep.Origin-Realm", "type": "*variable", - "value": "~*vars.OriginRealm", "mandatory": true}, - {"tag": "AuthApplicationId", "path": "*rep.Auth-Application-Id", "type": "*variable", - "value": "~*vars.*appid", "mandatory": true}, - {"tag": "CCRequestType", "path": "*rep.CC-Request-Type", "type": "*variable", - "value": "~*req.CC-Request-Type", "mandatory": true}, - {"tag": "CCRequestNumber", "path": "*rep.CC-Request-Number", "type": "*variable", - "value": "~*req.CC-Request-Number", "mandatory": true}, + {"tag": "SessionId", "path": "*rep.Session-Id", "type": "*variable", + "value": "~*req.Session-Id", "mandatory": true}, + {"tag": "ResultCode", "path": "*rep.Result-Code", "type": "*constant", + "value": "2001"}, + {"tag": "OriginHost", "path": "*rep.Origin-Host", "type": "*variable", + "value": "~*vars.OriginHost", "mandatory": true}, + {"tag": "OriginRealm", "path": "*rep.Origin-Realm", "type": "*variable", + "value": "~*vars.OriginRealm", "mandatory": true}, + {"tag": "AuthApplicationId", "path": "*rep.Auth-Application-Id", "type": "*variable", + "value": "~*vars.*appid", "mandatory": true}, + {"tag": "CCRequestType", "path": "*rep.CC-Request-Type", "type": "*variable", + "value": "~*req.CC-Request-Type", "mandatory": true}, + {"tag": "CCRequestNumber", "path": "*rep.CC-Request-Number", "type": "*variable", + "value": "~*req.CC-Request-Number", "mandatory": true}, ], "*asr": [ - {"tag": "SessionId", "path": "*diamreq.Session-Id", "type": "*variable", - "value": "~*req.Session-Id", "mandatory": true}, - {"tag": "OriginHost", "path": "*diamreq.Origin-Host", "type": "*variable", - "value": "~*req.Destination-Host", "mandatory": true}, - {"tag": "OriginRealm", "path": "*diamreq.Origin-Realm", "type": "*variable", - "value": "~*req.Destination-Realm", "mandatory": true}, - {"tag": "DestinationRealm", "path": "*diamreq.Destination-Realm", "type": "*variable", - "value": "~*req.Origin-Realm", "mandatory": true}, - {"tag": "DestinationHost", "path": "*diamreq.Destination-Host", "type": "*variable", - "value": "~*req.Origin-Host", "mandatory": true}, - {"tag": "AuthApplicationId", "path": "*diamreq.Auth-Application-Id", "type": "*variable", - "value": "~*vars.*appid", "mandatory": true}, + {"tag": "SessionId", "path": "*diamreq.Session-Id", "type": "*variable", + "value": "~*req.Session-Id", "mandatory": true}, + {"tag": "OriginHost", "path": "*diamreq.Origin-Host", "type": "*variable", + "value": "~*req.Destination-Host", "mandatory": true}, + {"tag": "OriginRealm", "path": "*diamreq.Origin-Realm", "type": "*variable", + "value": "~*req.Destination-Realm", "mandatory": true}, + {"tag": "DestinationRealm", "path": "*diamreq.Destination-Realm", "type": "*variable", + "value": "~*req.Origin-Realm", "mandatory": true}, + {"tag": "DestinationHost", "path": "*diamreq.Destination-Host", "type": "*variable", + "value": "~*req.Origin-Host", "mandatory": true}, + {"tag": "AuthApplicationId", "path": "*diamreq.Auth-Application-Id", "type": "*variable", + "value": "~*vars.*appid", "mandatory": true}, ], "*rar": [ {"tag": "SessionId", "path": "*diamreq.Session-Id", "type": "*variable", @@ -1216,7 +1216,7 @@ const CGRATES_CFG_JSON = ` {"tag": "ReAuthRequestType", "path": "*diamreq.Re-Auth-Request-Type", "type": "*constant", "value": "0"}, ], - "*dmr": [ + "*dmr": [ // used by RadiusAgent when sending Disconnect message towards the client {"tag": "User-Name", "path": "*radDAReq.User-Name", "type": "*variable", "value": "~*oreq.User-Name"}, {"tag": "NAS-IP-Address", "path": "*radDAReq.NAS-IP-Address", "type": "*variable", @@ -1226,7 +1226,7 @@ const CGRATES_CFG_JSON = ` {"tag": "Reply-Message", "path": "*radDAReq.Reply-Message", "type": "*variable", "value": "~*vars.DisconnectCause"}, ], - "*coa": [ + "*coa": [ // used by RadiusAgent when sending ChangeOfAuthorization message towards the client {"tag": "User-Name", "path": "*radDAReq.User-Name", "type": "*variable", "value": "~*oreq.User-Name"}, {"tag": "NAS-IP-Address", "path": "*radDAReq.NAS-IP-Address", "type": "*variable", @@ -1237,10 +1237,10 @@ const CGRATES_CFG_JSON = ` "value": "~*req.CustomFilter"}, ], "*errSip": [ - {"tag": "Request", "path": "*rep.Request", "type": "*constant", - "value": "SIP/2.0 500 Internal Server Error", "mandatory": true}, + {"tag": "Request", "path": "*rep.Request", "type": "*constant", + "value": "SIP/2.0 500 Internal Server Error", "mandatory": true}, ], - "*cdrLog": [ // cdrLog template is used in ActionS to build the event that is send to CDRs in case of *cdrLog actionType + "*cdrLog": [ // cdrLog template is used in ActionS to build the event that is sent to CDRs in case of *cdrLog actionType {"tag": "ToR", "path": "*cdr.ToR", "type": "*variable", "value": "~*req.BalanceType", "mandatory": true}, {"tag": "OriginHost", "path": "*cdr.OriginHost", "type": "*constant", diff --git a/data/conf/samples/radius_coa_disconnect/templates.json b/data/conf/samples/radius_coa_disconnect/templates.json new file mode 100644 index 000000000..b80849062 --- /dev/null +++ b/data/conf/samples/radius_coa_disconnect/templates.json @@ -0,0 +1,19 @@ +{ + + + +"templates": { + "mycoa": [ // used by RadiusAgent when sending ChangeOfAuthorization message towards the client + {"tag": "User-Name", "path": "*radDAReq.User-Name", "type": "*variable", + "value": "~*oreq.User-Name"}, + {"tag": "NAS-IP-Address", "path": "*radDAReq.NAS-IP-Address", "type": "*variable", + "value": "~*oreq.NAS-IP-Address"}, + {"tag": "Acct-Session-Id", "path": "*radDAReq.Acct-Session-Id", "type": "*variable", + "value": "~*oreq.Acct-Session-Id"}, + {"tag": "Filter-Id", "path": "*radDAReq.Filter-Id", "type": "*variable", + "value": "mycustomvalue"}, + ] +} + + +} \ No newline at end of file diff --git a/sessions/sessions.go b/sessions/sessions.go index f8a102005..bd7ccd78b 100644 --- a/sessions/sessions.go +++ b/sessions/sessions.go @@ -4002,7 +4002,7 @@ func (sS *SessionS) BiRPCV1ProcessCDR(ctx *context.Context, rply) } -func (sS *SessionS) sendRar(ctx *context.Context, s *Session, event map[string]any) (err error) { +func (sS *SessionS) sendRar(ctx *context.Context, s *Session, apiOpts map[string]any, event map[string]any) (err error) { clnt := sS.biJClnt(s.ClientConnID) if clnt == nil { return fmt.Errorf("calling %s requires bidirectional JSON connection, connID: <%s>", @@ -4020,9 +4020,10 @@ func (sS *SessionS) sendRar(ctx *context.Context, s *Session, event map[string]a } } args := utils.CGREvent{ - ID: utils.GenUUID(), - Time: utils.TimePointer(time.Now()), - Event: event, + ID: utils.GenUUID(), + Time: utils.TimePointer(time.Now()), + APIOpts: apiOpts, + Event: event, } var rply string @@ -4042,17 +4043,17 @@ func (sS *SessionS) BiRPCv1ReAuthorize(ctx *context.Context, if len(aSs) == 0 { return utils.ErrNotFound } - cache := utils.NewStringSet(nil) + uniqueSIDs := utils.NewStringSet(nil) for _, as := range aSs { - if cache.Has(as.CGRID) { + if uniqueSIDs.Has(as.CGRID) { continue } - cache.Add(as.CGRID) + uniqueSIDs.Add(as.CGRID) ss := sS.getSessions(as.CGRID, false) if len(ss) == 0 { continue } - if errTerm := sS.sendRar(ctx, ss[0], args.Event); errTerm != nil { + if errTerm := sS.sendRar(ctx, ss[0], args.APIOpts, args.Event); errTerm != nil { utils.Logger.Warning( fmt.Sprintf( "<%s> failed sending RAR for session with id: <%s>, err: <%s>", diff --git a/utils/consts.go b/utils/consts.go index 63b73331b..407d72019 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -797,6 +797,7 @@ const ( TmpSuffix = ".tmp" MetaDiamreq = "*diamreq" MetaRadDAReq = "*radDAReq" + MetaRadCoATemplate = "*radCoATemplate" MetaCost = "*cost" MetaGroup = "*group" InternalRPCSet = "InternalRPCSet"