From 5f04dc4f45b9657d46380499f92ae6e5c1bf5506 Mon Sep 17 00:00:00 2001 From: enahum Date: Tue, 5 Jul 2016 15:49:00 -0400 Subject: SAML support (#3494) * PLT-3073: Implement SAML/Okta Server side (EE) (#3422) * PLT-3137 Support for SAML configuration * PLT-3410 SAML Database Store * PLT-3411 CLI to add Identity Provider Certificate and Service Provider Private Key * PLT-3409 SAML Interface for EE * PLT-3139 Handle SAML authentication server side * Add localization messages * PLT-3443 SAML Obtain SP metadata * PLT-3142 Login & Switch to/from SAML * Remove Certs for Database & Clean SAML Request * Make required Username, FirstName and LastName * PLT-3140 Add SAML to System Console (#3476) * PLT-3140 Add SAML to System Console * Move web_client functions to client.jsx * Fix issues found by PM * update package.json mattermost driver * Fix text messages for SAML --- model/config.go | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ model/license.go | 6 +++ model/saml.go | 18 +++++++ 3 files changed, 180 insertions(+) create mode 100644 model/saml.go (limited to 'model') diff --git a/model/config.go b/model/config.go index a8c63b1eb..32994a279 100644 --- a/model/config.go +++ b/model/config.go @@ -227,6 +227,31 @@ type LocalizationSettings struct { AvailableLocales *string } +type SamlSettings struct { + // Basic + Enable *bool + Verify *bool + Encrypt *bool + + IdpUrl *string + IdpDescriptorUrl *string + AssertionConsumerServiceURL *string + + IdpCertificateFile *string + PublicCertificateFile *string + PrivateKeyFile *string + + // User Mapping + FirstNameAttribute *string + LastNameAttribute *string + EmailAttribute *string + UsernameAttribute *string + NicknameAttribute *string + LocaleAttribute *string + + LoginButtonText *string +} + type Config struct { ServiceSettings ServiceSettings TeamSettings TeamSettings @@ -242,6 +267,7 @@ type Config struct { LdapSettings LdapSettings ComplianceSettings ComplianceSettings LocalizationSettings LocalizationSettings + SamlSettings SamlSettings } func (o *Config) ToJson() string { @@ -627,6 +653,86 @@ func (o *Config) SetDefaults() { o.LocalizationSettings.AvailableLocales = new(string) *o.LocalizationSettings.AvailableLocales = "" } + + if o.SamlSettings.Enable == nil { + o.SamlSettings.Enable = new(bool) + *o.SamlSettings.Enable = false + } + + if o.SamlSettings.Verify == nil { + o.SamlSettings.Verify = new(bool) + *o.SamlSettings.Verify = false + } + + if o.SamlSettings.Encrypt == nil { + o.SamlSettings.Encrypt = new(bool) + *o.SamlSettings.Encrypt = false + } + + if o.SamlSettings.IdpUrl == nil { + o.SamlSettings.IdpUrl = new(string) + *o.SamlSettings.IdpUrl = "" + } + + if o.SamlSettings.IdpDescriptorUrl == nil { + o.SamlSettings.IdpDescriptorUrl = new(string) + *o.SamlSettings.IdpDescriptorUrl = "" + } + + if o.SamlSettings.IdpCertificateFile == nil { + o.SamlSettings.IdpCertificateFile = new(string) + *o.SamlSettings.IdpCertificateFile = "" + } + + if o.SamlSettings.PublicCertificateFile == nil { + o.SamlSettings.PublicCertificateFile = new(string) + *o.SamlSettings.PublicCertificateFile = "" + } + + if o.SamlSettings.PrivateKeyFile == nil { + o.SamlSettings.PrivateKeyFile = new(string) + *o.SamlSettings.PrivateKeyFile = "" + } + + if o.SamlSettings.AssertionConsumerServiceURL == nil { + o.SamlSettings.AssertionConsumerServiceURL = new(string) + *o.SamlSettings.AssertionConsumerServiceURL = "" + } + + if o.SamlSettings.LoginButtonText == nil || *o.SamlSettings.LoginButtonText == "" { + o.SamlSettings.LoginButtonText = new(string) + *o.SamlSettings.LoginButtonText = USER_AUTH_SERVICE_SAML_TEXT + } + + if o.SamlSettings.FirstNameAttribute == nil { + o.SamlSettings.FirstNameAttribute = new(string) + *o.SamlSettings.FirstNameAttribute = "" + } + + if o.SamlSettings.LastNameAttribute == nil { + o.SamlSettings.LastNameAttribute = new(string) + *o.SamlSettings.LastNameAttribute = "" + } + + if o.SamlSettings.EmailAttribute == nil { + o.SamlSettings.EmailAttribute = new(string) + *o.SamlSettings.EmailAttribute = "" + } + + if o.SamlSettings.UsernameAttribute == nil { + o.SamlSettings.UsernameAttribute = new(string) + *o.SamlSettings.UsernameAttribute = "" + } + + if o.SamlSettings.NicknameAttribute == nil { + o.SamlSettings.NicknameAttribute = new(string) + *o.SamlSettings.NicknameAttribute = "" + } + + if o.SamlSettings.LocaleAttribute == nil { + o.SamlSettings.LocaleAttribute = new(string) + *o.SamlSettings.LocaleAttribute = "" + } } func (o *Config) IsValid() *AppError { @@ -749,6 +855,56 @@ func (o *Config) IsValid() *AppError { } } + if *o.SamlSettings.Enable { + if len(*o.SamlSettings.IdpUrl) == 0 { + return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_idp_url.app_error", nil, "") + } + + if len(*o.SamlSettings.IdpDescriptorUrl) == 0 || !IsValidHttpUrl(*o.SamlSettings.IdpDescriptorUrl) { + return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_idp_descriptor_url.app_error", nil, "") + } + + if len(*o.SamlSettings.IdpCertificateFile) == 0 { + return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_idp_cert.app_error", nil, "") + } + + if len(*o.SamlSettings.EmailAttribute) == 0 { + return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_email_attribute.app_error", nil, "") + } + + if len(*o.SamlSettings.UsernameAttribute) == 0 { + return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_username_attribute.app_error", nil, "") + } + + if len(*o.SamlSettings.FirstNameAttribute) == 0 { + return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_first_name_attribute.app_error", nil, "") + } + + if len(*o.SamlSettings.LastNameAttribute) == 0 { + return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_last_name_attribute.app_error", nil, "") + } + + if *o.SamlSettings.Verify { + if len(*o.SamlSettings.AssertionConsumerServiceURL) == 0 || !IsValidHttpUrl(*o.SamlSettings.AssertionConsumerServiceURL) { + return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_assertion_consumer_service_url.app_error", nil, "") + } + } + + if *o.SamlSettings.Encrypt { + if len(*o.SamlSettings.PrivateKeyFile) == 0 { + return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_private_key.app_error", nil, "") + } + + if len(*o.SamlSettings.PublicCertificateFile) == 0 { + return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_public_cert.app_error", nil, "") + } + } + + if len(*o.SamlSettings.EmailAttribute) == 0 { + return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_email_attribute.app_error", nil, "") + } + } + return nil } diff --git a/model/license.go b/model/license.go index bc72ff9ad..9781e3bf0 100644 --- a/model/license.go +++ b/model/license.go @@ -39,6 +39,7 @@ type Features struct { Compliance *bool `json:"compliance"` CustomBrand *bool `json:"custom_brand"` MHPNS *bool `json:"mhpns"` + SAML *bool `json:"saml"` FutureFeatures *bool `json:"future_features"` } @@ -82,6 +83,11 @@ func (f *Features) SetDefaults() { f.MHPNS = new(bool) *f.MHPNS = *f.FutureFeatures } + + if f.SAML == nil { + f.SAML = new(bool) + *f.SAML = *f.FutureFeatures + } } func (l *License) IsExpired() bool { diff --git a/model/saml.go b/model/saml.go new file mode 100644 index 000000000..16d3845da --- /dev/null +++ b/model/saml.go @@ -0,0 +1,18 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +const ( + USER_AUTH_SERVICE_SAML = "saml" + USER_AUTH_SERVICE_SAML_TEXT = "With SAML" + SAML_IDP_CERTIFICATE = 1 + SAML_PRIVATE_KEY = 2 + SAML_PUBLIC_CERT = 3 +) + +type SamlAuthRequest struct { + Base64AuthRequest string + URL string + RelayState string +} -- cgit v1.2.3-1-g7c22