Added integration test for *stir_authorize

This commit is contained in:
Trial97
2020-04-16 15:42:58 +03:00
committed by Dan Christian Bogos
parent 465b0279cd
commit 0fadf12a51
17 changed files with 627 additions and 160 deletions

10
data/stir/generate_keys.sh Executable file
View File

@@ -0,0 +1,10 @@
#!/bin/sh
# generate private the key for ES256
openssl ecparam -genkey -name prime256v1 -noout -out stir_privatekey.pem
# generate the public key based on the private key
openssl ec -in stir_privatekey.pem -pubout -out stir_pubkey.pem
#generate the certificate for the private key
openssl req -new -x509 -key stir_privatekey.pem -out stir_cert.pem -days 3650 -subj "/C=DE/ST=Bavaria/L=Bad Reichenhall/O=ITsysCOM/OU=root/CN=localhost/emailAddress=contact@itsyscom.com"

16
data/stir/stir_cert.pem Normal file
View File

@@ -0,0 +1,16 @@
-----BEGIN CERTIFICATE-----
MIICczCCAhqgAwIBAgIJAMfbYJAZnigjMAoGCCqGSM49BAMCMIGUMQswCQYDVQQG
EwJERTEQMA4GA1UECAwHQmF2YXJpYTEYMBYGA1UEBwwPQmFkIFJlaWNoZW5oYWxs
MREwDwYDVQQKDAhJVHN5c0NPTTENMAsGA1UECwwEcm9vdDESMBAGA1UEAwwJbG9j
YWxob3N0MSMwIQYJKoZIhvcNAQkBFhRjb250YWN0QGl0c3lzY29tLmNvbTAeFw0y
MDA0MTYxMTU4MDBaFw0zMDA0MTQxMTU4MDBaMIGUMQswCQYDVQQGEwJERTEQMA4G
A1UECAwHQmF2YXJpYTEYMBYGA1UEBwwPQmFkIFJlaWNoZW5oYWxsMREwDwYDVQQK
DAhJVHN5c0NPTTENMAsGA1UECwwEcm9vdDESMBAGA1UEAwwJbG9jYWxob3N0MSMw
IQYJKoZIhvcNAQkBFhRjb250YWN0QGl0c3lzY29tLmNvbTBZMBMGByqGSM49AgEG
CCqGSM49AwEHA0IABI0uM5lqLWKilgdv7J/uL9blKDwENjdmba1LJnsJJdxKwGyK
JF0mUq7nCTz7M5QbWG24XJm1wuwyj/bvT6vxp1ajUzBRMB0GA1UdDgQWBBT6VrVO
TDbfJs5R/JG8xBTe8O8TkTAfBgNVHSMEGDAWgBT6VrVOTDbfJs5R/JG8xBTe8O8T
kTAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0cAMEQCID2rMfvx3Qyvvqr2
WMz4AgV1Yplp6kI0FDEH2w0GiTjoAiBsIF1TsUAwmmXYW8yaPyCVq7LYK9TUP2bu
oa27qsM7gA==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEICcL1+2nj9ylMlTKjSpIGx03gALK0cISciviwudQuvb9oAoGCCqGSM49
AwEHoUQDQgAEjS4zmWotYqKWB2/sn+4v1uUoPAQ2N2ZtrUsmewkl3ErAbIokXSZS
rucJPPszlBtYbbhcmbXC7DKP9u9Pq/GnVg==
-----END EC PRIVATE KEY-----

View File

@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjS4zmWotYqKWB2/sn+4v1uUoPAQ2
N2ZtrUsmewkl3ErAbIokXSZSrucJPPszlBtYbbhcmbXC7DKP9u9Pq/GnVg==
-----END PUBLIC KEY-----

View File

@@ -47,6 +47,7 @@ var (
testSes2ItLoadFromFolder,
testSes2ItInitSession,
testSes2ItAsActiveSessions,
testSes2StirAuthorize,
testSes2ItStopCgrEngine,
}
)
@@ -179,3 +180,41 @@ func testSes2ItStopCgrEngine(t *testing.T) {
t.Error(err)
}
}
func testSes2StirAuthorize(t *testing.T) {
args := &sessions.V1ProcessEventArgs{
Flags: []string{"*stir_authorize"},
CGREvent: &utils.CGREvent{
Tenant: "cgrates.org",
ID: "testSes2StirAuthorize",
Event: map[string]interface{}{
utils.ToR: utils.VOICE,
utils.OriginID: "testSes2StirAuthorize",
utils.RequestType: utils.META_PREPAID,
utils.Account: "1001",
utils.Subject: "ANY2CNT",
utils.Destination: "1002",
utils.Usage: 10 * time.Minute,
utils.STIRIdentity: "eyJhbGciOiJFUzI1NiIsInBwdCI6InNoYWtlbiIsInR5cCI6InBhc3Nwb3J0IiwieDV1IjoiL3Vzci9zaGFyZS9jZ3JhdGVzL3N0aXIvc3Rpcl9wdWJrZXkucGVtIn0.eyJhdHRlc3QiOiJBIiwiZGVzdCI6eyJ0biI6WyIxMDAyIl19LCJpYXQiOjE1ODcwMzg4MDIsIm9yaWciOnsidG4iOiIxMDAxIn0sIm9yaWdpZCI6IjEyMzQ1NiJ9.cMEMlFnfyTu8uxfeU4RoZTamA7ifFT9Ibwrvi1_LKwL2xAU6fZ_CSIxKbtyOpNhM_sV03x7CfA_v0T4sHkifzg;info=</usr/share/cgrates/stir/stir_pubkey.pem>;ppt=shaken",
},
},
}
var rply sessions.V1ProcessEventReply
if err := ses2RPC.Call(utils.SessionSv1ProcessEvent,
args, &rply); err != nil { // no error verificated with success
t.Error(err)
}
// 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)
}
// altered identity
args.CGREvent.Event[utils.STIRIdentity] = "eyJhbGciOiJFUzI1NiIsInBwdCI6InNoYWtlbiIsInR5cCI6InBhc3Nwb3J0IiwieDV1IjoiL3Vzci9zaGFyZS9jZ3JhdGVzL3N0aXIvc3Rpcl9wdWJrZXkucGVtIn0.eyJhdHRlc3QiOiJBIiwiZGVzdCI6eyJ0biI6WyIxMDAyIl19LCJpYXQiOjE1ODcwMzg4MDIsIm9yaWciOnsidG4iOiIxMDA1In0sIm9yaWdpZCI6IjEyMzQ1NiJ9.cMEMlFnfyTu8uxfeU4RoZTamA7ifFT9Ibwrvi1_LKwL2xAU6fZ_CSIxKbtyOpNhM_sV03x7CfA_v0T4sHkifzg;info=</usr/share/cgrates/stir/stir_pubkey.pem>;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)
}
}

