proxy_test.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. //go:build !plan9
  4. package main
  5. import (
  6. "net/http"
  7. "testing"
  8. "github.com/google/go-cmp/cmp"
  9. "go.uber.org/zap"
  10. "tailscale.com/client/tailscale/apitype"
  11. "tailscale.com/tailcfg"
  12. "tailscale.com/util/must"
  13. )
  14. func TestImpersonationHeaders(t *testing.T) {
  15. zl, err := zap.NewDevelopment()
  16. if err != nil {
  17. t.Fatal(err)
  18. }
  19. tests := []struct {
  20. name string
  21. emailish string
  22. tags []string
  23. capMap tailcfg.PeerCapMap
  24. wantHeaders http.Header
  25. }{
  26. {
  27. name: "user",
  28. emailish: "[email protected]",
  29. wantHeaders: http.Header{
  30. "Impersonate-User": {"[email protected]"},
  31. },
  32. },
  33. {
  34. name: "tagged",
  35. emailish: "tagged-device",
  36. tags: []string{"tag:foo", "tag:bar"},
  37. wantHeaders: http.Header{
  38. "Impersonate-User": {"node.ts.net"},
  39. "Impersonate-Group": {"tag:foo", "tag:bar"},
  40. },
  41. },
  42. {
  43. name: "user-with-cap",
  44. emailish: "[email protected]",
  45. capMap: tailcfg.PeerCapMap{
  46. capabilityName: {
  47. tailcfg.RawMessage(`{"impersonate":{"groups":["group1","group2"]}}`),
  48. tailcfg.RawMessage(`{"impersonate":{"groups":["group1","group3"]}}`), // One group is duplicated.
  49. tailcfg.RawMessage(`{"impersonate":{"groups":["group4"]}}`),
  50. tailcfg.RawMessage(`{"impersonate":{"groups":["group2"]}}`), // duplicate
  51. // These should be ignored, but should parse correctly.
  52. tailcfg.RawMessage(`{}`),
  53. tailcfg.RawMessage(`{"impersonate":{}}`),
  54. tailcfg.RawMessage(`{"impersonate":{"groups":[]}}`),
  55. },
  56. },
  57. wantHeaders: http.Header{
  58. "Impersonate-Group": {"group1", "group2", "group3", "group4"},
  59. "Impersonate-User": {"[email protected]"},
  60. },
  61. },
  62. {
  63. name: "tagged-with-cap",
  64. emailish: "tagged-device",
  65. tags: []string{"tag:foo", "tag:bar"},
  66. capMap: tailcfg.PeerCapMap{
  67. capabilityName: {
  68. tailcfg.RawMessage(`{"impersonate":{"groups":["group1"]}}`),
  69. },
  70. },
  71. wantHeaders: http.Header{
  72. "Impersonate-Group": {"group1"},
  73. "Impersonate-User": {"node.ts.net"},
  74. },
  75. },
  76. {
  77. name: "bad-cap",
  78. emailish: "tagged-device",
  79. tags: []string{"tag:foo", "tag:bar"},
  80. capMap: tailcfg.PeerCapMap{
  81. capabilityName: {
  82. tailcfg.RawMessage(`[]`),
  83. },
  84. },
  85. wantHeaders: http.Header{},
  86. },
  87. }
  88. for _, tc := range tests {
  89. r := must.Get(http.NewRequest("GET", "https://op.ts.net/api/foo", nil))
  90. r = r.WithContext(whoIsKey.WithValue(r.Context(), &apitype.WhoIsResponse{
  91. Node: &tailcfg.Node{
  92. Name: "node.ts.net",
  93. Tags: tc.tags,
  94. },
  95. UserProfile: &tailcfg.UserProfile{
  96. LoginName: tc.emailish,
  97. },
  98. CapMap: tc.capMap,
  99. }))
  100. addImpersonationHeaders(r, zl.Sugar())
  101. if d := cmp.Diff(tc.wantHeaders, r.Header); d != "" {
  102. t.Errorf("unexpected header (-want +got):\n%s", d)
  103. }
  104. }
  105. }