diff options
author | Daniel Schalla <daniel@schalla.me> | 2018-08-02 00:16:04 +0200 |
---|---|---|
committer | Christopher Speller <crspeller@gmail.com> | 2018-08-01 15:16:04 -0700 |
commit | 2936dc87d074e6d83147c9e6cf4ae8bac4e4af8d (patch) | |
tree | 2e843f8fdf8382b13fe0a902e7b6183f1f4475bd /app | |
parent | 90e84d76efa775cdf7c54363218bf6817cd1bf33 (diff) | |
download | chat-2936dc87d074e6d83147c9e6cf4ae8bac4e4af8d.tar.gz chat-2936dc87d074e6d83147c9e6cf4ae8bac4e4af8d.tar.bz2 chat-2936dc87d074e6d83147c9e6cf4ae8bac4e4af8d.zip |
CSRF Token Implementation for Plugins (#9192)
deleted test config
fix test config
Dont wipe the session token for plugins
Simplified Tokens; Generate CSRF for other sessions
Remove CSRF from Access Token; Remove Getter/Setter from Context
fix removed setter
remove getcsrf helper from plugin api
enforce csrf only for cookie auth
Diffstat (limited to 'app')
-rw-r--r-- | app/login.go | 2 | ||||
-rw-r--r-- | app/oauth.go | 1 | ||||
-rw-r--r-- | app/plugin_api.go | 10 | ||||
-rw-r--r-- | app/plugin_requests.go | 30 |
4 files changed, 39 insertions, 4 deletions
diff --git a/app/login.go b/app/login.go index 0d22f2635..4897ae171 100644 --- a/app/login.go +++ b/app/login.go @@ -126,7 +126,7 @@ func (a *App) GetUserForLogin(id, loginId string) (*model.User, *model.AppError) func (a *App) DoLogin(w http.ResponseWriter, r *http.Request, user *model.User, deviceId string) (*model.Session, *model.AppError) { session := &model.Session{UserId: user.Id, Roles: user.GetRawRoles(), DeviceId: deviceId, IsOAuth: false} - + session.GenerateCSRF() maxAge := *a.Config().ServiceSettings.SessionLengthWebInDays * 60 * 60 * 24 if len(deviceId) > 0 { diff --git a/app/oauth.go b/app/oauth.go index 60ea39255..a0123c0e9 100644 --- a/app/oauth.go +++ b/app/oauth.go @@ -334,6 +334,7 @@ func (a *App) GetOAuthAccessTokenForCodeFlow(clientId, grantType, redirectUri, c func (a *App) newSession(appName string, user *model.User) (*model.Session, *model.AppError) { // set new token an session session := &model.Session{UserId: user.Id, Roles: user.Roles, IsOAuth: true} + session.GenerateCSRF() session.SetExpireInDays(*a.Config().ServiceSettings.SessionLengthSSOInDays) session.AddProp(model.SESSION_PROP_PLATFORM, appName) session.AddProp(model.SESSION_PROP_OS, "OAuth2") diff --git a/app/plugin_api.go b/app/plugin_api.go index 66f17bdfb..31bfd401d 100644 --- a/app/plugin_api.go +++ b/app/plugin_api.go @@ -65,6 +65,16 @@ func (api *PluginAPI) UnregisterCommand(teamId, trigger string) error { return nil } +func (api *PluginAPI) GetSession(sessionId string) (*model.Session, *model.AppError) { + session, err := api.app.GetSessionById(sessionId) + + if err != nil { + return nil, err + } + + return session, nil +} + func (api *PluginAPI) GetConfig() *model.Config { return api.app.GetConfig() } diff --git a/app/plugin_requests.go b/app/plugin_requests.go index 2f9ac1476..ec6091017 100644 --- a/app/plugin_requests.go +++ b/app/plugin_requests.go @@ -8,11 +8,13 @@ import ( "path" "strings" + "bytes" "github.com/gorilla/mux" "github.com/mattermost/mattermost-server/mlog" "github.com/mattermost/mattermost-server/model" "github.com/mattermost/mattermost-server/plugin" "github.com/mattermost/mattermost-server/utils" + "io/ioutil" ) func (a *App) ServePluginRequest(w http.ResponseWriter, r *http.Request) { @@ -38,22 +40,44 @@ func (a *App) ServePluginRequest(w http.ResponseWriter, r *http.Request) { func (a *App) servePluginRequest(w http.ResponseWriter, r *http.Request, handler func(*plugin.Context, http.ResponseWriter, *http.Request)) { token := "" + context := &plugin.Context{} + cookieAuth := false authHeader := r.Header.Get(model.HEADER_AUTH) if strings.HasPrefix(strings.ToUpper(authHeader), model.HEADER_BEARER+" ") { token = authHeader[len(model.HEADER_BEARER)+1:] } else if strings.HasPrefix(strings.ToLower(authHeader), model.HEADER_TOKEN+" ") { token = authHeader[len(model.HEADER_TOKEN)+1:] - } else if cookie, _ := r.Cookie(model.SESSION_COOKIE_TOKEN); cookie != nil && (r.Method == "GET" || r.Header.Get(model.HEADER_REQUESTED_WITH) == model.HEADER_REQUESTED_WITH_XML) { + } else if cookie, _ := r.Cookie(model.SESSION_COOKIE_TOKEN); cookie != nil { token = cookie.Value + cookieAuth = true } else { token = r.URL.Query().Get("access_token") } r.Header.Del("Mattermost-User-Id") if token != "" { - if session, err := a.GetSession(token); session != nil && err == nil { + session, err := a.GetSession(token) + csrfCheckPassed := true + + if err == nil && cookieAuth && r.Method != "GET" && r.Header.Get(model.HEADER_REQUESTED_WITH) != model.HEADER_REQUESTED_WITH_XML { + bodyBytes, _ := ioutil.ReadAll(r.Body) + r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes)) + r.ParseForm() + sentToken := r.FormValue("csrf") + expectedToken := session.GetCSRF() + + if sentToken != expectedToken { + csrfCheckPassed = false + } + + // Set Request Body again, since otherwise form values aren't accessible in plugin handler + r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes)) + } + + if session != nil && err == nil && csrfCheckPassed { r.Header.Set("Mattermost-User-Id", session.UserId) + context.SessionId = session.Id } } @@ -76,5 +100,5 @@ func (a *App) servePluginRequest(w http.ResponseWriter, r *http.Request, handler r.URL.RawQuery = newQuery.Encode() r.URL.Path = strings.TrimPrefix(r.URL.Path, path.Join(subpath, "plugins", params["plugin_id"])) - handler(&plugin.Context{}, w, r) + handler(context, w, r) } |