mirror of
https://github.com/empayre/fleet.git
synced 2024-11-06 00:45:19 +00:00
use the configured EntityID for audience validation on MDM SSO (#16144)
for #16139 this fixes a copy/paste error that caused the MDM SSO flow to validate audiences using the global config EntityID since we also consider an audience valid if you set EntityID to be: - the same in both (case for local dev) - your Fleet URL or the full path to the SSO API endpoint (QA) we didn't notice this until now.
This commit is contained in:
parent
f0db77a4b7
commit
f078660243
1
changes/16139-sso-fix
Normal file
1
changes/16139-sso-fix
Normal file
@ -0,0 +1 @@
|
||||
* Fixed a bug that would cause MDM SSO to fail with certain valid configurations.
|
@ -720,15 +720,18 @@ func (svc *Service) mdmSSOHandleCallbackAuth(ctx context.Context, auth fleet.Aut
|
||||
return "", "", "", ctxerr.Wrap(ctx, err, "validate request in session")
|
||||
}
|
||||
|
||||
var ssoSettings fleet.SSOSettings
|
||||
if appConfig.SSOSettings != nil {
|
||||
ssoSettings = *appConfig.SSOSettings
|
||||
settings := appConfig.MDM.EndUserAuthentication.SSOProviderSettings
|
||||
// For now, until we get to #10999, we assume that SSO is disabled if
|
||||
// no settings are provided.
|
||||
if settings.IsEmpty() {
|
||||
err := &fleet.BadRequestError{Message: "organization not configured to use sso"}
|
||||
return "", "", "", ctxerr.Wrap(ctx, err, "get config for mdm sso callback")
|
||||
}
|
||||
|
||||
err = sso.ValidateAudiences(
|
||||
*metadata,
|
||||
auth,
|
||||
ssoSettings.EntityID,
|
||||
settings.EntityID,
|
||||
appConfig.ServerSettings.ServerURL,
|
||||
appConfig.ServerSettings.ServerURL+svc.config.Server.URLPrefix+"/api/v1/fleet/mdm/sso/callback",
|
||||
)
|
||||
|
@ -6604,13 +6604,31 @@ func (s *integrationMDMTestSuite) TestSSO() {
|
||||
s.runWorker()
|
||||
require.Equal(t, lastSubmittedProfile.ConfigurationWebURL, lastSubmittedProfile.URL)
|
||||
|
||||
// set-up valid settings
|
||||
acResp = appConfigResponse{}
|
||||
s.DoJSON("PATCH", "/api/latest/fleet/config", json.RawMessage(`{
|
||||
checkStoredIdPInfo := func(uuid, username, fullname, email string) {
|
||||
acc, err := s.ds.GetMDMIdPAccountByUUID(context.Background(), uuid)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, username, acc.Username)
|
||||
require.Equal(t, fullname, acc.Fullname)
|
||||
require.Equal(t, email, acc.Email)
|
||||
}
|
||||
|
||||
// test basic authentication for each supported config flow.
|
||||
//
|
||||
// IT admins can set up SSO as part of the same entity or as a completely
|
||||
// separate entity.
|
||||
//
|
||||
// Configs supporting each flow are defined in `tools/saml/config.php`
|
||||
configFlows := []string{
|
||||
"mdm.test.com", // independent, mdm-sso only app
|
||||
"https://localhost:8080", // app that supports both MDM and Fleet UI SSO
|
||||
}
|
||||
for _, entityID := range configFlows {
|
||||
acResp = appConfigResponse{}
|
||||
s.DoJSON("PATCH", "/api/latest/fleet/config", json.RawMessage(fmt.Sprintf(`{
|
||||
"server_settings": {"server_url": "https://localhost:8080"},
|
||||
"mdm": {
|
||||
"end_user_authentication": {
|
||||
"entity_id": "https://localhost:8080",
|
||||
"entity_id": "%s",
|
||||
"issuer_uri": "http://localhost:8080/simplesaml/saml2/idp/SSOService.php",
|
||||
"idp_name": "SimpleSAML",
|
||||
"metadata_url": "http://localhost:9080/simplesaml/saml2/idp/metadata.php"
|
||||
@ -6619,18 +6637,36 @@ func (s *integrationMDMTestSuite) TestSSO() {
|
||||
"enable_end_user_authentication": true
|
||||
}
|
||||
}
|
||||
}`), http.StatusOK, &acResp)
|
||||
}`, entityID)), http.StatusOK, &acResp)
|
||||
|
||||
s.runWorker()
|
||||
require.Contains(t, lastSubmittedProfile.URL, acResp.ServerSettings.ServerURL+"/mdm/sso")
|
||||
require.Equal(t, acResp.ServerSettings.ServerURL+"/mdm/sso", lastSubmittedProfile.ConfigurationWebURL)
|
||||
s.runWorker()
|
||||
require.Contains(t, lastSubmittedProfile.URL, acResp.ServerSettings.ServerURL+"/mdm/sso")
|
||||
require.Equal(t, acResp.ServerSettings.ServerURL+"/mdm/sso", lastSubmittedProfile.ConfigurationWebURL)
|
||||
|
||||
checkStoredIdPInfo := func(uuid, username, fullname, email string) {
|
||||
acc, err := s.ds.GetMDMIdPAccountByUUID(context.Background(), uuid)
|
||||
res := s.LoginMDMSSOUser("sso_user", "user123#")
|
||||
require.NotEmpty(t, res.Header.Get("Location"))
|
||||
require.Equal(t, http.StatusTemporaryRedirect, res.StatusCode)
|
||||
|
||||
u, err := url.Parse(res.Header.Get("Location"))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, username, acc.Username)
|
||||
require.Equal(t, fullname, acc.Fullname)
|
||||
require.Equal(t, email, acc.Email)
|
||||
q := u.Query()
|
||||
user1EnrollRef := q.Get("enrollment_reference")
|
||||
// without an EULA uploaded
|
||||
require.False(t, q.Has("eula_token"))
|
||||
require.True(t, q.Has("profile_token"))
|
||||
require.True(t, q.Has("enrollment_reference"))
|
||||
require.False(t, q.Has("error"))
|
||||
// the url retrieves a valid profile
|
||||
s.downloadAndVerifyEnrollmentProfile(
|
||||
fmt.Sprintf(
|
||||
"/api/mdm/apple/enroll?token=%s&enrollment_reference=%s",
|
||||
q.Get("profile_token"),
|
||||
user1EnrollRef,
|
||||
),
|
||||
)
|
||||
|
||||
// IdP info stored is accurate for the account
|
||||
checkStoredIdPInfo(user1EnrollRef, "sso_user", "SSO User 1", "sso_user@example.com")
|
||||
}
|
||||
|
||||
res := s.LoginMDMSSOUser("sso_user", "user123#")
|
||||
@ -6641,22 +6677,6 @@ func (s *integrationMDMTestSuite) TestSSO() {
|
||||
require.NoError(t, err)
|
||||
q := u.Query()
|
||||
user1EnrollRef := q.Get("enrollment_reference")
|
||||
// without an EULA uploaded
|
||||
require.False(t, q.Has("eula_token"))
|
||||
require.True(t, q.Has("profile_token"))
|
||||
require.True(t, q.Has("enrollment_reference"))
|
||||
require.False(t, q.Has("error"))
|
||||
// the url retrieves a valid profile
|
||||
s.downloadAndVerifyEnrollmentProfile(
|
||||
fmt.Sprintf(
|
||||
"/api/mdm/apple/enroll?token=%s&enrollment_reference=%s",
|
||||
q.Get("profile_token"),
|
||||
user1EnrollRef,
|
||||
),
|
||||
)
|
||||
|
||||
// IdP info stored is accurate for the account
|
||||
checkStoredIdPInfo(user1EnrollRef, "sso_user", "SSO User 1", "sso_user@example.com")
|
||||
|
||||
// upload an EULA
|
||||
pdfBytes := []byte("%PDF-1.pdf-contents")
|
||||
|
@ -9,3 +9,13 @@ $metadata['https://localhost:8080'] = array(
|
||||
'simplesaml.nameidattribute' => 'email',
|
||||
);
|
||||
|
||||
# used in integration tests and to validate SSO flows that use a
|
||||
# separate application for MDM SSO (with a single
|
||||
# AssertionConsumerService)
|
||||
$metadata['mdm.test.com'] = array(
|
||||
'AssertionConsumerService' => [
|
||||
'https://localhost:8080/api/v1/fleet/mdm/sso/callback',
|
||||
],
|
||||
'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddres',
|
||||
'simplesaml.nameidattribute' => 'email',
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user