Skip to content

Commit

Permalink
add agent request auth
Browse files Browse the repository at this point in the history
  • Loading branch information
Son Roy Almerol committed Nov 18, 2024
1 parent eca8fa5 commit 5e870a7
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 1 deletion.
24 changes: 23 additions & 1 deletion internal/agent/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
package agent

import (
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"strings"
"time"

"github.com/billgraziano/dpapi"
"github.com/sonroyaalmerol/pbs-plus/internal/utils"
"golang.org/x/sys/windows/registry"
)
Expand All @@ -22,9 +25,22 @@ func ProxmoxHTTPRequest(method, url string, body io.Reader, respBody any) error
if err != nil {
return fmt.Errorf("ProxmoxHTTPRequest: server url not found -> %w", err)
}

defer key.Close()

var drivePublicKey *string
keyStr := "Software\\PBSPlus\\Config\\SFTP-C"
if driveKey, err := registry.OpenKey(registry.LOCAL_MACHINE, keyStr, registry.QUERY_VALUE); err == nil {
defer driveKey.Close()
if publicKey, _, err := driveKey.GetStringValue("ServerKey"); err == nil {
if decrypted, err := dpapi.Decrypt(publicKey); err == nil {
if decoded, err := base64.StdEncoding.DecodeString(decrypted); err == nil {
decodedStr := string(decoded)
drivePublicKey = &decodedStr
}
}
}
}

if serverUrl, _, err = key.GetStringValue("ServerURL"); err != nil || serverUrl == "" {
return fmt.Errorf("ProxmoxHTTPRequest: server url not found -> %w", err)
}
Expand All @@ -43,7 +59,13 @@ func ProxmoxHTTPRequest(method, url string, body io.Reader, respBody any) error
return fmt.Errorf("ProxmoxHTTPRequest: error creating http request -> %w", err)
}

hostname, _ := os.Hostname()

req.Header.Add("Content-Type", "application/json")
if drivePublicKey != nil {
encodedKey := base64.StdEncoding.EncodeToString([]byte(*drivePublicKey))
req.Header.Set("Authorization", fmt.Sprintf("PBSPlusAPIAgent=%s---C:%s", hostname, encodedKey))
}

if httpClient == nil {
httpClient = &http.Client{
Expand Down
4 changes: 4 additions & 0 deletions internal/proxy/controllers/agents/agents.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ func AgentLogHandler(storeInstance *store.Store) func(http.ResponseWriter, *http
http.Error(w, "Invalid HTTP method", http.StatusBadRequest)
}

if err := store.CheckAgentAuth(r); err != nil {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
}

syslogger, err := syslog.InitializeLogger()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
Expand Down
4 changes: 4 additions & 0 deletions internal/proxy/controllers/targets/targets.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ func D2DTargetAgentHandler(storeInstance *store.Store) func(http.ResponseWriter,
http.Error(w, "Invalid HTTP method", http.StatusBadRequest)
}

if err := store.CheckAgentAuth(r); err != nil {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
}

var reqParsed NewAgentHostnameRequest
err := json.NewDecoder(r.Body).Decode(&reqParsed)
if err != nil {
Expand Down
51 changes: 51 additions & 0 deletions internal/store/auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package store

import (
"encoding/base64"
"fmt"
"net/http"
"os"
"path/filepath"
"reflect"
"strings"

"github.com/sonroyaalmerol/pbs-plus/internal/utils"
)

func CheckAgentAuth(r *http.Request) error {
auth := r.Header.Get("Authorization")
if !strings.HasPrefix(auth, "PBSPlusAPIAgent=") {
return fmt.Errorf("CheckAgentAuth: invalid auth prefix")
}

privKeyDir := filepath.Join(DbBasePath, "agent_keys")

authTok := strings.TrimPrefix(auth, "PBSPlusAPIAgent=")
authSplit := strings.Split(authTok, ":")

privKeyFilePath := filepath.Join(
privKeyDir,
fmt.Sprintf("%s.key", authSplit[0]),
)

privKeyFile, err := os.ReadFile(privKeyFilePath)
if err != nil {
return fmt.Errorf("CheckAgentAuth: error opening private key file \"%s\" -> %w", privKeyFilePath, err)
}

pubKey, err := utils.GeneratePublicKeyFromPrivateKey(privKeyFile)
if err != nil {
return fmt.Errorf("CheckAgentAuth: error generating pub key \"%s\" -> %w", privKeyFilePath, err)
}

passedPub, err := base64.StdEncoding.DecodeString(authSplit[1])
if err != nil {
return fmt.Errorf("CheckAgentAuth: error pub key -> %w", err)
}

if !reflect.DeepEqual(pubKey, passedPub) {
return fmt.Errorf("CheckAgentAuth: invalid auth")
}

return nil
}
28 changes: 28 additions & 0 deletions internal/utils/ssh_keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"crypto/x509"
"encoding/pem"
"fmt"
"sync"

"golang.org/x/crypto/ssh"
)
Expand Down Expand Up @@ -55,3 +56,30 @@ func generatePublicKey(privatekey *rsa.PublicKey) ([]byte, error) {

return pubKeyBytes, nil
}

var pubKeyCache sync.Map

func GeneratePublicKeyFromPrivateKey(encodedPrivateKey []byte) ([]byte, error) {
cached, ok := pubKeyCache.Load(encodedPrivateKey)
if ok {
return cached.([]byte), nil
}

block, _ := pem.Decode(encodedPrivateKey)
if block == nil || block.Type != "RSA PRIVATE KEY" {
return nil, fmt.Errorf("GeneratePublicKeyFromPrivateKey: invalid private key type or format")
}

privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("GeneratePublicKeyFromPrivateKey: error parsing private key -> %w", err)
}

publicKey, err := generatePublicKey(&privateKey.PublicKey)
if err != nil {
return nil, fmt.Errorf("GeneratePublicKeyFromPrivateKey: error generating public key -> %w", err)
}

pubKeyCache.Store(encodedPrivateKey, publicKey)
return publicKey, nil
}

0 comments on commit 5e870a7

Please sign in to comment.