diff options
author | Joram Wilander <jwawilander@gmail.com> | 2018-05-14 11:27:30 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-05-14 11:27:30 -0400 |
commit | 6a9aa855d1c862e4d39f8c00c6b7425405e7a612 (patch) | |
tree | 16f6326241b878a51e286c7bf70078b628b1f03d /web | |
parent | 47250c6629416b628a19e5571ac89f7b4646418c (diff) | |
download | chat-6a9aa855d1c862e4d39f8c00c6b7425405e7a612.tar.gz chat-6a9aa855d1c862e4d39f8c00c6b7425405e7a612.tar.bz2 chat-6a9aa855d1c862e4d39f8c00c6b7425405e7a612.zip |
Move SAML endpoints out of api package (#8780)
Diffstat (limited to 'web')
-rw-r--r-- | web/saml.go | 149 | ||||
-rw-r--r-- | web/web.go | 7 |
2 files changed, 156 insertions, 0 deletions
diff --git a/web/saml.go b/web/saml.go new file mode 100644 index 000000000..f3e5a12e8 --- /dev/null +++ b/web/saml.go @@ -0,0 +1,149 @@ +// 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/app" + "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") + 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(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 { + http.Redirect(w, r, app.GetProtocol(r)+"://"+r.Host, http.StatusFound) + } + } +} diff --git a/web/web.go b/web/web.go index 94363cfde..53276953e 100644 --- a/web/web.go +++ b/web/web.go @@ -32,6 +32,7 @@ func NewWeb(a *app.App, root *mux.Router) *Web { web.InitStatic() web.InitWebhooks() + web.InitSaml() return web } @@ -71,3 +72,9 @@ func Handle404(a *app.App, w http.ResponseWriter, r *http.Request) { func IsApiCall(r *http.Request) bool { return strings.Index(r.URL.Path, "/api/") == 0 } + +func ReturnStatusOK(w http.ResponseWriter) { + m := make(map[string]string) + m[model.STATUS] = model.STATUS_OK + w.Write([]byte(model.MapToJson(m))) +} |