dn_test.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. package ldap_test
  2. import (
  3. "reflect"
  4. "testing"
  5. "notabug.org/makenotabuggreatagain/ldap"
  6. )
  7. func TestSuccessfulDNParsing(t *testing.T) {
  8. testcases := map[string]ldap.DN{
  9. "": ldap.DN{[]*ldap.RelativeDN{}},
  10. "cn=Jim\\2C \\22Hasse Hö\\22 Hansson!,dc=dummy,dc=com": ldap.DN{[]*ldap.RelativeDN{
  11. &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"cn", "Jim, \"Hasse Hö\" Hansson!"}}},
  12. &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"dc", "dummy"}}},
  13. &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"dc", "com"}}}}},
  14. "UID=jsmith,DC=example,DC=net": ldap.DN{[]*ldap.RelativeDN{
  15. &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"UID", "jsmith"}}},
  16. &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "example"}}},
  17. &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "net"}}}}},
  18. "OU=Sales+CN=J. Smith,DC=example,DC=net": ldap.DN{[]*ldap.RelativeDN{
  19. &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{
  20. &ldap.AttributeTypeAndValue{"OU", "Sales"},
  21. &ldap.AttributeTypeAndValue{"CN", "J. Smith"}}},
  22. &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "example"}}},
  23. &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "net"}}}}},
  24. "1.3.6.1.4.1.1466.0=#04024869": ldap.DN{[]*ldap.RelativeDN{
  25. &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"1.3.6.1.4.1.1466.0", "Hi"}}}}},
  26. "1.3.6.1.4.1.1466.0=#04024869,DC=net": ldap.DN{[]*ldap.RelativeDN{
  27. &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"1.3.6.1.4.1.1466.0", "Hi"}}},
  28. &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "net"}}}}},
  29. "CN=Lu\\C4\\8Di\\C4\\87": ldap.DN{[]*ldap.RelativeDN{
  30. &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"CN", "Lučić"}}}}},
  31. " CN = Lu\\C4\\8Di\\C4\\87 ": ldap.DN{[]*ldap.RelativeDN{
  32. &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"CN", "Lučić"}}}}},
  33. ` A = 1 , B = 2 `: ldap.DN{[]*ldap.RelativeDN{
  34. &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"A", "1"}}},
  35. &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"B", "2"}}}}},
  36. ` A = 1 + B = 2 `: ldap.DN{[]*ldap.RelativeDN{
  37. &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{
  38. &ldap.AttributeTypeAndValue{"A", "1"},
  39. &ldap.AttributeTypeAndValue{"B", "2"}}}}},
  40. ` \ \ A\ \ = \ \ 1\ \ , \ \ B\ \ = \ \ 2\ \ `: ldap.DN{[]*ldap.RelativeDN{
  41. &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{" A ", " 1 "}}},
  42. &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{" B ", " 2 "}}}}},
  43. ` \ \ A\ \ = \ \ 1\ \ + \ \ B\ \ = \ \ 2\ \ `: ldap.DN{[]*ldap.RelativeDN{
  44. &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{
  45. &ldap.AttributeTypeAndValue{" A ", " 1 "},
  46. &ldap.AttributeTypeAndValue{" B ", " 2 "}}}}},
  47. }
  48. for test, answer := range testcases {
  49. dn, err := ldap.ParseDN(test)
  50. if err != nil {
  51. t.Errorf(err.Error())
  52. continue
  53. }
  54. if !reflect.DeepEqual(dn, &answer) {
  55. t.Errorf("Parsed DN %s is not equal to the expected structure", test)
  56. t.Logf("Expected:")
  57. for _, rdn := range answer.RDNs {
  58. for _, attribs := range rdn.Attributes {
  59. t.Logf("#%v\n", attribs)
  60. }
  61. }
  62. t.Logf("Actual:")
  63. for _, rdn := range dn.RDNs {
  64. for _, attribs := range rdn.Attributes {
  65. t.Logf("#%v\n", attribs)
  66. }
  67. }
  68. }
  69. }
  70. }
  71. func TestErrorDNParsing(t *testing.T) {
  72. testcases := map[string]string{
  73. "*": "DN ended with incomplete type, value pair",
  74. "cn=Jim\\0Test": "failed to decode escaped character: encoding/hex: invalid byte: U+0054 'T'",
  75. "cn=Jim\\0": "got corrupted escaped character",
  76. "DC=example,=net": "DN ended with incomplete type, value pair",
  77. "1=#0402486": "failed to decode BER encoding: encoding/hex: odd length hex string",
  78. "test,DC=example,DC=com": "incomplete type, value pair",
  79. "=test,DC=example,DC=com": "incomplete type, value pair",
  80. }
  81. for test, answer := range testcases {
  82. _, err := ldap.ParseDN(test)
  83. if err == nil {
  84. t.Errorf("Expected %s to fail parsing but succeeded\n", test)
  85. } else if err.Error() != answer {
  86. t.Errorf("Unexpected error on %s:\n%s\nvs.\n%s\n", test, answer, err.Error())
  87. }
  88. }
  89. }
  90. func TestDNEqual(t *testing.T) {
  91. testcases := []struct {
  92. A string
  93. B string
  94. Equal bool
  95. }{
  96. // Exact match
  97. {"", "", true},
  98. {"o=A", "o=A", true},
  99. {"o=A", "o=B", false},
  100. {"o=A,o=B", "o=A,o=B", true},
  101. {"o=A,o=B", "o=A,o=C", false},
  102. {"o=A+o=B", "o=A+o=B", true},
  103. {"o=A+o=B", "o=A+o=C", false},
  104. // Case mismatch in type is ignored
  105. {"o=A", "O=A", true},
  106. {"o=A,o=B", "o=A,O=B", true},
  107. {"o=A+o=B", "o=A+O=B", true},
  108. // Case mismatch in value is significant
  109. {"o=a", "O=A", false},
  110. {"o=a,o=B", "o=A,O=B", false},
  111. {"o=a+o=B", "o=A+O=B", false},
  112. // Multi-valued RDN order mismatch is ignored
  113. {"o=A+o=B", "O=B+o=A", true},
  114. // Number of RDN attributes is significant
  115. {"o=A+o=B", "O=B+o=A+O=B", false},
  116. // Missing values are significant
  117. {"o=A+o=B", "O=B+o=A+O=C", false}, // missing values matter
  118. {"o=A+o=B+o=C", "O=B+o=A", false}, // missing values matter
  119. // Whitespace tests
  120. // Matching
  121. {
  122. "cn=John Doe, ou=People, dc=sun.com",
  123. "cn=John Doe, ou=People, dc=sun.com",
  124. true,
  125. },
  126. // Difference in leading/trailing chars is ignored
  127. {
  128. "cn=John Doe, ou=People, dc=sun.com",
  129. "cn=John Doe,ou=People,dc=sun.com",
  130. true,
  131. },
  132. // Difference in values is significant
  133. {
  134. "cn=John Doe, ou=People, dc=sun.com",
  135. "cn=John Doe, ou=People, dc=sun.com",
  136. false,
  137. },
  138. }
  139. for i, tc := range testcases {
  140. a, err := ldap.ParseDN(tc.A)
  141. if err != nil {
  142. t.Errorf("%d: %v", i, err)
  143. continue
  144. }
  145. b, err := ldap.ParseDN(tc.B)
  146. if err != nil {
  147. t.Errorf("%d: %v", i, err)
  148. continue
  149. }
  150. if expected, actual := tc.Equal, a.Equal(b); expected != actual {
  151. t.Errorf("%d: when comparing '%s' and '%s' expected %v, got %v", i, tc.A, tc.B, expected, actual)
  152. continue
  153. }
  154. if expected, actual := tc.Equal, b.Equal(a); expected != actual {
  155. t.Errorf("%d: when comparing '%s' and '%s' expected %v, got %v", i, tc.A, tc.B, expected, actual)
  156. continue
  157. }
  158. }
  159. }
  160. func TestDNAncestor(t *testing.T) {
  161. testcases := []struct {
  162. A string
  163. B string
  164. Ancestor bool
  165. }{
  166. // Exact match returns false
  167. {"", "", false},
  168. {"o=A", "o=A", false},
  169. {"o=A,o=B", "o=A,o=B", false},
  170. {"o=A+o=B", "o=A+o=B", false},
  171. // Mismatch
  172. {"ou=C,ou=B,o=A", "ou=E,ou=D,ou=B,o=A", false},
  173. // Descendant
  174. {"ou=C,ou=B,o=A", "ou=E,ou=C,ou=B,o=A", true},
  175. }
  176. for i, tc := range testcases {
  177. a, err := ldap.ParseDN(tc.A)
  178. if err != nil {
  179. t.Errorf("%d: %v", i, err)
  180. continue
  181. }
  182. b, err := ldap.ParseDN(tc.B)
  183. if err != nil {
  184. t.Errorf("%d: %v", i, err)
  185. continue
  186. }
  187. if expected, actual := tc.Ancestor, a.AncestorOf(b); expected != actual {
  188. t.Errorf("%d: when comparing '%s' and '%s' expected %v, got %v", i, tc.A, tc.B, expected, actual)
  189. continue
  190. }
  191. }
  192. }