mirror of
https://github.com/empayre/fleet.git
synced 2024-11-06 08:55:24 +00:00
223 lines
9.7 KiB
Go
223 lines
9.7 KiB
Go
package service
|
|
|
|
import (
|
|
"bytes"
|
|
"compress/flate"
|
|
"encoding/base64"
|
|
"encoding/xml"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/fleetdm/fleet/v4/server/datastore/redis/redistest"
|
|
"github.com/fleetdm/fleet/v4/server/sso"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/stretchr/testify/suite"
|
|
)
|
|
|
|
type integrationSSOTestSuite struct {
|
|
suite.Suite
|
|
withServer
|
|
}
|
|
|
|
func (s *integrationSSOTestSuite) SetupSuite() {
|
|
s.withDS.SetupSuite("integrationSSOTestSuite")
|
|
|
|
pool := redistest.SetupRedis(s.T(), "zz", false, false, false)
|
|
users, server := RunServerForTestsWithDS(s.T(), s.ds, TestServerOpts{Pool: pool})
|
|
s.server = server
|
|
s.users = users
|
|
s.token = s.getTestAdminToken()
|
|
}
|
|
|
|
func TestIntegrationsSSO(t *testing.T) {
|
|
testingSuite := new(integrationSSOTestSuite)
|
|
testingSuite.s = &testingSuite.Suite
|
|
suite.Run(t, testingSuite)
|
|
}
|
|
|
|
func (s *integrationSSOTestSuite) TestGetSSOSettings() {
|
|
t := s.T()
|
|
|
|
// start a test server to serve as the SAML identity provider
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
fmt.Fprint(w, samltestIdPMetadata)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
// enable SSO
|
|
spec := []byte(fmt.Sprintf(`
|
|
sso_settings:
|
|
enable_sso: true
|
|
metadata_url: %s
|
|
entity_id: https://samltest.id/saml/idp
|
|
idp_name: SAMLtestIdP
|
|
`, srv.URL))
|
|
s.applyConfig(spec)
|
|
|
|
// double-check the settings
|
|
var resGet ssoSettingsResponse
|
|
s.DoJSON("GET", "/api/v1/fleet/sso", nil, http.StatusOK, &resGet)
|
|
require.True(t, resGet.Settings.SSOEnabled)
|
|
|
|
// initiate an SSO auth
|
|
var resIni initiateSSOResponse
|
|
s.DoJSON("POST", "/api/v1/fleet/sso", map[string]string{}, http.StatusOK, &resIni)
|
|
require.NotEmpty(t, resIni.URL)
|
|
|
|
parsed, err := url.Parse(resIni.URL)
|
|
require.NoError(t, err)
|
|
q := parsed.Query()
|
|
encoded := q.Get("SAMLRequest")
|
|
assert.NotEmpty(t, encoded)
|
|
authReq := inflate(t, encoded)
|
|
assert.Equal(t, "https://samltest.id/saml/idp", authReq.Issuer.Url)
|
|
assert.Equal(t, "Fleet", authReq.ProviderName)
|
|
assert.True(t, strings.HasPrefix(authReq.ID, "id"), authReq.ID)
|
|
}
|
|
|
|
func inflate(t *testing.T, s string) *sso.AuthnRequest {
|
|
t.Helper()
|
|
|
|
decoded, err := base64.StdEncoding.DecodeString(s)
|
|
require.NoError(t, err)
|
|
|
|
r := flate.NewReader(bytes.NewReader(decoded))
|
|
defer r.Close()
|
|
|
|
var req sso.AuthnRequest
|
|
require.NoError(t, xml.NewDecoder(r).Decode(&req))
|
|
return &req
|
|
}
|
|
|
|
const (
|
|
samltestIdPMetadata = `
|
|
<!-- The entity describing the SAMLtest IdP, named by the entityID below -->
|
|
|
|
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" ID="SAMLtestIdP" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:shibmd="urn:mace:shibboleth:metadata:1.0" xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:mdui="urn:oasis:names:tc:SAML:metadata:ui" validUntil="2100-01-01T00:00:42Z" entityID="https://samltest.id/saml/idp">
|
|
|
|
<IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol urn:oasis:names:tc:SAML:1.1:protocol urn:mace:shibboleth:1.0">
|
|
|
|
<Extensions>
|
|
<!-- An enumeration of the domains this IdP is able to assert scoped attributes, which are
|
|
typically those with a @ delimiter, like mail. Most IdP's serve only a single domain. It's crucial
|
|
for the SP to check received attribute values match permitted domains to prevent a recognized IdP from
|
|
sending attribute values for which a different recognized IdP is authoritative. -->
|
|
<shibmd:Scope regexp="false">samltest.id</shibmd:Scope>
|
|
|
|
<!-- Display information about this IdP that can be used by SP's and discovery
|
|
services to identify the IdP meaningfully for end users -->
|
|
<mdui:UIInfo>
|
|
<mdui:DisplayName xml:lang="en">SAMLtest IdP</mdui:DisplayName>
|
|
<mdui:Description xml:lang="en">A free and basic IdP for testing SAML deployments</mdui:Description>
|
|
<mdui:Logo height="90" width="225">https://samltest.id/saml/logo.png</mdui:Logo>
|
|
</mdui:UIInfo>
|
|
</Extensions>
|
|
|
|
<KeyDescriptor use="signing">
|
|
<ds:KeyInfo>
|
|
<ds:X509Data>
|
|
<ds:X509Certificate>
|
|
MIIDETCCAfmgAwIBAgIUZRpDhkNKl5eWtJqk0Bu1BgTTargwDQYJKoZIhvcNAQEL
|
|
BQAwFjEUMBIGA1UEAwwLc2FtbHRlc3QuaWQwHhcNMTgwODI0MjExNDEwWhcNMzgw
|
|
ODI0MjExNDEwWjAWMRQwEgYDVQQDDAtzYW1sdGVzdC5pZDCCASIwDQYJKoZIhvcN
|
|
AQEBBQADggEPADCCAQoCggEBAJrh9/PcDsiv3UeL8Iv9rf4WfLPxuOm9W6aCntEA
|
|
8l6c1LQ1Zyrz+Xa/40ZgP29ENf3oKKbPCzDcc6zooHMji2fBmgXp6Li3fQUzu7yd
|
|
+nIC2teejijVtrNLjn1WUTwmqjLtuzrKC/ePoZyIRjpoUxyEMJopAd4dJmAcCq/K
|
|
k2eYX9GYRlqvIjLFoGNgy2R4dWwAKwljyh6pdnPUgyO/WjRDrqUBRFrLQJorR2kD
|
|
c4seZUbmpZZfp4MjmWMDgyGM1ZnR0XvNLtYeWAyt0KkSvFoOMjZUeVK/4xR74F8e
|
|
8ToPqLmZEg9ZUx+4z2KjVK00LpdRkH9Uxhh03RQ0FabHW6UCAwEAAaNXMFUwHQYD
|
|
VR0OBBYEFJDbe6uSmYQScxpVJhmt7PsCG4IeMDQGA1UdEQQtMCuCC3NhbWx0ZXN0
|
|
LmlkhhxodHRwczovL3NhbWx0ZXN0LmlkL3NhbWwvaWRwMA0GCSqGSIb3DQEBCwUA
|
|
A4IBAQBNcF3zkw/g51q26uxgyuy4gQwnSr01Mhvix3Dj/Gak4tc4XwvxUdLQq+jC
|
|
cxr2Pie96klWhY/v/JiHDU2FJo9/VWxmc/YOk83whvNd7mWaNMUsX3xGv6AlZtCO
|
|
L3JhCpHjiN+kBcMgS5jrtGgV1Lz3/1zpGxykdvS0B4sPnFOcaCwHe2B9SOCWbDAN
|
|
JXpTjz1DmJO4ImyWPJpN1xsYKtm67Pefxmn0ax0uE2uuzq25h0xbTkqIQgJzyoE/
|
|
DPkBFK1vDkMfAW11dQ0BXatEnW7Gtkc0lh2/PIbHWj4AzxYMyBf5Gy6HSVOftwjC
|
|
voQR2qr2xJBixsg+MIORKtmKHLfU
|
|
</ds:X509Certificate>
|
|
</ds:X509Data>
|
|
</ds:KeyInfo>
|
|
|
|
</KeyDescriptor>
|
|
<KeyDescriptor use="signing">
|
|
<ds:KeyInfo>
|
|
<ds:X509Data>
|
|
<ds:X509Certificate>
|
|
MIIDEjCCAfqgAwIBAgIVAMECQ1tjghafm5OxWDh9hwZfxthWMA0GCSqGSIb3DQEB
|
|
CwUAMBYxFDASBgNVBAMMC3NhbWx0ZXN0LmlkMB4XDTE4MDgyNDIxMTQwOVoXDTM4
|
|
MDgyNDIxMTQwOVowFjEUMBIGA1UEAwwLc2FtbHRlc3QuaWQwggEiMA0GCSqGSIb3
|
|
DQEBAQUAA4IBDwAwggEKAoIBAQC0Z4QX1NFKs71ufbQwoQoW7qkNAJRIANGA4iM0
|
|
ThYghul3pC+FwrGv37aTxWXfA1UG9njKbbDreiDAZKngCgyjxj0uJ4lArgkr4AOE
|
|
jj5zXA81uGHARfUBctvQcsZpBIxDOvUUImAl+3NqLgMGF2fktxMG7kX3GEVNc1kl
|
|
bN3dfYsaw5dUrw25DheL9np7G/+28GwHPvLb4aptOiONbCaVvh9UMHEA9F7c0zfF
|
|
/cL5fOpdVa54wTI0u12CsFKt78h6lEGG5jUs/qX9clZncJM7EFkN3imPPy+0HC8n
|
|
spXiH/MZW8o2cqWRkrw3MzBZW3Ojk5nQj40V6NUbjb7kfejzAgMBAAGjVzBVMB0G
|
|
A1UdDgQWBBQT6Y9J3Tw/hOGc8PNV7JEE4k2ZNTA0BgNVHREELTArggtzYW1sdGVz
|
|
dC5pZIYcaHR0cHM6Ly9zYW1sdGVzdC5pZC9zYW1sL2lkcDANBgkqhkiG9w0BAQsF
|
|
AAOCAQEASk3guKfTkVhEaIVvxEPNR2w3vWt3fwmwJCccW98XXLWgNbu3YaMb2RSn
|
|
7Th4p3h+mfyk2don6au7Uyzc1Jd39RNv80TG5iQoxfCgphy1FYmmdaSfO8wvDtHT
|
|
TNiLArAxOYtzfYbzb5QrNNH/gQEN8RJaEf/g/1GTw9x/103dSMK0RXtl+fRs2nbl
|
|
D1JJKSQ3AdhxK/weP3aUPtLxVVJ9wMOQOfcy02l+hHMb6uAjsPOpOVKqi3M8XmcU
|
|
ZOpx4swtgGdeoSpeRyrtMvRwdcciNBp9UZome44qZAYH1iqrpmmjsfI9pJItsgWu
|
|
3kXPjhSfj1AJGR1l9JGvJrHki1iHTA==
|
|
</ds:X509Certificate>
|
|
</ds:X509Data>
|
|
</ds:KeyInfo>
|
|
|
|
</KeyDescriptor>
|
|
<KeyDescriptor use="encryption">
|
|
<ds:KeyInfo>
|
|
<ds:X509Data>
|
|
<ds:X509Certificate>
|
|
MIIDEjCCAfqgAwIBAgIVAPVbodo8Su7/BaHXUHykx0Pi5CFaMA0GCSqGSIb3DQEB
|
|
CwUAMBYxFDASBgNVBAMMC3NhbWx0ZXN0LmlkMB4XDTE4MDgyNDIxMTQwOVoXDTM4
|
|
MDgyNDIxMTQwOVowFjEUMBIGA1UEAwwLc2FtbHRlc3QuaWQwggEiMA0GCSqGSIb3
|
|
DQEBAQUAA4IBDwAwggEKAoIBAQCQb+1a7uDdTTBBFfwOUun3IQ9nEuKM98SmJDWa
|
|
MwM877elswKUTIBVh5gB2RIXAPZt7J/KGqypmgw9UNXFnoslpeZbA9fcAqqu28Z4
|
|
sSb2YSajV1ZgEYPUKvXwQEmLWN6aDhkn8HnEZNrmeXihTFdyr7wjsLj0JpQ+VUlc
|
|
4/J+hNuU7rGYZ1rKY8AA34qDVd4DiJ+DXW2PESfOu8lJSOteEaNtbmnvH8KlwkDs
|
|
1NvPTsI0W/m4SK0UdXo6LLaV8saIpJfnkVC/FwpBolBrRC/Em64UlBsRZm2T89ca
|
|
uzDee2yPUvbBd5kLErw+sC7i4xXa2rGmsQLYcBPhsRwnmBmlAgMBAAGjVzBVMB0G
|
|
A1UdDgQWBBRZ3exEu6rCwRe5C7f5QrPcAKRPUjA0BgNVHREELTArggtzYW1sdGVz
|
|
dC5pZIYcaHR0cHM6Ly9zYW1sdGVzdC5pZC9zYW1sL2lkcDANBgkqhkiG9w0BAQsF
|
|
AAOCAQEABZDFRNtcbvIRmblnZItoWCFhVUlq81ceSQddLYs8DqK340//hWNAbYdj
|
|
WcP85HhIZnrw6NGCO4bUipxZXhiqTA/A9d1BUll0vYB8qckYDEdPDduYCOYemKkD
|
|
dmnHMQWs9Y6zWiYuNKEJ9mf3+1N8knN/PK0TYVjVjXAf2CnOETDbLtlj6Nqb8La3
|
|
sQkYmU+aUdopbjd5JFFwbZRaj6KiHXHtnIRgu8sUXNPrgipUgZUOVhP0C0N5OfE4
|
|
JW8ZBrKgQC/6vJ2rSa9TlzI6JAa5Ww7gMXMP9M+cJUNQklcq+SBnTK8G+uBHgPKR
|
|
zBDsMIEzRtQZm4GIoHJae4zmnCekkQ==
|
|
</ds:X509Certificate>
|
|
</ds:X509Data>
|
|
</ds:KeyInfo>
|
|
|
|
</KeyDescriptor>
|
|
|
|
<!-- An endpoint for artifact resolution. Please see Wikipedia for more details about SAML
|
|
artifacts and when you may find them useful. -->
|
|
|
|
<ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://samltest.id/idp/profile/SAML2/SOAP/ArtifactResolution" index="1" />
|
|
|
|
<!-- A set of endpoints where the IdP can receive logout messages. These must match the public
|
|
facing addresses if this IdP is hosted behind a reverse proxy. -->
|
|
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://samltest.id/idp/profile/SAML2/Redirect/SLO"/>
|
|
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://samltest.id/idp/profile/SAML2/POST/SLO"/>
|
|
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign" Location="https://samltest.id/idp/profile/SAML2/POST-SimpleSign/SLO"/>
|
|
|
|
<!-- A set of endpoints the SP can send AuthnRequests to in order to trigger user authentication. -->
|
|
<SingleSignOnService Binding="urn:mace:shibboleth:1.0:profiles:AuthnRequest" Location="https://samltest.id/idp/profile/Shibboleth/SSO"/>
|
|
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://samltest.id/idp/profile/SAML2/POST/SSO"/>
|
|
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign" Location="https://samltest.id/idp/profile/SAML2/POST-SimpleSign/SSO"/>
|
|
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://samltest.id/idp/profile/SAML2/Redirect/SSO"/>
|
|
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://samltest.id/idp/profile/SAML2/SOAP/ECP"/>
|
|
|
|
</IDPSSODescriptor>
|
|
|
|
</EntityDescriptor>
|
|
`
|
|
)
|