...

Source file src/github.com/go-ldap/ldap/v3/dn_test.go

Documentation: github.com/go-ldap/ldap/v3

     1  package ldap
     2  
     3  import (
     4  	"reflect"
     5  	"testing"
     6  )
     7  
     8  func TestSuccessfulDNParsing(t *testing.T) {
     9  	testcases := map[string]DN{
    10  		"": {[]*RelativeDN{}},
    11  		"cn=Jim\\2C \\22Hasse Hö\\22 Hansson!,dc=dummy,dc=com": {[]*RelativeDN{
    12  			{[]*AttributeTypeAndValue{{"cn", "Jim, \"Hasse Hö\" Hansson!"}}},
    13  			{[]*AttributeTypeAndValue{{"dc", "dummy"}}},
    14  			{[]*AttributeTypeAndValue{{"dc", "com"}}},
    15  		}},
    16  		"UID=jsmith,DC=example,DC=net": {[]*RelativeDN{
    17  			{[]*AttributeTypeAndValue{{"UID", "jsmith"}}},
    18  			{[]*AttributeTypeAndValue{{"DC", "example"}}},
    19  			{[]*AttributeTypeAndValue{{"DC", "net"}}},
    20  		}},
    21  		"OU=Sales+CN=J. Smith,DC=example,DC=net": {[]*RelativeDN{
    22  			{[]*AttributeTypeAndValue{
    23  				{"OU", "Sales"},
    24  				{"CN", "J. Smith"},
    25  			}},
    26  			{[]*AttributeTypeAndValue{{"DC", "example"}}},
    27  			{[]*AttributeTypeAndValue{{"DC", "net"}}},
    28  		}},
    29  		"1.3.6.1.4.1.1466.0=#04024869": {[]*RelativeDN{
    30  			{[]*AttributeTypeAndValue{{"1.3.6.1.4.1.1466.0", "Hi"}}},
    31  		}},
    32  		"1.3.6.1.4.1.1466.0=#04024869,DC=net": {[]*RelativeDN{
    33  			{[]*AttributeTypeAndValue{{"1.3.6.1.4.1.1466.0", "Hi"}}},
    34  			{[]*AttributeTypeAndValue{{"DC", "net"}}},
    35  		}},
    36  		"CN=Lu\\C4\\8Di\\C4\\87": {[]*RelativeDN{
    37  			{[]*AttributeTypeAndValue{{"CN", "Lučić"}}},
    38  		}},
    39  		"  CN  =  Lu\\C4\\8Di\\C4\\87  ": {[]*RelativeDN{
    40  			{[]*AttributeTypeAndValue{{"CN", "Lučić"}}},
    41  		}},
    42  		`   A   =   1   ,   B   =   2   `: {[]*RelativeDN{
    43  			{[]*AttributeTypeAndValue{{"A", "1"}}},
    44  			{[]*AttributeTypeAndValue{{"B", "2"}}},
    45  		}},
    46  		`   A   =   1   +   B   =   2   `: {[]*RelativeDN{
    47  			{[]*AttributeTypeAndValue{
    48  				{"A", "1"},
    49  				{"B", "2"},
    50  			}},
    51  		}},
    52  		`   \ \ A\ \    =   \ \ 1\ \    ,   \ \ B\ \    =   \ \ 2\ \    `: {[]*RelativeDN{
    53  			{[]*AttributeTypeAndValue{{"  A  ", "  1  "}}},
    54  			{[]*AttributeTypeAndValue{{"  B  ", "  2  "}}},
    55  		}},
    56  		`   \ \ A\ \    =   \ \ 1\ \    +   \ \ B\ \    =   \ \ 2\ \    `: {[]*RelativeDN{
    57  			{[]*AttributeTypeAndValue{
    58  				{"  A  ", "  1  "},
    59  				{"  B  ", "  2  "},
    60  			}},
    61  		}},
    62  
    63  		`cn=john.doe;dc=example,dc=net`: {[]*RelativeDN{
    64  			{[]*AttributeTypeAndValue{{"cn", "john.doe"}}},
    65  			{[]*AttributeTypeAndValue{{"dc", "example"}}},
    66  			{[]*AttributeTypeAndValue{{"dc", "net"}}},
    67  		}},
    68  
    69  		// Escaped `;` should not be treated as RDN
    70  		`cn=john.doe\;weird name,dc=example,dc=net`: {[]*RelativeDN{
    71  			{[]*AttributeTypeAndValue{{"cn", "john.doe;weird name"}}},
    72  			{[]*AttributeTypeAndValue{{"dc", "example"}}},
    73  			{[]*AttributeTypeAndValue{{"dc", "net"}}},
    74  		}},
    75  		`cn=ZXhhbXBsZVRleHQ=,dc=dummy,dc=com`: {[]*RelativeDN{
    76  			{[]*AttributeTypeAndValue{{"cn", "ZXhhbXBsZVRleHQ="}}},
    77  			{[]*AttributeTypeAndValue{{"dc", "dummy"}}},
    78  			{[]*AttributeTypeAndValue{{"dc", "com"}}},
    79  		}},
    80  	}
    81  
    82  	for test, answer := range testcases {
    83  		dn, err := ParseDN(test)
    84  		if err != nil {
    85  			t.Errorf(err.Error())
    86  			continue
    87  		}
    88  		if !reflect.DeepEqual(dn, &answer) {
    89  			t.Errorf("Parsed DN %s is not equal to the expected structure", test)
    90  			t.Logf("Expected:")
    91  			for _, rdn := range answer.RDNs {
    92  				for _, attribs := range rdn.Attributes {
    93  					t.Logf("#%v\n", attribs)
    94  				}
    95  			}
    96  			t.Logf("Actual:")
    97  			for _, rdn := range dn.RDNs {
    98  				for _, attribs := range rdn.Attributes {
    99  					t.Logf("#%v\n", attribs)
   100  				}
   101  			}
   102  		}
   103  	}
   104  }
   105  
   106  func TestErrorDNParsing(t *testing.T) {
   107  	testcases := map[string]string{
   108  		"*":                       "DN ended with incomplete type, value pair",
   109  		"cn=Jim\\0Test":           "failed to decode escaped character: encoding/hex: invalid byte: U+0054 'T'",
   110  		"cn=Jim\\0":               "got corrupted escaped character",
   111  		"DC=example,=net":         "DN ended with incomplete type, value pair",
   112  		"1=#0402486":              "failed to decode BER encoding: encoding/hex: odd length hex string",
   113  		"test,DC=example,DC=com":  "incomplete type, value pair",
   114  		"=test,DC=example,DC=com": "incomplete type, value pair",
   115  	}
   116  
   117  	for test, answer := range testcases {
   118  		_, err := ParseDN(test)
   119  		if err == nil {
   120  			t.Errorf("Expected %s to fail parsing but succeeded\n", test)
   121  		} else if err.Error() != answer {
   122  			t.Errorf("Unexpected error on %s:\n%s\nvs.\n%s\n", test, answer, err.Error())
   123  		}
   124  	}
   125  }
   126  
   127  func TestDNEqual(t *testing.T) {
   128  	testcases := []struct {
   129  		A     string
   130  		B     string
   131  		Equal bool
   132  	}{
   133  		// Exact match
   134  		{"", "", true},
   135  		{"o=A", "o=A", true},
   136  		{"o=A", "o=B", false},
   137  
   138  		{"o=A,o=B", "o=A,o=B", true},
   139  		{"o=A,o=B", "o=A,o=C", false},
   140  
   141  		{"o=A+o=B", "o=A+o=B", true},
   142  		{"o=A+o=B", "o=A+o=C", false},
   143  
   144  		// Case mismatch in type is ignored
   145  		{"o=A", "O=A", true},
   146  		{"o=A,o=B", "o=A,O=B", true},
   147  		{"o=A+o=B", "o=A+O=B", true},
   148  
   149  		// Case mismatch in value is significant
   150  		{"o=a", "O=A", false},
   151  		{"o=a,o=B", "o=A,O=B", false},
   152  		{"o=a+o=B", "o=A+O=B", false},
   153  
   154  		// Multi-valued RDN order mismatch is ignored
   155  		{"o=A+o=B", "O=B+o=A", true},
   156  		// Number of RDN attributes is significant
   157  		{"o=A+o=B", "O=B+o=A+O=B", false},
   158  
   159  		// Missing values are significant
   160  		{"o=A+o=B", "O=B+o=A+O=C", false}, // missing values matter
   161  		{"o=A+o=B+o=C", "O=B+o=A", false}, // missing values matter
   162  
   163  		// Whitespace tests
   164  		// Matching
   165  		{
   166  			"cn=John Doe, ou=People, dc=sun.com",
   167  			"cn=John Doe, ou=People, dc=sun.com",
   168  			true,
   169  		},
   170  		// Difference in leading/trailing chars is ignored
   171  		{
   172  			"cn=\\ John\\20Doe, ou=People, dc=sun.com",
   173  			"cn= \\ John Doe,ou=People,dc=sun.com",
   174  			true,
   175  		},
   176  		// Difference in values is significant
   177  		{
   178  			"cn=John Doe, ou=People, dc=sun.com",
   179  			"cn=John  Doe, ou=People, dc=sun.com",
   180  			false,
   181  		},
   182  		// Test parsing of `;` for separating RDNs
   183  		{"cn=john;dc=example,dc=com", "cn=john,dc=example,dc=com", true}, // missing values matter
   184  	}
   185  
   186  	for i, tc := range testcases {
   187  		a, err := ParseDN(tc.A)
   188  		if err != nil {
   189  			t.Errorf("%d: %v", i, err)
   190  			continue
   191  		}
   192  		b, err := ParseDN(tc.B)
   193  		if err != nil {
   194  			t.Errorf("%d: %v", i, err)
   195  			continue
   196  		}
   197  		if expected, actual := tc.Equal, a.Equal(b); expected != actual {
   198  			t.Errorf("%d: when comparing %q and %q expected %v, got %v", i, a, b, expected, actual)
   199  			continue
   200  		}
   201  		if expected, actual := tc.Equal, b.Equal(a); expected != actual {
   202  			t.Errorf("%d: when comparing %q and %q expected %v, got %v", i, a, b, expected, actual)
   203  			continue
   204  		}
   205  
   206  		if expected, actual := a.Equal(b), a.String() == b.String(); expected != actual {
   207  			t.Errorf("%d: when asserting string comparison of %q and %q expected equal %v, got %v", i, a, b, expected, actual)
   208  			continue
   209  		}
   210  	}
   211  }
   212  
   213  func TestDNEqualFold(t *testing.T) {
   214  	testcases := []struct {
   215  		A     string
   216  		B     string
   217  		Equal bool
   218  	}{
   219  		// Match on case insensitive
   220  		{"o=A", "o=a", true},
   221  		{"o=A,o=b", "o=a,o=B", true},
   222  		{"o=a+o=B", "o=A+o=b", true},
   223  		{
   224  			"cn=users,ou=example,dc=com",
   225  			"cn=Users,ou=example,dc=com",
   226  			true,
   227  		},
   228  
   229  		// Match on case insensitive and case mismatch in type
   230  		{"o=A", "O=a", true},
   231  		{"o=A,o=b", "o=a,O=B", true},
   232  		{"o=a+o=B", "o=A+O=b", true},
   233  	}
   234  
   235  	for i, tc := range testcases {
   236  		a, err := ParseDN(tc.A)
   237  		if err != nil {
   238  			t.Errorf("%d: %v", i, err)
   239  			continue
   240  		}
   241  		b, err := ParseDN(tc.B)
   242  		if err != nil {
   243  			t.Errorf("%d: %v", i, err)
   244  			continue
   245  		}
   246  		if expected, actual := tc.Equal, a.EqualFold(b); expected != actual {
   247  			t.Errorf("%d: when comparing '%s' and '%s' expected %v, got %v", i, tc.A, tc.B, expected, actual)
   248  			continue
   249  		}
   250  		if expected, actual := tc.Equal, b.EqualFold(a); expected != actual {
   251  			t.Errorf("%d: when comparing '%s' and '%s' expected %v, got %v", i, tc.A, tc.B, expected, actual)
   252  			continue
   253  		}
   254  	}
   255  }
   256  
   257  func TestDNAncestor(t *testing.T) {
   258  	testcases := []struct {
   259  		A        string
   260  		B        string
   261  		Ancestor bool
   262  	}{
   263  		// Exact match returns false
   264  		{"", "", false},
   265  		{"o=A", "o=A", false},
   266  		{"o=A,o=B", "o=A,o=B", false},
   267  		{"o=A+o=B", "o=A+o=B", false},
   268  
   269  		// Mismatch
   270  		{"ou=C,ou=B,o=A", "ou=E,ou=D,ou=B,o=A", false},
   271  
   272  		// Descendant
   273  		{"ou=C,ou=B,o=A", "ou=E,ou=C,ou=B,o=A", true},
   274  	}
   275  
   276  	for i, tc := range testcases {
   277  		a, err := ParseDN(tc.A)
   278  		if err != nil {
   279  			t.Errorf("%d: %v", i, err)
   280  			continue
   281  		}
   282  		b, err := ParseDN(tc.B)
   283  		if err != nil {
   284  			t.Errorf("%d: %v", i, err)
   285  			continue
   286  		}
   287  		if expected, actual := tc.Ancestor, a.AncestorOf(b); expected != actual {
   288  			t.Errorf("%d: when comparing '%s' and '%s' expected %v, got %v", i, tc.A, tc.B, expected, actual)
   289  			continue
   290  		}
   291  	}
   292  }
   293  

View as plain text