Fallback to ConfigurationURL when ConfigurationWebURL is not set in macOS MDM enrollment profile (#30462)

This commit is contained in:
Sarah Gillespie 2025-07-02 13:47:42 -05:00 committed by GitHub
parent 95871bffa0
commit f00aecb382
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 105 additions and 38 deletions

View file

@ -0,0 +1,2 @@
- Fixed issue with macOS MDM migration where fleetd did not fallback to parsing the
`ConfigurationURL` when `ConfigurationWebURL` was not set in the MDM enrollment profile.

View file

@ -215,29 +215,40 @@ func CheckAssignedEnrollmentProfile(expectedURL string) error {
return errors.New("parsing profiles output: received null device enrollment configuration")
}
var configURL, configWebURL string
var assignedURL string
for _, line := range lines {
// Note the output may contain both ConfigurationURL and ConfigurationWebURL but we check only
// the latter for backwards compatibility.
// See https://github.com/fleetdm/fleet/blob/963b2438537de14e7e16f1f18857ed8a66d51bfc/server/mdm/apple/apple_mdm.go#L195
v, ok := parseEnrollmentProfileValue(line, "ConfigurationWebURL")
if ok {
assignedURL = v
if v, ok := parseEnrollmentProfileValue(line, "ConfigurationURL"); ok {
configURL = v
continue
}
if v, ok := parseEnrollmentProfileValue(line, "ConfigurationWebURL"); ok {
configWebURL = v
break
}
}
if assignedURL == "" {
return errors.New("parsing profiles output: missing or empty configuration web url")
switch {
case configURL == "" && configWebURL == "":
return errors.New("parsing profiles output: missing both configuration web url and configuration url")
case configWebURL != "":
// Always prefer web URL for consistency.
assignedURL = configWebURL
default:
// Fallback to configuration URL.
assignedURL = configURL
}
assigned, err := url.Parse(assignedURL)
if err != nil {
return fmt.Errorf("parsing profiles output: unable to parse configuration web url: %w", err)
return fmt.Errorf("parsing profiles output: unable to parse server url: %w", err)
}
if !strings.EqualFold(assigned.Hostname(), expected.Hostname()) {
return fmt.Errorf(`matching configuration web url: expected '%s' but found '%s'`, expected.Hostname(), assigned.Hostname())
return fmt.Errorf(`matching server url: expected '%s' but found '%s'`, expected.Hostname(), assigned.Hostname())
}
return nil

View file

@ -333,35 +333,31 @@ func TestCheckAssignedEnrollmentProfile(t *testing.T) {
name string
cmdOut *string
cmdErr error
wantOut bool
wantErr error
}{
{
"command error",
nil,
errors.New("some command error"),
false,
errors.New("some command error"),
name: "command error",
cmdOut: nil,
cmdErr: errors.New("some command error"),
wantErr: errors.New("some command error"),
},
{
"empty output",
ptr.String(""),
nil,
false,
errors.New("parsing profiles output: expected at least 2 lines but got 1"),
name: "empty output",
cmdOut: ptr.String(""),
cmdErr: nil,
wantErr: errors.New("parsing profiles output: expected at least 2 lines but got 1"),
},
{
"null profile",
ptr.String(`Device Enrollment configuration:
name: "null profile",
cmdOut: ptr.String(`Device Enrollment configuration:
(null)
`),
nil,
false,
errors.New("parsing profiles output: received null device enrollment configuration"),
cmdErr: nil,
wantErr: errors.New("parsing profiles output: received null device enrollment configuration"),
},
{
"mismatch profile",
ptr.String(`Device Enrollment configuration:
name: "mismatch profile",
cmdOut: ptr.String(`Device Enrollment configuration:
{
AllowPairing = 1;
AutoAdvanceSetup = 0;
@ -371,13 +367,12 @@ func TestCheckAssignedEnrollmentProfile(t *testing.T) {
...
}
`),
nil,
false,
errors.New(`configuration web url: expected 'valid.com' but found 'test.example.com'`),
cmdErr: nil,
wantErr: errors.New(`server url: expected 'valid.com' but found 'test.example.com'`),
},
{
"match profile",
ptr.String(`Device Enrollment configuration:
name: "match profile",
cmdOut: ptr.String(`Device Enrollment configuration:
{
AllowPairing = 1;
AutoAdvanceSetup = 0;
@ -387,13 +382,12 @@ func TestCheckAssignedEnrollmentProfile(t *testing.T) {
...
}
`),
nil,
false,
nil,
cmdErr: nil,
wantErr: nil,
},
{
"mixed case match",
ptr.String(`Device Enrollment configuration:
name: "mixed case match configuration web URL",
cmdOut: ptr.String(`Device Enrollment configuration:
{
AllowPairing = 1;
AutoAdvanceSetup = 0;
@ -403,9 +397,69 @@ func TestCheckAssignedEnrollmentProfile(t *testing.T) {
...
}
`),
nil,
false,
nil,
cmdErr: nil,
wantErr: nil,
},
{
name: "mixed case match configuration URL but wrong configuration web URL",
cmdOut: ptr.String(`Device Enrollment configuration:
{
AllowPairing = 1;
AutoAdvanceSetup = 0;
AwaitDeviceConfigured = 0;
ConfigurationURL = "https://vaLiD.com?tOken=1234";
ConfigurationWebURL = "https://test.ExaMplE.com/mdm/apple/enroll?token=1234";
...
}
`),
cmdErr: nil,
wantErr: errors.New(`server url: expected 'valid.com' but found 'test.ExaMplE.com'`),
},
{
name: "match configuration URL and empty configuration web URL",
cmdOut: ptr.String(`Device Enrollment configuration:
{
AllowPairing = 1;
AutoAdvanceSetup = 0;
AwaitDeviceConfigured = 0;
ConfigurationURL = "https://valid.com?token=1234";
ConfigurationWebURL = "";
...
}
`),
cmdErr: nil,
wantErr: nil,
},
{
name: "mixed case match configuration web URL and empty configuration URL",
cmdOut: ptr.String(`Device Enrollment configuration:
{
AllowPairing = 1;
AutoAdvanceSetup = 0;
AwaitDeviceConfigured = 0;
ConfigurationURL = "";
ConfigurationWebURL = "https://vaLiD.com?tOken=1234";
...
}
`),
cmdErr: nil,
wantErr: nil,
},
{
name: "unparseable URL",
cmdOut: ptr.String(`Device Enrollment configuration:
{
AllowPairing = 1;
AutoAdvanceSetup = 0;
AwaitDeviceConfigured = 0;
ConfigurationURL = "://invalid-url";
ConfigurationWebURL = "";
...
}
`),
cmdErr: nil,
wantErr: errors.New("parsing profiles output: unable to parse server url"),
},
}