github.com/google/go-github/v65@v65.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  	client, mux, _, teardown := setup()
    20  	defer teardown()
    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  	client, mux, _, teardown := setup()
   126  	defer teardown()
   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  	client, mux, _, teardown := setup()
   177  	defer teardown()
   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  	client, mux, _, teardown := setup()
   270  	defer teardown()
   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  	client, mux, _, teardown := setup()
   308  	defer teardown()
   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  	client, mux, _, teardown := setup()
   335  	defer teardown()
   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  	testJSONMarshal(t, &SCIMUserAttributes{}, `{
   361  		"userName":"","name":{"givenName":"","familyName":""},"emails":null
   362  	}`)
   363  
   364  	u := &SCIMUserAttributes{
   365  		UserName: "userName1",
   366  		Name: SCIMUserName{
   367  			GivenName:  "Name1",
   368  			FamilyName: "Fname",
   369  			Formatted:  String("formatted name"),
   370  		},
   371  		DisplayName: String("Name"),
   372  		Emails: []*SCIMUserEmail{
   373  			{
   374  				Value:   "value",
   375  				Primary: Bool(false),
   376  				Type:    String("type"),
   377  			},
   378  		},
   379  		Schemas:    []string{"schema1"},
   380  		ExternalID: String("id"),
   381  		Groups:     []string{"group1"},
   382  		Active:     Bool(true),
   383  	}
   384  
   385  	want := `{
   386  		"userName": "userName1",
   387  		"name": {
   388  			"givenName": "Name1",
   389  			"familyName": "Fname",
   390  			"formatted": "formatted name"
   391  		},
   392  		"displayName": "Name",
   393  		"emails": [{
   394  			"value": "value",
   395  			"primary": false,
   396  			"type": "type"
   397  		}],
   398  		"schemas": ["schema1"],
   399  		"externalId": "id",
   400  		"groups": ["group1"],
   401  		"active": true
   402  	}`
   403  
   404  	testJSONMarshal(t, u, want)
   405  }
   406  
   407  func TestUpdateAttributeForSCIMUserOperations_Marshal(t *testing.T) {
   408  	testJSONMarshal(t, &UpdateAttributeForSCIMUserOperations{}, `{}`)
   409  
   410  	u := &UpdateAttributeForSCIMUserOperations{
   411  		Op:   "TestOp",
   412  		Path: String("path"),
   413  	}
   414  
   415  	want := `{
   416  		"op": "TestOp",
   417  		"path": "path"
   418  	}`
   419  
   420  	testJSONMarshal(t, u, want)
   421  }
   422  
   423  func TestUpdateAttributeForSCIMUserOptions_Marshal(t *testing.T) {
   424  	testJSONMarshal(t, &UpdateAttributeForSCIMUserOptions{}, `{}`)
   425  
   426  	u := &UpdateAttributeForSCIMUserOptions{
   427  		Schemas: []string{"test", "schema"},
   428  		Operations: UpdateAttributeForSCIMUserOperations{
   429  			Op:   "TestOp",
   430  			Path: String("path"),
   431  		},
   432  	}
   433  
   434  	want := `{
   435  		"schemas": ["test", "schema"],
   436  		"operations": {
   437  			"op": "TestOp",
   438  			"path": "path"
   439  		}
   440  	}`
   441  
   442  	testJSONMarshal(t, u, want)
   443  }
   444  
   445  func TestListSCIMProvisionedIdentitiesOptions_addOptions(t *testing.T) {
   446  	testJSONMarshal(t, &ListSCIMProvisionedIdentitiesOptions{}, `{
   447  		"StartIndex": null,
   448  		"Count": null,
   449  		"Filter": null
   450  	}`)
   451  
   452  	url := "some/path"
   453  
   454  	testAddURLOptions(t, url, &ListSCIMProvisionedIdentitiesOptions{}, url)
   455  
   456  	testAddURLOptions(
   457  		t,
   458  		url,
   459  		&ListSCIMProvisionedIdentitiesOptions{
   460  			StartIndex: Int(1),
   461  			Count:      Int(10),
   462  		},
   463  		fmt.Sprintf("%s?count=10&startIndex=1", url),
   464  	)
   465  
   466  	testAddURLOptions(
   467  		t,
   468  		url,
   469  		&ListSCIMProvisionedIdentitiesOptions{
   470  			StartIndex: Int(1),
   471  			Count:      Int(10),
   472  			Filter:     String("test"),
   473  		},
   474  		fmt.Sprintf("%s?count=10&filter=test&startIndex=1", url),
   475  	)
   476  }
   477  
   478  func TestSCIMUserName_Marshal(t *testing.T) {
   479  	testJSONMarshal(t, &SCIMUserName{}, `{
   480  		"givenName":"","familyName":""
   481  	}`)
   482  
   483  	u := &SCIMUserName{
   484  		GivenName:  "Name1",
   485  		FamilyName: "Fname",
   486  		Formatted:  String("formatted name"),
   487  	}
   488  
   489  	want := `{
   490  			"givenName": "Name1",
   491  			"familyName": "Fname",
   492  			"formatted": "formatted name"	
   493  	}`
   494  	testJSONMarshal(t, u, want)
   495  }
   496  
   497  func TestSCIMMeta_Marshal(t *testing.T) {
   498  	testJSONMarshal(t, &SCIMMeta{}, `{}`)
   499  
   500  	u := &SCIMMeta{
   501  		ResourceType: String("test"),
   502  		Location:     String("test"),
   503  	}
   504  
   505  	want := `{
   506  		"resourceType": "test",
   507  		"location": "test"
   508  	}`
   509  
   510  	testJSONMarshal(t, u, want)
   511  }
   512  
   513  func TestSCIMProvisionedIdentities_Marshal(t *testing.T) {
   514  	testJSONMarshal(t, &SCIMProvisionedIdentities{}, `{}`)
   515  
   516  	u := &SCIMProvisionedIdentities{
   517  		Schemas:      []string{"test", "schema"},
   518  		TotalResults: Int(1),
   519  		ItemsPerPage: Int(2),
   520  		StartIndex:   Int(1),
   521  		Resources: []*SCIMUserAttributes{
   522  			{
   523  				UserName: "SCIM",
   524  				Name: SCIMUserName{
   525  					GivenName:  "scim",
   526  					FamilyName: "test",
   527  					Formatted:  String("SCIM"),
   528  				},
   529  				DisplayName: String("Test SCIM"),
   530  				Emails: []*SCIMUserEmail{
   531  					{
   532  						Value:   "test",
   533  						Primary: Bool(true),
   534  						Type:    String("test"),
   535  					},
   536  				},
   537  				Schemas:    []string{"schema1"},
   538  				ExternalID: String("id"),
   539  				Groups:     []string{"group1"},
   540  				Active:     Bool(true),
   541  			},
   542  		},
   543  	}
   544  
   545  	want := `{
   546  		"schemas": ["test", "schema"],
   547  		"totalResults": 1,
   548  		"itemsPerPage": 2,
   549  		"startIndex": 1,
   550  		"Resources": [{
   551  			"userName": "SCIM",
   552  			"name": {
   553  				"givenName": "scim",
   554  				"familyName": "test",
   555  				"formatted": "SCIM"
   556  			},
   557  			"displayName": "Test SCIM",
   558  			"emails": [{
   559  				"value": "test",
   560  				"primary": true,
   561  				"type": "test"
   562  			}],
   563  			"schemas": ["schema1"],
   564  			"externalId": "id",
   565  			"groups": ["group1"],
   566  			"active": true
   567  		}]
   568  	}`
   569  
   570  	testJSONMarshal(t, u, want)
   571  }