diff --git a/config/config_defaults.go b/config/config_defaults.go index 1dcbbb8b4..50028ffcd 100755 --- a/config/config_defaults.go +++ b/config/config_defaults.go @@ -367,8 +367,11 @@ const CGRATES_CFG_JSON = ` "terminate_attempts": 5, // attempts to get the session before terminating it "alterable_fields": [], // the session fields that can be updated //"min_dur_low_balance": "5s", // threshold which will trigger low balance warnings for prepaid calls (needs to be lower than debit_interval) - "stir_attest": "*any", // the default attest for stir/shaken authentification <*any|A|B|C> + "stir_allowed_attest": ["*any"], // the default attest for stir/shaken authentication <*any|A|B|C> "stir_payload_maxduration": "-1", // the duration that stir header is valid after it was created + "stir_default_attest": "A", // the default attest level if not mentioned in API + "stir_publickey_path": "", // the path to the public key + "stir_privatekey_path": "", // the path to the private key }, diff --git a/config/config_json_test.go b/config/config_json_test.go index 45d48b26a..1ec4ba5f8 100755 --- a/config/config_json_test.go +++ b/config/config_json_test.go @@ -694,8 +694,11 @@ func TestSmgJsonCfg(t *testing.T) { Channel_sync_interval: utils.StringPointer("0"), Terminate_attempts: utils.IntPointer(5), Alterable_fields: &[]string{}, - Stir_attest: utils.StringPointer(utils.META_ANY), + Stir_allowed_attest: &[]string{utils.META_ANY}, Stir_payload_maxduration: utils.StringPointer("-1"), + Stir_default_attest: utils.StringPointer("A"), + Stir_privatekey_path: utils.StringPointer(""), + Stir_publickey_path: utils.StringPointer(""), } if cfg, err := dfCgrJsonCfg.SessionSJsonCfg(); err != nil { t.Error(err) diff --git a/config/config_test.go b/config/config_test.go index 9cc2a21e5..fa2849905 100755 --- a/config/config_test.go +++ b/config/config_test.go @@ -621,8 +621,9 @@ func TestCgrCfgJSONDefaultsSMGenericCfg(t *testing.T) { ChannelSyncInterval: 0, TerminateAttempts: 5, AlterableFields: utils.NewStringSet([]string{}), - STIRAttest: utils.NewStringSet([]string{utils.META_ANY}), + STIRAllowedAttest: utils.NewStringSet([]string{utils.META_ANY}), STIRPayloadMaxduration: -1, + STIRDefaultAttest: "A", } if !reflect.DeepEqual(eSessionSCfg, cgrCfg.sessionSCfg) { t.Errorf("expecting: %s, received: %s", diff --git a/config/libconfig_json.go b/config/libconfig_json.go index e9847e25d..6acee7a5b 100755 --- a/config/libconfig_json.go +++ b/config/libconfig_json.go @@ -220,8 +220,11 @@ type SessionSJsonCfg struct { Terminate_attempts *int Alterable_fields *[]string Min_dur_low_balance *string - Stir_attest *string + Stir_allowed_attest *[]string Stir_payload_maxduration *string + Stir_default_attest *string + Stir_publickey_path *string + Stir_privatekey_path *string } // FreeSWITCHAgent config section diff --git a/config/sessionscfg.go b/config/sessionscfg.go index 31e7f7c79..ee35bf389 100644 --- a/config/sessionscfg.go +++ b/config/sessionscfg.go @@ -99,8 +99,11 @@ type SessionSCfg struct { TerminateAttempts int AlterableFields *utils.StringSet MinDurLowBalance time.Duration - STIRAttest *utils.StringSet + STIRAllowedAttest *utils.StringSet STIRPayloadMaxduration time.Duration + STIRDefaultAttest string + STIRPublicKeyPath string + STIRPrivateKeyPath string } func (scfg *SessionSCfg) loadFromJsonCfg(jsnCfg *SessionSJsonCfg) (err error) { @@ -277,14 +280,23 @@ func (scfg *SessionSCfg) loadFromJsonCfg(jsnCfg *SessionSJsonCfg) (err error) { return err } } - if jsnCfg.Stir_attest != nil { - scfg.STIRAttest = utils.NewStringSet(strings.Split(*jsnCfg.Stir_attest, utils.NestingSep)) + if jsnCfg.Stir_allowed_attest != nil { + scfg.STIRAllowedAttest = utils.NewStringSet(*jsnCfg.Stir_allowed_attest) } if jsnCfg.Stir_payload_maxduration != nil { if scfg.STIRPayloadMaxduration, err = utils.ParseDurationWithNanosecs(*jsnCfg.Stir_payload_maxduration); err != nil { return err } } + if jsnCfg.Stir_default_attest != nil { + scfg.STIRDefaultAttest = *jsnCfg.Stir_default_attest + } + if jsnCfg.Stir_publickey_path != nil { + scfg.STIRPublicKeyPath = *jsnCfg.Stir_publickey_path + } + if jsnCfg.Stir_privatekey_path != nil { + scfg.STIRPrivateKeyPath = *jsnCfg.Stir_privatekey_path + } return nil } @@ -316,7 +328,7 @@ func (scfg *SessionSCfg) AsMapInterface() map[string]interface{} { utils.TerminateAttemptsCfg: scfg.TerminateAttempts, utils.AlterableFieldsCfg: scfg.AlterableFields.AsSlice(), utils.MinDurLowBalanceCfg: scfg.MinDurLowBalance, - utils.STIRAtestCfg: strings.Join(scfg.STIRAttest.AsSlice(), utils.NestingSep), + utils.STIRAtestCfg: strings.Join(scfg.STIRAllowedAttest.AsSlice(), utils.NestingSep), utils.STIRPayloadMaxdurationCfg: scfg.STIRPayloadMaxduration, } } diff --git a/general_tests/session2_it_test.go b/general_tests/session2_it_test.go index 4fbfa4153..88ddbfd28 100644 --- a/general_tests/session2_it_test.go +++ b/general_tests/session2_it_test.go @@ -47,7 +47,8 @@ var ( testSes2ItLoadFromFolder, testSes2ItInitSession, testSes2ItAsActiveSessions, - testSes2StirAuthorize, + testSes2StirAuthenticate, + testSes2StirInit, testSes2ItStopCgrEngine, } ) @@ -181,9 +182,9 @@ func testSes2ItStopCgrEngine(t *testing.T) { } } -func testSes2StirAuthorize(t *testing.T) { +func testSes2StirAuthenticate(t *testing.T) { args := &sessions.V1ProcessEventArgs{ - Flags: []string{"*stir_authorize"}, + Flags: []string{utils.MetaSTIRAuthenticate}, CGREvent: &utils.CGREvent{ Tenant: "cgrates.org", ID: "testSes2StirAuthorize", @@ -207,14 +208,43 @@ func testSes2StirAuthorize(t *testing.T) { // altered originator args.CGREvent.Event[utils.STIROriginatorTn] = "1005" if err := ses2RPC.Call(utils.SessionSv1ProcessEvent, - args, &rply); err == nil || err.Error() != "*stir_authorize: wrong originatorTn" { - t.Errorf("Expected error :%q ,receved: %v", "*stir_authorize: wrong originatorTn", err) + args, &rply); err == nil || err.Error() != "*stir_authenticate: wrong originatorTn" { + t.Errorf("Expected error :%q ,receved: %v", "*stir_authenticate: wrong originatorTn", err) } // altered identity args.CGREvent.Event[utils.STIRIdentity] = "eyJhbGciOiJFUzI1NiIsInBwdCI6InNoYWtlbiIsInR5cCI6InBhc3Nwb3J0IiwieDV1IjoiL3Vzci9zaGFyZS9jZ3JhdGVzL3N0aXIvc3Rpcl9wdWJrZXkucGVtIn0.eyJhdHRlc3QiOiJBIiwiZGVzdCI6eyJ0biI6WyIxMDAyIl19LCJpYXQiOjE1ODcwMzg4MDIsIm9yaWciOnsidG4iOiIxMDA1In0sIm9yaWdpZCI6IjEyMzQ1NiJ9.cMEMlFnfyTu8uxfeU4RoZTamA7ifFT9Ibwrvi1_LKwL2xAU6fZ_CSIxKbtyOpNhM_sV03x7CfA_v0T4sHkifzg;info=;ppt=shaken" if err := ses2RPC.Call(utils.SessionSv1ProcessEvent, - args, &rply); err == nil || err.Error() != "*stir_authorize: crypto/ecdsa: verification error" { - t.Errorf("Expected error :%q ,receved: %v", "*stir_authorize: crypto/ecdsa: verification error", err) + args, &rply); err == nil || err.Error() != "*stir_authenticate: crypto/ecdsa: verification error" { + t.Errorf("Expected error :%q ,receved: %v", "*stir_authenticate: crypto/ecdsa: verification error", err) + } +} + +func testSes2StirInit(t *testing.T) { + args := &sessions.V1ProcessEventArgs{ + Flags: []string{utils.MetaSTIRInitiate}, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "testSes2StirInit", + Event: map[string]interface{}{ + utils.ToR: utils.VOICE, + utils.OriginID: "testSes2StirInit", + utils.RequestType: utils.META_PREPAID, + utils.Account: "1001", + utils.Subject: "ANY2CNT", + utils.Destination: "1002", + utils.Usage: 10 * time.Minute, + utils.STIRPublicKeyPath: "/usr/share/cgrates/stir/stir_pubkey.pem", + utils.STIRPrivateKeyPath: "/usr/share/cgrates/stir/stir_privatekey.pem", + }, + }, + } + var rply sessions.V1ProcessEventReply + if err := ses2RPC.Call(utils.SessionSv1ProcessEvent, + args, &rply); err != nil { // no error verificated with success + t.Error(err) + } + if err := sessions.AuthStirShaken(rply.STIRIdentity, "1001", "", "1002", "", utils.NewStringSet([]string{"A"}), 10*time.Minute); err != nil { + t.Fatal(err) } } diff --git a/packages/debian/changelog b/packages/debian/changelog index 33a70ec80..2a932a708 100644 --- a/packages/debian/changelog +++ b/packages/debian/changelog @@ -50,7 +50,8 @@ cgrates (0.11.0~dev) UNRELEASED; urgency=medium * [AgentS] Add ability to inject data in cache from agents * [Config] Config cache format change to include partitions * [ERs] Add *none EventReader type - * [SessionS] Added support for *stir_authorize + * [SessionS] Added support for *stir_authenticate + * [SessionS] Added support for *stir_initiate -- Alexandru Tripon Wed, 19 Feb 2020 13:25:52 +0200 diff --git a/sessions/sessions.go b/sessions/sessions.go index 78611ab9e..47fde4d14 100644 --- a/sessions/sessions.go +++ b/sessions/sessions.go @@ -2874,6 +2874,7 @@ type V1ProcessEventReply struct { Suppliers *engine.SortedSuppliers ThresholdIDs *[]string StatQueueIDs *[]string + STIRIdentity string } // AsNavigableMap is part of engine.NavigableMapper interface @@ -2956,8 +2957,8 @@ func (sS *SessionS) BiRPCv1ProcessEvent(clnt rpcclient.ClientConnector, if argsFlagsWithParams, err = utils.FlagsWithParamsFromSlice(args.Flags); err != nil { return } - if argsFlagsWithParams.HasKey(utils.MetaSTIRAuthorize) { - attest := sS.cgrCfg.SessionSCfg().STIRAttest + if argsFlagsWithParams.HasKey(utils.MetaSTIRAuthenticate) { + attest := sS.cgrCfg.SessionSCfg().STIRAllowedAttest if uattest := ev.GetStringIgnoreErrors(utils.STIRATest); uattest != utils.EmptyString { attest = utils.NewStringSet(strings.Split(uattest, utils.INFIELD_SEP)) } @@ -2973,6 +2974,34 @@ func (sS *SessionS) BiRPCv1ProcessEvent(clnt rpcclient.ClientConnector, attest, stirMaxDur); err != nil { return utils.NewSTIRError(err.Error()) } + } else if argsFlagsWithParams.HasKey(utils.MetaSTIRInitiate) { + attest := sS.cgrCfg.SessionSCfg().STIRDefaultAttest + if uattest := ev.GetStringIgnoreErrors(utils.STIRATest); uattest != utils.EmptyString { + attest = uattest + } + + destURI := ev.GetStringIgnoreErrors(utils.STIRDestinationTn) + destTn := utils.FirstNonEmpty(ev.GetStringIgnoreErrors(utils.STIRDestinationTn), ev.GetStringIgnoreErrors(utils.Destination)) + + dest := utils.NewPASSporTDestinationsIdentity(strings.Split(destTn, utils.INFIELD_SEP), strings.Split(destURI, utils.INFIELD_SEP)) + + var orig *utils.PASSporTOriginsIdentity + if origURI := ev.GetStringIgnoreErrors(utils.STIROriginatorURI); origURI != utils.EmptyString { + orig = utils.NewPASSporTOriginsIdentity(utils.EmptyString, origURI) + } else { + orig = utils.NewPASSporTOriginsIdentity( + utils.FirstNonEmpty(ev.GetStringIgnoreErrors(utils.STIROriginatorTn), + ev.GetStringIgnoreErrors(utils.Account)), + utils.EmptyString) + } + pubkeyPath := utils.FirstNonEmpty(ev.GetStringIgnoreErrors(utils.STIRPublicKeyPath), sS.cgrCfg.SessionSCfg().STIRPublicKeyPath) + prvkeyPath := utils.FirstNonEmpty(ev.GetStringIgnoreErrors(utils.STIRPrivateKeyPath), sS.cgrCfg.SessionSCfg().STIRPrivateKeyPath) + + payload := utils.NewPASSporTPayload(attest, args.CGREvent.ID, *dest, *orig) + header := utils.NewPASSporTHeader(pubkeyPath) + if rply.STIRIdentity, err = NewIdentity(header, payload, prvkeyPath, sS.cgrCfg.GeneralCfg().ReplyTimeout); err != nil { + return utils.NewSTIRError(err.Error()) + } } // check for *attribute if argsFlagsWithParams.HasKey(utils.MetaAttributes) { diff --git a/utils/consts.go b/utils/consts.go index 496223400..2b2e17739 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -669,7 +669,8 @@ const ( MetaRelease = "*release" MetaAllocate = "*allocate" MetaAuthorize = "*authorize" - MetaSTIRAuthorize = "*stir_authorize" + MetaSTIRAuthenticate = "*stir_authenticate" + MetaSTIRInitiate = "*stir_initiate" MetaInit = "*init" MetaRatingPlanCost = "*rating_plan_cost" RatingPlanIDs = "RatingPlanIDs" @@ -1985,6 +1986,8 @@ const ( STIROriginatorURI = "STIROriginatorURI" STIRDestinationTn = "STIRDestinationTn" STIRDestinationURI = "STIRDestinationURI" + STIRPublicKeyPath = "STIRPublicKeyPath" + STIRPrivateKeyPath = "STIRPrivateKeyPath" STIRExtraInfoPrefix = ";info=<" STIRExtraInfoSuffix = ">;alg=ES256;ppt=shaken" diff --git a/utils/errors.go b/utils/errors.go index 895f48a2c..4b7dee197 100644 --- a/utils/errors.go +++ b/utils/errors.go @@ -264,5 +264,5 @@ func ErrNotConvertibleTF(from, to string) error { // NewSTIRError returns a error with a *stir_authorize prefix func NewSTIRError(reason string) error { - return fmt.Errorf("%s: %s", MetaSTIRAuthorize, reason) + return fmt.Errorf("%s: %s", MetaSTIRAuthenticate, reason) } diff --git a/utils/errors_test.go b/utils/errors_test.go index d223e7c03..98ba2fc73 100644 --- a/utils/errors_test.go +++ b/utils/errors_test.go @@ -239,7 +239,7 @@ func TestNewErrChargerS(t *testing.T) { } func TestNewSTIRError(t *testing.T) { - expected := `*stir_authorize: wrong header` + expected := `*stir_authenticate: wrong header` if rcv := NewSTIRError("wrong header"); rcv.Error() != expected { t.Errorf("Expecting: %q, received: %q", expected, rcv.Error()) }