summaryrefslogtreecommitdiffstats
path: root/api
diff options
context:
space:
mode:
authorJoram Wilander <jwawilander@gmail.com>2017-04-20 09:55:02 -0400
committerGitHub <noreply@github.com>2017-04-20 09:55:02 -0400
commitbe9624e2adce7c95039e62fc4ee22538d7fa2d2f (patch)
tree318179b4d3a4cb5114f887797a5a4c836e5255d7 /api
parent1a0f8d1b3c7451eac43bfdc5971de060caabf441 (diff)
downloadchat-be9624e2adce7c95039e62fc4ee22538d7fa2d2f.tar.gz
chat-be9624e2adce7c95039e62fc4ee22538d7fa2d2f.tar.bz2
chat-be9624e2adce7c95039e62fc4ee22538d7fa2d2f.zip
Implement v4 endpoints for OAuth (#6040)
* Implement POST /oauth/apps endpoint for APIv4 * Implement GET /oauth/apps endpoint for APIv4 * Implement GET /oauth/apps/{app_id} and /oauth/apps/{app_id}/info endpoints for APIv4 * Refactor API version independent oauth endpoints * Implement DELETE /oauth/apps/{app_id} endpoint for APIv4 * Implement /oauth/apps/{app_id}/regen_secret endpoint for APIv4 * Implement GET /user/{user_id}/oauth/apps/authorized endpoint for APIv4 * Implement POST /oauth/deauthorize endpoint
Diffstat (limited to 'api')
-rw-r--r--api/apitestlib.go1
-rw-r--r--api/context.go29
-rw-r--r--api/oauth.go182
-rw-r--r--api/oauth_test.go1
4 files changed, 12 insertions, 201 deletions
diff --git a/api/apitestlib.go b/api/apitestlib.go
index af14ac431..e857a5080 100644
--- a/api/apitestlib.go
+++ b/api/apitestlib.go
@@ -75,6 +75,7 @@ func Setup() *TestHelper {
InitRouter()
wsapi.InitRouter()
app.StartServer()
+ api4.InitApi(false)
InitApi()
wsapi.InitApi()
utils.EnableDebugLogForTest()
diff --git a/api/context.go b/api/context.go
index 21bbb1e37..282b45c86 100644
--- a/api/context.go
+++ b/api/context.go
@@ -242,7 +242,7 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if c.Err.StatusCode == http.StatusUnauthorized {
http.Redirect(w, r, c.GetTeamURL()+"/?redirect="+url.QueryEscape(r.URL.Path), http.StatusTemporaryRedirect)
} else {
- RenderWebError(c.Err, w, r)
+ utils.RenderWebError(c.Err, w, r)
}
}
@@ -421,31 +421,6 @@ func IsApiCall(r *http.Request) bool {
return strings.Index(r.URL.Path, "/api/") == 0
}
-func RenderWebError(err *model.AppError, w http.ResponseWriter, r *http.Request) {
- T, _ := utils.GetTranslationsAndLocale(w, r)
-
- title := T("api.templates.error.title", map[string]interface{}{"SiteName": utils.ClientCfg["SiteName"]})
- message := err.Message
- details := err.DetailedError
- link := "/"
- linkMessage := T("api.templates.error.link")
-
- status := http.StatusTemporaryRedirect
- if err.StatusCode != http.StatusInternalServerError {
- status = err.StatusCode
- }
-
- http.Redirect(
- w,
- r,
- "/error?title="+url.QueryEscape(title)+
- "&message="+url.QueryEscape(message)+
- "&details="+url.QueryEscape(details)+
- "&link="+url.QueryEscape(link)+
- "&linkmessage="+url.QueryEscape(linkMessage),
- status)
-}
-
func Handle404(w http.ResponseWriter, r *http.Request) {
err := model.NewLocAppError("Handle404", "api.context.404.app_error", nil, "")
err.Translate(utils.T)
@@ -458,7 +433,7 @@ func Handle404(w http.ResponseWriter, r *http.Request) {
err.DetailedError = "There doesn't appear to be an api call for the url='" + r.URL.Path + "'. Typo? are you missing a team_id or user_id as part of the url?"
w.Write([]byte(err.ToJson()))
} else {
- RenderWebError(err, w, r)
+ utils.RenderWebError(err, w, r)
}
}
diff --git a/api/oauth.go b/api/oauth.go
index fa076c56e..6ff04d644 100644
--- a/api/oauth.go
+++ b/api/oauth.go
@@ -5,8 +5,6 @@ package api
import (
"net/http"
- "net/url"
- "strings"
l4g "github.com/alecthomas/log4go"
"github.com/gorilla/mux"
@@ -26,17 +24,8 @@ func InitOAuth() {
BaseRoutes.OAuth.Handle("/delete", ApiUserRequired(deleteOAuthApp)).Methods("POST")
BaseRoutes.OAuth.Handle("/{id:[A-Za-z0-9]+}/deauthorize", ApiUserRequired(deauthorizeOAuthApp)).Methods("POST")
BaseRoutes.OAuth.Handle("/{id:[A-Za-z0-9]+}/regen_secret", ApiUserRequired(regenerateOAuthSecret)).Methods("POST")
- BaseRoutes.OAuth.Handle("/{service:[A-Za-z0-9]+}/complete", AppHandlerIndependent(completeOAuth)).Methods("GET")
BaseRoutes.OAuth.Handle("/{service:[A-Za-z0-9]+}/login", AppHandlerIndependent(loginWithOAuth)).Methods("GET")
BaseRoutes.OAuth.Handle("/{service:[A-Za-z0-9]+}/signup", AppHandlerIndependent(signupWithOAuth)).Methods("GET")
-
- BaseRoutes.Root.Handle("/oauth/authorize", AppHandlerTrustRequester(authorizeOAuth)).Methods("GET")
- BaseRoutes.Root.Handle("/oauth/access_token", ApiAppHandlerTrustRequester(getAccessToken)).Methods("POST")
-
- // Handle all the old routes, to be later removed
- BaseRoutes.Root.Handle("/{service:[A-Za-z0-9]+}/complete", AppHandlerIndependent(completeOAuth)).Methods("GET")
- BaseRoutes.Root.Handle("/signup/{service:[A-Za-z0-9]+}/complete", AppHandlerIndependent(completeOAuth)).Methods("GET")
- BaseRoutes.Root.Handle("/login/{service:[A-Za-z0-9]+}/complete", AppHandlerIndependent(completeOAuth)).Methods("GET")
}
func registerOAuthApp(c *Context, w http.ResponseWriter, r *http.Request) {
@@ -126,7 +115,15 @@ func allowOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
c.LogAudit("attempt")
- redirectUrl, err := app.AllowOAuthAppAccessToUser(c.Session.UserId, responseType, clientId, redirectUri, scope, state)
+ authRequest := &model.AuthorizeRequest{
+ ResponseType: responseType,
+ ClientId: clientId,
+ RedirectUri: redirectUri,
+ Scope: scope,
+ State: state,
+ }
+
+ redirectUrl, err := app.AllowOAuthAppAccessToUser(c.Session.UserId, authRequest)
if err != nil {
c.Err = err
@@ -148,167 +145,6 @@ func getAuthorizedApps(c *Context, w http.ResponseWriter, r *http.Request) {
w.Write([]byte(model.OAuthAppListToJson(apps)))
}
-func completeOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- service := params["service"]
-
- code := r.URL.Query().Get("code")
- if len(code) == 0 {
- c.Err = model.NewLocAppError("completeOAuth", "api.oauth.complete_oauth.missing_code.app_error", map[string]interface{}{"service": strings.Title(service)}, "URL: "+r.URL.String())
- return
- }
-
- state := r.URL.Query().Get("state")
-
- uri := c.GetSiteURLHeader() + "/signup/" + service + "/complete"
-
- body, teamId, props, err := app.AuthorizeOAuthUser(service, code, state, uri)
- if err != nil {
- c.Err = err
- return
- }
-
- user, err := app.CompleteOAuth(service, body, teamId, props)
- if err != nil {
- c.Err = err
- return
- }
-
- action := props["action"]
-
- var redirectUrl string
- if action == model.OAUTH_ACTION_EMAIL_TO_SSO {
- redirectUrl = c.GetSiteURLHeader() + "/login?extra=signin_change"
- } else if action == model.OAUTH_ACTION_SSO_TO_EMAIL {
-
- redirectUrl = app.GetProtocol(r) + "://" + r.Host + "/claim?email=" + url.QueryEscape(props["email"])
- } else {
- doLogin(c, w, r, user, "")
- if c.Err != nil {
- return
- }
-
- redirectUrl = c.GetSiteURLHeader()
- }
-
- http.Redirect(w, r, redirectUrl, http.StatusTemporaryRedirect)
-}
-
-func authorizeOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
- if !utils.Cfg.ServiceSettings.EnableOAuthServiceProvider {
- c.Err = model.NewLocAppError("authorizeOAuth", "api.oauth.authorize_oauth.disabled.app_error", nil, "")
- c.Err.StatusCode = http.StatusNotImplemented
- return
- }
-
- responseType := r.URL.Query().Get("response_type")
- clientId := r.URL.Query().Get("client_id")
- redirect := r.URL.Query().Get("redirect_uri")
- scope := r.URL.Query().Get("scope")
- state := r.URL.Query().Get("state")
-
- if len(scope) == 0 {
- scope = model.DEFAULT_SCOPE
- }
-
- if len(responseType) == 0 || len(clientId) == 0 || len(redirect) == 0 {
- c.Err = model.NewLocAppError("authorizeOAuth", "api.oauth.authorize_oauth.missing.app_error", nil, "")
- return
- }
-
- var oauthApp *model.OAuthApp
- if result := <-app.Srv.Store.OAuth().GetApp(clientId); result.Err != nil {
- c.Err = result.Err
- return
- } else {
- oauthApp = result.Data.(*model.OAuthApp)
- }
-
- // here we should check if the user is logged in
- if len(c.Session.UserId) == 0 {
- http.Redirect(w, r, c.GetSiteURLHeader()+"/login?redirect_to="+url.QueryEscape(r.RequestURI), http.StatusFound)
- return
- }
-
- isAuthorized := false
- if result := <-app.Srv.Store.Preference().Get(c.Session.UserId, model.PREFERENCE_CATEGORY_AUTHORIZED_OAUTH_APP, clientId); result.Err == nil {
- // when we support scopes we should check if the scopes match
- isAuthorized = true
- }
-
- // Automatically allow if the app is trusted
- if oauthApp.IsTrusted || isAuthorized {
- redirectUrl, err := app.AllowOAuthAppAccessToUser(c.Session.UserId, model.AUTHCODE_RESPONSE_TYPE, clientId, redirect, scope, state)
-
- if err != nil {
- c.Err = err
- return
- }
-
- http.Redirect(w, r, redirectUrl, http.StatusFound)
- return
- }
-
- w.Header().Set("Content-Type", "text/html")
-
- w.Header().Set("Cache-Control", "no-cache, max-age=31556926, public")
- http.ServeFile(w, r, utils.FindDir(model.CLIENT_DIR)+"root.html")
-}
-
-func getAccessToken(c *Context, w http.ResponseWriter, r *http.Request) {
- r.ParseForm()
-
- code := r.FormValue("code")
- refreshToken := r.FormValue("refresh_token")
-
- grantType := r.FormValue("grant_type")
- switch grantType {
- case model.ACCESS_TOKEN_GRANT_TYPE:
- if len(code) == 0 {
- c.Err = model.NewLocAppError("getAccessToken", "api.oauth.get_access_token.missing_code.app_error", nil, "")
- return
- }
- case model.REFRESH_TOKEN_GRANT_TYPE:
- if len(refreshToken) == 0 {
- c.Err = model.NewLocAppError("getAccessToken", "api.oauth.get_access_token.missing_refresh_token.app_error", nil, "")
- return
- }
- default:
- c.Err = model.NewLocAppError("getAccessToken", "api.oauth.get_access_token.bad_grant.app_error", nil, "")
- return
- }
-
- clientId := r.FormValue("client_id")
- if len(clientId) != 26 {
- c.Err = model.NewLocAppError("getAccessToken", "api.oauth.get_access_token.bad_client_id.app_error", nil, "")
- return
- }
-
- secret := r.FormValue("client_secret")
- if len(secret) == 0 {
- c.Err = model.NewLocAppError("getAccessToken", "api.oauth.get_access_token.bad_client_secret.app_error", nil, "")
- return
- }
-
- redirectUri := r.FormValue("redirect_uri")
-
- c.LogAudit("attempt")
-
- accessRsp, err := app.GetOAuthAccessToken(clientId, grantType, redirectUri, code, secret, refreshToken)
- if err != nil {
- c.Err = err
- return
- }
-
- w.Header().Set("Content-Type", "application/json")
- w.Header().Set("Cache-Control", "no-store")
- w.Header().Set("Pragma", "no-cache")
-
- c.LogAudit("success")
-
- w.Write([]byte(accessRsp.ToJson()))
-}
-
func loginWithOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
service := params["service"]
diff --git a/api/oauth_test.go b/api/oauth_test.go
index 3dcaa0ddf..9e5102b97 100644
--- a/api/oauth_test.go
+++ b/api/oauth_test.go
@@ -28,7 +28,6 @@ func TestOAuthRegisterApp(t *testing.T) {
if _, err := Client.RegisterApp(oauthApp); err == nil {
t.Fatal("should have failed - oauth providing turned off")
}
-
}
utils.Cfg.ServiceSettings.EnableOAuthServiceProvider = true