code.gitea.io/gitea@v1.22.3/cmd/admin_auth_ldap_test.go (about)

     1  // Copyright 2019 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package cmd
     5  
     6  import (
     7  	"context"
     8  	"testing"
     9  
    10  	"code.gitea.io/gitea/models/auth"
    11  	"code.gitea.io/gitea/services/auth/source/ldap"
    12  
    13  	"github.com/stretchr/testify/assert"
    14  	"github.com/urfave/cli/v2"
    15  )
    16  
    17  func TestAddLdapBindDn(t *testing.T) {
    18  	// Mock cli functions to do not exit on error
    19  	osExiter := cli.OsExiter
    20  	defer func() { cli.OsExiter = osExiter }()
    21  	cli.OsExiter = func(code int) {}
    22  
    23  	// Test cases
    24  	cases := []struct {
    25  		args   []string
    26  		source *auth.Source
    27  		errMsg string
    28  	}{
    29  		// case 0
    30  		{
    31  			args: []string{
    32  				"ldap-test",
    33  				"--name", "ldap (via Bind DN) source full",
    34  				"--not-active",
    35  				"--security-protocol", "ldaps",
    36  				"--skip-tls-verify",
    37  				"--host", "ldap-bind-server full",
    38  				"--port", "9876",
    39  				"--user-search-base", "ou=Users,dc=full-domain-bind,dc=org",
    40  				"--user-filter", "(memberOf=cn=user-group,ou=example,dc=full-domain-bind,dc=org)",
    41  				"--admin-filter", "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)",
    42  				"--restricted-filter", "(memberOf=cn=restricted-group,ou=example,dc=full-domain-bind,dc=org)",
    43  				"--username-attribute", "uid-bind full",
    44  				"--firstname-attribute", "givenName-bind full",
    45  				"--surname-attribute", "sn-bind full",
    46  				"--email-attribute", "mail-bind full",
    47  				"--public-ssh-key-attribute", "publickey-bind full",
    48  				"--avatar-attribute", "avatar-bind full",
    49  				"--bind-dn", "cn=readonly,dc=full-domain-bind,dc=org",
    50  				"--bind-password", "secret-bind-full",
    51  				"--attributes-in-bind",
    52  				"--synchronize-users",
    53  				"--page-size", "99",
    54  			},
    55  			source: &auth.Source{
    56  				Type:          auth.LDAP,
    57  				Name:          "ldap (via Bind DN) source full",
    58  				IsActive:      false,
    59  				IsSyncEnabled: true,
    60  				Cfg: &ldap.Source{
    61  					Name:                  "ldap (via Bind DN) source full",
    62  					Host:                  "ldap-bind-server full",
    63  					Port:                  9876,
    64  					SecurityProtocol:      ldap.SecurityProtocol(1),
    65  					SkipVerify:            true,
    66  					BindDN:                "cn=readonly,dc=full-domain-bind,dc=org",
    67  					BindPassword:          "secret-bind-full",
    68  					UserBase:              "ou=Users,dc=full-domain-bind,dc=org",
    69  					AttributeUsername:     "uid-bind full",
    70  					AttributeName:         "givenName-bind full",
    71  					AttributeSurname:      "sn-bind full",
    72  					AttributeMail:         "mail-bind full",
    73  					AttributesInBind:      true,
    74  					AttributeSSHPublicKey: "publickey-bind full",
    75  					AttributeAvatar:       "avatar-bind full",
    76  					SearchPageSize:        99,
    77  					Filter:                "(memberOf=cn=user-group,ou=example,dc=full-domain-bind,dc=org)",
    78  					AdminFilter:           "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)",
    79  					RestrictedFilter:      "(memberOf=cn=restricted-group,ou=example,dc=full-domain-bind,dc=org)",
    80  					Enabled:               true,
    81  				},
    82  			},
    83  		},
    84  		// case 1
    85  		{
    86  			args: []string{
    87  				"ldap-test",
    88  				"--name", "ldap (via Bind DN) source min",
    89  				"--security-protocol", "unencrypted",
    90  				"--host", "ldap-bind-server min",
    91  				"--port", "1234",
    92  				"--user-search-base", "ou=Users,dc=min-domain-bind,dc=org",
    93  				"--user-filter", "(memberOf=cn=user-group,ou=example,dc=min-domain-bind,dc=org)",
    94  				"--email-attribute", "mail-bind min",
    95  			},
    96  			source: &auth.Source{
    97  				Type:     auth.LDAP,
    98  				Name:     "ldap (via Bind DN) source min",
    99  				IsActive: true,
   100  				Cfg: &ldap.Source{
   101  					Name:             "ldap (via Bind DN) source min",
   102  					Host:             "ldap-bind-server min",
   103  					Port:             1234,
   104  					SecurityProtocol: ldap.SecurityProtocol(0),
   105  					UserBase:         "ou=Users,dc=min-domain-bind,dc=org",
   106  					AttributeMail:    "mail-bind min",
   107  					Filter:           "(memberOf=cn=user-group,ou=example,dc=min-domain-bind,dc=org)",
   108  					Enabled:          true,
   109  				},
   110  			},
   111  		},
   112  		// case 2
   113  		{
   114  			args: []string{
   115  				"ldap-test",
   116  				"--name", "ldap (via Bind DN) source",
   117  				"--security-protocol", "zzzzz",
   118  				"--host", "ldap-server",
   119  				"--port", "1234",
   120  				"--user-search-base", "ou=Users,dc=domain,dc=org",
   121  				"--user-filter", "(memberOf=cn=user-group,ou=example,dc=domain,dc=org)",
   122  				"--email-attribute", "mail",
   123  			},
   124  			errMsg: "Unknown security protocol name: zzzzz",
   125  		},
   126  		// case 3
   127  		{
   128  			args: []string{
   129  				"ldap-test",
   130  				"--security-protocol", "unencrypted",
   131  				"--host", "ldap-server",
   132  				"--port", "1234",
   133  				"--user-search-base", "ou=Users,dc=domain,dc=org",
   134  				"--user-filter", "(memberOf=cn=user-group,ou=example,dc=domain,dc=org)",
   135  				"--email-attribute", "mail",
   136  			},
   137  			errMsg: "name is not set",
   138  		},
   139  		// case 4
   140  		{
   141  			args: []string{
   142  				"ldap-test",
   143  				"--name", "ldap (via Bind DN) source",
   144  				"--host", "ldap-server",
   145  				"--port", "1234",
   146  				"--user-search-base", "ou=Users,dc=domain,dc=org",
   147  				"--user-filter", "(memberOf=cn=user-group,ou=example,dc=domain,dc=org)",
   148  				"--email-attribute", "mail",
   149  			},
   150  			errMsg: "security-protocol is not set",
   151  		},
   152  		// case 5
   153  		{
   154  			args: []string{
   155  				"ldap-test",
   156  				"--name", "ldap (via Bind DN) source",
   157  				"--security-protocol", "unencrypted",
   158  				"--port", "1234",
   159  				"--user-search-base", "ou=Users,dc=domain,dc=org",
   160  				"--user-filter", "(memberOf=cn=user-group,ou=example,dc=domain,dc=org)",
   161  				"--email-attribute", "mail",
   162  			},
   163  			errMsg: "host is not set",
   164  		},
   165  		// case 6
   166  		{
   167  			args: []string{
   168  				"ldap-test",
   169  				"--name", "ldap (via Bind DN) source",
   170  				"--security-protocol", "unencrypted",
   171  				"--host", "ldap-server",
   172  				"--user-search-base", "ou=Users,dc=domain,dc=org",
   173  				"--user-filter", "(memberOf=cn=user-group,ou=example,dc=domain,dc=org)",
   174  				"--email-attribute", "mail",
   175  			},
   176  			errMsg: "port is not set",
   177  		},
   178  		// case 7
   179  		{
   180  			args: []string{
   181  				"ldap-test",
   182  				"--name", "ldap (via Bind DN) source",
   183  				"--security-protocol", "unencrypted",
   184  				"--host", "ldap-server",
   185  				"--port", "1234",
   186  				"--user-search-base", "ou=Users,dc=domain,dc=org",
   187  				"--email-attribute", "mail",
   188  			},
   189  			errMsg: "user-filter is not set",
   190  		},
   191  		// case 8
   192  		{
   193  			args: []string{
   194  				"ldap-test",
   195  				"--name", "ldap (via Bind DN) source",
   196  				"--security-protocol", "unencrypted",
   197  				"--host", "ldap-server",
   198  				"--port", "1234",
   199  				"--user-search-base", "ou=Users,dc=domain,dc=org",
   200  				"--user-filter", "(memberOf=cn=user-group,ou=example,dc=domain,dc=org)",
   201  			},
   202  			errMsg: "email-attribute is not set",
   203  		},
   204  	}
   205  
   206  	for n, c := range cases {
   207  		// Mock functions.
   208  		var createdAuthSource *auth.Source
   209  		service := &authService{
   210  			initDB: func(context.Context) error {
   211  				return nil
   212  			},
   213  			createAuthSource: func(ctx context.Context, authSource *auth.Source) error {
   214  				createdAuthSource = authSource
   215  				return nil
   216  			},
   217  			updateAuthSource: func(ctx context.Context, authSource *auth.Source) error {
   218  				assert.FailNow(t, "case %d: should not call updateAuthSource", n)
   219  				return nil
   220  			},
   221  			getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) {
   222  				assert.FailNow(t, "case %d: should not call getAuthSourceByID", n)
   223  				return nil, nil
   224  			},
   225  		}
   226  
   227  		// Create a copy of command to test
   228  		app := cli.NewApp()
   229  		app.Flags = microcmdAuthAddLdapBindDn.Flags
   230  		app.Action = service.addLdapBindDn
   231  
   232  		// Run it
   233  		err := app.Run(c.args)
   234  		if c.errMsg != "" {
   235  			assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
   236  		} else {
   237  			assert.NoError(t, err, "case %d: should have no errors", n)
   238  			assert.Equal(t, c.source, createdAuthSource, "case %d: wrong authSource", n)
   239  		}
   240  	}
   241  }
   242  
   243  func TestAddLdapSimpleAuth(t *testing.T) {
   244  	// Mock cli functions to do not exit on error
   245  	osExiter := cli.OsExiter
   246  	defer func() { cli.OsExiter = osExiter }()
   247  	cli.OsExiter = func(code int) {}
   248  
   249  	// Test cases
   250  	cases := []struct {
   251  		args       []string
   252  		authSource *auth.Source
   253  		errMsg     string
   254  	}{
   255  		// case 0
   256  		{
   257  			args: []string{
   258  				"ldap-test",
   259  				"--name", "ldap (simple auth) source full",
   260  				"--not-active",
   261  				"--security-protocol", "starttls",
   262  				"--skip-tls-verify",
   263  				"--host", "ldap-simple-server full",
   264  				"--port", "987",
   265  				"--user-search-base", "ou=Users,dc=full-domain-simple,dc=org",
   266  				"--user-filter", "(&(objectClass=posixAccount)(full-simple-cn=%s))",
   267  				"--admin-filter", "(memberOf=cn=admin-group,ou=example,dc=full-domain-simple,dc=org)",
   268  				"--restricted-filter", "(memberOf=cn=restricted-group,ou=example,dc=full-domain-simple,dc=org)",
   269  				"--username-attribute", "uid-simple full",
   270  				"--firstname-attribute", "givenName-simple full",
   271  				"--surname-attribute", "sn-simple full",
   272  				"--email-attribute", "mail-simple full",
   273  				"--public-ssh-key-attribute", "publickey-simple full",
   274  				"--avatar-attribute", "avatar-simple full",
   275  				"--user-dn", "cn=%s,ou=Users,dc=full-domain-simple,dc=org",
   276  			},
   277  			authSource: &auth.Source{
   278  				Type:     auth.DLDAP,
   279  				Name:     "ldap (simple auth) source full",
   280  				IsActive: false,
   281  				Cfg: &ldap.Source{
   282  					Name:                  "ldap (simple auth) source full",
   283  					Host:                  "ldap-simple-server full",
   284  					Port:                  987,
   285  					SecurityProtocol:      ldap.SecurityProtocol(2),
   286  					SkipVerify:            true,
   287  					UserDN:                "cn=%s,ou=Users,dc=full-domain-simple,dc=org",
   288  					UserBase:              "ou=Users,dc=full-domain-simple,dc=org",
   289  					AttributeUsername:     "uid-simple full",
   290  					AttributeName:         "givenName-simple full",
   291  					AttributeSurname:      "sn-simple full",
   292  					AttributeMail:         "mail-simple full",
   293  					AttributeSSHPublicKey: "publickey-simple full",
   294  					AttributeAvatar:       "avatar-simple full",
   295  					Filter:                "(&(objectClass=posixAccount)(full-simple-cn=%s))",
   296  					AdminFilter:           "(memberOf=cn=admin-group,ou=example,dc=full-domain-simple,dc=org)",
   297  					RestrictedFilter:      "(memberOf=cn=restricted-group,ou=example,dc=full-domain-simple,dc=org)",
   298  					Enabled:               true,
   299  				},
   300  			},
   301  		},
   302  		// case 1
   303  		{
   304  			args: []string{
   305  				"ldap-test",
   306  				"--name", "ldap (simple auth) source min",
   307  				"--security-protocol", "unencrypted",
   308  				"--host", "ldap-simple-server min",
   309  				"--port", "123",
   310  				"--user-filter", "(&(objectClass=posixAccount)(min-simple-cn=%s))",
   311  				"--email-attribute", "mail-simple min",
   312  				"--user-dn", "cn=%s,ou=Users,dc=min-domain-simple,dc=org",
   313  			},
   314  			authSource: &auth.Source{
   315  				Type:     auth.DLDAP,
   316  				Name:     "ldap (simple auth) source min",
   317  				IsActive: true,
   318  				Cfg: &ldap.Source{
   319  					Name:             "ldap (simple auth) source min",
   320  					Host:             "ldap-simple-server min",
   321  					Port:             123,
   322  					SecurityProtocol: ldap.SecurityProtocol(0),
   323  					UserDN:           "cn=%s,ou=Users,dc=min-domain-simple,dc=org",
   324  					AttributeMail:    "mail-simple min",
   325  					Filter:           "(&(objectClass=posixAccount)(min-simple-cn=%s))",
   326  					Enabled:          true,
   327  				},
   328  			},
   329  		},
   330  		// case 2
   331  		{
   332  			args: []string{
   333  				"ldap-test",
   334  				"--name", "ldap (simple auth) source",
   335  				"--security-protocol", "zzzzz",
   336  				"--host", "ldap-server",
   337  				"--port", "123",
   338  				"--user-filter", "(&(objectClass=posixAccount)(cn=%s))",
   339  				"--email-attribute", "mail",
   340  				"--user-dn", "cn=%s,ou=Users,dc=domain,dc=org",
   341  			},
   342  			errMsg: "Unknown security protocol name: zzzzz",
   343  		},
   344  		// case 3
   345  		{
   346  			args: []string{
   347  				"ldap-test",
   348  				"--security-protocol", "unencrypted",
   349  				"--host", "ldap-server",
   350  				"--port", "123",
   351  				"--user-filter", "(&(objectClass=posixAccount)(cn=%s))",
   352  				"--email-attribute", "mail",
   353  				"--user-dn", "cn=%s,ou=Users,dc=domain,dc=org",
   354  			},
   355  			errMsg: "name is not set",
   356  		},
   357  		// case 4
   358  		{
   359  			args: []string{
   360  				"ldap-test",
   361  				"--name", "ldap (simple auth) source",
   362  				"--host", "ldap-server",
   363  				"--port", "123",
   364  				"--user-filter", "(&(objectClass=posixAccount)(cn=%s))",
   365  				"--email-attribute", "mail",
   366  				"--user-dn", "cn=%s,ou=Users,dc=domain,dc=org",
   367  			},
   368  			errMsg: "security-protocol is not set",
   369  		},
   370  		// case 5
   371  		{
   372  			args: []string{
   373  				"ldap-test",
   374  				"--name", "ldap (simple auth) source",
   375  				"--security-protocol", "unencrypted",
   376  				"--port", "123",
   377  				"--user-filter", "(&(objectClass=posixAccount)(cn=%s))",
   378  				"--email-attribute", "mail",
   379  				"--user-dn", "cn=%s,ou=Users,dc=domain,dc=org",
   380  			},
   381  			errMsg: "host is not set",
   382  		},
   383  		// case 6
   384  		{
   385  			args: []string{
   386  				"ldap-test",
   387  				"--name", "ldap (simple auth) source",
   388  				"--security-protocol", "unencrypted",
   389  				"--host", "ldap-server",
   390  				"--user-filter", "(&(objectClass=posixAccount)(cn=%s))",
   391  				"--email-attribute", "mail",
   392  				"--user-dn", "cn=%s,ou=Users,dc=domain,dc=org",
   393  			},
   394  			errMsg: "port is not set",
   395  		},
   396  		// case 7
   397  		{
   398  			args: []string{
   399  				"ldap-test",
   400  				"--name", "ldap (simple auth) source",
   401  				"--security-protocol", "unencrypted",
   402  				"--host", "ldap-server",
   403  				"--port", "123",
   404  				"--email-attribute", "mail",
   405  				"--user-dn", "cn=%s,ou=Users,dc=domain,dc=org",
   406  			},
   407  			errMsg: "user-filter is not set",
   408  		},
   409  		// case 8
   410  		{
   411  			args: []string{
   412  				"ldap-test",
   413  				"--name", "ldap (simple auth) source",
   414  				"--security-protocol", "unencrypted",
   415  				"--host", "ldap-server",
   416  				"--port", "123",
   417  				"--user-filter", "(&(objectClass=posixAccount)(cn=%s))",
   418  				"--user-dn", "cn=%s,ou=Users,dc=domain,dc=org",
   419  			},
   420  			errMsg: "email-attribute is not set",
   421  		},
   422  		// case 9
   423  		{
   424  			args: []string{
   425  				"ldap-test",
   426  				"--name", "ldap (simple auth) source",
   427  				"--security-protocol", "unencrypted",
   428  				"--host", "ldap-server",
   429  				"--port", "123",
   430  				"--user-filter", "(&(objectClass=posixAccount)(cn=%s))",
   431  				"--email-attribute", "mail",
   432  			},
   433  			errMsg: "user-dn is not set",
   434  		},
   435  	}
   436  
   437  	for n, c := range cases {
   438  		// Mock functions.
   439  		var createdAuthSource *auth.Source
   440  		service := &authService{
   441  			initDB: func(context.Context) error {
   442  				return nil
   443  			},
   444  			createAuthSource: func(ctx context.Context, authSource *auth.Source) error {
   445  				createdAuthSource = authSource
   446  				return nil
   447  			},
   448  			updateAuthSource: func(ctx context.Context, authSource *auth.Source) error {
   449  				assert.FailNow(t, "case %d: should not call updateAuthSource", n)
   450  				return nil
   451  			},
   452  			getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) {
   453  				assert.FailNow(t, "case %d: should not call getAuthSourceByID", n)
   454  				return nil, nil
   455  			},
   456  		}
   457  
   458  		// Create a copy of command to test
   459  		app := cli.NewApp()
   460  		app.Flags = microcmdAuthAddLdapSimpleAuth.Flags
   461  		app.Action = service.addLdapSimpleAuth
   462  
   463  		// Run it
   464  		err := app.Run(c.args)
   465  		if c.errMsg != "" {
   466  			assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
   467  		} else {
   468  			assert.NoError(t, err, "case %d: should have no errors", n)
   469  			assert.Equal(t, c.authSource, createdAuthSource, "case %d: wrong authSource", n)
   470  		}
   471  	}
   472  }
   473  
   474  func TestUpdateLdapBindDn(t *testing.T) {
   475  	// Mock cli functions to do not exit on error
   476  	osExiter := cli.OsExiter
   477  	defer func() { cli.OsExiter = osExiter }()
   478  	cli.OsExiter = func(code int) {}
   479  
   480  	// Test cases
   481  	cases := []struct {
   482  		args               []string
   483  		id                 int64
   484  		existingAuthSource *auth.Source
   485  		authSource         *auth.Source
   486  		errMsg             string
   487  	}{
   488  		// case 0
   489  		{
   490  			args: []string{
   491  				"ldap-test",
   492  				"--id", "23",
   493  				"--name", "ldap (via Bind DN) source full",
   494  				"--not-active",
   495  				"--security-protocol", "LDAPS",
   496  				"--skip-tls-verify",
   497  				"--host", "ldap-bind-server full",
   498  				"--port", "9876",
   499  				"--user-search-base", "ou=Users,dc=full-domain-bind,dc=org",
   500  				"--user-filter", "(memberOf=cn=user-group,ou=example,dc=full-domain-bind,dc=org)",
   501  				"--admin-filter", "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)",
   502  				"--restricted-filter", "(memberOf=cn=restricted-group,ou=example,dc=full-domain-bind,dc=org)",
   503  				"--username-attribute", "uid-bind full",
   504  				"--firstname-attribute", "givenName-bind full",
   505  				"--surname-attribute", "sn-bind full",
   506  				"--email-attribute", "mail-bind full",
   507  				"--public-ssh-key-attribute", "publickey-bind full",
   508  				"--avatar-attribute", "avatar-bind full",
   509  				"--bind-dn", "cn=readonly,dc=full-domain-bind,dc=org",
   510  				"--bind-password", "secret-bind-full",
   511  				"--synchronize-users",
   512  				"--page-size", "99",
   513  			},
   514  			id: 23,
   515  			existingAuthSource: &auth.Source{
   516  				Type:     auth.LDAP,
   517  				IsActive: true,
   518  				Cfg: &ldap.Source{
   519  					Enabled: true,
   520  				},
   521  			},
   522  			authSource: &auth.Source{
   523  				Type:          auth.LDAP,
   524  				Name:          "ldap (via Bind DN) source full",
   525  				IsActive:      false,
   526  				IsSyncEnabled: true,
   527  				Cfg: &ldap.Source{
   528  					Name:                  "ldap (via Bind DN) source full",
   529  					Host:                  "ldap-bind-server full",
   530  					Port:                  9876,
   531  					SecurityProtocol:      ldap.SecurityProtocol(1),
   532  					SkipVerify:            true,
   533  					BindDN:                "cn=readonly,dc=full-domain-bind,dc=org",
   534  					BindPassword:          "secret-bind-full",
   535  					UserBase:              "ou=Users,dc=full-domain-bind,dc=org",
   536  					AttributeUsername:     "uid-bind full",
   537  					AttributeName:         "givenName-bind full",
   538  					AttributeSurname:      "sn-bind full",
   539  					AttributeMail:         "mail-bind full",
   540  					AttributesInBind:      false,
   541  					AttributeSSHPublicKey: "publickey-bind full",
   542  					AttributeAvatar:       "avatar-bind full",
   543  					SearchPageSize:        99,
   544  					Filter:                "(memberOf=cn=user-group,ou=example,dc=full-domain-bind,dc=org)",
   545  					AdminFilter:           "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)",
   546  					RestrictedFilter:      "(memberOf=cn=restricted-group,ou=example,dc=full-domain-bind,dc=org)",
   547  					Enabled:               true,
   548  				},
   549  			},
   550  		},
   551  		// case 1
   552  		{
   553  			args: []string{
   554  				"ldap-test",
   555  				"--id", "1",
   556  			},
   557  			authSource: &auth.Source{
   558  				Type: auth.LDAP,
   559  				Cfg:  &ldap.Source{},
   560  			},
   561  		},
   562  		// case 2
   563  		{
   564  			args: []string{
   565  				"ldap-test",
   566  				"--id", "1",
   567  				"--name", "ldap (via Bind DN) source",
   568  			},
   569  			authSource: &auth.Source{
   570  				Type: auth.LDAP,
   571  				Name: "ldap (via Bind DN) source",
   572  				Cfg: &ldap.Source{
   573  					Name: "ldap (via Bind DN) source",
   574  				},
   575  			},
   576  		},
   577  		// case 3
   578  		{
   579  			args: []string{
   580  				"ldap-test",
   581  				"--id", "1",
   582  				"--not-active",
   583  			},
   584  			existingAuthSource: &auth.Source{
   585  				Type:     auth.LDAP,
   586  				IsActive: true,
   587  				Cfg:      &ldap.Source{},
   588  			},
   589  			authSource: &auth.Source{
   590  				Type:     auth.LDAP,
   591  				IsActive: false,
   592  				Cfg:      &ldap.Source{},
   593  			},
   594  		},
   595  		// case 4
   596  		{
   597  			args: []string{
   598  				"ldap-test",
   599  				"--id", "1",
   600  				"--security-protocol", "LDAPS",
   601  			},
   602  			authSource: &auth.Source{
   603  				Type: auth.LDAP,
   604  				Cfg: &ldap.Source{
   605  					SecurityProtocol: ldap.SecurityProtocol(1),
   606  				},
   607  			},
   608  		},
   609  		// case 5
   610  		{
   611  			args: []string{
   612  				"ldap-test",
   613  				"--id", "1",
   614  				"--skip-tls-verify",
   615  			},
   616  			authSource: &auth.Source{
   617  				Type: auth.LDAP,
   618  				Cfg: &ldap.Source{
   619  					SkipVerify: true,
   620  				},
   621  			},
   622  		},
   623  		// case 6
   624  		{
   625  			args: []string{
   626  				"ldap-test",
   627  				"--id", "1",
   628  				"--host", "ldap-server",
   629  			},
   630  			authSource: &auth.Source{
   631  				Type: auth.LDAP,
   632  				Cfg: &ldap.Source{
   633  					Host: "ldap-server",
   634  				},
   635  			},
   636  		},
   637  		// case 7
   638  		{
   639  			args: []string{
   640  				"ldap-test",
   641  				"--id", "1",
   642  				"--port", "389",
   643  			},
   644  			authSource: &auth.Source{
   645  				Type: auth.LDAP,
   646  				Cfg: &ldap.Source{
   647  					Port: 389,
   648  				},
   649  			},
   650  		},
   651  		// case 8
   652  		{
   653  			args: []string{
   654  				"ldap-test",
   655  				"--id", "1",
   656  				"--user-search-base", "ou=Users,dc=domain,dc=org",
   657  			},
   658  			authSource: &auth.Source{
   659  				Type: auth.LDAP,
   660  				Cfg: &ldap.Source{
   661  					UserBase: "ou=Users,dc=domain,dc=org",
   662  				},
   663  			},
   664  		},
   665  		// case 9
   666  		{
   667  			args: []string{
   668  				"ldap-test",
   669  				"--id", "1",
   670  				"--user-filter", "(memberOf=cn=user-group,ou=example,dc=domain,dc=org)",
   671  			},
   672  			authSource: &auth.Source{
   673  				Type: auth.LDAP,
   674  				Cfg: &ldap.Source{
   675  					Filter: "(memberOf=cn=user-group,ou=example,dc=domain,dc=org)",
   676  				},
   677  			},
   678  		},
   679  		// case 10
   680  		{
   681  			args: []string{
   682  				"ldap-test",
   683  				"--id", "1",
   684  				"--admin-filter", "(memberOf=cn=admin-group,ou=example,dc=domain,dc=org)",
   685  			},
   686  			authSource: &auth.Source{
   687  				Type: auth.LDAP,
   688  				Cfg: &ldap.Source{
   689  					AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=domain,dc=org)",
   690  				},
   691  			},
   692  		},
   693  		// case 11
   694  		{
   695  			args: []string{
   696  				"ldap-test",
   697  				"--id", "1",
   698  				"--username-attribute", "uid",
   699  			},
   700  			authSource: &auth.Source{
   701  				Type: auth.LDAP,
   702  				Cfg: &ldap.Source{
   703  					AttributeUsername: "uid",
   704  				},
   705  			},
   706  		},
   707  		// case 12
   708  		{
   709  			args: []string{
   710  				"ldap-test",
   711  				"--id", "1",
   712  				"--firstname-attribute", "givenName",
   713  			},
   714  			authSource: &auth.Source{
   715  				Type: auth.LDAP,
   716  				Cfg: &ldap.Source{
   717  					AttributeName: "givenName",
   718  				},
   719  			},
   720  		},
   721  		// case 13
   722  		{
   723  			args: []string{
   724  				"ldap-test",
   725  				"--id", "1",
   726  				"--surname-attribute", "sn",
   727  			},
   728  			authSource: &auth.Source{
   729  				Type: auth.LDAP,
   730  				Cfg: &ldap.Source{
   731  					AttributeSurname: "sn",
   732  				},
   733  			},
   734  		},
   735  		// case 14
   736  		{
   737  			args: []string{
   738  				"ldap-test",
   739  				"--id", "1",
   740  				"--email-attribute", "mail",
   741  			},
   742  			authSource: &auth.Source{
   743  				Type: auth.LDAP,
   744  				Cfg: &ldap.Source{
   745  					AttributeMail: "mail",
   746  				},
   747  			},
   748  		},
   749  		// case 15
   750  		{
   751  			args: []string{
   752  				"ldap-test",
   753  				"--id", "1",
   754  				"--attributes-in-bind",
   755  			},
   756  			authSource: &auth.Source{
   757  				Type: auth.LDAP,
   758  				Cfg: &ldap.Source{
   759  					AttributesInBind: true,
   760  				},
   761  			},
   762  		},
   763  		// case 16
   764  		{
   765  			args: []string{
   766  				"ldap-test",
   767  				"--id", "1",
   768  				"--public-ssh-key-attribute", "publickey",
   769  			},
   770  			authSource: &auth.Source{
   771  				Type: auth.LDAP,
   772  				Cfg: &ldap.Source{
   773  					AttributeSSHPublicKey: "publickey",
   774  				},
   775  			},
   776  		},
   777  		// case 17
   778  		{
   779  			args: []string{
   780  				"ldap-test",
   781  				"--id", "1",
   782  				"--bind-dn", "cn=readonly,dc=domain,dc=org",
   783  			},
   784  			authSource: &auth.Source{
   785  				Type: auth.LDAP,
   786  				Cfg: &ldap.Source{
   787  					BindDN: "cn=readonly,dc=domain,dc=org",
   788  				},
   789  			},
   790  		},
   791  		// case 18
   792  		{
   793  			args: []string{
   794  				"ldap-test",
   795  				"--id", "1",
   796  				"--bind-password", "secret",
   797  			},
   798  			authSource: &auth.Source{
   799  				Type: auth.LDAP,
   800  				Cfg: &ldap.Source{
   801  					BindPassword: "secret",
   802  				},
   803  			},
   804  		},
   805  		// case 19
   806  		{
   807  			args: []string{
   808  				"ldap-test",
   809  				"--id", "1",
   810  				"--synchronize-users",
   811  			},
   812  			authSource: &auth.Source{
   813  				Type:          auth.LDAP,
   814  				IsSyncEnabled: true,
   815  				Cfg:           &ldap.Source{},
   816  			},
   817  		},
   818  		// case 20
   819  		{
   820  			args: []string{
   821  				"ldap-test",
   822  				"--id", "1",
   823  				"--page-size", "12",
   824  			},
   825  			authSource: &auth.Source{
   826  				Type: auth.LDAP,
   827  				Cfg: &ldap.Source{
   828  					SearchPageSize: 12,
   829  				},
   830  			},
   831  		},
   832  		// case 21
   833  		{
   834  			args: []string{
   835  				"ldap-test",
   836  				"--id", "1",
   837  				"--security-protocol", "xxxxx",
   838  			},
   839  			errMsg: "Unknown security protocol name: xxxxx",
   840  		},
   841  		// case 22
   842  		{
   843  			args: []string{
   844  				"ldap-test",
   845  			},
   846  			errMsg: "id is not set",
   847  		},
   848  		// case 23
   849  		{
   850  			args: []string{
   851  				"ldap-test",
   852  				"--id", "1",
   853  			},
   854  			existingAuthSource: &auth.Source{
   855  				Type: auth.OAuth2,
   856  				Cfg:  &ldap.Source{},
   857  			},
   858  			errMsg: "Invalid authentication type. expected: LDAP (via BindDN), actual: OAuth2",
   859  		},
   860  		// case 24
   861  		{
   862  			args: []string{
   863  				"ldap-test",
   864  				"--id", "24",
   865  				"--name", "ldap (via Bind DN) flip 'active' and 'user sync' attributes",
   866  				"--active",
   867  				"--disable-synchronize-users",
   868  			},
   869  			id: 24,
   870  			existingAuthSource: &auth.Source{
   871  				Type:          auth.LDAP,
   872  				IsActive:      false,
   873  				IsSyncEnabled: true,
   874  				Cfg: &ldap.Source{
   875  					Name:    "ldap (via Bind DN) flip 'active' and 'user sync' attributes",
   876  					Enabled: true,
   877  				},
   878  			},
   879  			authSource: &auth.Source{
   880  				Type:          auth.LDAP,
   881  				Name:          "ldap (via Bind DN) flip 'active' and 'user sync' attributes",
   882  				IsActive:      true,
   883  				IsSyncEnabled: false,
   884  				Cfg: &ldap.Source{
   885  					Name:    "ldap (via Bind DN) flip 'active' and 'user sync' attributes",
   886  					Enabled: true,
   887  				},
   888  			},
   889  		},
   890  	}
   891  
   892  	for n, c := range cases {
   893  		// Mock functions.
   894  		var updatedAuthSource *auth.Source
   895  		service := &authService{
   896  			initDB: func(context.Context) error {
   897  				return nil
   898  			},
   899  			createAuthSource: func(ctx context.Context, authSource *auth.Source) error {
   900  				assert.FailNow(t, "case %d: should not call createAuthSource", n)
   901  				return nil
   902  			},
   903  			updateAuthSource: func(ctx context.Context, authSource *auth.Source) error {
   904  				updatedAuthSource = authSource
   905  				return nil
   906  			},
   907  			getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) {
   908  				if c.id != 0 {
   909  					assert.Equal(t, c.id, id, "case %d: wrong id", n)
   910  				}
   911  				if c.existingAuthSource != nil {
   912  					return c.existingAuthSource, nil
   913  				}
   914  				return &auth.Source{
   915  					Type: auth.LDAP,
   916  					Cfg:  &ldap.Source{},
   917  				}, nil
   918  			},
   919  		}
   920  
   921  		// Create a copy of command to test
   922  		app := cli.NewApp()
   923  		app.Flags = microcmdAuthUpdateLdapBindDn.Flags
   924  		app.Action = service.updateLdapBindDn
   925  
   926  		// Run it
   927  		err := app.Run(c.args)
   928  		if c.errMsg != "" {
   929  			assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
   930  		} else {
   931  			assert.NoError(t, err, "case %d: should have no errors", n)
   932  			assert.Equal(t, c.authSource, updatedAuthSource, "case %d: wrong authSource", n)
   933  		}
   934  	}
   935  }
   936  
   937  func TestUpdateLdapSimpleAuth(t *testing.T) {
   938  	// Mock cli functions to do not exit on error
   939  	osExiter := cli.OsExiter
   940  	defer func() { cli.OsExiter = osExiter }()
   941  	cli.OsExiter = func(code int) {}
   942  
   943  	// Test cases
   944  	cases := []struct {
   945  		args               []string
   946  		id                 int64
   947  		existingAuthSource *auth.Source
   948  		authSource         *auth.Source
   949  		errMsg             string
   950  	}{
   951  		// case 0
   952  		{
   953  			args: []string{
   954  				"ldap-test",
   955  				"--id", "7",
   956  				"--name", "ldap (simple auth) source full",
   957  				"--not-active",
   958  				"--security-protocol", "starttls",
   959  				"--skip-tls-verify",
   960  				"--host", "ldap-simple-server full",
   961  				"--port", "987",
   962  				"--user-search-base", "ou=Users,dc=full-domain-simple,dc=org",
   963  				"--user-filter", "(&(objectClass=posixAccount)(full-simple-cn=%s))",
   964  				"--admin-filter", "(memberOf=cn=admin-group,ou=example,dc=full-domain-simple,dc=org)",
   965  				"--restricted-filter", "(memberOf=cn=restricted-group,ou=example,dc=full-domain-simple,dc=org)",
   966  				"--username-attribute", "uid-simple full",
   967  				"--firstname-attribute", "givenName-simple full",
   968  				"--surname-attribute", "sn-simple full",
   969  				"--email-attribute", "mail-simple full",
   970  				"--public-ssh-key-attribute", "publickey-simple full",
   971  				"--avatar-attribute", "avatar-simple full",
   972  				"--user-dn", "cn=%s,ou=Users,dc=full-domain-simple,dc=org",
   973  			},
   974  			id: 7,
   975  			authSource: &auth.Source{
   976  				Type:     auth.DLDAP,
   977  				Name:     "ldap (simple auth) source full",
   978  				IsActive: false,
   979  				Cfg: &ldap.Source{
   980  					Name:                  "ldap (simple auth) source full",
   981  					Host:                  "ldap-simple-server full",
   982  					Port:                  987,
   983  					SecurityProtocol:      ldap.SecurityProtocol(2),
   984  					SkipVerify:            true,
   985  					UserDN:                "cn=%s,ou=Users,dc=full-domain-simple,dc=org",
   986  					UserBase:              "ou=Users,dc=full-domain-simple,dc=org",
   987  					AttributeUsername:     "uid-simple full",
   988  					AttributeName:         "givenName-simple full",
   989  					AttributeSurname:      "sn-simple full",
   990  					AttributeMail:         "mail-simple full",
   991  					AttributeSSHPublicKey: "publickey-simple full",
   992  					AttributeAvatar:       "avatar-simple full",
   993  					Filter:                "(&(objectClass=posixAccount)(full-simple-cn=%s))",
   994  					AdminFilter:           "(memberOf=cn=admin-group,ou=example,dc=full-domain-simple,dc=org)",
   995  					RestrictedFilter:      "(memberOf=cn=restricted-group,ou=example,dc=full-domain-simple,dc=org)",
   996  				},
   997  			},
   998  		},
   999  		// case 1
  1000  		{
  1001  			args: []string{
  1002  				"ldap-test",
  1003  				"--id", "1",
  1004  			},
  1005  			authSource: &auth.Source{
  1006  				Type: auth.DLDAP,
  1007  				Cfg:  &ldap.Source{},
  1008  			},
  1009  		},
  1010  		// case 2
  1011  		{
  1012  			args: []string{
  1013  				"ldap-test",
  1014  				"--id", "1",
  1015  				"--name", "ldap (simple auth) source",
  1016  			},
  1017  			authSource: &auth.Source{
  1018  				Type: auth.DLDAP,
  1019  				Name: "ldap (simple auth) source",
  1020  				Cfg: &ldap.Source{
  1021  					Name: "ldap (simple auth) source",
  1022  				},
  1023  			},
  1024  		},
  1025  		// case 3
  1026  		{
  1027  			args: []string{
  1028  				"ldap-test",
  1029  				"--id", "1",
  1030  				"--not-active",
  1031  			},
  1032  			existingAuthSource: &auth.Source{
  1033  				Type:     auth.DLDAP,
  1034  				IsActive: true,
  1035  				Cfg:      &ldap.Source{},
  1036  			},
  1037  			authSource: &auth.Source{
  1038  				Type:     auth.DLDAP,
  1039  				IsActive: false,
  1040  				Cfg:      &ldap.Source{},
  1041  			},
  1042  		},
  1043  		// case 4
  1044  		{
  1045  			args: []string{
  1046  				"ldap-test",
  1047  				"--id", "1",
  1048  				"--security-protocol", "starttls",
  1049  			},
  1050  			authSource: &auth.Source{
  1051  				Type: auth.DLDAP,
  1052  				Cfg: &ldap.Source{
  1053  					SecurityProtocol: ldap.SecurityProtocol(2),
  1054  				},
  1055  			},
  1056  		},
  1057  		// case 5
  1058  		{
  1059  			args: []string{
  1060  				"ldap-test",
  1061  				"--id", "1",
  1062  				"--skip-tls-verify",
  1063  			},
  1064  			authSource: &auth.Source{
  1065  				Type: auth.DLDAP,
  1066  				Cfg: &ldap.Source{
  1067  					SkipVerify: true,
  1068  				},
  1069  			},
  1070  		},
  1071  		// case 6
  1072  		{
  1073  			args: []string{
  1074  				"ldap-test",
  1075  				"--id", "1",
  1076  				"--host", "ldap-server",
  1077  			},
  1078  			authSource: &auth.Source{
  1079  				Type: auth.DLDAP,
  1080  				Cfg: &ldap.Source{
  1081  					Host: "ldap-server",
  1082  				},
  1083  			},
  1084  		},
  1085  		// case 7
  1086  		{
  1087  			args: []string{
  1088  				"ldap-test",
  1089  				"--id", "1",
  1090  				"--port", "987",
  1091  			},
  1092  			authSource: &auth.Source{
  1093  				Type: auth.DLDAP,
  1094  				Cfg: &ldap.Source{
  1095  					Port: 987,
  1096  				},
  1097  			},
  1098  		},
  1099  		// case 8
  1100  		{
  1101  			args: []string{
  1102  				"ldap-test",
  1103  				"--id", "1",
  1104  				"--user-search-base", "ou=Users,dc=domain,dc=org",
  1105  			},
  1106  			authSource: &auth.Source{
  1107  				Type: auth.DLDAP,
  1108  				Cfg: &ldap.Source{
  1109  					UserBase: "ou=Users,dc=domain,dc=org",
  1110  				},
  1111  			},
  1112  		},
  1113  		// case 9
  1114  		{
  1115  			args: []string{
  1116  				"ldap-test",
  1117  				"--id", "1",
  1118  				"--user-filter", "(&(objectClass=posixAccount)(cn=%s))",
  1119  			},
  1120  			authSource: &auth.Source{
  1121  				Type: auth.DLDAP,
  1122  				Cfg: &ldap.Source{
  1123  					Filter: "(&(objectClass=posixAccount)(cn=%s))",
  1124  				},
  1125  			},
  1126  		},
  1127  		// case 10
  1128  		{
  1129  			args: []string{
  1130  				"ldap-test",
  1131  				"--id", "1",
  1132  				"--admin-filter", "(memberOf=cn=admin-group,ou=example,dc=domain,dc=org)",
  1133  			},
  1134  			authSource: &auth.Source{
  1135  				Type: auth.DLDAP,
  1136  				Cfg: &ldap.Source{
  1137  					AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=domain,dc=org)",
  1138  				},
  1139  			},
  1140  		},
  1141  		// case 11
  1142  		{
  1143  			args: []string{
  1144  				"ldap-test",
  1145  				"--id", "1",
  1146  				"--username-attribute", "uid",
  1147  			},
  1148  			authSource: &auth.Source{
  1149  				Type: auth.DLDAP,
  1150  				Cfg: &ldap.Source{
  1151  					AttributeUsername: "uid",
  1152  				},
  1153  			},
  1154  		},
  1155  		// case 12
  1156  		{
  1157  			args: []string{
  1158  				"ldap-test",
  1159  				"--id", "1",
  1160  				"--firstname-attribute", "givenName",
  1161  			},
  1162  			authSource: &auth.Source{
  1163  				Type: auth.DLDAP,
  1164  				Cfg: &ldap.Source{
  1165  					AttributeName: "givenName",
  1166  				},
  1167  			},
  1168  		},
  1169  		// case 13
  1170  		{
  1171  			args: []string{
  1172  				"ldap-test",
  1173  				"--id", "1",
  1174  				"--surname-attribute", "sn",
  1175  			},
  1176  			authSource: &auth.Source{
  1177  				Type: auth.DLDAP,
  1178  				Cfg: &ldap.Source{
  1179  					AttributeSurname: "sn",
  1180  				},
  1181  			},
  1182  		},
  1183  		// case 14
  1184  		{
  1185  			args: []string{
  1186  				"ldap-test",
  1187  				"--id", "1",
  1188  				"--email-attribute", "mail",
  1189  			},
  1190  			authSource: &auth.Source{
  1191  				Type: auth.DLDAP,
  1192  				Cfg: &ldap.Source{
  1193  					AttributeMail: "mail",
  1194  				},
  1195  			},
  1196  		},
  1197  		// case 15
  1198  		{
  1199  			args: []string{
  1200  				"ldap-test",
  1201  				"--id", "1",
  1202  				"--public-ssh-key-attribute", "publickey",
  1203  			},
  1204  			authSource: &auth.Source{
  1205  				Type: auth.DLDAP,
  1206  				Cfg: &ldap.Source{
  1207  					AttributeSSHPublicKey: "publickey",
  1208  				},
  1209  			},
  1210  		},
  1211  		// case 16
  1212  		{
  1213  			args: []string{
  1214  				"ldap-test",
  1215  				"--id", "1",
  1216  				"--user-dn", "cn=%s,ou=Users,dc=domain,dc=org",
  1217  			},
  1218  			authSource: &auth.Source{
  1219  				Type: auth.DLDAP,
  1220  				Cfg: &ldap.Source{
  1221  					UserDN: "cn=%s,ou=Users,dc=domain,dc=org",
  1222  				},
  1223  			},
  1224  		},
  1225  		// case 17
  1226  		{
  1227  			args: []string{
  1228  				"ldap-test",
  1229  				"--id", "1",
  1230  				"--security-protocol", "xxxxx",
  1231  			},
  1232  			errMsg: "Unknown security protocol name: xxxxx",
  1233  		},
  1234  		// case 18
  1235  		{
  1236  			args: []string{
  1237  				"ldap-test",
  1238  			},
  1239  			errMsg: "id is not set",
  1240  		},
  1241  		// case 19
  1242  		{
  1243  			args: []string{
  1244  				"ldap-test",
  1245  				"--id", "1",
  1246  			},
  1247  			existingAuthSource: &auth.Source{
  1248  				Type: auth.PAM,
  1249  				Cfg:  &ldap.Source{},
  1250  			},
  1251  			errMsg: "Invalid authentication type. expected: LDAP (simple auth), actual: PAM",
  1252  		},
  1253  		// case 20
  1254  		{
  1255  			args: []string{
  1256  				"ldap-test",
  1257  				"--id", "20",
  1258  				"--name", "ldap (simple auth) flip 'active' attribute",
  1259  				"--active",
  1260  			},
  1261  			id: 20,
  1262  			existingAuthSource: &auth.Source{
  1263  				Type:     auth.DLDAP,
  1264  				IsActive: false,
  1265  				Cfg: &ldap.Source{
  1266  					Name:    "ldap (simple auth) flip 'active' attribute",
  1267  					Enabled: true,
  1268  				},
  1269  			},
  1270  			authSource: &auth.Source{
  1271  				Type:     auth.DLDAP,
  1272  				Name:     "ldap (simple auth) flip 'active' attribute",
  1273  				IsActive: true,
  1274  				Cfg: &ldap.Source{
  1275  					Name:    "ldap (simple auth) flip 'active' attribute",
  1276  					Enabled: true,
  1277  				},
  1278  			},
  1279  		},
  1280  	}
  1281  
  1282  	for n, c := range cases {
  1283  		// Mock functions.
  1284  		var updatedAuthSource *auth.Source
  1285  		service := &authService{
  1286  			initDB: func(context.Context) error {
  1287  				return nil
  1288  			},
  1289  			createAuthSource: func(ctx context.Context, authSource *auth.Source) error {
  1290  				assert.FailNow(t, "case %d: should not call createAuthSource", n)
  1291  				return nil
  1292  			},
  1293  			updateAuthSource: func(ctx context.Context, authSource *auth.Source) error {
  1294  				updatedAuthSource = authSource
  1295  				return nil
  1296  			},
  1297  			getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) {
  1298  				if c.id != 0 {
  1299  					assert.Equal(t, c.id, id, "case %d: wrong id", n)
  1300  				}
  1301  				if c.existingAuthSource != nil {
  1302  					return c.existingAuthSource, nil
  1303  				}
  1304  				return &auth.Source{
  1305  					Type: auth.DLDAP,
  1306  					Cfg:  &ldap.Source{},
  1307  				}, nil
  1308  			},
  1309  		}
  1310  
  1311  		// Create a copy of command to test
  1312  		app := cli.NewApp()
  1313  		app.Flags = microcmdAuthUpdateLdapSimpleAuth.Flags
  1314  		app.Action = service.updateLdapSimpleAuth
  1315  
  1316  		// Run it
  1317  		err := app.Run(c.args)
  1318  		if c.errMsg != "" {
  1319  			assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
  1320  		} else {
  1321  			assert.NoError(t, err, "case %d: should have no errors", n)
  1322  			assert.Equal(t, c.authSource, updatedAuthSource, "case %d: wrong authSource", n)
  1323  		}
  1324  	}
  1325  }