modified config+authorization

This commit is contained in:
Joel Schmid 2021-11-26 15:57:40 +01:00
parent 261cfb96c4
commit 5c33c5ff14
6 changed files with 103 additions and 71 deletions

5
.gitignore vendored
View file

@ -12,7 +12,4 @@
*.out
# Dependency directories (remove the comment below to include it)
# vendor/
#run-script including environment-variable values for test instances
run.ps1
# vendor/

42
.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,42 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "weather-api",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/main.go",
"env": {
"MONGO_HOST":"localhost:27017",
"MONGO_DB":"weathersensors",
"MONGO_COLLECTION":"data",
"MONGO_USER":"root",
"MONGO_PASSWORD":"rootPassXXX",
"INFLUX_HOST":"localhost",
"INFLUX_TOKEN":"token",
"INFLUX_ORG":"weather-org",
"INFLUX_BUCKET":"weatherdata",
"MQTT_HOST":"localhost:1883",
"MQTT_TOPIC":"sensor/#",
"MQTT_USER":"mqtt",
"MQTT_PASSWORD":"mqtt",
"MQTT_PUBLISH_DELAY":"1000",
"MQTT_ANONYMOUS":"false",
"ACCESS_CONTROL_ALLOW_ORIGIN_HEADER":"*",
"USE_JWT_TOKEN_VALIDATION_URL":"false",
"JWT_TOKEN_VALIDATION_URL":"localhost:5000",
"USE_JWT_TOKEN_VALIDATION_SECRET":"false",
"JWT_TOKEN_VALIDATION_SECRET":"token_Secret_value",
"ALLOW_UNREGISTERED_SENSORS":"true",
},
}
]
}

View file

@ -24,7 +24,7 @@ Key | Default-Wert | Auswirkung
MONGO_HOST | localhost:27017 | Hostadresse mongodb
MONGO_DB | weathersensors | DB-Namen mongodb
MONGO_USER | admin | Username mongodb
MONGO_PASS | admin | Passwort mongodb
MONGO_PASSWORD | admin | Passwort mongodb
MONGO_COLLECTION | sensors | mongodb-Collection, in der Wettersensoren gespeichert werden
INFLUX_HOST | localhost:8086 | Hostadresse influxdb
INFLUX_TOKEN | token | Token für influxDB
@ -33,13 +33,13 @@ INFLUX_BUCKET | bucket_name | Bucket-Namen, in dem die Wetterdaten abgespeichert
MQTT_HOST | localhost:1883 | Hostadresse MQTT-Broker
MQTT_TOPIC | sensor/# | MQTT-Topic, in welchem nach Wetterdaten geschaut wird
MQTT_USER | mqtt | Username für MQTT
MQTT_PASS | mqtt | Passwort für MQTT
MQTT_PASSWORD | mqtt | Passwort für MQTT
MQTT_PUBLISH_DELAY | 1000 | Innerhalb dieser Zeitspanne wird ein Wetterdatensatz noch durch weiter eintreffende Werte ergänzt. Danach wird der Datensatz veröffentlicht (in Millisekunden)
MQTT_ANONYMOUS | false | Anonyme Anmeldung am MQTT-Broker verwenden (ohne Username und Passwort)
ACCESS_CONTROL_ALLOW_ORIGIN_HEADER | * | CORS-Header
USE_JWT_TOKEN_VALIDATION_URL | false | Tokenvalidierung an einer URL
JWT_TOKEN_VALIDATION_URL | localhost:5000 | URL für die JWT-Token Validierung
USE_JWT_TOKEN_VALIDATION_SECRET | true | Tokenvalidierung mit der Angabe eines Secrets
JWT_TOKEN_VALIDATION_SECRET | token_Secret_value | Secret um die Signatur des JWT-Tokens zu überprüfen
ALLOW_UNREGISTERED_SENSORS | false | Wetterdaten nicht registrierter Sensoren erlauben
## Applikation lokal ausführen
Eine lokal ausgeführte Test-Instanz der Wetter-API muss mit URLs, Tokens und ähnlichem über Umgebungsvariablen konfiguriert werden.
Das PowerShell-Skript `run_default.ps1` ist eine Vorlage für den start einer eigenen Instanz, lediglich die Umgebungsvariablen müsssen hierzu angepasst werden. Am besten wird der Inhalt dieses Skriptes in ein weiteres Skript (z.B. `run.ps1`) kopiert. Dieses wird von Git ignoriert, geheime Zugangsdaten (z.B. zu MQTT Broker, InfluxDB) werden so nicht ins Git-Repository eingefügt.

