Added sentrypeer credentials in config && cache partition

This commit is contained in:
gezimbll
2023-07-14 05:57:42 -04:00
committed by Dan Christian Bogos
parent 2c1f5012fc
commit 9af02771fd
11 changed files with 176 additions and 87 deletions

View File

@@ -55,36 +55,3 @@ func (ban APIBanCfg) Clone() (cln *APIBanCfg) {
}
return
}
type SentryPeerCfg struct {
Token string
Url string
}
func (sp *SentryPeerCfg) loadFromJSONCfg(jsnCfg *SentryPeerJsonCfg) (err error) {
if jsnCfg == nil {
return
}
if jsnCfg.Url != nil {
sp.Url = *jsnCfg.Url
}
if jsnCfg.Token != nil {
sp.Token = *jsnCfg.Token
}
return
}
func (sp *SentryPeerCfg) AsMapInterface() map[string]any {
return map[string]any{
"URL": sp.Url,
"Token": sp.Token,
}
}
func (sp *SentryPeerCfg) Clone() (cln *SentryPeerCfg) {
cln = &SentryPeerCfg{
Url: sp.Url,
Token: sp.Token,
}
return
}

View File

@@ -304,6 +304,7 @@ const CGRATES_CFG_JSON = `
"*uch": {"limit": -1, "ttl": "3h", "static_ttl": false, "remote":false, "replicate": false}, // User cache
"*stir": {"limit": -1, "ttl": "3h", "static_ttl": false, "remote":false, "replicate": false}, // stirShaken cache keys
"*apiban":{"limit": -1, "ttl": "2m", "static_ttl": false, "remote":false, "replicate": false},
"*sentrypeer":{"limit": -1, "ttl": "86400s", "static_ttl": true, "remote":false, "replicate": false},
"*caps_events": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // caps cached samples
"*replication_hosts": {"limit": 0, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // the replication hosts cache(used when replication_filtered is enbled)
},
@@ -1268,7 +1269,8 @@ const CGRATES_CFG_JSON = `
},
"sentrypeer":{
"url":"",
"token":"",
"clientID":"",
"clientSecret":"",
}
}`

View File

@@ -877,8 +877,9 @@ type APIBanJsonCfg struct {
}
type SentryPeerJsonCfg struct {
Token *string
Url *string
ClientID *string
ClientSecret *string
Url *string
}
type CoreSJsonCfg struct {

58
config/sentrypeer.go Normal file
View File

@@ -0,0 +1,58 @@
/*
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 config
type SentryPeerCfg struct {
ClientID string
ClientSecret string
Url string
}
func (sp *SentryPeerCfg) loadFromJSONCfg(jsnCfg *SentryPeerJsonCfg) (err error) {
if jsnCfg == nil {
return
}
if jsnCfg.Url != nil {
sp.Url = *jsnCfg.Url
}
if jsnCfg.ClientSecret != nil {
sp.ClientSecret = *jsnCfg.ClientSecret
}
if jsnCfg.ClientID != nil {
sp.ClientID = *jsnCfg.ClientID
}
return
}
func (sp *SentryPeerCfg) AsMapInterface() map[string]any {
return map[string]any{
"URL": sp.Url,
"ClientSecret": sp.ClientSecret,
"ClientID": sp.ClientID,
}
}
func (sp *SentryPeerCfg) Clone() (cln *SentryPeerCfg) {
cln = &SentryPeerCfg{
Url: sp.Url,
ClientSecret: sp.ClientSecret,
ClientID: sp.ClientID,
}
return
}

View File

@@ -111,9 +111,11 @@
"apiers_conns": ["*internal"]
}
// "sentrypeer":{
// "url":"https://sentrypeer.com/api/",
// "token":"put token here",
// },
//"sentrypeer":{
//"url":"https://sentrypeer.com/api/",
//"clientID":"",
//"clientSecret":"",
//},
}

View File

@@ -127,9 +127,10 @@
"apiers_conns": ["*internal"],
},
//"sentrypeer":{
//"url":"https://sentrypeer.com/api/",
//"token":""
//},
// "sentrypeer":{
// "url":"https://sentrypeer.com/api/",
// "clientID":"",
// "clientSecret":"",
// },
}

View File

@@ -118,9 +118,10 @@
"apiers_conns": ["*internal"],
},
// "sentrypeer":{
// "url":"https://sentrypeer.com/api/",
// "token":"put token here",
// },
//"sentrypeer":{
//"url":"https://sentrypeer.com/api/",
//"clientID":"",
//"clientSecret":"",
//},
}

View File

@@ -103,9 +103,10 @@
"apiers_conns": ["*internal"],
},
// "sentrypeer":{
// "url":"https://sentrypeer.com/api/",
// "token":"put token here",
// },
//"sentrypeer":{
//"url":"https://sentrypeer.com/api/",
//"clientID":"",
//"clientSecret":"",
//},
}

View File

@@ -270,7 +270,7 @@ func (dm *DataManager) CacheDataFromDB(prfx string, ids []string, mustBeCached b
case utils.MetaAPIBan:
_, err = dm.GetAPIBan(utils.EmptyString, config.CgrConfig().APIBanCfg().Keys, false, false, true)
case utils.MetaSentryPeer:
_, err = GetSentryPeer(utils.EmptyString, config.CgrConfig().SentryPeerCfg().Url, config.CgrConfig().SentryPeerCfg().Token, utils.EmptyString, false, true)
_, err = GetSentryPeer(utils.EmptyString, config.CgrConfig().SentryPeerCfg().Url, config.CgrConfig().SentryPeerCfg().ClientID, config.CgrConfig().SentryPeerCfg().ClientSecret, utils.EmptyString, false, true)
}
if err != nil {
if err != utils.ErrNotFound && err != utils.ErrDSPProfileNotFound && err != utils.ErrDSPHostNotFound {

View File

@@ -19,7 +19,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package engine
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"github.com/cgrates/cgrates/config"
@@ -27,6 +30,10 @@ import (
"github.com/cgrates/cgrates/utils"
)
type TokenResponse struct {
AccessToken string `json:"access_token"`
}
// MatchingItemIDsForEvent returns the list of item IDs matching fieldName/fieldValue for an event
// fieldIDs limits the fields which are checked against indexes
// helper on top of dataDB.GetIndexes, adding utils.MetaAny to list of fields queried
@@ -120,13 +127,51 @@ func WeightFromDynamics(dWs []*utils.DynamicWeight,
}
return 0.0, nil
}
func GetSentryPeer(val, url, token, path string, cacheRead, cacheWrite bool) (found bool, err error) {
func getToken(clientID, clientSecret string, cacheWrite bool, token *TokenResponse) (err error) {
var resp *http.Response
payload := map[string]string{
"client_id": clientID,
"client_secret": clientSecret,
"audience": "https://sentrypeer.com/api",
"grant_type": "client_credentials",
}
jsonPayload, _ := json.Marshal(payload)
resp, err = getHTTP("POST", "https://authz.sentrypeer.com/oauth/token", bytes.NewBuffer(jsonPayload), map[string][]string{"Content-Type": {"application/json"}})
if err != nil {
return err
}
defer resp.Body.Close()
err = json.NewDecoder(resp.Body).Decode(&token)
if err != nil {
return err
}
if cacheWrite {
if err = Cache.Set(utils.MetaSentryPeer, "*token", token.AccessToken, nil, true, utils.NonTransactional); err != nil {
return err
}
}
return
}
func GetSentryPeer(val, url, clientID, clientSecret, path string, cacheRead, cacheWrite bool) (found bool, err error) {
valpath := utils.ConcatenatedKey(path, val)
var (
token TokenResponse
resp *http.Response
cachedReq bool
)
if cacheRead {
if x, ok := Cache.Get(utils.MetaSentryPeer, valpath); ok && x != nil { // Attempt to find in cache first
return x.(bool), nil
}
var cachedToken any
if cachedToken, cachedReq = Cache.Get(utils.MetaSentryPeer, "*token"); cachedReq && cachedToken != nil {
token.AccessToken = cachedToken.(string)
}
}
if !cachedReq {
if err = getToken(clientID, clientSecret, cacheWrite, &token); err != nil {
return
}
}
switch path {
case "*ip":
@@ -134,46 +179,57 @@ func GetSentryPeer(val, url, token, path string, cacheRead, cacheWrite bool) (fo
case "*number":
url += "phone-numbers/"
}
var req *http.Request
if req, err = http.NewRequest("GET", url+val, nil); err != nil {
resp, err = getHTTP("GET", url+val, nil, map[string][]string{"Authorization": {fmt.Sprintf("Bearer %v", token.AccessToken)}})
if err != nil {
return
}
if token != "" {
req.Header = http.Header{
"Authorization": {fmt.Sprintf("Bearer %s", token)},
defer resp.Body.Close()
if resp.StatusCode == http.StatusUnauthorized || resp.StatusCode == http.StatusForbidden {
Cache.Remove(utils.MetaSentryPeer, "*token", true, utils.NonTransactional)
utils.Logger.Warning("SentryPeer redirecting to new bearer token ")
if err = getToken(clientID, clientSecret, cacheWrite, &token); err != nil {
return
}
resp, err = getHTTP("GET", url+val, nil, map[string][]string{"Authorization": {fmt.Sprintf("Bearer %v", token.AccessToken)}})
if err != nil {
return
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusUnauthorized || resp.StatusCode == http.StatusForbidden {
return false, fmt.Errorf("still unauthorized after getting new token")
}
}
var resp *http.Response
resp, err = http.DefaultClient.Do(req)
if err != nil {
return false, err
}
defer resp.Body.Close()
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
switch {
case resp.StatusCode >= http.StatusOK && resp.StatusCode < http.StatusMultipleChoices:
if cacheWrite {
if err = Cache.Set(utils.MetaSentryPeer, valpath, false, nil, true, utils.NonTransactional); err != nil {
return
}
}
return false, nil
case resp.StatusCode == http.StatusNotFound:
if cacheWrite {
if err = Cache.Set(utils.MetaSentryPeer, valpath, true, nil, true, utils.NonTransactional); err != nil {
return false, err
}
}
return true, nil
} else {
switch {
case resp.StatusCode == http.StatusNotFound:
if cacheWrite {
if err = Cache.Set(utils.MetaSentryPeer, valpath, false, nil, true, utils.NonTransactional); err != nil {
return false, err
}
}
return
case resp.StatusCode >= 400 && resp.StatusCode < 500:
err = fmt.Errorf("client error<%s>", resp.Status)
return
case resp.StatusCode >= 500:
err = fmt.Errorf("server error<%s>", resp.Status)
return
default:
err = fmt.Errorf("unexpected status code<%s>", resp.Status)
}
case resp.StatusCode >= http.StatusBadRequest && resp.StatusCode < http.StatusInternalServerError:
err = fmt.Errorf("client err <%v>", resp.Status)
case resp.StatusCode >= http.StatusInternalServerError:
err = fmt.Errorf("server error<%s>", resp.Status)
default:
err = fmt.Errorf("unexpected status code<%s>", resp.Status)
}
return
utils.Logger.Warning(fmt.Sprintf("Sentrypeer filter got %v ", err.Error()))
return false, err
}
func getHTTP(method, url string, payload io.Reader, headers map[string][]string) (resp *http.Response, err error) {
var req *http.Request
if req, err = http.NewRequest(method, url, payload); err != nil {
return
}
req.Header = headers
return http.DefaultClient.Do(req)
}

View File

@@ -659,7 +659,7 @@ func (fltr *FilterRule) passSentryPeer(dDP utils.DataProvider) (bool, error) {
if fltr.Values[0] != "*number" && fltr.Values[0] != "*ip" {
return false, fmt.Errorf("invalid value for sentrypeer filter: <%s>", fltr.Values[0])
}
return GetSentryPeer(strVal, config.CgrConfig().SentryPeerCfg().Url, config.CgrConfig().SentryPeerCfg().Token, fltr.Values[0], true, true)
return GetSentryPeer(strVal, config.CgrConfig().SentryPeerCfg().Url, config.CgrConfig().SentryPeerCfg().ClientID, config.CgrConfig().SentryPeerCfg().ClientSecret, fltr.Values[0], true, true)
}
func parseTime(rsr *config.RSRParser, dDp utils.DataProvider) (_ time.Time, err error) {