diff options
author | Christopher Speller <crspeller@gmail.com> | 2015-08-18 08:47:35 -0400 |
---|---|---|
committer | Christopher Speller <crspeller@gmail.com> | 2015-08-18 08:47:35 -0400 |
commit | 2f1dcf6f5267ecf85d14c8a36a9d3059a5d41218 (patch) | |
tree | 1de5578c9050a33635960fc046fdf97339254be0 /api/user.go | |
parent | 96d1eb1c800a427e31e63970e57d0824a3bc91e3 (diff) | |
parent | a7f09be9783f3354ab38d4fb4fb82085241d018f (diff) | |
download | chat-2f1dcf6f5267ecf85d14c8a36a9d3059a5d41218.tar.gz chat-2f1dcf6f5267ecf85d14c8a36a9d3059a5d41218.tar.bz2 chat-2f1dcf6f5267ecf85d14c8a36a9d3059a5d41218.zip |
Merge pull request #381 from mattermost/mm-1705
MM-1705 add google as an oauth single-sign-on service
Diffstat (limited to 'api/user.go')
-rw-r--r-- | api/user.go | 59 |
1 files changed, 46 insertions, 13 deletions
diff --git a/api/user.go b/api/user.go index a42f81cf1..303ec2b0a 100644 --- a/api/user.go +++ b/api/user.go @@ -7,6 +7,7 @@ import ( "bytes" "code.google.com/p/freetype-go/freetype" l4g "code.google.com/p/log4go" + b64 "encoding/base64" "fmt" "github.com/gorilla/mux" "github.com/mattermost/platform/model" @@ -1304,7 +1305,7 @@ func getStatuses(c *Context, w http.ResponseWriter, r *http.Request) { } } -func GetAuthorizationCode(c *Context, w http.ResponseWriter, r *http.Request, teamName, service, redirectUri string) { +func GetAuthorizationCode(c *Context, w http.ResponseWriter, r *http.Request, teamName, service, redirectUri, loginHint string) { if s, ok := utils.Cfg.SSOSettings[service]; !ok || !s.Allow { c.Err = model.NewAppError("GetAuthorizationCode", "Unsupported OAuth service provider", "service="+service) @@ -1314,21 +1315,49 @@ func GetAuthorizationCode(c *Context, w http.ResponseWriter, r *http.Request, te clientId := utils.Cfg.SSOSettings[service].Id endpoint := utils.Cfg.SSOSettings[service].AuthEndpoint - state := model.HashPassword(clientId) + scope := utils.Cfg.SSOSettings[service].Scope + + stateProps := map[string]string{"team": teamName, "hash": model.HashPassword(clientId)} + state := b64.StdEncoding.EncodeToString([]byte(model.MapToJson(stateProps))) + + authUrl := endpoint + "?response_type=code&client_id=" + clientId + "&redirect_uri=" + url.QueryEscape(redirectUri) + "&state=" + url.QueryEscape(state) + + if len(scope) > 0 { + authUrl += "&scope=" + utils.UrlEncode(scope) + } + + if len(loginHint) > 0 { + authUrl += "&login_hint=" + utils.UrlEncode(loginHint) + } - authUrl := endpoint + "?response_type=code&client_id=" + clientId + "&redirect_uri=" + url.QueryEscape(redirectUri+"?team="+teamName) + "&state=" + url.QueryEscape(state) http.Redirect(w, r, authUrl, http.StatusFound) } -func AuthorizeOAuthUser(service, code, state, redirectUri string) (io.ReadCloser, *model.AppError) { +func AuthorizeOAuthUser(service, code, state, redirectUri string) (io.ReadCloser, *model.Team, *model.AppError) { if s, ok := utils.Cfg.SSOSettings[service]; !ok || !s.Allow { - return nil, model.NewAppError("AuthorizeOAuthUser", "Unsupported OAuth service provider", "service="+service) + return nil, nil, model.NewAppError("AuthorizeOAuthUser", "Unsupported OAuth service provider", "service="+service) } - if !model.ComparePassword(state, utils.Cfg.SSOSettings[service].Id) { - return nil, model.NewAppError("AuthorizeOAuthUser", "Invalid state", "") + stateStr := "" + if b, err := b64.StdEncoding.DecodeString(state); err != nil { + return nil, nil, model.NewAppError("AuthorizeOAuthUser", "Invalid state", err.Error()) + } else { + stateStr = string(b) } + stateProps := model.MapFromJson(strings.NewReader(stateStr)) + + if !model.ComparePassword(stateProps["hash"], utils.Cfg.SSOSettings[service].Id) { + return nil, nil, model.NewAppError("AuthorizeOAuthUser", "Invalid state", "") + } + + teamName := stateProps["team"] + if len(teamName) == 0 { + return nil, nil, model.NewAppError("AuthorizeOAuthUser", "Invalid state; missing team name", "") + } + + tchan := Srv.Store.Team().GetByName(teamName) + p := url.Values{} p.Set("client_id", utils.Cfg.SSOSettings[service].Id) p.Set("client_secret", utils.Cfg.SSOSettings[service].Secret) @@ -1344,17 +1373,17 @@ func AuthorizeOAuthUser(service, code, state, redirectUri string) (io.ReadCloser var ar *model.AccessResponse if resp, err := client.Do(req); err != nil { - return nil, model.NewAppError("AuthorizeOAuthUser", "Token request failed", err.Error()) + return nil, nil, model.NewAppError("AuthorizeOAuthUser", "Token request failed", err.Error()) } else { ar = model.AccessResponseFromJson(resp.Body) } - if ar.TokenType != model.ACCESS_TOKEN_TYPE { - return nil, model.NewAppError("AuthorizeOAuthUser", "Bad token type", "token_type="+ar.TokenType) + if strings.ToLower(ar.TokenType) != model.ACCESS_TOKEN_TYPE { + return nil, nil, model.NewAppError("AuthorizeOAuthUser", "Bad token type", "token_type="+ar.TokenType) } if len(ar.AccessToken) == 0 { - return nil, model.NewAppError("AuthorizeOAuthUser", "Missing access token", "") + return nil, nil, model.NewAppError("AuthorizeOAuthUser", "Missing access token", "") } p = url.Values{} @@ -1366,9 +1395,13 @@ func AuthorizeOAuthUser(service, code, state, redirectUri string) (io.ReadCloser req.Header.Set("Authorization", "Bearer "+ar.AccessToken) if resp, err := client.Do(req); err != nil { - return nil, model.NewAppError("AuthorizeOAuthUser", "Token request to "+service+" failed", err.Error()) + return nil, nil, model.NewAppError("AuthorizeOAuthUser", "Token request to "+service+" failed", err.Error()) } else { - return resp.Body, nil + if result := <-tchan; result.Err != nil { + return nil, nil, result.Err + } else { + return resp.Body, result.Data.(*model.Team), nil + } } } |