View file

@ -24,10 +24,19 @@ var bearerTokenRegexPattern = "^(?i:Bearer\\s+)([A-Za-z0-9-_=]+\\.[A-Za-z0-9-_=]
var bearerTokenRegex *regexp.Regexp = regexp.MustCompile(bearerTokenRegexPattern)
type UserClaims struct {
type User struct {
Uid string `json:"uid"`
Username string `json:"username"`
Roles []string `json:"role"`
}
type ValidationResponse struct {
ValidationSuccessfull bool
Identity User
}
type UserClaims struct {
User
jwt.StandardClaims
}
@ -74,7 +83,8 @@ func (api *weatherRestApi) handleRequests() *mux.Router {
//sensor specific stuff
sensorRouter := router.PathPrefix("/{_dummy:(?i)sensor}").Subrouter()
sensorRouter.Use(api.IsAuthorized)
sensorRouter.Use(api.UseJwtTokenValidationSecret)
sensorRouter.Use(api.UseJwtTokenValidationUrl)
sensorRouter.HandleFunc("/{id}/{_dummy:(?i)weather-data}", api.getWeatherDataHandler).Methods("GET")
sensorRouter.HandleFunc("/{id}/{_dummy:(?i)weather-data}", api.addWeatherDataHandler).Methods("POST")
@ -281,14 +291,13 @@ func (api *weatherRestApi) homePageHandler(w http.ResponseWriter, r *http.Reques
fmt.Fprintf(w, "Welcome to the Weather API!")
}
func (api *weatherRestApi) IsAuthorized(next http.Handler) http.Handler {
func (api *weatherRestApi) UseJwtTokenValidationUrl(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !api.config.UseTokenAuthorization {
if !api.config.UseJwtTokenValidationUrl {
next.ServeHTTP(w, r)
return
}
req, err := http.NewRequest(http.MethodGet, api.config.ValidateTokenUrl, &bytes.Buffer{})
req, err := http.NewRequest(http.MethodGet, api.config.JwtTokenValidationUrl, &bytes.Buffer{})
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
@ -302,18 +311,35 @@ func (api *weatherRestApi) IsAuthorized(next http.Handler) http.Handler {
return
}
claims, err := api.parseToken(r.Header)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
r.Header.Set(userIdHeader, claims.Uid)
if resp.StatusCode == http.StatusOK {
next.ServeHTTP(w, r)
if resp.StatusCode != http.StatusOK {
http.Error(w, resp.Status, resp.StatusCode)
return
}
http.Error(w, "", http.StatusUnauthorized)
validation := new(ValidationResponse)
err = json.NewDecoder(resp.Body).Decode(validation)
if err != nil || !validation.ValidationSuccessfull {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
r.Header.Set(userIdHeader, validation.Identity.Uid)
next.ServeHTTP(w, r)
})
}
func (api *weatherRestApi) UseJwtTokenValidationSecret(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !api.config.UseJwtTokenValidationSecret {
next.ServeHTTP(w, r)
return
}
claims, err := api.parseToken(r.Header)
if err != nil {
http.Error(w, err.Error(), http.StatusUnauthorized)
return
}
r.Header.Set(userIdHeader, claims.Uid)
next.ServeHTTP(w, r)
})
}
@ -331,7 +357,7 @@ func (api *weatherRestApi) parseToken(header http.Header) (*UserClaims, error) {
jwtFromHeader,
claims,
func(token *jwt.Token) (interface{}, error) {
return []byte(api.config.JwtTokenSecret), nil
return []byte(api.config.JwtTokenValidationSecret), nil
},
)
return claims, err

View file

@ -32,16 +32,18 @@ type MqttConfig struct {
type RestConfig struct {
AccessControlAllowOriginHeader string
UseTokenAuthorization bool
ValidateTokenUrl string
JwtTokenSecret string
Insecure bool
UseJwtTokenValidationUrl bool
JwtTokenValidationUrl string
UseJwtTokenValidationSecret bool
JwtTokenValidationSecret string
}
var MongoConfiguration = MongoConfig{
Host: getEnv("MONGO_HOST", "localhost:27017"),
Database: getEnv("MONGO_DB", "weathersensors"),
Username: getEnv("MONGO_USER", "admin"),
Password: getEnv("MONGO_PASS", "admin"),
Password: getEnv("MONGO_PASSWORD", "admin"),
Collection: getEnv("MONGO_COLLECTION", "sensors"),
}
@ -56,16 +58,17 @@ var MqttConfiguration = MqttConfig{
Host: getEnv("MQTT_HOST", "localhost:1883"),
Topic: getEnv("MQTT_TOPIC", "sensor/#"),
Username: getEnv("MQTT_USER", "mqtt"),
Password: getEnv("MQTT_PASS", "mqtt"),
Password: getEnv("MQTT_PASSWORD", "mqtt"),
PublishDelay: getEnvDuration("MQTT_PUBLISH_DELAY", time.Second),
AllowAnonymousAuthentication: getEnvBool("MQTT_ANONYMOUS", false),
}
var RestConfiguration = RestConfig{
AccessControlAllowOriginHeader: getEnv("ACCESS_CONTROL_ALLOW_ORIGIN_HEADER", "*"),
UseTokenAuthorization: getEnvBool("USE_TOKEN_AUTHORIZATION", false),
ValidateTokenUrl: getEnv("JWT_TOKEN_VALIDATION_URL", "https://api.swablab.de/ldap/validateToken"),
JwtTokenSecret: getEnv("JWT_TOKEN_SECRET", "my_token_string"),
UseJwtTokenValidationUrl: getEnvBool("USE_JWT_TOKEN_VALIDATION_URL", false),
JwtTokenValidationUrl: getEnv("JWT_TOKEN_VALIDATION_URL", "localhost:5000"),
UseJwtTokenValidationSecret: getEnvBool("USE_JWT_TOKEN_VALIDATION_SECRET", true),
JwtTokenValidationSecret: getEnv("JWT_TOKEN_VALIDATION_SECRET", "my_token_string"),
}
var AllowUnregisteredSensors = getEnvBool("ALLOW_UNREGISTERED_SENSORS", false)
@ -90,16 +93,6 @@ func getEnvBool(key string, fallback bool) bool {
return fallback
}
func getEnvInt(key string, fallback int64) int64 {
if value, ok := os.LookupEnv(key); ok {
if iValue, err := strconv.ParseInt(value, 10, 64); err == nil {
return iValue
}
}
return fallback
}
func getEnvDuration(key string, fallback time.Duration) time.Duration {
if value, ok := os.LookupEnv(key); ok {
if iValue, err := strconv.ParseInt(value, 10, 64); err == nil {

View file

@ -1,26 +0,0 @@
#build the application
go build main.go
#set environment variables for weather-api configuration
Set-Item -Path "Env:INFLUX_HOST" -Value "localhost:8086"
Set-Item -Path "Env:INFLUX_TOKEN" -Value "token"
Set-Item -Path "Env:INFLUX_ORG" -Value "org-name"
Set-Item -Path "Env:INFLUX_BUCKET" -Value "bucket-name"
Set-Item -Path "Env:MQTT_HOST" -Value "localhost:1883"
Set-Item -Path "Env:MQTT_TOPIC" -Value "sensor/#"
Set-Item -Path "Env:MQTT_USER" -Value "mqtt"
Set-Item -Path "Env:MQTT_PASS" -Value "mqtt"
Set-Item -Path "Env:MQTT_PUBLISH_DELAY" -Value "1000"
Set-Item -Path "Env:MQTT_ANONYMOUS" -Value "false"
Set-Item -Path "Env:MONGO_HOST" -Value "localhost:27017"
Set-Item -Path "Env:MONGO_DB" -Value "weathersensors"
Set-Item -Path "Env:MONGO_COLLECTION" -Value "sensors"
Set-Item -Path "Env:MONGO_USER" -Value "admin"
Set-Item -Path "Env:MONGO_PASS" -Value "admin"
Set-Item -Path "Env:ALLOW_UNREGISTERED_SENSORS" -Value "false"
#start application
Start-Process "main.exe" -Wait -NoNewWindow