From 2ac8e11f466f838ff34314c5e4e2785ebe2d036d Mon Sep 17 00:00:00 2001
From: Unknwon <u@gogs.io>
Date: Wed, 2 Sep 2015 02:40:15 -0400
Subject: [PATCH] #842 able to use access token replace basic auth

---
 gogs.go                       |  2 +-
 models/error.go               | 20 ++++++++++++++
 models/token.go               |  7 +----
 modules/auth/auth.go          | 50 ++++++++++++++++++++---------------
 modules/middleware/context.go |  2 +-
 routers/repo/http.go          |  2 +-
 templates/.VERSION            |  2 +-
 7 files changed, 53 insertions(+), 32 deletions(-)

diff --git a/gogs.go b/gogs.go
index edebcc4efa..dc7d13483c 100644
--- a/gogs.go
+++ b/gogs.go
@@ -17,7 +17,7 @@ import (
 	"github.com/gogits/gogs/modules/setting"
 )
 
-const APP_VER = "0.6.7.0901 Beta"
+const APP_VER = "0.6.7.0902 Beta"
 
 func init() {
 	runtime.GOMAXPROCS(runtime.NumCPU())
diff --git a/models/error.go b/models/error.go
index 4d888c870b..92cc187b43 100644
--- a/models/error.go
+++ b/models/error.go
@@ -183,6 +183,26 @@ func (err ErrDeployKeyNameAlreadyUsed) Error() string {
 	return fmt.Sprintf("public key already exists: [repo_id: %d, name: %s]", err.RepoID, err.Name)
 }
 
+//    _____                                   ___________     __
+//   /  _  \   ____  ____  ____   ______ _____\__    ___/___ |  | __ ____   ____
+//  /  /_\  \_/ ___\/ ___\/ __ \ /  ___//  ___/ |    | /  _ \|  |/ // __ \ /    \
+// /    |    \  \__\  \__\  ___/ \___ \ \___ \  |    |(  <_> )    <\  ___/|   |  \
+// \____|__  /\___  >___  >___  >____  >____  > |____| \____/|__|_ \\___  >___|  /
+//         \/     \/    \/    \/     \/     \/                    \/    \/     \/
+
+type ErrAccessTokenNotExist struct {
+	SHA string
+}
+
+func IsErrAccessTokenNotExist(err error) bool {
+	_, ok := err.(ErrAccessTokenNotExist)
+	return ok
+}
+
+func (err ErrAccessTokenNotExist) Error() string {
+	return fmt.Sprintf("access token does not exist: [sha: %s]", err.SHA)
+}
+
 // ________                            .__                __  .__
 // \_____  \_______  _________    ____ |__|____________ _/  |_|__| ____   ____
 //  /   |   \_  __ \/ ___\__  \  /    \|  \___   /\__  \\   __\  |/  _ \ /    \
diff --git a/models/token.go b/models/token.go
index 6c4328e53e..852a910fec 100644
--- a/models/token.go
+++ b/models/token.go
@@ -5,17 +5,12 @@
 package models
 
 import (
-	"errors"
 	"time"
 
 	"github.com/gogits/gogs/modules/base"
 	"github.com/gogits/gogs/modules/uuid"
 )
 
-var (
-	ErrAccessTokenNotExist = errors.New("Access token does not exist")
-)
-
 // AccessToken represents a personal access token.
 type AccessToken struct {
 	ID                int64 `xorm:"pk autoincr"`
@@ -42,7 +37,7 @@ func GetAccessTokenBySHA(sha string) (*AccessToken, error) {
 	if err != nil {
 		return nil, err
 	} else if !has {
-		return nil, ErrAccessTokenNotExist
+		return nil, ErrAccessTokenNotExist{sha}
 	}
 	return t, nil
 }
diff --git a/modules/auth/auth.go b/modules/auth/auth.go
index 71cb2bb28b..9b62459479 100644
--- a/modules/auth/auth.go
+++ b/modules/auth/auth.go
@@ -5,7 +5,6 @@
 package auth
 
 import (
-	"net/http"
 	"reflect"
 	"strings"
 	"time"
@@ -26,34 +25,41 @@ func IsAPIPath(url string) bool {
 	return strings.HasPrefix(url, "/api/")
 }
 
-// SignedInId returns the id of signed in user.
-func SignedInId(req *http.Request, sess session.Store) int64 {
+// SignedInID returns the id of signed in user.
+func SignedInID(ctx *macaron.Context, sess session.Store) int64 {
 	if !models.HasEngine {
 		return 0
 	}
 
-	// API calls need to check access token.
-	if IsAPIPath(req.URL.Path) {
-		auHead := req.Header.Get("Authorization")
+	// Check access token.
+	tokenSHA := ctx.Query("token")
+	if len(tokenSHA) == 0 {
+		// Well, check with header again.
+		auHead := ctx.Req.Header.Get("Authorization")
 		if len(auHead) > 0 {
 			auths := strings.Fields(auHead)
 			if len(auths) == 2 && auths[0] == "token" {
-				t, err := models.GetAccessTokenBySHA(auths[1])
-				if err != nil {
-					if err != models.ErrAccessTokenNotExist {
-						log.Error(4, "GetAccessTokenBySHA: %v", err)
-					}
-					return 0
-				}
-				t.Updated = time.Now()
-				if err = models.UpdateAccessToekn(t); err != nil {
-					log.Error(4, "UpdateAccessToekn: %v", err)
-				}
-				return t.UID
+				tokenSHA = auths[1]
 			}
 		}
 	}
 
+	// Let's see if token is valid.
+	if len(tokenSHA) > 0 {
+		t, err := models.GetAccessTokenBySHA(tokenSHA)
+		if err != nil {
+			if models.IsErrAccessTokenNotExist(err) {
+				log.Error(4, "GetAccessTokenBySHA: %v", err)
+			}
+			return 0
+		}
+		t.Updated = time.Now()
+		if err = models.UpdateAccessToekn(t); err != nil {
+			log.Error(4, "UpdateAccessToekn: %v", err)
+		}
+		return t.UID
+	}
+
 	uid := sess.Get("uid")
 	if uid == nil {
 		return 0
@@ -72,16 +78,16 @@ func SignedInId(req *http.Request, sess session.Store) int64 {
 
 // SignedInUser returns the user object of signed user.
 // It returns a bool value to indicate whether user uses basic auth or not.
-func SignedInUser(req *http.Request, sess session.Store) (*models.User, bool) {
+func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool) {
 	if !models.HasEngine {
 		return nil, false
 	}
 
-	uid := SignedInId(req, sess)
+	uid := SignedInID(ctx, sess)
 
 	if uid <= 0 {
 		if setting.Service.EnableReverseProxyAuth {
-			webAuthUser := req.Header.Get(setting.ReverseProxyAuthUser)
+			webAuthUser := ctx.Req.Header.Get(setting.ReverseProxyAuthUser)
 			if len(webAuthUser) > 0 {
 				u, err := models.GetUserByName(webAuthUser)
 				if err != nil {
@@ -112,7 +118,7 @@ func SignedInUser(req *http.Request, sess session.Store) (*models.User, bool) {
 		}
 
 		// Check with basic auth.
-		baHead := req.Header.Get("Authorization")
+		baHead := ctx.Req.Header.Get("Authorization")
 		if len(baHead) > 0 {
 			auths := strings.Fields(baHead)
 			if len(auths) == 2 && auths[0] == "Basic" {
diff --git a/modules/middleware/context.go b/modules/middleware/context.go
index 9a8bb8865e..141e8ace40 100644
--- a/modules/middleware/context.go
+++ b/modules/middleware/context.go
@@ -211,7 +211,7 @@ func Contexter() macaron.Handler {
 		}
 
 		// Get user from session if logined.
-		ctx.User, ctx.IsBasicAuth = auth.SignedInUser(ctx.Req.Request, ctx.Session)
+		ctx.User, ctx.IsBasicAuth = auth.SignedInUser(ctx.Context, ctx.Session)
 
 		if ctx.User != nil {
 			ctx.IsSigned = true
diff --git a/routers/repo/http.go b/routers/repo/http.go
index 9c1f227391..52c9fbd39e 100644
--- a/routers/repo/http.go
+++ b/routers/repo/http.go
@@ -115,7 +115,7 @@ func Http(ctx *middleware.Context) {
 			// Assume username now is a token.
 			token, err := models.GetAccessTokenBySHA(authUsername)
 			if err != nil {
-				if err == models.ErrAccessTokenNotExist {
+				if models.IsErrAccessTokenNotExist(err) {
 					ctx.HandleText(401, "invalid token")
 				} else {
 					ctx.Handle(500, "GetAccessTokenBySha", err)
diff --git a/templates/.VERSION b/templates/.VERSION
index bcf63ee3df..21be2047c5 100644
--- a/templates/.VERSION
+++ b/templates/.VERSION
@@ -1 +1 @@
-0.6.7.0901 Beta
\ No newline at end of file
+0.6.7.0902 Beta
\ No newline at end of file