Set givenName and familyName as required. (#28103)

For #23236 

Bug fix, per Figma

# Checklist for submitter

- [x] Added/updated automated tests
- [x] A detailed QA plan exists on the associated ticket (if it isn't
there, work with the product group's QA engineer to add it)
- [x] Manual QA for all new/changed functionality
This commit is contained in:
Victor Lyuboslavsky 2025-04-10 15:27:19 -05:00 committed by GitHub
parent 747af2247b
commit d15b49143e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 19 additions and 23 deletions

View file

@ -6,6 +6,7 @@ import (
"testing"
"time"
"github.com/elimity-com/scim/errors"
"github.com/fleetdm/fleet/v4/server/authz"
"github.com/fleetdm/fleet/v4/server/datastore/mysql"
"github.com/fleetdm/fleet/v4/server/service"
@ -710,16 +711,10 @@ func testCreateUser(t *testing.T, s *Suite) {
"active": true,
}
var createResp1 map[string]interface{}
s.DoJSON(t, "POST", scimPath("/Users"), userWithoutGivenName, http.StatusCreated, &createResp1)
assert.Equal(t, "no-given-name@example.com", createResp1["userName"])
userID1 := createResp1["id"].(string)
// Verify name only has familyName
name1, ok := createResp1["name"].(map[string]interface{})
assert.True(t, ok, "Name should be an object")
assert.Equal(t, "NoGivenName", name1["familyName"])
assert.Nil(t, name1["givenName"], "givenName should be nil")
var errorResp map[string]interface{}
s.DoJSON(t, "POST", scimPath("/Users"), userWithoutGivenName, http.StatusBadRequest, &errorResp)
assert.EqualValues(t, errorResp["schemas"], []interface{}{"urn:ietf:params:scim:api:messages:2.0:Error"})
assert.Equal(t, errors.ScimErrorInvalidValue.Detail, errorResp["detail"])
// Test creating a user without familyName
userWithoutFamilyName := map[string]interface{}{
@ -738,16 +733,10 @@ func testCreateUser(t *testing.T, s *Suite) {
"active": true,
}
var createResp2 map[string]interface{}
s.DoJSON(t, "POST", scimPath("/Users"), userWithoutFamilyName, http.StatusCreated, &createResp2)
assert.Equal(t, "no-family-name@example.com", createResp2["userName"])
userID2 := createResp2["id"].(string)
// Verify name only has givenName
name2, ok := createResp2["name"].(map[string]interface{})
assert.True(t, ok, "Name should be an object")
assert.Equal(t, "NoFamilyName", name2["givenName"])
assert.Nil(t, name2["familyName"], "familyName should be nil")
errorResp = nil
s.DoJSON(t, "POST", scimPath("/Users"), userWithoutFamilyName, http.StatusBadRequest, &errorResp)
assert.EqualValues(t, errorResp["schemas"], []interface{}{"urn:ietf:params:scim:api:messages:2.0:Error"})
assert.Equal(t, errors.ScimErrorInvalidValue.Detail, errorResp["detail"])
// Test creating a user without emails
userWithoutEmails := map[string]interface{}{
@ -937,8 +926,6 @@ func testCreateUser(t *testing.T, s *Suite) {
assert.Equal(t, "external-system-123456", createResp6["externalId"])
// Make sure these users can be deleted.
s.Do(t, "DELETE", scimPath("/Users/"+userID1), nil, http.StatusNoContent)
s.Do(t, "DELETE", scimPath("/Users/"+userID2), nil, http.StatusNoContent)
s.Do(t, "DELETE", scimPath("/Users/"+userID3), nil, http.StatusNoContent)
s.Do(t, "DELETE", scimPath("/Users/"+userID4), nil, http.StatusNoContent)
s.Do(t, "DELETE", scimPath("/Users/"+userID5), nil, http.StatusNoContent)
@ -1050,7 +1037,8 @@ func testPatchUserFailure(t *testing.T, s *Suite) {
"value": map[string]interface{}{
"active": false,
"name": map[string]interface{}{
"givenName": "Updated",
"givenName": "Updated",
"familyName": "Updated",
},
},
},

View file

@ -6,6 +6,7 @@ import (
"fmt"
"io"
"net/http"
"strings"
"github.com/elimity-com/scim"
"github.com/elimity-com/scim/errors"
@ -54,10 +55,12 @@ func RegisterSCIM(
schema.SimpleStringParams(schema.StringParams{
Description: optional.NewString("The family name of the User, or last name in most Western languages (e.g., 'Jensen' given the full name 'Ms. Barbara J Jensen, III')."),
Name: "familyName",
Required: true,
}),
schema.SimpleStringParams(schema.StringParams{
Description: optional.NewString("The given name of the User, or first name in most Western languages (e.g., 'Barbara' given the full name 'Ms. Barbara J Jensen, III')."),
Name: "givenName",
Required: true,
}),
},
}),
@ -242,6 +245,11 @@ func LastRequestMiddleware(ds fleet.Datastore, logger kitlog.Logger, next http.H
} else {
details = multi.body.String()
}
if multi.statusCode == errors.ScimErrorInvalidValue.Status && details == errors.ScimErrorInvalidValue.Detail &&
strings.Contains(r.URL.Path, "/Users") {
// We customize the error message here since we can't do it inside the 3rd party SCIM library.
details = `Missing required attributes. "userName", "givenName", and "familyName" are required. Please configure your identity provider to send required attributes to Fleet.`
}
default:
status = "error"
details = fmt.Sprintf("Unhandled status code: %d", multi.statusCode)