View File

@@ -50,6 +50,7 @@ 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
-- Alexandru Tripon <alexandru.tripon@itsyscom.com> Wed, 19 Feb 2020 13:25:52 +0200

View File

@@ -24,6 +24,7 @@ import (
"strings"
"time"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
"github.com/dgrijalva/jwt-go"
@@ -205,23 +206,19 @@ func (pi *ProcessedStirIdentity) VerifyPayload(originatorTn, originatorURI, dest
if hdrMaxDur >= 0 && time.Now().After(time.Unix(pi.Payload.IAT, 0).Add(hdrMaxDur)) {
return errors.New("expired payload")
}
if originatorTn != utils.EmptyString {
if originatorTn != pi.Payload.Orig.Tn {
return errors.New("wrong originatorTn")
}
} else {
if originatorURI != utils.EmptyString {
if originatorURI != pi.Payload.Orig.URI {
return errors.New("wrong originatorURI")
}
} else if originatorTn != pi.Payload.Orig.Tn {
return errors.New("wrong originatorTn")
}
if destinationTn != utils.EmptyString {
if !utils.SliceHasMember(pi.Payload.Dest.Tn, destinationTn) {
return errors.New("wrong destinationTn")
}
} else {
if destinationURI != utils.EmptyString {
if !utils.SliceHasMember(pi.Payload.Dest.URI, destinationURI) {
return errors.New("wrong destinationURI")
}
} else if !utils.SliceHasMember(pi.Payload.Dest.Tn, destinationTn) {
return errors.New("wrong destinationTn")
}
return
}
@@ -258,7 +255,7 @@ func NewIdentity(header *utils.PASSporTHeader, payload *utils.PASSporTPayload, p
return
}
func authStirShaken(identity, originatorTn, originatorURI, destinationTn, destinationURI string,
func AuthStirShaken(identity, originatorTn, originatorURI, destinationTn, destinationURI string,
attest *utils.StringSet, hdrMaxDur time.Duration) (err error) {
var pi *ProcessedStirIdentity
if pi, err = NewProcessedIdentity(identity); err != nil {
@@ -267,8 +264,8 @@ func authStirShaken(identity, originatorTn, originatorURI, destinationTn, destin
if !pi.VerifyHeader() {
return errors.New("wrong header")
}
if err = pi.VerifySignature(time.Second); err != nil {
if err = pi.VerifySignature(config.CgrConfig().GeneralCfg().ReplyTimeout); err != nil {
return
}
return pi.VerifyPayload(originatorTn, originatorURI, destinationTn, destinationURI, hdrMaxDur, attest) // verificare in lista
return pi.VerifyPayload(originatorTn, originatorURI, destinationTn, destinationURI, hdrMaxDur, attest)
}

View File

@@ -25,6 +25,7 @@ import (
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
"github.com/dgrijalva/jwt-go"
)
func TestLibSessionSGetSetCGRID(t *testing.T) {
@@ -146,3 +147,165 @@ func TestGetFlagIDs(t *testing.T) {
t.Errorf("Expected %s , received: %s", utils.ToJSON(eOut), utils.ToJSON(rcv))
}
}
func TestNewProcessedIdentity(t *testing.T) {
if _, err := NewProcessedIdentity(""); err == nil ||
err.Error() != "missing parts of the message header" {
t.Errorf("Expected %q received: %v", "missing parts of the message header", err)
}
if _, err := NewProcessedIdentity(";"); err == nil ||
err.Error() != "wrong header format" {
t.Errorf("Expected %q received: %v", "wrong header format", err)
}
if _, err := NewProcessedIdentity("eyJhbGciOiJFUzI1NiIsInBwdCI6InNoYWtlbiIsInR,5cCI6InBhc3Nwb3J0IiwieDV1IjoiaHR0cHM6Ly93d3cuZXhhbXBsZS5vcmcvY2VydC5jZXIifQ.eyJhdHRlc3QiOiJBIiwiZGVzdCI6eyJ0biI6WyIxMDAyIl19LCJpYXQiOjE1ODcwMTk4MjIsIm9yaWc,iOnsidG4iOiIxMDAxIn0sIm9yaWdpZCI6IjEyMzQ1NiJ9.4ybtWmgqdkNyJLS9Iv3PuJV8ZxR7yZ_NEBhCpKCEu2WBiTchqwoqoWpI17Q_ALm38tbnpay32t95ZY_LhSgwJg;info=<https://www.example.org/cert.cer>;ppt=shaken"); err == nil {
t.Errorf("Expected error")
}
if _, err := NewProcessedIdentity("eyJhbGciOiJFUzI1NiIsInBwdCI6InNoYWtlbiIsInR5cCI6InBhc3Nwb3J0IiwieDV1IjoiaHR0cHM6Ly93d3cuZXhhbXBsZS5vcmcvY2VydC5jZXIifQ.eyJhdHRlc3QiOiJBIiwiZGVzdCI6eyJ0biI6WyIxMDAyIl19LCJpYXQiOjE1ODcwMTk4MjIsIm9yaWc,iOnsidG4iOiIxMDAxIn0sIm9yaWdpZCI6IjEyMzQ1NiJ9.4ybtWmgqdkNyJLS9Iv3PuJV8ZxR7yZ_NEBhCpKCEu2WBiTchqwoqoWpI17Q_ALm38tbnpay32t95ZY_LhSgwJg;info=<https://www.example.org/cert.cer>;ppt=shaken"); err == nil {
t.Errorf("Expected error")
}
expected := &ProcessedStirIdentity{
Tokens: []string{"info=<https://www.example.org/cert.cer>", "ppt=shaken"},
SigningStr: "eyJhbGciOiJFUzI1NiIsInBwdCI6InNoYWtlbiIsInR5cCI6InBhc3Nwb3J0IiwieDV1IjoiaHR0cHM6Ly93d3cuZXhhbXBsZS5vcmcvY2VydC5jZXIifQ.eyJhdHRlc3QiOiJBIiwiZGVzdCI6eyJ0biI6WyIxMDAyIl19LCJpYXQiOjE1ODcwMTk4MjIsIm9yaWciOnsidG4iOiIxMDAxIn0sIm9yaWdpZCI6IjEyMzQ1NiJ9",
Signature: "4ybtWmgqdkNyJLS9Iv3PuJV8ZxR7yZ_NEBhCpKCEu2WBiTchqwoqoWpI17Q_ALm38tbnpay32t95ZY_LhSgwJg",
Header: &utils.PASSporTHeader{
Typ: utils.STIRTyp,
Alg: utils.STIRAlg,
Ppt: utils.STIRPpt,
X5u: "https://www.example.org/cert.cer",
},
Payload: &utils.PASSporTPayload{
ATTest: "A",
Dest: utils.PASSporTDestinationsIdentity{
Tn: []string{"1002"},
},
IAT: 1587019822,
Orig: utils.PASSporTOriginsIdentity{
Tn: "1001",
},
OrigID: "123456",
},
}
if rply, err := NewProcessedIdentity("eyJhbGciOiJFUzI1NiIsInBwdCI6InNoYWtlbiIsInR5cCI6InBhc3Nwb3J0IiwieDV1IjoiaHR0cHM6Ly93d3cuZXhhbXBsZS5vcmcvY2VydC5jZXIifQ.eyJhdHRlc3QiOiJBIiwiZGVzdCI6eyJ0biI6WyIxMDAyIl19LCJpYXQiOjE1ODcwMTk4MjIsIm9yaWciOnsidG4iOiIxMDAxIn0sIm9yaWdpZCI6IjEyMzQ1NiJ9.4ybtWmgqdkNyJLS9Iv3PuJV8ZxR7yZ_NEBhCpKCEu2WBiTchqwoqoWpI17Q_ALm38tbnpay32t95ZY_LhSgwJg;info=<https://www.example.org/cert.cer>;ppt=shaken"); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(expected, rply) {
t.Errorf("Expected: %s, received:%s", utils.ToJSON(expected), utils.ToJSON(rply))
}
}
func TestProcessedIdentityVerifyHeader(t *testing.T) {
args := &ProcessedStirIdentity{
Tokens: []string{"info=<https://www.example.org/cert.cer>", "ppt=shaken", "extra", "alg=ES256"},
Header: &utils.PASSporTHeader{
Typ: utils.STIRTyp,
Alg: utils.STIRAlg,
Ppt: utils.STIRPpt,
X5u: "https://www.example.org/cert.cer",
},
}
if !args.VerifyHeader() {
t.Errorf("Expected the header to be valid")
}
args.Header.Typ = "1"
if args.VerifyHeader() {
t.Errorf("Expected the header to not be valid")
}
args.Tokens = []string{"info=<https://www.example.org/cert.cer>", "ppt=shaken", "alg=wrongArg"}
if args.VerifyHeader() {
t.Errorf("Expected the header to not be valid")
}
args.Tokens = []string{"info=<https://www.example.org/cert.cer>", "ppt=wrongExtension"}
if args.VerifyHeader() {
t.Errorf("Expected the header to not be valid")
}
args.Tokens = []string{"info=<", "ppt=shaken"}
if args.VerifyHeader() {
t.Errorf("Expected the header to not be valid")
}
}
func TestProcessedIdentityVerifyPayload(t *testing.T) {
args := &ProcessedStirIdentity{
Payload: &utils.PASSporTPayload{
ATTest: "C",
Dest: utils.PASSporTDestinationsIdentity{
Tn: []string{"1002"},
},
IAT: 1587019822,
Orig: utils.PASSporTOriginsIdentity{
Tn: "1001",
},
OrigID: "123456",
},
}
if err := args.VerifyPayload("1001", "", "1002", "", -1, utils.NewStringSet([]string{utils.META_ANY})); err != nil {
t.Error(err)
}
if err := args.VerifyPayload("1001", "", "1003", "", -1, utils.NewStringSet([]string{utils.META_ANY})); err == nil ||
err.Error() != "wrong destinationTn" {
t.Errorf("Expected error: %s,receved %v", "wrong destinationTn", err)
}
if err := args.VerifyPayload("1001", "", "1003", "1002", -1, utils.NewStringSet([]string{utils.META_ANY})); err == nil ||
err.Error() != "wrong destinationURI" {
t.Errorf("Expected error: %s,receved %v", "wrong destinationURI", err)
}
if err := args.VerifyPayload("1002", "", "1003", "1002", -1, utils.NewStringSet([]string{utils.META_ANY})); err == nil ||
err.Error() != "wrong originatorTn" {
t.Errorf("Expected error: %s,receved %v", "wrong originatorTn", err)
}
if err := args.VerifyPayload("1002", "1001", "1003", "1002", -1, utils.NewStringSet([]string{utils.META_ANY})); err == nil ||
err.Error() != "wrong originatorURI" {
t.Errorf("Expected error: %s,receved %v", "wrong originatorURI", err)
}
if err := args.VerifyPayload("1001", "", "1002", "", time.Second, utils.NewStringSet([]string{utils.META_ANY})); err == nil ||
err.Error() != "expired payload" {
t.Errorf("Expected error: %s,receved %v", "expired payload", err)
}
if err := args.VerifyPayload("1001", "", "1002", "", time.Second, utils.NewStringSet([]string{"A"})); err == nil ||
err.Error() != "wrong attest level" {
t.Errorf("Expected error: %s,receved %v", "wrong attest level", err)
}
}
func TestAuthStirShaken(t *testing.T) {
if err := AuthStirShaken("", "1001", "", "1002", "", utils.NewStringSet([]string{utils.META_ANY}), -1); err == nil {
t.Error("Expected invalid identity")
}
if err := AuthStirShaken(
"eyJhbGciOiJFUzI1NiIsInBwdCI6InNoYWtlbiIsInR5cCI6InBhc3Nwb3J0IiwieDV1IjoiaHR0cHM6Ly93d3cuZXhhbXBsZS5vcmcvY2VydC5jZXIifQ.eyJhdHRlc3QiOiJBIiwiZGVzdCI6eyJ0biI6WyIxMDAyIl19LCJpYXQiOjE1ODcwMTk4MjIsIm9yaWciOnsidG4iOiIxMDAxIn0sIm9yaWdpZCI6IjEyMzQ1NiJ9.4ybtWmgqdkNyJLS9Iv3PuJV8ZxR7yZ_NEBhCpKCEu2WBiTchqwoqoWpI17Q_ALm38tbnpay32t95ZY_LhSgwJg;info=<https://www.example.org/cert.cer2>;ppt=shaken",
"1001", "", "1002", "", utils.NewStringSet([]string{utils.META_ANY}), -1); err == nil {
t.Error("Expected invalid identity")
}
engine.Cache.Set(utils.CacheSTIR, "https://www.example.org/cert.cer", nil,
nil, true, utils.NonTransactional)
if err := AuthStirShaken(
"eyJhbGciOiJFUzI1NiIsInBwdCI6InNoYWtlbiIsInR5cCI6InBhc3Nwb3J0IiwieDV1IjoiaHR0cHM6Ly93d3cuZXhhbXBsZS5vcmcvY2VydC5jZXIifQ.eyJhdHRlc3QiOiJBIiwiZGVzdCI6eyJ0biI6WyIxMDAyIl19LCJpYXQiOjE1ODcwMTk4MjIsIm9yaWciOnsidG4iOiIxMDAxIn0sIm9yaWdpZCI6IjEyMzQ1NiJ9.4ybtWmgqdkNyJLS9Iv3PuJV8ZxR7yZ_NEBhCpKCEu2WBiTchqwoqoWpI17Q_ALm38tbnpay32t95ZY_LhSgwJg;info=<https://www.example.org/cert.cer>;ppt=shaken", "1001", "", "1002", "", utils.NewStringSet([]string{utils.META_ANY}), -1); err == nil {
t.Error("Expected invalid identity")
}
pubkeyBuf := []byte(`-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESt8sEh55Yc579vLHjFRWVQO27p4Y
aa+jqv4dwkr/FLEcN1zC76Y/IniI65fId55hVJvN3ORuzUqYEtzD3irmsw==
-----END PUBLIC KEY-----
`)
pubKey, err := jwt.ParseECPublicKeyFromPEM(pubkeyBuf)
if err != nil {
t.Fatal(err)
}
engine.Cache.Set(utils.CacheSTIR, "https://www.example.org/cert.cer", pubKey,
nil, true, utils.NonTransactional)
if err := AuthStirShaken(
"eyJhbGciOiJFUzI1NiIsInBwdCI6InNoYWtlbiIsInR5cCI6InBhc3Nwb3J0IiwieDV1IjoiaHR0cHM6Ly93d3cuZXhhbXBsZS5vcmcvY2VydC5jZXIifQ.eyJhdHRlc3QiOiJBIiwiZGVzdCI6eyJ0biI6WyIxMDAyIl19LCJpYXQiOjE1ODcwMTk4MjIsIm9yaWciOnsidG4iOiIxMDAxIn0sIm9yaWdpZCI6IjEyMzQ1NiJ9.4ybtWmgqdkNyJLS9Iv3PuJV8ZxR7yZ_NEBhCpKCEu2WBiTchqwoqoWpI17Q_ALm38tbnpay32t95ZY_LhSgwJg;info=<https://www.example.org/cert.cer>;ppt=shaken", "1001", "", "1003", "", utils.NewStringSet([]string{utils.META_ANY}), -1); err == nil {
t.Error("Expected invalid identity")
}
if err := AuthStirShaken(
"eyJhbGciOiJFUzI1NiIsInBwdCI6InNoYWtlbiIsInR5cCI6InBhc3Nwb3J0IiwieDV1IjoiaHR0cHM6Ly93d3cuZXhhbXBsZS5vcmcvY2VydC5jZXIifQ.eyJhdHRlc3QiOiJBIiwiZGVzdCI6eyJ0biI6WyIxMDAyIl19LCJpYXQiOjE1ODcwMTk4MjIsIm9yaWciOnsidG4iOiIxMDAxIn0sIm9yaWdpZCI6IjEyMzQ1NiJ9.4ybtWmgqdkNyJLS9Iv3PuJV8ZxR7yZ_NEBhCpKCEu2WBiTchqwoqoWpI17Q_ALm38tbnpay32t95ZY_LhSgwJg;info=<https://www.example.org/cert.cer>;ppt=shaken", "1001", "", "1002", "", utils.NewStringSet([]string{utils.META_ANY}), -1); err != nil {
t.Fatal(err)
}
}

View File

@@ -361,12 +361,10 @@ func TestSessionAsCGREvents(t *testing.T) {
CGRID: "RandomCGRID",
Tenant: "cgrates.org",
EventStart: engine.NewMapEvent(startEv),
SRuns: []*SRun{
&SRun{
SRuns: []*SRun{{
Event: engine.NewMapEvent(ev),
TotalUsage: time.Duration(2 * time.Second),
},
},
}},
}
//check for some fields if populated correct
cgrEvs, err := s.asCGREvents()
@@ -420,16 +418,13 @@ func TestSessionAsExternalSessions(t *testing.T) {
Tenant: "cgrates.org",
EventStart: engine.NewMapEvent(startEv),
DebitInterval: time.Second,
SRuns: []*SRun{
&SRun{
SRuns: []*SRun{{
Event: engine.NewMapEvent(ev),
TotalUsage: time.Duration(2 * time.Second),
NextAutoDebit: &tTime,
},
},
}},
}
exp := []*ExternalSession{
&ExternalSession{
exp := []*ExternalSession{{
CGRID: "RandomCGRID",
RunID: utils.MetaDefault,
ToR: utils.VOICE,
@@ -456,8 +451,7 @@ func TestSessionAsExternalSessions(t *testing.T) {
// aSs[i].MaxRate: sr.CD.MaxRate,
// aSs[i].MaxRateUnit: sr.CD.MaxRateUnit,
// aSs[i].MaxCostSoFar: sr.CD.MaxCostSoFar,
},
}
}}
//check for some fields if populated correct
rply := s.AsExternalSessions("", "ALL")
if !reflect.DeepEqual(exp, rply) {
@@ -503,8 +497,7 @@ func TestSessionAsExternalSessions2(t *testing.T) {
Tenant: "cgrates.org",
EventStart: engine.NewMapEvent(startEv),
DebitInterval: time.Second,
SRuns: []*SRun{
&SRun{
SRuns: []*SRun{{
Event: engine.NewMapEvent(ev),
TotalUsage: time.Duration(2 * time.Second),
CD: &engine.CallDescriptor{
@@ -513,12 +506,10 @@ func TestSessionAsExternalSessions2(t *testing.T) {
MaxRate: 11,
MaxRateUnit: 30 * time.Second,
MaxCostSoFar: 20,
},
},
}},
},
}
exp := []*ExternalSession{
&ExternalSession{
exp := []*ExternalSession{{
CGRID: "RandomCGRID",
RunID: utils.MetaDefault,
ToR: utils.VOICE,
@@ -544,8 +535,7 @@ func TestSessionAsExternalSessions2(t *testing.T) {
MaxRate: 11,
MaxRateUnit: 30 * time.Second,
MaxCostSoFar: 20,
},
}
}}
//check for some fields if populated correct
rply := s.AsExternalSessions("", "ALL")
if !reflect.DeepEqual(exp, rply) {
@@ -593,8 +583,7 @@ func TestSessionAsExternalSessions3(t *testing.T) {
Tenant: "cgrates.org",
EventStart: engine.NewMapEvent(startEv),
DebitInterval: time.Second,
SRuns: []*SRun{
&SRun{
SRuns: []*SRun{{
Event: engine.NewMapEvent(ev),
TotalUsage: time.Duration(2 * time.Second),
CD: &engine.CallDescriptor{
@@ -605,8 +594,7 @@ func TestSessionAsExternalSessions3(t *testing.T) {
MaxCostSoFar: 20,
},
NextAutoDebit: &tTime,
},
},
}},
}
exp := &ExternalSession{
CGRID: "RandomCGRID",
@@ -663,7 +651,8 @@ func TestSessiontotalUsage(t *testing.T) {
EventStart: engine.NewMapEvent(nil),
DebitInterval: time.Duration(18),
SRuns: []*SRun{
{Event: engine.NewMapEvent(nil),
{
Event: engine.NewMapEvent(nil),
CD: &engine.CallDescriptor{Category: "test"},
EventCost: &engine.EventCost{CGRID: "testCGRID"},
ExtraDuration: time.Duration(1),
@@ -671,7 +660,8 @@ func TestSessiontotalUsage(t *testing.T) {
TotalUsage: time.Duration(5),
NextAutoDebit: &tTime,
},
{Event: engine.NewMapEvent(nil),
{
Event: engine.NewMapEvent(nil),
CD: &engine.CallDescriptor{Category: "test2"},
EventCost: &engine.EventCost{CGRID: "testCGRID2"},
ExtraDuration: time.Duration(4),
@@ -714,5 +704,73 @@ func TestSessionstopDebitLoops(t *testing.T) {
if session.debitStop != nil {
t.Errorf("Expecting: nil, received: %s", utils.ToJSON(session.debitStop))
}
}
func TestUpdateSRuns(t *testing.T) {
startEv := map[string]interface{}{
utils.EVENT_NAME: "TEST_EVENT",
utils.ToR: utils.VOICE,
utils.OriginID: "123451",
utils.Account: "1001",
utils.Subject: "1001",
utils.Destination: "1004",
utils.Category: "call",
utils.Tenant: "cgrates.org",
utils.RequestType: utils.META_PREPAID,
utils.SetupTime: time.Date(2016, time.January, 5, 18, 30, 59, 0, time.UTC),
utils.AnswerTime: time.Date(2016, time.January, 5, 18, 31, 05, 0, time.UTC),
utils.Usage: time.Duration(2 * time.Second),
utils.Cost: 12.12,
}
ev := map[string]interface{}{
utils.EVENT_NAME: "TEST_EVENT2",
utils.ToR: utils.VOICE,
utils.OriginID: "123451",
utils.Account: "1001",
utils.Subject: "1001",
utils.Destination: "1004",
utils.Category: "call",
utils.RunID: utils.MetaDefault,
utils.Tenant: "cgrates.org",
utils.RequestType: utils.META_PREPAID,
utils.SetupTime: time.Date(2016, time.January, 5, 18, 30, 59, 0, time.UTC),
utils.AnswerTime: time.Date(2016, time.January, 5, 18, 31, 05, 0, time.UTC),
utils.Usage: time.Duration(2 * time.Second),
utils.Cost: 12.13,
}
s := &Session{
CGRID: "RandomCGRID",
Tenant: "cgrates.org",
EventStart: engine.NewMapEvent(startEv),
DebitInterval: time.Second,
SRuns: []*SRun{{
Event: engine.NewMapEvent(ev),
TotalUsage: time.Duration(2 * time.Second),
CD: &engine.CallDescriptor{
LoopIndex: 10,
DurationIndex: 3 * time.Second,
MaxRate: 11,
MaxRateUnit: 30 * time.Second,
MaxCostSoFar: 20,
},
}},
}
updEv := map[string]interface{}{
utils.EVENT_NAME: "TEST_EVENT2",
utils.Tenant: "cgrates.org",
utils.RequestType: utils.META_POSTPAID,
}
s.updateSRuns(updEv, utils.NewStringSet(nil))
if s.SRuns[0].Event[utils.RequestType] != utils.META_PREPAID {
t.Errorf("Expected session to not change")
}
s.UpdateSRuns(updEv, utils.NewStringSet(nil))
if s.SRuns[0].Event[utils.RequestType] != utils.META_PREPAID {
t.Errorf("Expected session to not change")
}
s.UpdateSRuns(updEv, utils.NewStringSet([]string{utils.RequestType}))
if s.SRuns[0].Event[utils.RequestType] != utils.META_POSTPAID {
t.Errorf("Expected request type to be: %q, received: %q",
utils.META_POSTPAID, s.SRuns[0].Event[utils.RequestType])
}
}

View File

@@ -2965,7 +2965,7 @@ func (sS *SessionS) BiRPCv1ProcessEvent(clnt rpcclient.ClientConnector,
if stirMaxDur, err = ev.GetDuration(utils.STIRPayloadMaxDuration); err != nil {
stirMaxDur = sS.cgrCfg.SessionSCfg().STIRPayloadMaxduration
}
if err = authStirShaken(ev.GetStringIgnoreErrors(utils.STIRIdentity),
if err = AuthStirShaken(ev.GetStringIgnoreErrors(utils.STIRIdentity),
utils.FirstNonEmpty(ev.GetStringIgnoreErrors(utils.STIROriginatorTn), ev.GetStringIgnoreErrors(utils.Account)),
ev.GetStringIgnoreErrors(utils.STIROriginatorURI),
utils.FirstNonEmpty(ev.GetStringIgnoreErrors(utils.STIRDestinationTn), ev.GetStringIgnoreErrors(utils.Destination)),

View File

@@ -30,7 +30,6 @@ import (
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
"github.com/cgrates/rpcclient"
"github.com/dgrijalva/jwt-go"
)
var attrs = &engine.AttrSProcessEventReply{
@@ -2209,22 +2208,3 @@ func TestSessionSfilterSessionsCount(t *testing.T) {
t.Errorf("Expected %v , received: %s", 2, utils.ToJSON(noSess))
}
}
func TestStirShaken(t *testing.T) {
pubkeyBuf := []byte(`-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESt8sEh55Yc579vLHjFRWVQO27p4Y
aa+jqv4dwkr/FLEcN1zC76Y/IniI65fId55hVJvN3ORuzUqYEtzD3irmsw==
-----END PUBLIC KEY-----
`)
pubKey, err := jwt.ParseECPublicKeyFromPEM(pubkeyBuf)
if err != nil {
t.Fatal(err)
}
engine.Cache.Set(utils.CacheSTIR, "https://www.example.org/cert.cer", pubKey,
nil, true, utils.NonTransactional)
if err := authStirShaken(
"eyJhbGciOiJFUzI1NiIsInBwdCI6InNoYWtlbiIsInR5cCI6InBhc3Nwb3J0IiwieDV1IjoiaHR0cHM6Ly93d3cuZXhhbXBsZS5vcmcvY2VydC5jZXIifQ.eyJhdHRlc3QiOiJBIiwiZGVzdCI6eyJ0biI6WyIxMDAyIl19LCJpYXQiOjE1ODcwMTk4MjIsIm9yaWciOnsidG4iOiIxMDAxIn0sIm9yaWdpZCI6IjEyMzQ1NiJ9.4ybtWmgqdkNyJLS9Iv3PuJV8ZxR7yZ_NEBhCpKCEu2WBiTchqwoqoWpI17Q_ALm38tbnpay32t95ZY_LhSgwJg;info=<https://www.example.org/cert.cer>;ppt=shaken", "1001", "", "1002", "", utils.NewStringSet([]string{utils.META_ANY}), -1); err != nil {
t.Fatal(err)
}
}

View File

@@ -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", MetaSTIRAuthorize, reason)
}

View File

@@ -230,3 +230,17 @@ func TestErrNotConvertibleTF(t *testing.T) {
t.Errorf("Expecting: not convertible : from: test_type1 to:test_type2, received: %+v", rcv)
}
}
func TestNewErrChargerS(t *testing.T) {
expected := `CHARGERS_ERROR:NOT_FOUND`
if rcv := NewErrChargerS(ErrNotFound); rcv.Error() != expected {
t.Errorf("Expecting: %q, received: %q", expected, rcv.Error())
}
}
func TestNewSTIRError(t *testing.T) {
expected := `*stir_authorize: wrong header`
if rcv := NewSTIRError("wrong header"); rcv.Error() != expected {
t.Errorf("Expecting: %q, received: %q", expected, rcv.Error())
}
}

View File

@@ -70,8 +70,8 @@ type PASSporTOriginsIdentity struct {
}
// NewPASSporTPayload returns an new PASSporTPayload with the given origin and destination
func NewPASSporTPayload(attest, originID string, dest PASSporTDestinationsIdentity, orig PASSporTOriginsIdentity) PASSporTPayload {
return PASSporTPayload{
func NewPASSporTPayload(attest, originID string, dest PASSporTDestinationsIdentity, orig PASSporTOriginsIdentity) *PASSporTPayload {
return &PASSporTPayload{
ATTest: attest,
Dest: dest,
IAT: time.Now().Unix(),

72
utils/stir_shaken_test.go Normal file
View File

@@ -0,0 +1,72 @@
/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package utils
import (
"reflect"
"testing"
)
func TestNewPASSporTHeader(t *testing.T) {
expected := &PASSporTHeader{
Alg: STIRAlg,
Ppt: STIRPpt,
Typ: STIRTyp,
X5u: "path/to/certificate",
}
if rply := NewPASSporTHeader("path/to/certificate"); !reflect.DeepEqual(expected, rply) {
t.Errorf("Expected: %s,received: %s", ToJSON(expected), ToJSON(rply))
}
}
func TestNewPASSporTDestinationsIdentity(t *testing.T) {
expected := &PASSporTDestinationsIdentity{
Tn: []string{"1001"},
URI: []string{"1002@cgrates.org"},
}
if rply := NewPASSporTDestinationsIdentity([]string{"1001"}, []string{"1002@cgrates.org"}); !reflect.DeepEqual(expected, rply) {
t.Errorf("Expected: %s,received: %s", ToJSON(expected), ToJSON(rply))
}
}
func TestNewPASSporTOriginsIdentity(t *testing.T) {
expected := &PASSporTOriginsIdentity{
Tn: "1001",
}
if rply := NewPASSporTOriginsIdentity("1001", ""); !reflect.DeepEqual(expected, rply) {
t.Errorf("Expected: %s,received: %s", ToJSON(expected), ToJSON(rply))
}
}
func TestNewPASSporTPayload(t *testing.T) {
dst := NewPASSporTDestinationsIdentity([]string{"1001"}, nil)
orig := NewPASSporTOriginsIdentity("1002", "")
expected := &PASSporTPayload{
ATTest: "A",
Dest: *dst,
IAT: 0,
Orig: *orig,
OrigID: "123456",
}
rply := NewPASSporTPayload("A", "123456", *dst, *orig)
rply.IAT = 0
if !reflect.DeepEqual(expected, rply) {
t.Errorf("Expected: %s,received: %s", ToJSON(expected), ToJSON(rply))
}
}

View File

@@ -22,6 +22,7 @@ import (
"crypto/ecdsa"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
@@ -31,55 +32,67 @@ import (
"github.com/dgrijalva/jwt-go"
)
// NewECDSAPrvKey creates a private key from the path
func NewECDSAPrvKey(prvKeyPath string, timeout time.Duration) (prvKey *ecdsa.PrivateKey, err error) {
// NewECDSAPrvKeyFromReader creates a private key from io.Reader
func NewECDSAPrvKeyFromReader(reader io.Reader) (prvKey *ecdsa.PrivateKey, err error) {
var prvkeyBuf []byte
if prvkeyBuf, err = GetDataAtPath(prvKeyPath, timeout); err != nil {
if prvkeyBuf, err = ioutil.ReadAll(reader); err != nil {
return
}
return jwt.ParseECPrivateKeyFromPEM(prvkeyBuf)
}
// NewECDSAPubKey returns a public key from the path
func NewECDSAPubKey(pubKeyPath string, timeout time.Duration) (pubKey *ecdsa.PublicKey, err error) {
// NewECDSAPubKeyFromReader returns a public key from io.Reader
func NewECDSAPubKeyFromReader(reader io.Reader) (pubKey *ecdsa.PublicKey, err error) {
var pubkeyBuf []byte
if pubkeyBuf, err = GetDataAtPath(pubKeyPath, timeout); err != nil {
if pubkeyBuf, err = ioutil.ReadAll(reader); err != nil {
return
}
return jwt.ParseECPublicKeyFromPEM(pubkeyBuf)
}
// getURLFile returns the file from URL
func getURLFile(urlVal string, timeout time.Duration) (body []byte, err error) {
// NewECDSAPrvKey creates a private key from the path
func NewECDSAPrvKey(prvKeyPath string, timeout time.Duration) (prvKey *ecdsa.PrivateKey, err error) {
var prvKeyBuf io.ReadCloser
if prvKeyBuf, err = GetReaderFromPath(prvKeyPath, timeout); err != nil {
return
}
prvKey, err = NewECDSAPrvKeyFromReader(prvKeyBuf)
prvKeyBuf.Close()
return
}
// NewECDSAPubKey returns a public key from the path
func NewECDSAPubKey(pubKeyPath string, timeout time.Duration) (pubKey *ecdsa.PublicKey, err error) {
var pubKeyBuf io.ReadCloser
if pubKeyBuf, err = GetReaderFromPath(pubKeyPath, timeout); err != nil {
return
}
pubKey, err = NewECDSAPubKeyFromReader(pubKeyBuf)
pubKeyBuf.Close()
return
}
// GetReaderFromPath returns the reader at the given path
func GetReaderFromPath(path string, timeout time.Duration) (r io.ReadCloser, err error) {
if !IsURL(path) {
return os.Open(path)
}
httpClient := http.Client{
Timeout: timeout,
}
var resp *http.Response
if resp, err = httpClient.Get(urlVal); err != nil {
if resp, err = httpClient.Get(path); err != nil {
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
resp.Body.Close()
err = fmt.Errorf("http status error: %v", resp.StatusCode)
return
}
return ioutil.ReadAll(resp.Body)
}
func GetDataAtPath(path string, timeout time.Duration) (body []byte, err error) {
if IsURL(path) {
return getURLFile(path, timeout)
}
var file *os.File
if file, err = os.Open(path); err != nil {
return
}
body, err = ioutil.ReadAll(file)
file.Close()
return
return resp.Body, nil
}
// EncodeBase64JSON encodes the structure in json and then the string in base64
func EncodeBase64JSON(val interface{}) (enc string, err error) {
var b []byte
if b, err = json.Marshal(val); err != nil {
@@ -89,6 +102,7 @@ func EncodeBase64JSON(val interface{}) (enc string, err error) {
return
}
// DecodeBase64JSON decodes the base64 json string in the given interface
func DecodeBase64JSON(data string, val interface{}) (err error) {
var b []byte
if b, err = jwt.DecodeSegment(data); err != nil {
@@ -97,6 +111,7 @@ func DecodeBase64JSON(data string, val interface{}) (err error) {
return json.Unmarshal(b, val)
}
// RemoveWhiteSpaces removes white spaces from string
func RemoveWhiteSpaces(str string) string {
rout := make([]rune, 0, len(str))
for _, r := range str {

View File

@@ -0,0 +1,93 @@
/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package utils
import (
"bytes"
"math"
"reflect"
"testing"
)
func TestRemoveWhiteSpaces(t *testing.T) {
strWithWS := ` A String
With White Spaces`
expected := `AStringWithWhiteSpaces`
if rply := RemoveWhiteSpaces(strWithWS); rply != expected {
t.Errorf("Expected: %q, received: %q", expected, rply)
}
}
func TestEncodeBase64JSON(t *testing.T) {
var args interface{}
args = math.NaN()
if _, err := EncodeBase64JSON(args); err == nil {
t.Errorf("Expected error")
}
args = map[string]interface{}{"Q": 1}
expected := `eyJRIjoxfQ`
if rply, err := EncodeBase64JSON(args); err != nil {
t.Error(err)
} else if rply != expected {
t.Errorf("Expected: %q,received: %q", expected, rply)
}
}
func TestDecodeBase64JSON(t *testing.T) {
args := `eyJRIjoxfQ`
var rply1 string
if err := DecodeBase64JSON(args, &rply1); err == nil {
t.Errorf("Expected error")
}
var rply2 map[string]interface{}
expected := map[string]interface{}{"Q": 1.}
if err := DecodeBase64JSON(args, &rply2); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(expected, rply2) {
t.Errorf("Expected: %s,received: %s", ToJSON(expected), ToJSON(rply2))
}
args = `eyJRIjoxfQ,`
if err := DecodeBase64JSON(args, &rply2); err == nil {
t.Errorf("Expected error")
}
}
type testErrReader struct{}
func (testErrReader) Read([]byte) (int, error) { return 0, ErrNotFound }
func TestNewECDSAPrvKeyFromReader(t *testing.T) {
if _, err := NewECDSAPrvKeyFromReader(new(testErrReader)); err == nil {
t.Errorf("Expected error")
}
r := bytes.NewBuffer([]byte("invalid certificate"))
if _, err := NewECDSAPrvKeyFromReader(r); err == nil {
t.Errorf("Expected error")
}
}
func TestNewECDSAPubKeyFromReader(t *testing.T) {
if _, err := NewECDSAPubKeyFromReader(new(testErrReader)); err == nil {
t.Errorf("Expected error")
}
r := bytes.NewBuffer([]byte("invalid certificate"))
if _, err := NewECDSAPubKeyFromReader(r); err == nil {
t.Errorf("Expected error")
}
}