Adds JWT token checks

main
Yasen Pramatarov 2024-09-03 13:57:17 +03:00
parent 051cb65495
commit 5521229f82
5 changed files with 75 additions and 13 deletions

View File

@ -15,6 +15,6 @@ All notable changes to this project will be documented in this file.
### Added ### Added
- Initial version in PHP - Initial version in PHP
- New version in folder "go", written in Go - New version in folder "go", written in Go
- Added endpoints for /nginx, /prosody, /jicofo, /jvb - Added endpoints for /nginx, /prosody, /jicofo, /jvb, /jibri
- Added a config file and default values - Added a config file and default values
- Initial vesion of a build script - Initial vesion of a build script

View File

@ -2,4 +2,7 @@ module jilo-agent
go 1.22.6 go 1.22.6
require gopkg.in/yaml.v2 v2.4.0 // indirect require (
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

View File

@ -1,3 +1,5 @@
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

View File

@ -5,6 +5,9 @@
# the port on which the agent will listen # the port on which the agent will listen
agent_port: 8081 agent_port: 8081
# secret for checking JWT (same as in Jilo Web agent config)
secret_key: "mysecretkey"
# the port we check for nginx # the port we check for nginx
nginx_port: 80 nginx_port: 80

View File

@ -12,9 +12,10 @@ Version: 0.1
package main package main
import ( import (
"encoding/json"
"fmt" "fmt"
"encoding/json"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"github.com/dgrijalva/jwt-go"
"io/ioutil" "io/ioutil"
"log" "log"
"net/http" "net/http"
@ -27,6 +28,7 @@ import (
// Config holds the structure of the configuration file // Config holds the structure of the configuration file
type Config struct { type Config struct {
AgentPort int `yaml:"agent_port"` AgentPort int `yaml:"agent_port"`
SecretKey string `yaml:"secret_key"`
NginxPort int `yaml:"nginx_port"` NginxPort int `yaml:"nginx_port"`
ProsodyPort int `yaml:"prosody_port"` ProsodyPort int `yaml:"prosody_port"`
JicofoStatsURL string `yaml:"jicofo_stats_url"` JicofoStatsURL string `yaml:"jicofo_stats_url"`
@ -34,6 +36,13 @@ type Config struct {
JibriHealthURL string `yaml:"jibri_health_url"` JibriHealthURL string `yaml:"jibri_health_url"`
} }
// Claims holds JWT access right
type Claims struct {
Username string `json:"sub"`
Role string `json:"role"`
jwt.StandardClaims
}
// NginxData holds the nginx data structure for the API response to /nginx // NginxData holds the nginx data structure for the API response to /nginx
type NginxData struct { type NginxData struct {
NginxState string `json:"nginx_state"` NginxState string `json:"nginx_state"`
@ -64,6 +73,8 @@ type JibriData struct {
JibriHealthData map[string]interface{} `json:"jibri_health_data"` JibriHealthData map[string]interface{} `json:"jibri_health_data"`
} }
var secretKey []byte
// getServiceState checks the status of the speciied service // getServiceState checks the status of the speciied service
func getServiceState(service string) string { func getServiceState(service string) string {
output, err := exec.Command("systemctl", "is-active", service).Output() output, err := exec.Command("systemctl", "is-active", service).Output()
@ -145,6 +156,48 @@ func loadConfig(filename string) (Config) {
return config return config
} }
// authenticationJWT handles the JWT auth
func authenticationJWT(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
tokenString := r.Header.Get("Authorization")
// empty auth header
if tokenString == "" {
http.Error(w, "Auth header not received", http.StatusUnauthorized)
return
}
// remove "Bearer "
if len(tokenString) > 7 && tokenString[:7] == "Bearer " {
tokenString = tokenString[7:]
}
claims := &Claims{}
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
return secretKey, nil
})
// JWT errors
if err != nil {
if err == jwt.ErrSignatureInvalid {
http.Error(w, "Invalid JWT signature", http.StatusUnauthorized)
return
}
http.Error(w, "Error parsing JWT", http.StatusUnauthorized)
return
}
// JWT invalid
if !token.Valid {
http.Error(w, "Invali JWT token", http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r)
})
}
// nginxHandler handles the /nginx endpoint // nginxHandler handles the /nginx endpoint
func nginxHandler(config Config, w http.ResponseWriter, r *http.Request) { func nginxHandler(config Config, w http.ResponseWriter, r *http.Request) {
data := NginxData { data := NginxData {
@ -201,23 +254,24 @@ func main() {
// load the configuration // load the configuration
config := loadConfig("jilo-agent.conf") config := loadConfig("jilo-agent.conf")
secretKey = []byte(config.SecretKey)
// endpoints // endpoints
http.HandleFunc("/nginx", func(w http.ResponseWriter, r *http.Request) { http.Handle("/nginx", authenticationJWT(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
nginxHandler(config, w, r) nginxHandler(config, w, r)
}) })))
http.HandleFunc("/prosody", func(w http.ResponseWriter, r *http.Request) { http.Handle("/prosody", authenticationJWT(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
prosodyHandler(config, w, r) prosodyHandler(config, w, r)
}) })))
http.HandleFunc("/jicofo", func(w http.ResponseWriter, r *http.Request) { http.Handle("/jicofo", authenticationJWT(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
jicofoHandler(config, w, r) jicofoHandler(config, w, r)
}) })))
http.HandleFunc("/jvb", func(w http.ResponseWriter, r *http.Request) { http.Handle("/jvb", authenticationJWT(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
jvbHandler(config, w, r) jvbHandler(config, w, r)
}) })))
http.HandleFunc("/jibri", func(w http.ResponseWriter, r *http.Request) { http.Handle("/jibri", authenticationJWT(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
jibriHandler(config, w, r) jibriHandler(config, w, r)
}) })))
// start the http server // start the http server
agentPortStr := fmt.Sprintf(":%d", config.AgentPort) agentPortStr := fmt.Sprintf(":%d", config.AgentPort)