From 588c818c0d5e86c43379a36ae342ea693b5a0b4c Mon Sep 17 00:00:00 2001 From: Thomas Vogl Date: Wed, 21 Jul 2021 15:38:38 +0200 Subject: [PATCH] .. --- HttpServer.go | 38 ++++++++++++++++++++--- config.go | 1 + database.go | 50 ++++++++++++++---------------- go.mod | 3 ++ go.sum | 4 +++ main.go | 6 ++-- oauth2.go | 24 +++++++++----- renderer.go | 4 +-- resources/templates/adminpage.html | 5 ++- 9 files changed, 87 insertions(+), 48 deletions(-) diff --git a/HttpServer.go b/HttpServer.go index fa3a08c..383b5d0 100644 --- a/HttpServer.go +++ b/HttpServer.go @@ -1,12 +1,14 @@ package main import ( + "crypto/subtle" "encoding/json" "fmt" "github.com/gorilla/mux" log "github.com/sirupsen/logrus" "net" "net/http" + auth "github.com/abbot/go-http-auth" ) @@ -108,11 +110,11 @@ func (h *HttpServer) doaction(w http.ResponseWriter, r *http.Request, params *Ad case "add": host := r.URL.Query().Get("host") - _, err := h._database.CreateHost(host) + pw, _, err := h._database.CreateHost(host) if err == nil { params.Alerts = append(params.Alerts, Alert{ Type: "success", - Message: fmt.Sprintf("created host %s", host), + Message: fmt.Sprintf("created host %s\npassword: %s", host, pw), }) } else { params.Alerts = append(params.Alerts, Alert{ @@ -154,6 +156,7 @@ func (h *HttpServer) adminPage(w http.ResponseWriter, r *http.Request) { params.Alerts = make([]Alert, 0) params.Hosts = make(map[string]string) params.IpAddresses = h._ipAddresses + params.LogoutUrl = h._oauth.LogoutUrl h.doaction(w,r, params) @@ -161,8 +164,7 @@ func (h *HttpServer) adminPage(w http.ResponseWriter, r *http.Request) { claims, _ := h._oauth.GetClaims(w, token) - params.Email = claims.Email - params.Profile = claims.Profile + params.Claims = *claims if settings.FilterString != nil { params.Hosts = h._database.GetExistingHosts(*settings.FilterString) @@ -275,13 +277,35 @@ func (h *HttpServer) updateHandler(w http.ResponseWriter, r *http.Request) { log.Info("authorization successful.") log.Info("will update host ", host, " ip ", myip) - w.WriteHeader(http.StatusOK) + + if !h._database.ExistHost(host) { + w.WriteHeader(http.StatusInternalServerError) + return + } else { + err := h._dnsclient.Update(host, myip) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + } else { + w.WriteHeader(http.StatusOK) + } + } + + + } func (h *HttpServer) Listen() { h._server.ListenAndServe() } +func Secret(user, realm string) string { + if user == "john" { + // password is "hello" + return "$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1" + } + return "" +} + func CreateHttpServer(config *Config) *HttpServer { var httpserver *HttpServer @@ -315,6 +339,10 @@ func CreateHttpServer(config *Config) *HttpServer { Handler: r, } + auth := auth.NewBasicAuthenticator(config.AuthRealm, func(user string) { + return httpserver._database._db.Get("hosts/"+ user) + }) + r.HandleFunc("/register", httpserver.registerHandler) r.HandleFunc("/update", httpserver.updateHandler) r.HandleFunc("/admin", httpserver.adminPage) diff --git a/config.go b/config.go index bb22008..c0ad4c8 100644 --- a/config.go +++ b/config.go @@ -10,5 +10,6 @@ type Config struct { OAuth2ClientSecret string IssuerUrl string ZoneUrl string + AuthRealm string } diff --git a/database.go b/database.go index 0a8634a..b9e3702 100644 --- a/database.go +++ b/database.go @@ -1,23 +1,19 @@ package main import ( - "bytes" - "crypto/rand" "crypto/sha256" - "crypto/sha512" - "encoding/base64" "errors" "github.com/miekg/dns" + "github.com/patrickmn/go-cache" + password "github.com/sethvargo/go-password/password" log "github.com/sirupsen/logrus" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/util" - "math" - "math/big" + bcrypt "golang.org/x/crypto/bcrypt" "os" "path" "strings" "time" - "github.com/patrickmn/go-cache" ) type Database struct { @@ -57,11 +53,11 @@ func (d *Database) Authorize(host string, token_user string) bool { return false } - if len(token) < sha512.Size { + if len(token) < sha256.Size { return false } - if len(token_user) < sha512.Size { + if len(token_user) < sha256.Size { return false } @@ -74,24 +70,21 @@ func (d *Database) Authorize(host string, token_user string) bool { return false } -func generateToken() string { - maxInt := big.NewInt(math.MaxInt64) - randInt, err := rand.Int(rand.Reader, maxInt) +func generateToken() (string, []byte, error) { + pw, err := password.Generate(64, 10, 10, false, false) if err != nil { - log.Fatal(err) + return "", nil, err } - h_plain := []byte(randInt.String() + time.Now().String()) - h:= sha256.Sum256(h_plain) + hash, errHash := bcrypt.GenerateFromPassword([]byte(pw), bcrypt.DefaultCost) - for i:=0;i<10000; i++ { - h = sha256.Sum256(h[:]) + if errHash != nil { + return "", nil , errHash } - var buf bytes.Buffer - base64.NewEncoder(base64.URLEncoding, &buf).Write(h[:]) - return buf.String() + + return pw, hash, nil } func (d *Database) IsBannedHost(host string) bool { @@ -119,24 +112,27 @@ func (d *Database) IncrementBanHost(host string) { } -func (d *Database) CreateHost(host string) (string, error) { +func (d *Database) CreateHost(host string) (string, []byte, error) { if d.ExistHost(host) { - return "", errors.New("host already existent") + return "", nil, errors.New("host already existent") } if host == "" { - return "", errors.New("given hostname is empty") + return "", nil, errors.New("given hostname is empty") } if _, ok := dns.IsDomainName(host + "." + d._zone); !ok { - return "", errors.New("given hostname is invalid") + return "", nil, errors.New("given hostname is invalid") } - token := generateToken() - d._db.Put([]byte("hosts/" + host), []byte(token), nil) + pw, hash, errToken := generateToken() + if errToken != nil { + return "", nil, errToken + } - return token, nil + d._db.Put([]byte("hosts/" + host), hash, nil) + return pw, hash, nil } diff --git a/go.mod b/go.mod index efe4f18..f45e65f 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,14 @@ module ddnsService go 1.15 require ( + github.com/abbot/go-http-auth v0.4.0 github.com/coreos/go-oidc/v3 v3.0.0 github.com/gorilla/mux v1.8.0 github.com/miekg/dns v1.1.35 github.com/patrickmn/go-cache v2.1.0+incompatible + github.com/sethvargo/go-password v0.2.0 github.com/sirupsen/logrus v1.7.0 github.com/syndtr/goleveldb v1.0.0 + golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d ) diff --git a/go.sum b/go.sum index 0c6c206..95fb10a 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,6 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/abbot/go-http-auth v0.4.0 h1:QjmvZ5gSC7jm3Zg54DqWE/T5m1t2AfDu6QlXJT0EVT0= +github.com/abbot/go-http-auth v0.4.0/go.mod h1:Cz6ARTIzApMJDzh5bRMSUou6UMSp0IEXg9km/ci7TJM= github.com/coreos/go-oidc/v3 v3.0.0 h1:/mAA0XMgYJw2Uqm7WKGCsKnjitE/+A0FFbOmiRJm7LQ= github.com/coreos/go-oidc/v3 v3.0.0/go.mod h1:rEJ/idjfUyfkBit1eI1fvyr+64/g9dcKpAm8MJMesvo= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -27,6 +29,8 @@ github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaR github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sethvargo/go-password v0.2.0 h1:BTDl4CC/gjf/axHMaDQtw507ogrXLci6XRiLc7i/UHI= +github.com/sethvargo/go-password v0.2.0/go.mod h1:Ym4Mr9JXLBycr02MFuVQ/0JHidNetSgbzutTr3zsYXE= github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/main.go b/main.go index 4ac016a..eec6cb9 100644 --- a/main.go +++ b/main.go @@ -4,9 +4,9 @@ func main() { config := Config{ DataDir: "/var/lib/ddnsService", - Addr: ":8999", OAuth2ClientID: "0oa472q93Zu227hXY5d6", - OAuth2ClientSecret: "sj98SdfZxjkYxUd8NCbyhSuPX1D7kPARDRJ0kVUe", - IssuerUrl: "https://dev-1614211.okta.com/oauth2/default", + Addr: ":8999", OAuth2ClientID: "ddnsService", + OAuth2ClientSecret: "", + IssuerUrl: "https://auth.voglfrei.net/auth/realms/master", OAuth2RedirectUrl: "http://localhost:8999/admin", ZoneUrl: "hub.voglfrei.net"} server := CreateHttpServer(&config) diff --git a/oauth2.go b/oauth2.go index 5230e4e..c889325 100644 --- a/oauth2.go +++ b/oauth2.go @@ -13,15 +13,19 @@ import ( type OidcClams struct { Email string `json:"email"` Profile string `json:"profile"` + Username string `json:"preferred_username"` } type OAuth2 struct { + LogoutUrl string `json:"end_session_endpoint"` + _ctx context.Context _oauth2Config *oauth2.Config _oidcVerifier *oidc.IDTokenVerifier _oidcProvider *oidc.Provider _nonces map[string]string + } func (o *OAuth2) GetClaims(w http.ResponseWriter, token *oidc.IDToken) (*OidcClams, error) { @@ -42,6 +46,7 @@ func (o *OAuth2) checkOAuth(w http.ResponseWriter, r *http.Request, allowRedirec if err == nil { log.Info("got id_token cookie") token, err := o._oidcVerifier.Verify(o._ctx, cookie.Value) + if err != nil { http.Error(w, "Failed to verify ID Token: "+err.Error(), http.StatusInternalServerError) return nil, false @@ -60,7 +65,6 @@ func (o *OAuth2) checkOAuth(w http.ResponseWriter, r *http.Request, allowRedirec return nil, false } delete(o._nonces, state) - oauth2Token, err := o._oauth2Config.Exchange(o._ctx, code) if err != nil { http.Error(w, "Failed to exchange token: "+err.Error(), http.StatusInternalServerError) @@ -72,7 +76,7 @@ func (o *OAuth2) checkOAuth(w http.ResponseWriter, r *http.Request, allowRedirec http.Error(w, "No id_token field in oauth2 token.", http.StatusInternalServerError) return nil, false } - log.Info(rawIDToken) + token, err2 := o._oidcVerifier.Verify(o._ctx, rawIDToken) if err2 != nil { http.Error(w, "Failed to verify ID Token: "+err.Error(), http.StatusInternalServerError) @@ -99,9 +103,10 @@ func (o *OAuth2) checkOAuth(w http.ResponseWriter, r *http.Request, allowRedirec } else { //no auth code and no bearer -> redirect if allowRedirect { - nonce := generateToken() - o._nonces[nonce] = nonce - http.Redirect(w, r, o._oauth2Config.AuthCodeURL(nonce), http.StatusFound) + pw, _ , _ := generateToken(); + o._nonces[pw] = pw + + http.Redirect(w, r, o._oauth2Config.AuthCodeURL(pw), http.StatusFound) } return nil, false @@ -123,7 +128,6 @@ func CreateOAuth2(config *Config) (*OAuth2, error) { // Configure an OpenID Connect aware OAuth2 client. verifier := provider.Verifier(oidcConfig) - oauthConfig := oauth2.Config{ ClientID: config.OAuth2ClientID, ClientSecret: config.OAuth2ClientSecret, @@ -132,11 +136,15 @@ func CreateOAuth2(config *Config) (*OAuth2, error) { Scopes: []string{oidc.ScopeOpenID, "profile", "email"}, } - return &OAuth2{ + ret := OAuth2{ _ctx: ctx, _oauth2Config: &oauthConfig, _oidcVerifier: verifier, _oidcProvider: provider, _nonces: make(map[string]string), - }, nil + } + + err = provider.Claims(&ret) + + return &ret, nil } \ No newline at end of file diff --git a/renderer.go b/renderer.go index df6cd0e..ef3b888 100644 --- a/renderer.go +++ b/renderer.go @@ -7,10 +7,10 @@ import ( type AdminPageParams struct { Hosts map[string]string - Email string - Profile string + Claims OidcClams Alerts []Alert IpAddresses map[string][]string + LogoutUrl string } diff --git a/resources/templates/adminpage.html b/resources/templates/adminpage.html index 1625358..ba04080 100644 --- a/resources/templates/adminpage.html +++ b/resources/templates/adminpage.html @@ -13,12 +13,11 @@
-
Logged in as {{.Email}}
+
Logged in as {{.Claims.Username}} ({{.Claims.Email}})
-

{{.Profile}}