summaryrefslogtreecommitdiffstats
path: root/modules/auth
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2021-01-05 21:05:40 +0800
committerGitHub <noreply@github.com>2021-01-05 21:05:40 +0800
commit15a475b7dbcf7923d9518dff7764b20e404eb774 (patch)
tree8789f1f82c5e41345b442df4e58120bdd5f8bade /modules/auth
parent126c9331d6d8789563fae5d5bac2196d63fee0e8 (diff)
downloadgitea-15a475b7dbcf7923d9518dff7764b20e404eb774.tar.gz
gitea-15a475b7dbcf7923d9518dff7764b20e404eb774.zip
Fix recovery middleware to render gitea style page. (#13857)
* Some changes to fix recovery * Move Recovery to middlewares * Remove trace code * Fix lint * add session middleware and remove dependent on macaron for sso * Fix panic 500 page rendering * Fix bugs * Fix fmt * Fix vendor * recover unnecessary change * Fix lint and addd some comments about the copied codes. * Use util.StatDir instead of com.StatDir Co-authored-by: 6543 <6543@obermui.de>
Diffstat (limited to 'modules/auth')
-rw-r--r--modules/auth/auth.go25
-rw-r--r--modules/auth/sso/basic.go12
-rw-r--r--modules/auth/sso/interface.go19
-rw-r--r--modules/auth/sso/oauth2.go22
-rw-r--r--modules/auth/sso/reverseproxy.go19
-rw-r--r--modules/auth/sso/session.go7
-rw-r--r--modules/auth/sso/sso.go28
-rw-r--r--modules/auth/sso/sspi_windows.go17
-rw-r--r--modules/auth/sso/user.go33
9 files changed, 98 insertions, 84 deletions
diff --git a/modules/auth/auth.go b/modules/auth/auth.go
index 16ea9f15e3..1f4b9ec5be 100644
--- a/modules/auth/auth.go
+++ b/modules/auth/auth.go
@@ -9,13 +9,10 @@ import (
"reflect"
"strings"
- "code.gitea.io/gitea/models"
- "code.gitea.io/gitea/modules/auth/sso"
"code.gitea.io/gitea/modules/validation"
"gitea.com/macaron/binding"
"gitea.com/macaron/macaron"
- "gitea.com/macaron/session"
"github.com/unknwon/com"
)
@@ -24,28 +21,6 @@ func IsAPIPath(url string) bool {
return strings.HasPrefix(url, "/api/")
}
-// SignedInUser returns the user object of signed user.
-// It returns a bool value to indicate whether user uses basic auth or not.
-func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool) {
- if !models.HasEngine {
- return nil, false
- }
-
- // Try to sign in with each of the enabled plugins
- for _, ssoMethod := range sso.Methods() {
- if !ssoMethod.IsEnabled() {
- continue
- }
- user := ssoMethod.VerifyAuthData(ctx, sess)
- if user != nil {
- _, isBasic := ssoMethod.(*sso.Basic)
- return user, isBasic
- }
- }
-
- return nil, false
-}
-
// Form form binding interface
type Form interface {
binding.Validator
diff --git a/modules/auth/sso/basic.go b/modules/auth/sso/basic.go
index aab4eceebc..2db1147fc4 100644
--- a/modules/auth/sso/basic.go
+++ b/modules/auth/sso/basic.go
@@ -6,6 +6,7 @@
package sso
import (
+ "net/http"
"strings"
"code.gitea.io/gitea/models"
@@ -13,9 +14,6 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
-
- "gitea.com/macaron/macaron"
- "gitea.com/macaron/session"
)
// Ensure the struct implements the interface.
@@ -49,8 +47,8 @@ func (b *Basic) IsEnabled() bool {
// "Authorization" header of the request and returns the corresponding user object for that
// name/token on successful validation.
// Returns nil if header is empty or validation fails.
-func (b *Basic) VerifyAuthData(ctx *macaron.Context, sess session.Store) *models.User {
- baHead := ctx.Req.Header.Get("Authorization")
+func (b *Basic) VerifyAuthData(req *http.Request, store DataStore, sess SessionStore) *models.User {
+ baHead := req.Header.Get("Authorization")
if len(baHead) == 0 {
return nil
}
@@ -75,7 +73,7 @@ func (b *Basic) VerifyAuthData(ctx *macaron.Context, sess session.Store) *models
uid := CheckOAuthAccessToken(authToken)
if uid != 0 {
var err error
- ctx.Data["IsApiToken"] = true
+ store.GetData()["IsApiToken"] = true
u, err = models.GetUserByID(uid)
if err != nil {
@@ -108,7 +106,7 @@ func (b *Basic) VerifyAuthData(ctx *macaron.Context, sess session.Store) *models
return nil
}
} else {
- ctx.Data["IsApiToken"] = true
+ store.GetData()["IsApiToken"] = true
}
return u
diff --git a/modules/auth/sso/interface.go b/modules/auth/sso/interface.go
index 89cc227e79..5f7089a2da 100644
--- a/modules/auth/sso/interface.go
+++ b/modules/auth/sso/interface.go
@@ -5,12 +5,23 @@
package sso
import (
- "code.gitea.io/gitea/models"
+ "net/http"
- "gitea.com/macaron/macaron"
- "gitea.com/macaron/session"
+ "code.gitea.io/gitea/models"
)
+// DataStore represents a data store
+type DataStore interface {
+ GetData() map[string]interface{}
+}
+
+// SessionStore represents a session store
+type SessionStore interface {
+ Get(interface{}) interface{}
+ Set(interface{}, interface{}) error
+ Delete(interface{}) error
+}
+
// SingleSignOn represents a SSO authentication method (plugin) for HTTP requests.
type SingleSignOn interface {
// Init should be called exactly once before using any of the other methods,
@@ -29,5 +40,5 @@ type SingleSignOn interface {
// or a new user object (with id = 0) populated with the information that was found
// in the authentication data (username or email).
// Returns nil if verification fails.
- VerifyAuthData(ctx *macaron.Context, sess session.Store) *models.User
+ VerifyAuthData(http *http.Request, store DataStore, sess SessionStore) *models.User
}
diff --git a/modules/auth/sso/oauth2.go b/modules/auth/sso/oauth2.go
index 3f530f036f..5c15ed4257 100644
--- a/modules/auth/sso/oauth2.go
+++ b/modules/auth/sso/oauth2.go
@@ -6,15 +6,13 @@
package sso
import (
+ "net/http"
"strings"
"time"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
-
- "gitea.com/macaron/macaron"
- "gitea.com/macaron/session"
)
// Ensure the struct implements the interface.
@@ -63,15 +61,15 @@ func (o *OAuth2) Free() error {
}
// userIDFromToken returns the user id corresponding to the OAuth token.
-func (o *OAuth2) userIDFromToken(ctx *macaron.Context) int64 {
+func (o *OAuth2) userIDFromToken(req *http.Request, store DataStore) int64 {
// Check access token.
- tokenSHA := ctx.Query("token")
+ tokenSHA := req.Form.Get("token")
if len(tokenSHA) == 0 {
- tokenSHA = ctx.Query("access_token")
+ tokenSHA = req.Form.Get("access_token")
}
if len(tokenSHA) == 0 {
// Well, check with header again.
- auHead := ctx.Req.Header.Get("Authorization")
+ auHead := req.Header.Get("Authorization")
if len(auHead) > 0 {
auths := strings.Fields(auHead)
if len(auths) == 2 && (auths[0] == "token" || strings.ToLower(auths[0]) == "bearer") {
@@ -87,7 +85,7 @@ func (o *OAuth2) userIDFromToken(ctx *macaron.Context) int64 {
if strings.Contains(tokenSHA, ".") {
uid := CheckOAuthAccessToken(tokenSHA)
if uid != 0 {
- ctx.Data["IsApiToken"] = true
+ store.GetData()["IsApiToken"] = true
}
return uid
}
@@ -102,7 +100,7 @@ func (o *OAuth2) userIDFromToken(ctx *macaron.Context) int64 {
if err = models.UpdateAccessToken(t); err != nil {
log.Error("UpdateAccessToken: %v", err)
}
- ctx.Data["IsApiToken"] = true
+ store.GetData()["IsApiToken"] = true
return t.UID
}
@@ -116,16 +114,16 @@ func (o *OAuth2) IsEnabled() bool {
// or the "Authorization" header and returns the corresponding user object for that ID.
// If verification is successful returns an existing user object.
// Returns nil if verification fails.
-func (o *OAuth2) VerifyAuthData(ctx *macaron.Context, sess session.Store) *models.User {
+func (o *OAuth2) VerifyAuthData(req *http.Request, store DataStore, sess SessionStore) *models.User {
if !models.HasEngine {
return nil
}
- if isInternalPath(ctx) || !isAPIPath(ctx) && !isAttachmentDownload(ctx) {
+ if isInternalPath(req) || !isAPIPath(req) && !isAttachmentDownload(req) {
return nil
}
- id := o.userIDFromToken(ctx)
+ id := o.userIDFromToken(req, store)
if id <= 0 {
return nil
}
diff --git a/modules/auth/sso/reverseproxy.go b/modules/auth/sso/reverseproxy.go
index 1b543ce104..c1bd4e3959 100644
--- a/modules/auth/sso/reverseproxy.go
+++ b/modules/auth/sso/reverseproxy.go
@@ -6,14 +6,13 @@
package sso
import (
+ "net/http"
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
- "gitea.com/macaron/macaron"
- "gitea.com/macaron/session"
gouuid "github.com/google/uuid"
)
@@ -31,8 +30,8 @@ type ReverseProxy struct {
}
// getUserName extracts the username from the "setting.ReverseProxyAuthUser" header
-func (r *ReverseProxy) getUserName(ctx *macaron.Context) string {
- webAuthUser := strings.TrimSpace(ctx.Req.Header.Get(setting.ReverseProxyAuthUser))
+func (r *ReverseProxy) getUserName(req *http.Request) string {
+ webAuthUser := strings.TrimSpace(req.Header.Get(setting.ReverseProxyAuthUser))
if len(webAuthUser) == 0 {
return ""
}
@@ -61,8 +60,8 @@ func (r *ReverseProxy) IsEnabled() bool {
// If a username is available in the "setting.ReverseProxyAuthUser" header an existing
// user object is returned (populated with username or email found in header).
// Returns nil if header is empty.
-func (r *ReverseProxy) VerifyAuthData(ctx *macaron.Context, sess session.Store) *models.User {
- username := r.getUserName(ctx)
+func (r *ReverseProxy) VerifyAuthData(req *http.Request, store DataStore, sess SessionStore) *models.User {
+ username := r.getUserName(req)
if len(username) == 0 {
return nil
}
@@ -70,7 +69,7 @@ func (r *ReverseProxy) VerifyAuthData(ctx *macaron.Context, sess session.Store)
user, err := models.GetUserByName(username)
if err != nil {
if models.IsErrUserNotExist(err) && r.isAutoRegisterAllowed() {
- return r.newUser(ctx)
+ return r.newUser(req)
}
log.Error("GetUserByName: %v", err)
return nil
@@ -86,15 +85,15 @@ func (r *ReverseProxy) isAutoRegisterAllowed() bool {
// newUser creates a new user object for the purpose of automatic registration
// and populates its name and email with the information present in request headers.
-func (r *ReverseProxy) newUser(ctx *macaron.Context) *models.User {
- username := r.getUserName(ctx)
+func (r *ReverseProxy) newUser(req *http.Request) *models.User {
+ username := r.getUserName(req)
if len(username) == 0 {
return nil
}
email := gouuid.New().String() + "@localhost"
if setting.Service.EnableReverseProxyEmail {
- webAuthEmail := ctx.Req.Header.Get(setting.ReverseProxyAuthEmail)
+ webAuthEmail := req.Header.Get(setting.ReverseProxyAuthEmail)
if len(webAuthEmail) > 0 {
email = webAuthEmail
}
diff --git a/modules/auth/sso/session.go b/modules/auth/sso/session.go
index c9176b9c31..b64f477e02 100644
--- a/modules/auth/sso/session.go
+++ b/modules/auth/sso/session.go
@@ -5,10 +5,9 @@
package sso
import (
- "code.gitea.io/gitea/models"
+ "net/http"
- "gitea.com/macaron/macaron"
- "gitea.com/macaron/session"
+ "code.gitea.io/gitea/models"
)
// Ensure the struct implements the interface.
@@ -40,7 +39,7 @@ func (s *Session) IsEnabled() bool {
// VerifyAuthData checks if there is a user uid stored in the session and returns the user
// object for that uid.
// Returns nil if there is no user uid stored in the session.
-func (s *Session) VerifyAuthData(ctx *macaron.Context, sess session.Store) *models.User {
+func (s *Session) VerifyAuthData(req *http.Request, store DataStore, sess SessionStore) *models.User {
user := SessionUser(sess)
if user != nil {
return user
diff --git a/modules/auth/sso/sso.go b/modules/auth/sso/sso.go
index c2e36f3f5e..d54310168e 100644
--- a/modules/auth/sso/sso.go
+++ b/modules/auth/sso/sso.go
@@ -7,15 +7,14 @@ package sso
import (
"fmt"
+ "net/http"
"reflect"
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/middlewares"
"code.gitea.io/gitea/modules/setting"
-
- "gitea.com/macaron/macaron"
- "gitea.com/macaron/session"
)
// ssoMethods contains the list of SSO authentication plugins in the order they are expected to be
@@ -73,7 +72,7 @@ func Free() {
}
// SessionUser returns the user object corresponding to the "uid" session variable.
-func SessionUser(sess session.Store) *models.User {
+func SessionUser(sess SessionStore) *models.User {
// Get user ID
uid := sess.Get("uid")
if uid == nil {
@@ -96,22 +95,22 @@ func SessionUser(sess session.Store) *models.User {
}
// isAPIPath returns true if the specified URL is an API path
-func isAPIPath(ctx *macaron.Context) bool {
- return strings.HasPrefix(ctx.Req.URL.Path, "/api/")
+func isAPIPath(req *http.Request) bool {
+ return strings.HasPrefix(req.URL.Path, "/api/")
}
// isInternalPath returns true if the specified URL is an internal API path
-func isInternalPath(ctx *macaron.Context) bool {
- return strings.HasPrefix(ctx.Req.URL.Path, "/api/internal/")
+func isInternalPath(req *http.Request) bool {
+ return strings.HasPrefix(req.URL.Path, "/api/internal/")
}
// isAttachmentDownload check if request is a file download (GET) with URL to an attachment
-func isAttachmentDownload(ctx *macaron.Context) bool {
- return strings.HasPrefix(ctx.Req.URL.Path, "/attachments/") && ctx.Req.Method == "GET"
+func isAttachmentDownload(req *http.Request) bool {
+ return strings.HasPrefix(req.URL.Path, "/attachments/") && req.Method == "GET"
}
// handleSignIn clears existing session variables and stores new ones for the specified user object
-func handleSignIn(ctx *macaron.Context, sess session.Store, user *models.User) {
+func handleSignIn(resp http.ResponseWriter, req *http.Request, sess SessionStore, user *models.User) {
_ = sess.Delete("openid_verified_uri")
_ = sess.Delete("openid_signin_remember")
_ = sess.Delete("openid_determined_email")
@@ -132,15 +131,16 @@ func handleSignIn(ctx *macaron.Context, sess session.Store, user *models.User) {
// Language setting of the user overwrites the one previously set
// If the user does not have a locale set, we save the current one.
if len(user.Language) == 0 {
- user.Language = ctx.Locale.Language()
+ lc := middlewares.Locale(resp, req)
+ user.Language = lc.Language()
if err := models.UpdateUserCols(user, "language"); err != nil {
log.Error(fmt.Sprintf("Error updating user language [user: %d, locale: %s]", user.ID, user.Language))
return
}
}
- ctx.SetCookie("lang", user.Language, nil, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
+ middlewares.SetCookie(resp, "lang", user.Language, nil, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
// Clear whatever CSRF has right now, force to generate a new one
- ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
+ middlewares.SetCookie(resp, setting.CSRFCookieName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
}
diff --git a/modules/auth/sso/sspi_windows.go b/modules/auth/sso/sspi_windows.go
index 62013737ca..5850dcf6e2 100644
--- a/modules/auth/sso/sspi_windows.go
+++ b/modules/auth/sso/sspi_windows.go
@@ -6,6 +6,7 @@ package sso
import (
"errors"
+ "net/http"
"reflect"
"strings"
@@ -64,7 +65,7 @@ func (s *SSPI) IsEnabled() bool {
// If authentication is successful, returs the corresponding user object.
// If negotiation should continue or authentication fails, immediately returns a 401 HTTP
// response code, as required by the SPNEGO protocol.
-func (s *SSPI) VerifyAuthData(ctx *macaron.Context, sess session.Store) *models.User {
+func (s *SSPI) VerifyAuthData(req *http.Request, store DataStore, sess SessionStore) *models.User {
if !s.shouldAuthenticate(ctx) {
return nil
}
@@ -75,7 +76,7 @@ func (s *SSPI) VerifyAuthData(ctx *macaron.Context, sess session.Store) *models.
return nil
}
- userInfo, outToken, err := sspiAuth.Authenticate(ctx.Req.Request, ctx.Resp)
+ userInfo, outToken, err := sspiAuth.Authenticate(req, ctx.Resp)
if err != nil {
log.Warn("Authentication failed with error: %v\n", err)
sspiAuth.AppendAuthenticateHeader(ctx.Resp, outToken)
@@ -139,18 +140,18 @@ func (s *SSPI) getConfig() (*models.SSPIConfig, error) {
return sources[0].SSPI(), nil
}
-func (s *SSPI) shouldAuthenticate(ctx *macaron.Context) (shouldAuth bool) {
+func (s *SSPI) shouldAuthenticate(req *http.Request) (shouldAuth bool) {
shouldAuth = false
- path := strings.TrimSuffix(ctx.Req.URL.Path, "/")
+ path := strings.TrimSuffix(req.URL.Path, "/")
if path == "/user/login" {
- if ctx.Req.FormValue("user_name") != "" && ctx.Req.FormValue("password") != "" {
+ if req.FormValue("user_name") != "" && req.FormValue("password") != "" {
shouldAuth = false
} else if ctx.Req.FormValue("auth_with_sspi") == "1" {
shouldAuth = true
}
- } else if isInternalPath(ctx) {
+ } else if isInternalPath(req) {
shouldAuth = false
- } else if isAPIPath(ctx) || isAttachmentDownload(ctx) {
+ } else if isAPIPath(req) || isAttachmentDownload(req) {
shouldAuth = true
}
return
@@ -158,7 +159,7 @@ func (s *SSPI) shouldAuthenticate(ctx *macaron.Context) (shouldAuth bool) {
// newUser creates a new user object for the purpose of automatic registration
// and populates its name and email with the information present in request headers.
-func (s *SSPI) newUser(ctx *macaron.Context, username string, cfg *models.SSPIConfig) (*models.User, error) {
+func (s *SSPI) newUser(username string, cfg *models.SSPIConfig) (*models.User, error) {
email := gouuid.New().String() + "@localhost.localdomain"
user := &models.User{
Name: username,
diff --git a/modules/auth/sso/user.go b/modules/auth/sso/user.go
new file mode 100644
index 0000000000..69bbebccc7
--- /dev/null
+++ b/modules/auth/sso/user.go
@@ -0,0 +1,33 @@
+// Copyright 2020 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package sso
+
+import (
+ "net/http"
+
+ "code.gitea.io/gitea/models"
+)
+
+// 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, ds DataStore, sess SessionStore) (*models.User, bool) {
+ if !models.HasEngine {
+ return nil, false
+ }
+
+ // Try to sign in with each of the enabled plugins
+ for _, ssoMethod := range Methods() {
+ if !ssoMethod.IsEnabled() {
+ continue
+ }
+ user := ssoMethod.VerifyAuthData(req, ds, sess)
+ if user != nil {
+ _, isBasic := ssoMethod.(*Basic)
+ return user, isBasic
+ }
+ }
+
+ return nil, false
+}