changeset 5610:a826d84485c8 erdms2

Use token server to fetch token for ERDMS requests.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 31 Oct 2022 19:05:28 +0100
parents e1936db6db8e
children 8062c4a05ad9
files pkg/config/config.go pkg/imports/erdms.go pkg/soap/erdms2/service.go pkg/soap/oauth.go pkg/soap/soap.go
diffstat 5 files changed, 97 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/pkg/config/config.go	Mon Oct 31 17:51:54 2022 +0100
+++ b/pkg/config/config.go	Mon Oct 31 19:05:28 2022 +0100
@@ -132,6 +132,9 @@
 // LogLevel is the log level of the application.
 func LogLevel() log.Level { return log.ParseLogLevel(viper.GetString("log-level")) }
 
+// TokenURL is the ERDMS token service URL.
+func TokenURL() string { return viper.GetString("token-url") }
+
 var (
 	proxyKeyOnce       sync.Once
 	proxyKey           []byte
@@ -307,6 +310,7 @@
 	str("log-file", "", "path to a file to log to.")
 	str("log-level", log.InfoLogLevel.String(), "path to a file to log to.")
 
+	str("token-url", "", "URL to the ERDMS token server.")
 }
 
 var (
--- a/pkg/imports/erdms.go	Mon Oct 31 17:51:54 2022 +0100
+++ b/pkg/imports/erdms.go	Mon Oct 31 19:05:28 2022 +0100
@@ -20,6 +20,7 @@
 	"fmt"
 	"strings"
 
+	"gemma.intevation.de/gemma/pkg/config"
 	"gemma.intevation.de/gemma/pkg/log"
 	"gemma.intevation.de/gemma/pkg/soap"
 	erdms "gemma.intevation.de/gemma/pkg/soap/erdms2"
@@ -72,12 +73,15 @@
 		return nil, nil, err
 	}
 
-	var auth *soap.BasicAuth
-	if username != "" {
-		auth = &soap.BasicAuth{
-			Login:    username,
-			Password: password,
+	var auth soap.Auth
+
+	if tokenURL := config.TokenURL(); tokenURL != "" && username != "" {
+		token, err := soap.FetchToken(tokenURL, username, password)
+		if err != nil {
+			return nil, nil, fmt.Errorf(
+				"error requesting token for ERDMS service: %w", err)
 		}
+		auth = token
 	}
 
 	client := erdms.NewRefService(URL, insecure, auth)
--- a/pkg/soap/erdms2/service.go	Mon Oct 31 17:51:54 2022 +0100
+++ b/pkg/soap/erdms2/service.go	Mon Oct 31 19:05:28 2022 +0100
@@ -1732,7 +1732,7 @@
 	client *soap.SOAPClient
 }
 
-func NewRefService(url string, tls bool, auth *soap.BasicAuth) RefWeb {
+func NewRefService(url string, tls bool, auth soap.Auth) RefWeb {
 	return NewRefWeb(soap.NewSOAPClient(url, tls, auth))
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/soap/oauth.go	Mon Oct 31 19:05:28 2022 +0100
@@ -0,0 +1,71 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2022 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+package soap
+
+import (
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"strings"
+)
+
+type Token struct {
+	AccessToken string `json:"access_token"`
+	Scope       string `json:"scope"`
+	TokenType   string `json:"token_type"`
+	ExpiresIn   int    `json:"expires_in"`
+}
+
+func (token *Token) AddAuth(request *http.Request) {
+	request.Header.Add("Authorization", "Bearer "+token.AccessToken)
+}
+
+func FetchToken(tokenURL, key, secret string) (*Token, error) {
+
+	keyPair := key + ":" + secret
+
+	encodedKeyPair := base64.URLEncoding.EncodeToString([]byte(keyPair))
+
+	req, err := http.NewRequest(
+		http.MethodPost,
+		tokenURL,
+		strings.NewReader("grant_type=client_credentials"))
+
+	if err != nil {
+		return nil, err
+	}
+
+	req.Header.Set("Authorization", "Basic "+encodedKeyPair)
+
+	resp, err := http.DefaultClient.Do(req)
+	if err != nil {
+		return nil, err
+	}
+
+	if resp.StatusCode != http.StatusOK {
+		return nil, fmt.Errorf(
+			"POST failed: %s (%d)",
+			http.StatusText(resp.StatusCode),
+			resp.StatusCode)
+	}
+
+	var token Token
+	defer resp.Body.Close()
+
+	if err = json.NewDecoder(resp.Body).Decode(&token); err != nil {
+		return nil, err
+	}
+	return &token, err
+}
--- a/pkg/soap/soap.go	Mon Oct 31 17:51:54 2022 +0100
+++ b/pkg/soap/soap.go	Mon Oct 31 19:05:28 2022 +0100
@@ -100,15 +100,23 @@
 	Data string `xml:",chardata"`
 }
 
+type Auth interface {
+	AddAuth(request *http.Request)
+}
+
 type BasicAuth struct {
 	Login    string
 	Password string
 }
 
+func (ba *BasicAuth) AddAuth(request *http.Request) {
+	request.SetBasicAuth(ba.Login, ba.Password)
+}
+
 type SOAPClient struct {
 	url     string
 	tlsCfg  *tls.Config
-	auth    *BasicAuth
+	auth    Auth
 	headers []interface{}
 }
 
@@ -205,14 +213,14 @@
 	return f.String
 }
 
-func NewSOAPClient(url string, insecureSkipVerify bool, auth *BasicAuth) *SOAPClient {
+func NewSOAPClient(url string, insecureSkipVerify bool, auth Auth) *SOAPClient {
 	tlsCfg := &tls.Config{
 		InsecureSkipVerify: insecureSkipVerify,
 	}
 	return NewSOAPClientWithTLSConfig(url, tlsCfg, auth)
 }
 
-func NewSOAPClientWithTLSConfig(url string, tlsCfg *tls.Config, auth *BasicAuth) *SOAPClient {
+func NewSOAPClientWithTLSConfig(url string, tlsCfg *tls.Config, auth Auth) *SOAPClient {
 	return &SOAPClient{
 		url:    url,
 		tlsCfg: tlsCfg,
@@ -256,7 +264,7 @@
 		return err
 	}
 	if s.auth != nil {
-		req.SetBasicAuth(s.auth.Login, s.auth.Password)
+		s.auth.AddAuth(req)
 	}
 
 	req.Header.Add("Content-Type", "text/xml; charset=\"utf-8\"")