Support for Embeded chat (#9129)

* Add ucLive support

crazy testing

lovely logs

more cookie work arounds

Added Access-Control-Expose-Headers to user login

Add complete_saml_body template and revert loginWithSaml endpoint

Set Access-Control-Allow-Credentials to true in user login

Login via email instead of username

Clean up code

Add comment to give some context

Move faml logic into saml function

Communicate via chrome sendMessage api

Remove unused code

Add config to support multiple extensions

Clean up embedded complete_saml template

Fix indentation for templates

Added license header to extension.go

Add EnableExperimentalExtensions flag

Extension validated for email auth

Clean up api auth code

Remove complete_saml_body.html

* Add extension support in saml

* Clean up code

* Clean up extension validation
This commit is contained in:
Chris Duarte
2018-07-18 14:56:38 -07:00
committed by Christopher Speller
parent 6b27b74f0c
commit 3fcecd521a
7 changed files with 167 additions and 0 deletions

82
app/extension.go Normal file
View File

@@ -0,0 +1,82 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package app
import (
"github.com/mattermost/mattermost-server/model"
"html/template"
"net/http"
)
func (a *App) isExtensionSupportEnabled() bool {
return *a.Config().ExtensionSettings.EnableExperimentalExtensions
}
func (a *App) isExtensionValid(extensionId string) bool {
extensionIsValid := false
extensionIDs := a.Config().ExtensionSettings.AllowedExtensionsIDs
for _, id := range extensionIDs {
if extensionId == id {
extensionIsValid = true
}
}
return extensionIsValid
}
func (a *App) ValidateExtension(extensionId string) *model.AppError {
enabled := a.isExtensionSupportEnabled()
if !enabled {
return model.NewAppError("completeSaml", "api.user.saml.extension_unsupported", nil, "", http.StatusInternalServerError)
}
valid := a.isExtensionValid(extensionId)
if !valid {
params := map[string]interface{}{"ExtensionId": extensionId}
return model.NewAppError("completeSaml", "api.user.saml.invalid_extension", params, "", http.StatusInternalServerError)
}
return nil
}
func (a *App) SendMessageToExtension(w http.ResponseWriter, extensionId string, token string) *model.AppError {
var err error
var t *template.Template
if len(extensionId) == 0 {
return model.NewAppError("completeSaml", "api.user.saml.extension_id.app_error", nil, "", http.StatusInternalServerError)
}
t = template.New("complete_saml_extension_body")
t, err = t.ParseFiles("templates/complete_saml_extension_body.html")
if err != nil {
return model.NewAppError("completeSaml", "api.user.saml.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
}
w.Header().Set("Content-Type", "text/html")
w.WriteHeader(http.StatusOK)
var errMessage string
if len(token) == 0 {
loginError := model.NewAppError("completeSaml", "api.user.saml.app_error", nil, "", http.StatusInternalServerError)
errMessage = loginError.Message
}
data := struct {
ExtensionId string
Token string
Error string
}{
extensionId,
token,
errMessage,
}
if err := t.Execute(w, data); err != nil {
return model.NewAppError("completeSaml", "api.user.saml.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
}
return nil
}

View File

@@ -194,6 +194,10 @@
"LoginButtonBorderColor": "",
"LoginButtonTextColor": ""
},
"ExtensionSettings": {
"EnableExperimentalExtensions": false,
"AllowedExtensionsIDs": []
},
"RateLimitSettings": {
"Enable": false,
"PerSec": 10,

View File

@@ -2166,6 +2166,22 @@
"id": "api.user.send_deactivate_email_and_forget.failed.error",
"translation": "Failed to send the deactivate account email successfully"
},
{
"id": "api.user.saml.app_error",
"translation": "Unable to process SAML login request."
},
{
"id": "api.user.saml.extension_unsupported",
"translation": "Extensions are not supported."
},
{
"id": "api.user.saml.extension_id.app_error",
"translation": "Invalid extension id"
},
{
"id": "api.user.saml.invalid_extension",
"translation": "Extension with extension_id={{.ExtensionId}} is not supported."
},
{
"id": "api.user.send_email_change_email_and_forget.error",
"translation": "Failed to send email change notification email successfully"

View File

@@ -907,6 +907,21 @@ func (s *EmailSettings) SetDefaults() {
}
}
type ExtensionSettings struct {
EnableExperimentalExtensions *bool
AllowedExtensionsIDs []string
}
func (s *ExtensionSettings) SetDefaults() {
if s.EnableExperimentalExtensions == nil {
s.EnableExperimentalExtensions = NewBool(false)
}
if s.AllowedExtensionsIDs == nil {
s.AllowedExtensionsIDs = []string{}
}
}
type RateLimitSettings struct {
Enable *bool
PerSec *int
@@ -1870,6 +1885,7 @@ type Config struct {
PasswordSettings PasswordSettings
FileSettings FileSettings
EmailSettings EmailSettings
ExtensionSettings ExtensionSettings
RateLimitSettings RateLimitSettings
PrivacySettings PrivacySettings
SupportSettings SupportSettings
@@ -1967,6 +1983,7 @@ func (o *Config) SetDefaults() {
o.MessageExportSettings.SetDefaults()
o.TimezoneSettings.SetDefaults()
o.DisplaySettings.SetDefaults()
o.ExtensionSettings.SetDefaults()
}
func (o *Config) IsValid() *AppError {

View File

@@ -17,6 +17,7 @@ const (
OAUTH_ACTION_EMAIL_TO_SSO = "email_to_sso"
OAUTH_ACTION_SSO_TO_EMAIL = "sso_to_email"
OAUTH_ACTION_MOBILE = "mobile"
OAUTH_ACTION_CLIENT = "client"
)
type OAuthApp struct {

View File

@@ -0,0 +1,30 @@
{{define "complete_saml_extension_body"}}
<html>
<head>
<script>
document.addEventListener("DOMContentLoaded", function(event) {
var extensionId = {{.ExtensionId}};
if (!extensionId) {
return;
}
chrome.runtime.sendMessage(
extensionId,
{
value: {{.Token}},
error: {{.Error}}
},
function(response) {
}
);
});
</script>
</head>
<body>
Login Successful
</body>
</html>
{{end}}

View File

@@ -32,6 +32,7 @@ func loginWithSaml(c *Context, w http.ResponseWriter, r *http.Request) {
}
action := r.URL.Query().Get("action")
redirectTo := r.URL.Query().Get("redirect_to")
extensionId := r.URL.Query().Get("extension_id")
relayProps := map[string]string{}
relayState := ""
@@ -47,6 +48,15 @@ func loginWithSaml(c *Context, w http.ResponseWriter, r *http.Request) {
relayProps["redirect_to"] = redirectTo
}
if len(extensionId) != 0 {
relayProps["extension_id"] = extensionId
err := c.App.ValidateExtension(extensionId)
if err != nil {
c.Err = err
return
}
}
if len(relayProps) > 0 {
relayState = b64.StdEncoding.EncodeToString([]byte(model.MapToJson(relayProps)))
}
@@ -141,6 +151,13 @@ func completeSaml(c *Context, w http.ResponseWriter, r *http.Request) {
if action == model.OAUTH_ACTION_MOBILE {
ReturnStatusOK(w)
} else if action == model.OAUTH_ACTION_CLIENT {
err = c.App.SendMessageToExtension(w, relayProps["extension_id"], c.Session.Token)
if err != nil {
c.Err = err
return
}
} else {
http.Redirect(w, r, c.GetSiteURLHeader(), http.StatusFound)
}