mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-22 15:48:44 +05:00
Add basic authentication to HTTP API
This adds support for basic authentication for the HTTP API with new configuration values to control if basic auth is used, the basic auth realm URL, and the location to a basic .htpasswd file. github.com/abbot/go-http-auth is added as a dependency as it efficiently implements basic auth, as well as .htpasswd file monitoring.
This commit is contained in:
@@ -530,7 +530,12 @@ func startRpc(server *utils.Server, internalRaterChan,
|
||||
}
|
||||
go server.ServeJSON(cfg.RPCJSONListen)
|
||||
go server.ServeGOB(cfg.RPCGOBListen)
|
||||
go server.ServeHTTP(cfg.HTTPListen)
|
||||
go server.ServeHTTP(
|
||||
cfg.HTTPListen,
|
||||
cfg.HTTPApiUseBasicAuth,
|
||||
cfg.HTTPApiBasicAuthRealm,
|
||||
cfg.HTTPApiHtpasswdFile,
|
||||
)
|
||||
}
|
||||
|
||||
func writePid() {
|
||||
|
||||
@@ -203,6 +203,9 @@ type CGRConfig struct {
|
||||
RPCJSONListen string // RPC JSON listening address
|
||||
RPCGOBListen string // RPC GOB listening address
|
||||
HTTPListen string // HTTP listening address
|
||||
HTTPApiUseBasicAuth bool // Use basic auth for HTTP API
|
||||
HTTPApiBasicAuthRealm string // Basic auth realm URL
|
||||
HTTPApiHtpasswdFile string // Basic auth htpasswd file path
|
||||
DefaultReqType string // Use this request type if not defined on top
|
||||
DefaultCategory string // set default type of record
|
||||
DefaultTenant string // set default tenant
|
||||
@@ -503,6 +506,11 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error {
|
||||
return err
|
||||
}
|
||||
|
||||
jsnHttpApiCfg, err := jsnCfg.HttpApiJsonCfg()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jsnTpDbCfg, err := jsnCfg.DbJsonCfg(TPDB_JSN)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -779,6 +787,18 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error {
|
||||
}
|
||||
}
|
||||
|
||||
if jsnHttpApiCfg != nil {
|
||||
if jsnHttpApiCfg.Use_basic_auth != nil {
|
||||
self.HTTPApiUseBasicAuth = *jsnHttpApiCfg.Use_basic_auth
|
||||
}
|
||||
if jsnHttpApiCfg.Basic_auth_realm != nil {
|
||||
self.HTTPApiBasicAuthRealm = *jsnHttpApiCfg.Basic_auth_realm
|
||||
}
|
||||
if jsnHttpApiCfg.Htpasswd_file != nil {
|
||||
self.HTTPApiHtpasswdFile = *jsnHttpApiCfg.Htpasswd_file
|
||||
}
|
||||
}
|
||||
|
||||
if jsnRALsCfg != nil {
|
||||
if jsnRALsCfg.Enabled != nil {
|
||||
self.RALsEnabled = *jsnRALsCfg.Enabled
|
||||
|
||||
@@ -45,7 +45,7 @@ const CGRATES_CFG_JSON = `
|
||||
"internal_ttl": "2m", // maximum duration to wait for internal connections before giving up
|
||||
"locking_timeout": "5s", // timeout internal locks to avoid deadlocks
|
||||
"cache_dump_dir": "", // cache dump for faster start (leave empty to disable)
|
||||
"log_level": 6, // control the level of messages logged (0-emerg to 7-debug)
|
||||
"log_level": 6, // control the level of messages logged (0-emerg to 7-debug)
|
||||
},
|
||||
|
||||
|
||||
@@ -72,6 +72,13 @@ const CGRATES_CFG_JSON = `
|
||||
},
|
||||
|
||||
|
||||
"http_api": { // HTTP API configuration
|
||||
"use_basic_auth": false, // use basic authentication
|
||||
"basic_auth_realm": "", // basic auth realm URL
|
||||
"htpasswd_file": "" // basic auth htpasswd file location
|
||||
},
|
||||
|
||||
|
||||
"tariffplan_db": { // database used to store active tariff plan configuration
|
||||
"db_type": "redis", // tariffplan_db type: <redis|mongo>
|
||||
"db_host": "127.0.0.1", // tariffplan_db host address
|
||||
@@ -244,7 +251,7 @@ const CGRATES_CFG_JSON = `
|
||||
"sms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from SMS unit to call duration in some billing systems)
|
||||
"mms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from MMS unit to call duration in some billing systems)
|
||||
"generic_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from GENERIC unit to call duration in some billing systems)
|
||||
"cost_multiply_factor": 1, // multiply cost before export, eg: add VAT
|
||||
"cost_multiply_factor": 1, // multiply cost before export, eg: add VAT
|
||||
"export_directory": "/var/spool/cgrates/cdre", // path where the exported CDRs will be placed
|
||||
"header_fields": [], // template of the exported header fields
|
||||
"content_fields": [ // template of the exported content fields
|
||||
|
||||
@@ -29,6 +29,7 @@ const (
|
||||
GENERAL_JSN = "general"
|
||||
CACHE_JSN = "cache"
|
||||
LISTEN_JSN = "listen"
|
||||
HTTP_API_JSN = "http_api"
|
||||
TPDB_JSN = "tariffplan_db"
|
||||
DATADB_JSN = "data_db"
|
||||
STORDB_JSN = "stor_db"
|
||||
@@ -118,6 +119,18 @@ func (self CgrJsonCfg) ListenJsonCfg() (*ListenJsonCfg, error) {
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func (self CgrJsonCfg) HttpApiJsonCfg() (*HTTPApiJsonCfg, error) {
|
||||
rawCfg, hasKey := self[HTTP_API_JSN]
|
||||
if !hasKey {
|
||||
return nil, nil
|
||||
}
|
||||
cfg := new(HTTPApiJsonCfg)
|
||||
if err := json.Unmarshal(*rawCfg, cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func (self CgrJsonCfg) DbJsonCfg(section string) (*DbJsonCfg, error) {
|
||||
rawCfg, hasKey := self[section]
|
||||
if !hasKey {
|
||||
|
||||
@@ -46,6 +46,13 @@ type ListenJsonCfg struct {
|
||||
Http *string
|
||||
}
|
||||
|
||||
// HTTP API config section
|
||||
type HTTPApiJsonCfg struct {
|
||||
Use_basic_auth *bool
|
||||
Basic_auth_realm *string
|
||||
Htpasswd_file *string
|
||||
}
|
||||
|
||||
// Database config
|
||||
type DbJsonCfg struct {
|
||||
Db_type *string
|
||||
|
||||
@@ -51,6 +51,12 @@
|
||||
// },
|
||||
|
||||
|
||||
// "http_api" { // HTTP API configuration
|
||||
// "use_basic_auth": false, // use basic authentication
|
||||
// "basic_auth_realm": "", // basic auth realm URL
|
||||
// "htpasswd_file": "", // basic auth htpasswd file location
|
||||
// },
|
||||
|
||||
// "tariffplan_db": { // database used to store active tariff plan configuration
|
||||
// "db_type": "redis", // tariffplan_db type: <redis|mongo>
|
||||
// "db_host": "127.0.0.1", // tariffplan_db host address
|
||||
@@ -199,7 +205,7 @@
|
||||
// "sms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from SMS unit to call duration in some billing systems)
|
||||
// "mms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from MMS unit to call duration in some billing systems)
|
||||
// "generic_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from GENERIC unit to call duration in some billing systems)
|
||||
// "cost_multiply_factor": 1, // multiply cost before export, eg: add VAT
|
||||
// "cost_multiply_factor": 1, // multiply cost before export, eg: add VAT
|
||||
// "export_directory": "/var/spool/cgrates/cdre", // path where the exported CDRs will be placed
|
||||
// "header_fields": [], // template of the exported header fields
|
||||
// "content_fields": [ // template of the exported content fields
|
||||
|
||||
19
glide.lock
generated
19
glide.lock
generated
@@ -1,6 +1,8 @@
|
||||
hash: da953ea34fabe4e21f4dde6344f3b7ab5a75e02122a1c17af5ea434058fc77fb
|
||||
updated: 2016-09-06T20:33:01.649869367+02:00
|
||||
hash: cfda8a78a96bf7b3b471463d5ddf3330d6ae2089d5ac7c9a31b0f312e6518595
|
||||
updated: 2016-11-10T08:26:28.162167756-07:00
|
||||
imports:
|
||||
- name: github.com/abbot/go-http-auth
|
||||
version: efc9484eee77263a11f158ef4f30fcc30298a942
|
||||
- name: github.com/bit4bit/gami
|
||||
version: 3a7f98e7efce7ed7f22c2169b666910b8abb15dc
|
||||
- name: github.com/cenk/hub
|
||||
@@ -26,13 +28,17 @@ imports:
|
||||
- internal/parser/findutil
|
||||
- internal/parser/intfns
|
||||
- internal/parser/pathexpr
|
||||
- internal/xconst
|
||||
- internal/xsort
|
||||
- literals/boollit
|
||||
- literals/numlit
|
||||
- literals/strlit
|
||||
- tree
|
||||
- tree/xmltree
|
||||
- tree/xmltree/xmlbuilder
|
||||
- tree/xmltree/xmlele
|
||||
- tree/xmltree/xmlnode
|
||||
- xconst
|
||||
- xfn
|
||||
- xsort
|
||||
- name: github.com/DisposaBoy/JsonConfigReader
|
||||
version: 33a99fdf1d5ee1f79b5077e9c06f955ad356d5f4
|
||||
- name: github.com/fiorix/go-diameter
|
||||
@@ -76,6 +82,11 @@ imports:
|
||||
version: 5cd0f2b3b6cca8e3a0a4101821e41a73cb59bed6
|
||||
subpackages:
|
||||
- codec
|
||||
- name: golang.org/x/crypto
|
||||
version: 9477e0b78b9ac3d0b03822fd95422e2fe07627cd
|
||||
subpackages:
|
||||
- bcrypt
|
||||
- blowfish
|
||||
- name: golang.org/x/net
|
||||
version: 1358eff22f0dd0c54fc521042cc607f6ff4b531a
|
||||
subpackages:
|
||||
|
||||
@@ -39,3 +39,5 @@ import:
|
||||
- package: github.com/hashicorp/golang-lru
|
||||
- package: github.com/cgrates/aringo
|
||||
- package: github.com/bit4bit/gami
|
||||
- package: github.com/abbot/go-http-auth
|
||||
version: ~0.3.0
|
||||
|
||||
@@ -29,8 +29,8 @@ import (
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/abbot/go-http-auth"
|
||||
"github.com/cenk/rpc2"
|
||||
"golang.org/x/net/websocket"
|
||||
)
|
||||
import _ "net/http/pprof"
|
||||
|
||||
@@ -140,17 +140,23 @@ func (s *Server) ServeGOB(addr string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) ServeHTTP(addr string) {
|
||||
func handleRequest(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
res := NewRPCRequest(r.Body).Call()
|
||||
io.Copy(w, res)
|
||||
}
|
||||
|
||||
func (s *Server) ServeHTTP(addr string, useBasicAuth bool, basicAuthRealm string, htpasswdFile string) {
|
||||
if s.rpcEnabled {
|
||||
http.HandleFunc("/jsonrpc", func(w http.ResponseWriter, req *http.Request) {
|
||||
defer req.Body.Close()
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
res := NewRPCRequest(req.Body).Call()
|
||||
io.Copy(w, res)
|
||||
})
|
||||
http.Handle("/ws", websocket.Handler(func(ws *websocket.Conn) {
|
||||
jsonrpc.ServeConn(ws)
|
||||
}))
|
||||
if useBasicAuth {
|
||||
Logger.Info(fmt.Sprintf("Configuring CGRateS HTTP server to use basic auth (realm: %s, htpasswd: %s).", basicAuthRealm, htpasswdFile))
|
||||
secrets := auth.HtpasswdFileProvider(htpasswdFile)
|
||||
authenticator := auth.NewBasicAuthenticator(basicAuthRealm, secrets)
|
||||
http.HandleFunc("/jsonrpc", auth.JustCheck(authenticator, handleRequest))
|
||||
} else {
|
||||
http.HandleFunc("/jsonrpc", handleRequest)
|
||||
}
|
||||
s.httpEnabled = true
|
||||
}
|
||||
if !s.httpEnabled {
|
||||
|
||||
Reference in New Issue
Block a user