Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions lib/fixtures/fixtures.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,35 @@ spec:
C7yZIZM0DuazwkaenExrncvPtF6KL7eccudcknNjhRjFD3Yx1nNXgbVRHvVaElm0YxLiLcl8l0Rn
pHM7WKwFyW1dvEDax3BGj9/cbKvpvcwR</ds:X509Certificate></ds:X509Data></ds:KeyInfo></md:KeyDescriptor><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://dev-813354.oktapreview.com/app/gravitationaldev813354_teleportsaml_1/exkafftca6RqPVgyZ0h7/sso/saml"/><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://dev-813354.oktapreview.com/app/gravitationaldev813354_teleportsaml_1/exkafftca6RqPVgyZ0h7/sso/saml"/></md:IDPSSODescriptor></md:EntityDescriptor>`

const SAMLOktaConnectorV2WithPadding = `kind: saml
version: v2
metadata:
name: OktaSAML
namespace: default
spec:
acs: https://localhost:3080/v1/webapi/saml/acs
attributes_to_roles:
- {name: "groups", value: "Everyone", roles: ["admin"]}
entity_descriptor: |
<?xml version="1.0" encoding="UTF-8"?><md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="http://www.okta.com/exkafftca6RqPVgyZ0h7"><md:IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"><md:KeyDescriptor use="signing"><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509Data><ds:X509Certificate>MIIDpDCCAoygAwIBAgIGAVvvlUB6MA0GCSqGSIb3DQEBCwUAMIGSMQswCQYDVQQGEwJVUzETMBEG
A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU
MBIGA1UECwwLU1NPUHJvdmlkZXIxEzARBgNVBAMMCmRldi04MTMzNTQxHDAaBgkqhkiG9w0BCQEW
DWluZm9Ab2t0YS5jb20wHhcNMTcwNTA5MjMzODQ3WhcNMjcwNTA5MjMzOTQ3WjCBkjELMAkGA1UE
BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNV
BAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRMwEQYDVQQDDApkZXYtODEzMzU0MRwwGgYJ
KoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
ltQB+ZTGKoaNiWQRZ/bzl9oNmbjFyLiVlDASaYnuv1yBx70/Tzr9VXn0gWkl5yH0zIpzREvR5qM1
VAaH3dgNbxTg15f0e5xDk7r5ggS11mX5p8S1Ca9UQmqhRRv7jhMJxHbCy4rFV5jO/uyNQDaMZLPd
zFuzpwKaWhy/UCQ3lDmNzxp3Q6T3FULV+fvs7tJp+8p6qfpoGkANGVfs/Jx/kgbbk0JZG2wk4VVl
b1rZTZJWQ6hCLwTAsD/WixcUx1BFTXmqoZTYNETATVJQ+bEMCVf8K4hxbH6hEgjoL//AE9zgpa1m
uvKwevYBvYZ/+VRy+It3d9mq73AdrG9vchE3qQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQASANAj
8JQdBdKIrrbU6n1egwETwkOUwWyUja/5t+C/RIZPuKP5XmsUhFecbCrML2+M7HG0l5leqyD3u5pS
yhyBz99QWZegoRJy05tciuQUCyPrp6zDzl5De3byq5WQ6Ke+uiRb2GFdDNDhLuMlE48aLWyjm4qh
31Q0/wAWJ1zwmrYxu4p/OhZemU7myuSF5tp35rzV3CPRN31d2UcZAwzMUgwKkCE3yT1o+lLskg/k
C7yZIZM0DuazwkaenExrncvPtF6KL7eccudcknNjhRjFD3Yx1nNXgbVRHvVaElm0YxLiLcl8l0Rn
pHM7WKwFyW1dvEDax3BGj9/cbKvpvcwR
</ds:X509Certificate></ds:X509Data></ds:KeyInfo></md:KeyDescriptor><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://dev-813354.oktapreview.com/app/gravitationaldev813354_teleportsaml_1/exkafftca6RqPVgyZ0h7/sso/saml"/><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://dev-813354.oktapreview.com/app/gravitationaldev813354_teleportsaml_1/exkafftca6RqPVgyZ0h7/sso/saml"/></md:IDPSSODescriptor></md:EntityDescriptor>`

const (
TLSCACertPEM = apifixtures.TLSCACertPEM
TLSCAKeyPEM = apifixtures.TLSCAKeyPEM
Expand Down
8 changes: 7 additions & 1 deletion lib/services/saml.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,13 @@ func CheckSAMLEntityDescriptor(entityDescriptor string) ([]*x509.Certificate, er

for _, kd := range metadata.IDPSSODescriptor.KeyDescriptors {
for _, samlCert := range kd.KeyInfo.X509Data.X509Certificates {
certData, err := base64.StdEncoding.DecodeString(strings.TrimSpace(samlCert.Data))
// The certificate is base64 encoded and can be split into multiple lines.
// Each line can be padded with spaces/tabs, so we need to remove them first
// before decoding otherwise we'll get an error.
// We need to run this through strings.Fields to remove spaces/tabs
// from each line and then join them back with newlines.
// The last step isn't strictly necessary, but it makes payload more readable.
certData, err := base64.StdEncoding.DecodeString(strings.Join(strings.Fields(samlCert.Data), "\n"))
if err != nil {
return nil, trace.Wrap(err, "failed to decode certificate defined in entity_descriptor")
}
Expand Down
29 changes: 17 additions & 12 deletions lib/services/saml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,25 @@ func TestParseFromMetadata(t *testing.T) {
func TestCheckSAMLEntityDescriptor(t *testing.T) {
t.Parallel()

input := fixtures.SAMLOktaConnectorV2

decoder := kyaml.NewYAMLOrJSONDecoder(strings.NewReader(input), defaults.LookaheadBufSize)
var raw UnknownResource
err := decoder.Decode(&raw)
require.NoError(t, err)
for name, input := range map[string]string{
"without certificate padding": fixtures.SAMLOktaConnectorV2,
"with certificate padding": fixtures.SAMLOktaConnectorV2WithPadding,
} {
t.Run(name, func(t *testing.T) {
decoder := kyaml.NewYAMLOrJSONDecoder(strings.NewReader(input), defaults.LookaheadBufSize)
var raw UnknownResource
err := decoder.Decode(&raw)
require.NoError(t, err)

oc, err := UnmarshalSAMLConnector(raw.Raw)
require.NoError(t, err)
oc, err := UnmarshalSAMLConnector(raw.Raw)
require.NoError(t, err)

ed := oc.GetEntityDescriptor()
certs, err := CheckSAMLEntityDescriptor(ed)
require.NoError(t, err)
require.Len(t, certs, 1)
ed := oc.GetEntityDescriptor()
certs, err := CheckSAMLEntityDescriptor(ed)
require.NoError(t, err)
require.Len(t, certs, 1)
})
}
}

func TestValidateRoles(t *testing.T) {
Expand Down