remote_mtls_test.go 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. package runtime
  2. import (
  3. "context"
  4. "net/http"
  5. "net/http/httptest"
  6. "net/url"
  7. "strconv"
  8. "testing"
  9. "github.com/mhsanaei/3x-ui/v3/internal/database/model"
  10. )
  11. // nodeForPlainServer builds an http (non-TLS) node so do()'s token handling can
  12. // be exercised without TLS scaffolding.
  13. func nodeForPlainServer(t *testing.T, srv *httptest.Server, mode, token string) *model.Node {
  14. t.Helper()
  15. u, err := url.Parse(srv.URL)
  16. if err != nil {
  17. t.Fatalf("parse url: %v", err)
  18. }
  19. port, err := strconv.Atoi(u.Port())
  20. if err != nil {
  21. t.Fatalf("parse port: %v", err)
  22. }
  23. return &model.Node{
  24. Id: 1, Name: "n1", Scheme: "http", Address: u.Hostname(), Port: port,
  25. BasePath: "/", ApiToken: token, Enable: true, AllowPrivateAddress: true,
  26. TlsVerifyMode: mode,
  27. }
  28. }
  29. // TestRemoteDo_MTLSNodeNoBearer asserts that an mtls node with no API token
  30. // sends its request with NO Authorization header and does not trip the
  31. // empty-token precondition; while a non-mtls node with no token still errors.
  32. func TestRemoteDo_MTLSNodeNoBearer(t *testing.T) {
  33. var reached bool
  34. var gotAuth string
  35. srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  36. reached = true
  37. gotAuth = r.Header.Get("Authorization")
  38. w.Header().Set("Content-Type", "application/json")
  39. _, _ = w.Write([]byte(`{"success":true}`))
  40. }))
  41. defer srv.Close()
  42. t.Run("mtls without token sends no Authorization header", func(t *testing.T) {
  43. reached, gotAuth = false, "sentinel"
  44. r := NewRemote(nodeForPlainServer(t, srv, "mtls", ""), nil)
  45. if _, err := r.do(context.Background(), http.MethodGet, "ping", nil); err != nil {
  46. t.Fatalf("mtls node with no token must not error on the token precondition: %v", err)
  47. }
  48. if !reached {
  49. t.Fatal("request did not reach the server")
  50. }
  51. if gotAuth != "" {
  52. t.Fatalf("Authorization header = %q, want empty for a tokenless mtls node", gotAuth)
  53. }
  54. })
  55. t.Run("non-mtls without token still errors", func(t *testing.T) {
  56. reached = false
  57. r := NewRemote(nodeForPlainServer(t, srv, "verify", ""), nil)
  58. if _, err := r.do(context.Background(), http.MethodGet, "ping", nil); err == nil {
  59. t.Fatal("non-mtls node with no token must still error")
  60. }
  61. if reached {
  62. t.Fatal("non-mtls tokenless request must not reach the server")
  63. }
  64. })
  65. }