...

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

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

     1  package ldap
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"reflect"
     7  	"runtime"
     8  	"testing"
     9  
    10  	ber "github.com/go-asn1-ber/asn1-ber"
    11  )
    12  
    13  func TestControlPaging(t *testing.T) {
    14  	runControlTest(t, NewControlPaging(0))
    15  	runControlTest(t, NewControlPaging(100))
    16  }
    17  
    18  func TestControlManageDsaIT(t *testing.T) {
    19  	runControlTest(t, NewControlManageDsaIT(true))
    20  	runControlTest(t, NewControlManageDsaIT(false))
    21  }
    22  
    23  func TestControlMicrosoftNotification(t *testing.T) {
    24  	runControlTest(t, NewControlMicrosoftNotification())
    25  }
    26  
    27  func TestControlMicrosoftShowDeleted(t *testing.T) {
    28  	runControlTest(t, NewControlMicrosoftShowDeleted())
    29  }
    30  
    31  func TestControlMicrosoftServerLinkTTL(t *testing.T) {
    32  	runControlTest(t, NewControlMicrosoftServerLinkTTL())
    33  }
    34  
    35  func TestControlSubtreeDelete(t *testing.T) {
    36  	runControlTest(t, NewControlSubtreeDelete())
    37  }
    38  
    39  func TestControlString(t *testing.T) {
    40  	runControlTest(t, NewControlString("x", true, "y"))
    41  	runControlTest(t, NewControlString("x", true, ""))
    42  	runControlTest(t, NewControlString("x", false, "y"))
    43  	runControlTest(t, NewControlString("x", false, ""))
    44  }
    45  
    46  func TestControlDirSync(t *testing.T) {
    47  	runControlTest(t, NewRequestControlDirSync(DirSyncObjectSecurity, 1000, nil))
    48  	runControlTest(t, NewRequestControlDirSync(DirSyncObjectSecurity, 1000, []byte("I'm a cookie!")))
    49  }
    50  
    51  func runControlTest(t *testing.T, originalControl Control) {
    52  	header := ""
    53  	if callerpc, _, line, ok := runtime.Caller(1); ok {
    54  		if caller := runtime.FuncForPC(callerpc); caller != nil {
    55  			header = fmt.Sprintf("%s:%d: ", caller.Name(), line)
    56  		}
    57  	}
    58  
    59  	encodedPacket := originalControl.Encode()
    60  	encodedBytes := encodedPacket.Bytes()
    61  
    62  	// Decode directly from the encoded packet (ensures Value is correct)
    63  	fromPacket, err := DecodeControl(encodedPacket)
    64  	if err != nil {
    65  		t.Errorf("%sdecoding encoded bytes control failed: %s", header, err)
    66  	}
    67  	if !bytes.Equal(encodedBytes, fromPacket.Encode().Bytes()) {
    68  		t.Errorf("%sround-trip from encoded packet failed", header)
    69  	}
    70  	if reflect.TypeOf(originalControl) != reflect.TypeOf(fromPacket) {
    71  		t.Errorf("%sgot different type decoding from encoded packet: %T vs %T", header, fromPacket, originalControl)
    72  	}
    73  
    74  	// Decode from the wire bytes (ensures ber-encoding is correct)
    75  	pkt, err := ber.DecodePacketErr(encodedBytes)
    76  	if err != nil {
    77  		t.Errorf("%sdecoding encoded bytes failed: %s", header, err)
    78  	}
    79  	fromBytes, err := DecodeControl(pkt)
    80  	if err != nil {
    81  		t.Errorf("%sdecoding control failed: %s", header, err)
    82  	}
    83  	if !bytes.Equal(encodedBytes, fromBytes.Encode().Bytes()) {
    84  		t.Errorf("%sround-trip from encoded bytes failed", header)
    85  	}
    86  	if reflect.TypeOf(originalControl) != reflect.TypeOf(fromPacket) {
    87  		t.Errorf("%sgot different type decoding from encoded bytes: %T vs %T", header, fromBytes, originalControl)
    88  	}
    89  }
    90  
    91  func TestDescribeControlManageDsaIT(t *testing.T) {
    92  	runAddControlDescriptions(t, NewControlManageDsaIT(false), "Control Type (Manage DSA IT)")
    93  	runAddControlDescriptions(t, NewControlManageDsaIT(true), "Control Type (Manage DSA IT)", "Criticality")
    94  }
    95  
    96  func TestDescribeControlPaging(t *testing.T) {
    97  	runAddControlDescriptions(t, NewControlPaging(100), "Control Type (Paging)", "Control Value (Paging)")
    98  	runAddControlDescriptions(t, NewControlPaging(0), "Control Type (Paging)", "Control Value (Paging)")
    99  }
   100  
   101  func TestDescribeControlSubtreeDelete(t *testing.T) {
   102  	runAddControlDescriptions(t, NewControlSubtreeDelete(), "Control Type (Subtree Delete Control)")
   103  }
   104  
   105  func TestDescribeControlMicrosoftNotification(t *testing.T) {
   106  	runAddControlDescriptions(t, NewControlMicrosoftNotification(), "Control Type (Change Notification - Microsoft)")
   107  }
   108  
   109  func TestDescribeControlMicrosoftShowDeleted(t *testing.T) {
   110  	runAddControlDescriptions(t, NewControlMicrosoftShowDeleted(), "Control Type (Show Deleted Objects - Microsoft)")
   111  }
   112  
   113  func TestDescribeControlMicrosoftServerLinkTTL(t *testing.T) {
   114  	runAddControlDescriptions(t, NewControlMicrosoftServerLinkTTL(), "Control Type (Return TTL-DNs for link values with associated expiry times - Microsoft)")
   115  }
   116  
   117  func TestDescribeControlString(t *testing.T) {
   118  	runAddControlDescriptions(t, NewControlString("x", true, "y"), "Control Type ()", "Criticality", "Control Value")
   119  	runAddControlDescriptions(t, NewControlString("x", true, ""), "Control Type ()", "Criticality")
   120  	runAddControlDescriptions(t, NewControlString("x", false, "y"), "Control Type ()", "Control Value")
   121  	runAddControlDescriptions(t, NewControlString("x", false, ""), "Control Type ()")
   122  }
   123  
   124  func TestDescribeControlDirSync(t *testing.T) {
   125  	runAddControlDescriptions(t, NewRequestControlDirSync(DirSyncObjectSecurity, 1000, nil), "Control Type (DirSync)", "Criticality", "Control Value")
   126  }
   127  
   128  func runAddControlDescriptions(t *testing.T, originalControl Control, childDescriptions ...string) {
   129  	header := ""
   130  	if callerpc, _, line, ok := runtime.Caller(1); ok {
   131  		if caller := runtime.FuncForPC(callerpc); caller != nil {
   132  			header = fmt.Sprintf("%s:%d: ", caller.Name(), line)
   133  		}
   134  	}
   135  
   136  	encodedControls := encodeControls([]Control{originalControl})
   137  	_ = addControlDescriptions(encodedControls)
   138  	encodedPacket := encodedControls.Children[0]
   139  	if len(encodedPacket.Children) != len(childDescriptions) {
   140  		t.Errorf("%sinvalid number of children: %d != %d", header, len(encodedPacket.Children), len(childDescriptions))
   141  	}
   142  	for i, desc := range childDescriptions {
   143  		if encodedPacket.Children[i].Description != desc {
   144  			t.Errorf("%sdescription not as expected: %s != %s", header, encodedPacket.Children[i].Description, desc)
   145  		}
   146  	}
   147  }
   148  
   149  func TestDecodeControl(t *testing.T) {
   150  	type args struct {
   151  		packet *ber.Packet
   152  	}
   153  
   154  	tests := []struct {
   155  		name    string
   156  		args    args
   157  		want    Control
   158  		wantErr bool
   159  	}{
   160  		{
   161  			name: "timeBeforeExpiration", args: args{packet: ber.DecodePacket([]byte{0xa0, 0x29, 0x30, 0x27, 0x4, 0x19, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x32, 0x2e, 0x32, 0x2e, 0x32, 0x37, 0x2e, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x4, 0xa, 0x30, 0x8, 0xa0, 0x6, 0x80, 0x4, 0x7f, 0xff, 0xf6, 0x5c})},
   162  			want: &ControlBeheraPasswordPolicy{Expire: 2147481180, Grace: -1, Error: -1, ErrorString: ""}, wantErr: false,
   163  		},
   164  		{
   165  			name: "graceAuthNsRemaining", args: args{packet: ber.DecodePacket([]byte{0xa0, 0x26, 0x30, 0x24, 0x4, 0x19, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x32, 0x2e, 0x32, 0x2e, 0x32, 0x37, 0x2e, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x4, 0x7, 0x30, 0x5, 0xa0, 0x3, 0x81, 0x1, 0x11})},
   166  			want: &ControlBeheraPasswordPolicy{Expire: -1, Grace: 17, Error: -1, ErrorString: ""}, wantErr: false,
   167  		},
   168  		{
   169  			name: "passwordExpired", args: args{packet: ber.DecodePacket([]byte{0xa0, 0x24, 0x30, 0x22, 0x4, 0x19, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x32, 0x2e, 0x32, 0x2e, 0x32, 0x37, 0x2e, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x4, 0x5, 0x30, 0x3, 0x81, 0x1, 0x0})},
   170  			want: &ControlBeheraPasswordPolicy{Expire: -1, Grace: -1, Error: 0, ErrorString: "Password expired"}, wantErr: false,
   171  		},
   172  		{
   173  			name: "accountLocked", args: args{packet: ber.DecodePacket([]byte{0xa0, 0x24, 0x30, 0x22, 0x4, 0x19, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x32, 0x2e, 0x32, 0x2e, 0x32, 0x37, 0x2e, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x4, 0x5, 0x30, 0x3, 0x81, 0x1, 0x1})},
   174  			want: &ControlBeheraPasswordPolicy{Expire: -1, Grace: -1, Error: 1, ErrorString: "Account locked"}, wantErr: false,
   175  		},
   176  		{
   177  			name: "passwordModNotAllowed", args: args{packet: ber.DecodePacket([]byte{0xa0, 0x24, 0x30, 0x22, 0x4, 0x19, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x32, 0x2e, 0x32, 0x2e, 0x32, 0x37, 0x2e, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x4, 0x5, 0x30, 0x3, 0x81, 0x1, 0x3})},
   178  			want: &ControlBeheraPasswordPolicy{Expire: -1, Grace: -1, Error: 3, ErrorString: "Policy prevents password modification"}, wantErr: false,
   179  		},
   180  		{
   181  			name: "mustSupplyOldPassword", args: args{packet: ber.DecodePacket([]byte{0xa0, 0x24, 0x30, 0x22, 0x4, 0x19, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x32, 0x2e, 0x32, 0x2e, 0x32, 0x37, 0x2e, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x4, 0x5, 0x30, 0x3, 0x81, 0x1, 0x4})},
   182  			want: &ControlBeheraPasswordPolicy{Expire: -1, Grace: -1, Error: 4, ErrorString: "Policy requires old password in order to change password"}, wantErr: false,
   183  		},
   184  		{
   185  			name: "insufficientPasswordQuality", args: args{packet: ber.DecodePacket([]byte{0xa0, 0x24, 0x30, 0x22, 0x4, 0x19, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x32, 0x2e, 0x32, 0x2e, 0x32, 0x37, 0x2e, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x4, 0x5, 0x30, 0x3, 0x81, 0x1, 0x5})},
   186  			want: &ControlBeheraPasswordPolicy{Expire: -1, Grace: -1, Error: 5, ErrorString: "Password fails quality checks"}, wantErr: false,
   187  		},
   188  		{
   189  			name: "passwordTooShort", args: args{packet: ber.DecodePacket([]byte{0xa0, 0x24, 0x30, 0x22, 0x4, 0x19, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x32, 0x2e, 0x32, 0x2e, 0x32, 0x37, 0x2e, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x4, 0x5, 0x30, 0x3, 0x81, 0x1, 0x6})},
   190  			want: &ControlBeheraPasswordPolicy{Expire: -1, Grace: -1, Error: 6, ErrorString: "Password is too short for policy"}, wantErr: false,
   191  		},
   192  		{
   193  			name: "passwordTooYoung", args: args{packet: ber.DecodePacket([]byte{0xa0, 0x24, 0x30, 0x22, 0x4, 0x19, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x32, 0x2e, 0x32, 0x2e, 0x32, 0x37, 0x2e, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x4, 0x5, 0x30, 0x3, 0x81, 0x1, 0x7})},
   194  			want: &ControlBeheraPasswordPolicy{Expire: -1, Grace: -1, Error: 7, ErrorString: "Password has been changed too recently"}, wantErr: false,
   195  		},
   196  		{
   197  			name: "passwordInHistory", args: args{packet: ber.DecodePacket([]byte{0xa0, 0x24, 0x30, 0x22, 0x4, 0x19, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x32, 0x2e, 0x32, 0x2e, 0x32, 0x37, 0x2e, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x4, 0x5, 0x30, 0x3, 0x81, 0x1, 0x8})},
   198  			want: &ControlBeheraPasswordPolicy{Expire: -1, Grace: -1, Error: 8, ErrorString: "New password is in list of old passwords"}, wantErr: false,
   199  		},
   200  	}
   201  	for i := range tests {
   202  		err := addControlDescriptions(tests[i].args.packet)
   203  		if err != nil {
   204  			t.Fatal(err)
   205  		}
   206  		tests[i].args.packet = tests[i].args.packet.Children[0]
   207  	}
   208  
   209  	for _, tt := range tests {
   210  		t.Run(tt.name, func(t *testing.T) {
   211  			got, err := DecodeControl(tt.args.packet)
   212  			if (err != nil) != tt.wantErr {
   213  				t.Errorf("DecodeControl() error = %v, wantErr %v", err, tt.wantErr)
   214  				return
   215  			}
   216  			if !reflect.DeepEqual(got, tt.want) {
   217  				t.Errorf("DecodeControl() got = %v, want %v", got, tt.want)
   218  			}
   219  		})
   220  	}
   221  }
   222  
   223  func TestControlServerSideSortingDecoding(t *testing.T) {
   224  	control := NewControlServerSideSortingWithSortKeys([]*SortKey{{
   225  		MatchingRule:  "foo",
   226  		AttributeType: "foobar",
   227  		Reverse:       true,
   228  	}, {
   229  		MatchingRule:  "foo",
   230  		AttributeType: "foobar",
   231  		Reverse:       false,
   232  	}, {
   233  		MatchingRule:  "",
   234  		AttributeType: "",
   235  		Reverse:       false,
   236  	}, {
   237  		MatchingRule:  "totoRule",
   238  		AttributeType: "",
   239  		Reverse:       false,
   240  	}, {
   241  		MatchingRule:  "",
   242  		AttributeType: "totoType",
   243  		Reverse:       false,
   244  	}})
   245  
   246  	controlDecoded, err := NewControlServerSideSorting(control.Encode())
   247  	if err != nil {
   248  		t.Fatal(err)
   249  	}
   250  
   251  	if control.GetControlType() != controlDecoded.GetControlType() {
   252  		t.Fatalf("control type mismatch: control:%s - decoded:%s", control.GetControlType(), controlDecoded.GetControlType())
   253  	}
   254  
   255  	if len(control.SortKeys) != len(controlDecoded.SortKeys) {
   256  		t.Fatalf("sort keys length mismatch (control: %d - decoded: %d)", len(control.SortKeys), len(controlDecoded.SortKeys))
   257  	}
   258  
   259  	for i, sk := range control.SortKeys {
   260  		dsk := controlDecoded.SortKeys[i]
   261  
   262  		if sk.AttributeType != dsk.AttributeType {
   263  			t.Fatalf("attribute type mismatch for sortkey %d", i)
   264  		}
   265  
   266  		if sk.MatchingRule != dsk.MatchingRule {
   267  			t.Fatalf("matching rule mismatch for sortkey %d", i)
   268  		}
   269  
   270  		if sk.Reverse != dsk.Reverse {
   271  			t.Fatalf("reverse mismtach for sortkey %d", i)
   272  		}
   273  	}
   274  }
   275  

View as plain text