github.com/google/go-github/v66@v66.0.0/github/scim_test.go (about)

     1  // Copyright 2021 The go-github AUTHORS. All rights reserved.
     2  //
     3  // Use of this source code is governed by a BSD-style
     4  // license that can be found in the LICENSE file.
     5  
     6  package github
     7  
     8  import (
     9  	"context"
    10  	"fmt"
    11  	"net/http"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/google/go-cmp/cmp"
    16  )
    17  
    18  func TestSCIMService_ListSCIMProvisionedIdentities(t *testing.T) {
    19  	t.Parallel()
    20  	client, mux, _ := setup(t)
    21  
    22  	mux.HandleFunc("/scim/v2/organizations/o/Users", func(w http.ResponseWriter, r *http.Request) {
    23  		testMethod(t, r, "GET")
    24  		w.WriteHeader(http.StatusOK)
    25  		_, _ = w.Write([]byte(`{
    26  			"schemas": [
    27  			  "urn:ietf:params:scim:api:messages:2.0:ListResponse"
    28  			],
    29  			"totalResults": 1,
    30  			"itemsPerPage": 1,
    31  			"startIndex": 1,
    32  			"Resources": [
    33  			  {
    34  				"schemas": [
    35  				  "urn:ietf:params:scim:schemas:core:2.0:User"
    36  				],
    37  				"id": "5fc0c238-1112-11e8-8e45-920c87bdbd75",
    38  				"externalId": "00u1dhhb1fkIGP7RL1d8",
    39  				"userName": "octocat@github.com",
    40  				"displayName": "Mona Octocat",
    41  				"name": {
    42  				  "givenName": "Mona",
    43  				  "familyName": "Octocat",
    44  				  "formatted": "Mona Octocat"
    45  				},
    46  				"emails": [
    47  				  {
    48  					"value": "octocat@github.com",
    49  					"primary": true
    50  				  }
    51  				],
    52  				"active": true,
    53  				"meta": {
    54  				  "resourceType": "User",
    55  				  "created": "2018-02-13T15:05:24.000-00:00",
    56  				  "lastModified": "2018-02-13T15:05:24.000-00:00",
    57  				  "location": "https://api.github.com/scim/v2/organizations/octo-org/Users/5fc0c238-1112-11e8-8e45-920c87bdbd75"
    58  				}
    59  			  }
    60  			]
    61  		  }`))
    62  	})
    63  
    64  	ctx := context.Background()
    65  	opts := &ListSCIMProvisionedIdentitiesOptions{}
    66  	identities, _, err := client.SCIM.ListSCIMProvisionedIdentities(ctx, "o", opts)
    67  	if err != nil {
    68  		t.Errorf("SCIM.ListSCIMProvisionedIdentities returned error: %v", err)
    69  	}
    70  
    71  	date := Timestamp{time.Date(2018, time.February, 13, 15, 5, 24, 0, time.UTC)}
    72  	want := SCIMProvisionedIdentities{
    73  		Schemas:      []string{"urn:ietf:params:scim:api:messages:2.0:ListResponse"},
    74  		TotalResults: Int(1),
    75  		ItemsPerPage: Int(1),
    76  		StartIndex:   Int(1),
    77  		Resources: []*SCIMUserAttributes{
    78  			{
    79  				ID: String("5fc0c238-1112-11e8-8e45-920c87bdbd75"),
    80  				Meta: &SCIMMeta{
    81  					ResourceType: String("User"),
    82  					Created:      &date,
    83  					LastModified: &date,
    84  					Location:     String("https://api.github.com/scim/v2/organizations/octo-org/Users/5fc0c238-1112-11e8-8e45-920c87bdbd75"),
    85  				},
    86  				UserName: "octocat@github.com",
    87  				Name: SCIMUserName{
    88  					GivenName:  "Mona",
    89  					FamilyName: "Octocat",
    90  					Formatted:  String("Mona Octocat"),
    91  				},
    92  				DisplayName: String("Mona Octocat"),
    93  				Emails: []*SCIMUserEmail{
    94  					{
    95  						Value:   "octocat@github.com",
    96  						Primary: Bool(true),
    97  					},
    98  				},
    99  				Schemas:    []string{"urn:ietf:params:scim:schemas:core:2.0:User"},
   100  				ExternalID: String("00u1dhhb1fkIGP7RL1d8"),
   101  				Groups:     nil,
   102  				Active:     Bool(true),
   103  			},
   104  		},
   105  	}
   106  
   107  	if !cmp.Equal(identities, &want) {
   108  		diff := cmp.Diff(identities, want)
   109  		t.Errorf("SCIM.ListSCIMProvisionedIdentities returned %+v, want %+v: diff %+v", identities, want, diff)
   110  	}
   111  
   112  	const methodName = "ListSCIMProvisionedIdentities"
   113  	testBadOptions(t, methodName, func() (err error) {
   114  		_, _, err = client.SCIM.ListSCIMProvisionedIdentities(ctx, "\n", opts)
   115  		return err
   116  	})
   117  
   118  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   119  		_, r, err := client.SCIM.ListSCIMProvisionedIdentities(ctx, "o", opts)
   120  		return r, err
   121  	})
   122  }
   123  
   124  func TestSCIMService_ProvisionAndInviteSCIMUser(t *testing.T) {
   125  	t.Parallel()
   126  	client, mux, _ := setup(t)
   127  
   128  	mux.HandleFunc("/scim/v2/organizations/o/Users", func(w http.ResponseWriter, r *http.Request) {
   129  		testMethod(t, r, "POST")
   130  		w.WriteHeader(http.StatusCreated)
   131  		fmt.Fprint(w, `{"id":"1234567890","userName":"userName"}`)
   132  	})
   133  
   134  	ctx := context.Background()
   135  	opts := &SCIMUserAttributes{
   136  		UserName: "userName",
   137  		Name: SCIMUserName{
   138  			GivenName:  "givenName",
   139  			FamilyName: "familyName",
   140  		},
   141  		Emails: []*SCIMUserEmail{
   142  			{
   143  				Value: "octocat@github.com",
   144  			},
   145  		},
   146  	}
   147  	user, _, err := client.SCIM.ProvisionAndInviteSCIMUser(ctx, "o", opts)
   148  	if err != nil {
   149  		t.Errorf("SCIM.ProvisionAndInviteSCIMUser returned error: %v", err)
   150  	}
   151  
   152  	want := &SCIMUserAttributes{
   153  		ID:       String("1234567890"),
   154  		UserName: "userName",
   155  	}
   156  	if !cmp.Equal(user, want) {
   157  		t.Errorf("SCIM.ProvisionAndInviteSCIMUser returned %+v, want %+v", user, want)
   158  	}
   159  
   160  	const methodName = "ProvisionAndInviteSCIMUser"
   161  	testBadOptions(t, methodName, func() (err error) {
   162  		_, _, err = client.SCIM.ProvisionAndInviteSCIMUser(ctx, "\n", opts)
   163  		return err
   164  	})
   165  
   166  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   167  		got, resp, err := client.SCIM.ProvisionAndInviteSCIMUser(ctx, "o", opts)
   168  		if got != nil {
   169  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   170  		}
   171  		return resp, err
   172  	})
   173  }
   174  
   175  func TestSCIMService_GetSCIMProvisioningInfoForUser(t *testing.T) {
   176  	t.Parallel()
   177  	client, mux, _ := setup(t)
   178  
   179  	mux.HandleFunc("/scim/v2/organizations/o/Users/123", func(w http.ResponseWriter, r *http.Request) {
   180  		testMethod(t, r, "GET")
   181  		w.WriteHeader(http.StatusOK)
   182  		_, _ = w.Write([]byte(`{
   183  			"schemas": [
   184  			  "urn:ietf:params:scim:schemas:core:2.0:User"
   185  			],
   186  			"id": "edefdfedf-050c-11e7-8d32",
   187  			"externalId": "a7d0f98382",
   188  			"userName": "mona.octocat@okta.example.com",
   189  			"displayName": "Mona Octocat",
   190  			"name": {
   191  			  "givenName": "Mona",
   192  			  "familyName": "Octocat",
   193  			  "formatted": "Mona Octocat"
   194  			},
   195  			"emails": [
   196  			  {
   197  				"value": "mona.octocat@okta.example.com",
   198  				"primary": true
   199  			  },
   200  			  {
   201  				"value": "mona@octocat.github.com"
   202  			  }
   203  			],
   204  			"active": true,
   205  			"meta": {
   206  			  "resourceType": "User",
   207  			  "created": "2017-03-09T16:11:13-00:00",
   208  			  "lastModified": "2017-03-09T16:11:13-00:00",
   209  			  "location": "https://api.github.com/scim/v2/organizations/octo-org/Users/edefdfedf-050c-11e7-8d32"
   210  			}
   211  		  }`))
   212  	})
   213  
   214  	ctx := context.Background()
   215  	user, _, err := client.SCIM.GetSCIMProvisioningInfoForUser(ctx, "o", "123")
   216  	if err != nil {
   217  		t.Errorf("SCIM.GetSCIMProvisioningInfoForUser returned error: %v", err)
   218  	}
   219  
   220  	date := Timestamp{time.Date(2017, time.March, 9, 16, 11, 13, 0, time.UTC)}
   221  	want := SCIMUserAttributes{
   222  		ID: String("edefdfedf-050c-11e7-8d32"),
   223  		Meta: &SCIMMeta{
   224  			ResourceType: String("User"),
   225  			Created:      &date,
   226  			LastModified: &date,
   227  			Location:     String("https://api.github.com/scim/v2/organizations/octo-org/Users/edefdfedf-050c-11e7-8d32"),
   228  		},
   229  		UserName: "mona.octocat@okta.example.com",
   230  		Name: SCIMUserName{
   231  			GivenName:  "Mona",
   232  			FamilyName: "Octocat",
   233  			Formatted:  String("Mona Octocat"),
   234  		},
   235  		DisplayName: String("Mona Octocat"),
   236  		Emails: []*SCIMUserEmail{
   237  			{
   238  				Value:   "mona.octocat@okta.example.com",
   239  				Primary: Bool(true),
   240  			},
   241  			{
   242  				Value: "mona@octocat.github.com",
   243  			},
   244  		},
   245  		Schemas:    []string{"urn:ietf:params:scim:schemas:core:2.0:User"},
   246  		ExternalID: String("a7d0f98382"),
   247  		Groups:     nil,
   248  		Active:     Bool(true),
   249  	}
   250  
   251  	if !cmp.Equal(user, &want) {
   252  		diff := cmp.Diff(user, want)
   253  		t.Errorf("SCIM.ListSCIMProvisionedIdentities returned %+v, want %+v: diff %+v", user, want, diff)
   254  	}
   255  
   256  	const methodName = "GetSCIMProvisioningInfoForUser"
   257  	testBadOptions(t, methodName, func() error {
   258  		_, _, err := client.SCIM.GetSCIMProvisioningInfoForUser(ctx, "\n", "123")
   259  		return err
   260  	})
   261  
   262  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   263  		_, r, err := client.SCIM.GetSCIMProvisioningInfoForUser(ctx, "o", "123")
   264  		return r, err
   265  	})
   266  }
   267  
   268  func TestSCIMService_UpdateProvisionedOrgMembership(t *testing.T) {
   269  	t.Parallel()
   270  	client, mux, _ := setup(t)
   271  
   272  	mux.HandleFunc("/scim/v2/organizations/o/Users/123", func(w http.ResponseWriter, r *http.Request) {
   273  		testMethod(t, r, "PUT")
   274  		w.WriteHeader(http.StatusOK)
   275  	})
   276  
   277  	ctx := context.Background()
   278  	opts := &SCIMUserAttributes{
   279  		UserName: "userName",
   280  		Name: SCIMUserName{
   281  			GivenName:  "givenName",
   282  			FamilyName: "familyName",
   283  		},
   284  		Emails: []*SCIMUserEmail{
   285  			{
   286  				Value: "octocat@github.com",
   287  			},
   288  		},
   289  	}
   290  	_, err := client.SCIM.UpdateProvisionedOrgMembership(ctx, "o", "123", opts)
   291  	if err != nil {
   292  		t.Errorf("SCIM.UpdateProvisionedOrgMembership returned error: %v", err)
   293  	}
   294  
   295  	const methodName = "UpdateProvisionedOrgMembership"
   296  	testBadOptions(t, methodName, func() error {
   297  		_, err := client.SCIM.UpdateProvisionedOrgMembership(ctx, "\n", "123", opts)
   298  		return err
   299  	})
   300  
   301  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   302  		return client.SCIM.UpdateProvisionedOrgMembership(ctx, "o", "123", opts)
   303  	})
   304  }
   305  
   306  func TestSCIMService_UpdateAttributeForSCIMUser(t *testing.T) {
   307  	t.Parallel()
   308  	client, mux, _ := setup(t)
   309  
   310  	mux.HandleFunc("/scim/v2/organizations/o/Users/123", func(w http.ResponseWriter, r *http.Request) {
   311  		testMethod(t, r, "PATCH")
   312  		w.WriteHeader(http.StatusNoContent)
   313  	})
   314  
   315  	ctx := context.Background()
   316  	opts := &UpdateAttributeForSCIMUserOptions{}
   317  	_, err := client.SCIM.UpdateAttributeForSCIMUser(ctx, "o", "123", opts)
   318  	if err != nil {
   319  		t.Errorf("SCIM.UpdateAttributeForSCIMUser returned error: %v", err)
   320  	}
   321  
   322  	const methodName = "UpdateAttributeForSCIMUser"
   323  	testBadOptions(t, methodName, func() error {
   324  		_, err := client.SCIM.UpdateAttributeForSCIMUser(ctx, "\n", "123", opts)
   325  		return err
   326  	})
   327  
   328  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   329  		return client.SCIM.UpdateAttributeForSCIMUser(ctx, "o", "123", opts)
   330  	})
   331  }
   332  
   333  func TestSCIMService_DeleteSCIMUserFromOrg(t *testing.T) {
   334  	t.Parallel()
   335  	client, mux, _ := setup(t)
   336  
   337  	mux.HandleFunc("/scim/v2/organizations/o/Users/123", func(w http.ResponseWriter, r *http.Request) {
   338  		testMethod(t, r, "DELETE")
   339  		w.WriteHeader(http.StatusNoContent)
   340  	})
   341  
   342  	ctx := context.Background()
   343  	_, err := client.SCIM.DeleteSCIMUserFromOrg(ctx, "o", "123")
   344  	if err != nil {
   345  		t.Errorf("SCIM.DeleteSCIMUserFromOrg returned error: %v", err)
   346  	}
   347  
   348  	const methodName = "DeleteSCIMUserFromOrg"
   349  	testBadOptions(t, methodName, func() error {
   350  		_, err := client.SCIM.DeleteSCIMUserFromOrg(ctx, "\n", "")
   351  		return err
   352  	})
   353  
   354  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   355  		return client.SCIM.DeleteSCIMUserFromOrg(ctx, "o", "123")
   356  	})
   357  }
   358  
   359  func TestSCIMUserAttributes_Marshal(t *testing.T) {
   360  	t.Parallel()
   361  	testJSONMarshal(t, &SCIMUserAttributes{}, `{
   362  		"userName":"","name":{"givenName":"","familyName":""},"emails":null
   363  	}`)
   364  
   365  	u := &SCIMUserAttributes{
   366  		UserName: "userName1",
   367  		Name: SCIMUserName{
   368  			GivenName:  "Name1",
   369  			FamilyName: "Fname",
   370  			Formatted:  String("formatted name"),
   371  		},
   372  		DisplayName: String("Name"),
   373  		Emails: []*SCIMUserEmail{
   374  			{
   375  				Value:   "value",
   376  				Primary: Bool(false),
   377  				Type:    String("type"),
   378  			},
   379  		},
   380  		Schemas:    []string{"schema1"},
   381  		ExternalID: String("id"),
   382  		Groups:     []string{"group1"},
   383  		Active:     Bool(true),
   384  	}
   385  
   386  	want := `{
   387  		"userName": "userName1",
   388  		"name": {
   389  			"givenName": "Name1",
   390  			"familyName": "Fname",
   391  			"formatted": "formatted name"
   392  		},
   393  		"displayName": "Name",
   394  		"emails": [{
   395  			"value": "value",
   396  			"primary": false,
   397  			"type": "type"
   398  		}],
   399  		"schemas": ["schema1"],
   400  		"externalId": "id",
   401  		"groups": ["group1"],
   402  		"active": true
   403  	}`
   404  
   405  	testJSONMarshal(t, u, want)
   406  }
   407  
   408  func TestUpdateAttributeForSCIMUserOperations_Marshal(t *testing.T) {
   409  	t.Parallel()
   410  	testJSONMarshal(t, &UpdateAttributeForSCIMUserOperations{}, `{}`)
   411  
   412  	u := &UpdateAttributeForSCIMUserOperations{
   413  		Op:   "TestOp",
   414  		Path: String("path"),
   415  	}
   416  
   417  	want := `{
   418  		"op": "TestOp",
   419  		"path": "path"
   420  	}`
   421  
   422  	testJSONMarshal(t, u, want)
   423  }
   424  
   425  func TestUpdateAttributeForSCIMUserOptions_Marshal(t *testing.T) {
   426  	t.Parallel()
   427  	testJSONMarshal(t, &UpdateAttributeForSCIMUserOptions{}, `{}`)
   428  
   429  	u := &UpdateAttributeForSCIMUserOptions{
   430  		Schemas: []string{"test", "schema"},
   431  		Operations: UpdateAttributeForSCIMUserOperations{
   432  			Op:   "TestOp",
   433  			Path: String("path"),
   434  		},
   435  	}
   436  
   437  	want := `{
   438  		"schemas": ["test", "schema"],
   439  		"operations": {
   440  			"op": "TestOp",
   441  			"path": "path"
   442  		}
   443  	}`
   444  
   445  	testJSONMarshal(t, u, want)
   446  }
   447  
   448  func TestListSCIMProvisionedIdentitiesOptions_addOptions(t *testing.T) {
   449  	t.Parallel()
   450  	testJSONMarshal(t, &ListSCIMProvisionedIdentitiesOptions{}, `{
   451  		"StartIndex": null,
   452  		"Count": null,
   453  		"Filter": null
   454  	}`)
   455  
   456  	url := "some/path"
   457  
   458  	testAddURLOptions(t, url, &ListSCIMProvisionedIdentitiesOptions{}, url)
   459  
   460  	testAddURLOptions(
   461  		t,
   462  		url,
   463  		&ListSCIMProvisionedIdentitiesOptions{
   464  			StartIndex: Int(1),
   465  			Count:      Int(10),
   466  		},
   467  		fmt.Sprintf("%s?count=10&startIndex=1", url),
   468  	)
   469  
   470  	testAddURLOptions(
   471  		t,
   472  		url,
   473  		&ListSCIMProvisionedIdentitiesOptions{
   474  			StartIndex: Int(1),
   475  			Count:      Int(10),
   476  			Filter:     String("test"),
   477  		},
   478  		fmt.Sprintf("%s?count=10&filter=test&startIndex=1", url),
   479  	)
   480  }
   481  
   482  func TestSCIMUserName_Marshal(t *testing.T) {
   483  	t.Parallel()
   484  	testJSONMarshal(t, &SCIMUserName{}, `{
   485  		"givenName":"","familyName":""
   486  	}`)
   487  
   488  	u := &SCIMUserName{
   489  		GivenName:  "Name1",
   490  		FamilyName: "Fname",
   491  		Formatted:  String("formatted name"),
   492  	}
   493  
   494  	want := `{
   495  			"givenName": "Name1",
   496  			"familyName": "Fname",
   497  			"formatted": "formatted name"
   498  	}`
   499  	testJSONMarshal(t, u, want)
   500  }
   501  
   502  func TestSCIMMeta_Marshal(t *testing.T) {
   503  	t.Parallel()
   504  	testJSONMarshal(t, &SCIMMeta{}, `{}`)
   505  
   506  	u := &SCIMMeta{
   507  		ResourceType: String("test"),
   508  		Location:     String("test"),
   509  	}
   510  
   511  	want := `{
   512  		"resourceType": "test",
   513  		"location": "test"
   514  	}`
   515  
   516  	testJSONMarshal(t, u, want)
   517  }
   518  
   519  func TestSCIMProvisionedIdentities_Marshal(t *testing.T) {
   520  	t.Parallel()
   521  	testJSONMarshal(t, &SCIMProvisionedIdentities{}, `{}`)
   522  
   523  	u := &SCIMProvisionedIdentities{
   524  		Schemas:      []string{"test", "schema"},
   525  		TotalResults: Int(1),
   526  		ItemsPerPage: Int(2),
   527  		StartIndex:   Int(1),
   528  		Resources: []*SCIMUserAttributes{
   529  			{
   530  				UserName: "SCIM",
   531  				Name: SCIMUserName{
   532  					GivenName:  "scim",
   533  					FamilyName: "test",
   534  					Formatted:  String("SCIM"),
   535  				},
   536  				DisplayName: String("Test SCIM"),
   537  				Emails: []*SCIMUserEmail{
   538  					{
   539  						Value:   "test",
   540  						Primary: Bool(true),
   541  						Type:    String("test"),
   542  					},
   543  				},
   544  				Schemas:    []string{"schema1"},
   545  				ExternalID: String("id"),
   546  				Groups:     []string{"group1"},
   547  				Active:     Bool(true),
   548  			},
   549  		},
   550  	}
   551  
   552  	want := `{
   553  		"schemas": ["test", "schema"],
   554  		"totalResults": 1,
   555  		"itemsPerPage": 2,
   556  		"startIndex": 1,
   557  		"Resources": [{
   558  			"userName": "SCIM",
   559  			"name": {
   560  				"givenName": "scim",
   561  				"familyName": "test",
   562  				"formatted": "SCIM"
   563  			},
   564  			"displayName": "Test SCIM",
   565  			"emails": [{
   566  				"value": "test",
   567  				"primary": true,
   568  				"type": "test"
   569  			}],
   570  			"schemas": ["schema1"],
   571  			"externalId": "id",
   572  			"groups": ["group1"],
   573  			"active": true
   574  		}]
   575  	}`
   576  
   577  	testJSONMarshal(t, u, want)
   578  }