From e191f47aedf8b993024bbdc075510b612440c589 Mon Sep 17 00:00:00 2001 From: Roberto Dip Date: Fri, 23 Dec 2022 14:55:17 -0300 Subject: [PATCH] fix failed enrollments due to duplicate slashes on paths (#9089) This ensures URLs in enrollment profiles are properly formatted, preventing errors as described in #9088. --- changes/9088-mdm-enroll-urls | 1 + server/service/apple_mdm.go | 35 +++++++++++++++++++++++++------- server/service/apple_mdm_test.go | 32 +++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 7 deletions(-) create mode 100644 changes/9088-mdm-enroll-urls diff --git a/changes/9088-mdm-enroll-urls b/changes/9088-mdm-enroll-urls new file mode 100644 index 0000000000..a0a51e7b85 --- /dev/null +++ b/changes/9088-mdm-enroll-urls @@ -0,0 +1 @@ +- Fixed an issue causing enrollment profiles to fail if the server URL had a trailing slash. diff --git a/server/service/apple_mdm.go b/server/service/apple_mdm.go index 1b5a62951b..2f3b28a740 100644 --- a/server/service/apple_mdm.go +++ b/server/service/apple_mdm.go @@ -9,6 +9,8 @@ import ( "io" "mime/multipart" "net/http" + "net/url" + "path" "strconv" "text/template" @@ -82,13 +84,25 @@ func (svc *Service) NewMDMAppleEnrollmentProfile(ctx context.Context, enrollment } } - profile.EnrollmentURL = svc.mdmAppleEnrollURL(profile.Token, appConfig) + enrollmentURL, err := svc.mdmAppleEnrollURL(profile.Token, appConfig) + if err != nil { + return nil, ctxerr.Wrap(ctx, err) + } + profile.EnrollmentURL = enrollmentURL return profile, nil } -func (svc *Service) mdmAppleEnrollURL(token string, appConfig *fleet.AppConfig) string { - return fmt.Sprintf("%s%s?token=%s", appConfig.ServerSettings.ServerURL, apple_mdm.EnrollPath, token) +func (svc *Service) mdmAppleEnrollURL(token string, appConfig *fleet.AppConfig) (string, error) { + enrollURL, err := url.Parse(appConfig.ServerSettings.ServerURL) + if err != nil { + return "", err + } + enrollURL.Path = path.Join(enrollURL.Path, apple_mdm.EnrollPath) + q := enrollURL.Query() + q.Set("token", token) + enrollURL.RawQuery = q.Encode() + return enrollURL.String(), nil } // setDEPProfile define a "DEP profile" on https://mdmenrollment.apple.com and @@ -104,7 +118,10 @@ func (svc *Service) setDEPProfile(ctx context.Context, enrollmentProfile *fleet. } // Override url and configuration_web_url with Fleet's enroll path (publicly accessible address). - enrollURL := svc.mdmAppleEnrollURL(enrollmentProfile.Token, appConfig) + enrollURL, err := svc.mdmAppleEnrollURL(enrollmentProfile.Token, appConfig) + if err != nil { + return fmt.Errorf("generating enrollment URL: %w", err) + } depProfileRequest["url"] = enrollURL depProfileRequest["configuration_web_url"] = enrollURL depProfile, err := json.Marshal(depProfileRequest) @@ -181,7 +198,11 @@ func (svc *Service) ListMDMAppleEnrollmentProfiles(ctx context.Context) ([]*flee return nil, ctxerr.Wrap(ctx, err) } for i := range enrollments { - enrollments[i].EnrollmentURL = svc.mdmAppleEnrollURL(enrollments[i].Token, appConfig) + enrollURL, err := svc.mdmAppleEnrollURL(enrollments[i].Token, appConfig) + if err != nil { + return nil, ctxerr.Wrap(ctx, err) + } + enrollments[i].EnrollmentURL = enrollURL } return enrollments, nil } @@ -804,8 +825,8 @@ var enrollmentProfileMobileconfigTemplate = template.Must(template.New("").Parse `)) func generateEnrollmentProfileMobileconfig(orgName, fleetURL, scepChallenge, topic string) ([]byte, error) { - scepURL := fleetURL + apple_mdm.SCEPPath - serverURL := fleetURL + apple_mdm.MDMPath + scepURL := path.Join(fleetURL, apple_mdm.SCEPPath) + serverURL := path.Join(fleetURL, apple_mdm.MDMPath) var buf bytes.Buffer if err := enrollmentProfileMobileconfigTemplate.Execute(&buf, struct { diff --git a/server/service/apple_mdm_test.go b/server/service/apple_mdm_test.go index e21773967a..2d7de83d47 100644 --- a/server/service/apple_mdm_test.go +++ b/server/service/apple_mdm_test.go @@ -188,3 +188,35 @@ func TestAppleMDMAuthorization(t *testing.T) { _, err = svc.NewMDMAppleDEPKeyPair(ctx) require.NoError(t, err) } + +func TestMDMAppleEnrollURL(t *testing.T) { + svc := Service{} + + cases := []struct { + appConfig *fleet.AppConfig + expectedURL string + }{ + { + appConfig: &fleet.AppConfig{ + ServerSettings: fleet.ServerSettings{ + ServerURL: "https://foo.example.com", + }, + }, + expectedURL: "https://foo.example.com/api/mdm/apple/enroll?token=tok", + }, + { + appConfig: &fleet.AppConfig{ + ServerSettings: fleet.ServerSettings{ + ServerURL: "https://foo.example.com/", + }, + }, + expectedURL: "https://foo.example.com/api/mdm/apple/enroll?token=tok", + }, + } + + for _, tt := range cases { + enrollURL, err := svc.mdmAppleEnrollURL("tok", tt.appConfig) + require.NoError(t, err) + require.Equal(t, tt.expectedURL, enrollURL) + } +}