Files
mattermost/web/saml.go
Chris Duarte 3fcecd521a 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
2018-07-18 14:56:38 -07:00

166 lines
4.3 KiB
Go

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package web
import (
b64 "encoding/base64"
"net/http"
"strings"
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"
)
func (w *Web) InitSaml() {
w.MainRouter.Handle("/login/sso/saml", w.NewHandler(loginWithSaml)).Methods("GET")
w.MainRouter.Handle("/login/sso/saml", w.NewHandler(completeSaml)).Methods("POST")
}
func loginWithSaml(c *Context, w http.ResponseWriter, r *http.Request) {
samlInterface := c.App.Saml
if samlInterface == nil {
c.Err = model.NewAppError("loginWithSaml", "api.user.saml.not_available.app_error", nil, "", http.StatusFound)
return
}
teamId, err := c.App.GetTeamIdFromQuery(r.URL.Query())
if err != nil {
c.Err = err
return
}
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 := ""
if len(action) != 0 {
relayProps["team_id"] = teamId
relayProps["action"] = action
if action == model.OAUTH_ACTION_EMAIL_TO_SSO {
relayProps["email"] = r.URL.Query().Get("email")
}
}
if len(redirectTo) != 0 {
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)))
}
if data, err := samlInterface.BuildRequest(relayState); err != nil {
c.Err = err
return
} else {
w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
http.Redirect(w, r, data.URL, http.StatusFound)
}
}
func completeSaml(c *Context, w http.ResponseWriter, r *http.Request) {
samlInterface := c.App.Saml
if samlInterface == nil {
c.Err = model.NewAppError("completeSaml", "api.user.saml.not_available.app_error", nil, "", http.StatusFound)
return
}
//Validate that the user is with SAML and all that
encodedXML := r.FormValue("SAMLResponse")
relayState := r.FormValue("RelayState")
relayProps := make(map[string]string)
if len(relayState) > 0 {
stateStr := ""
if b, err := b64.StdEncoding.DecodeString(relayState); err != nil {
c.Err = model.NewAppError("completeSaml", "api.user.authorize_oauth_user.invalid_state.app_error", nil, err.Error(), http.StatusFound)
return
} else {
stateStr = string(b)
}
relayProps = model.MapFromJson(strings.NewReader(stateStr))
}
action := relayProps["action"]
if user, err := samlInterface.DoLogin(encodedXML, relayProps); err != nil {
if action == model.OAUTH_ACTION_MOBILE {
err.Translate(c.T)
w.Write([]byte(err.ToJson()))
} else {
c.Err = err
c.Err.StatusCode = http.StatusFound
}
return
} else {
if err := c.App.CheckUserAllAuthenticationCriteria(user, ""); err != nil {
c.Err = err
c.Err.StatusCode = http.StatusFound
return
}
switch action {
case model.OAUTH_ACTION_SIGNUP:
teamId := relayProps["team_id"]
if len(teamId) > 0 {
c.App.Go(func() {
if err := c.App.AddUserToTeamByTeamId(teamId, user); err != nil {
mlog.Error(err.Error())
} else {
c.App.AddDirectChannels(teamId, user)
}
})
}
case model.OAUTH_ACTION_EMAIL_TO_SSO:
if err := c.App.RevokeAllSessions(user.Id); err != nil {
c.Err = err
return
}
c.LogAuditWithUserId(user.Id, "Revoked all sessions for user")
c.App.Go(func() {
if err := c.App.SendSignInChangeEmail(user.Email, strings.Title(model.USER_AUTH_SERVICE_SAML)+" SSO", user.Locale, c.App.GetSiteURL()); err != nil {
mlog.Error(err.Error())
}
})
}
session, err := c.App.DoLogin(w, r, user, "")
if err != nil {
c.Err = err
return
}
c.Session = *session
if val, ok := relayProps["redirect_to"]; ok {
http.Redirect(w, r, c.GetSiteURLHeader()+val, http.StatusFound)
return
}
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)
}
}
}