get.pme.sh/pnats@v0.0.0-20240304004023-26bb5a137ed0/internal/ldap/dn_test.go (about)

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