diff options
Diffstat (limited to 'modules/auth/sso/basic.go')
-rw-r--r-- | modules/auth/sso/basic.go | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/modules/auth/sso/basic.go b/modules/auth/sso/basic.go new file mode 100644 index 0000000000..7f1841df71 --- /dev/null +++ b/modules/auth/sso/basic.go @@ -0,0 +1,125 @@ +// Copyright 2014 The Gogs Authors. All rights reserved. +// Copyright 2019 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 ( + "strings" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/base" + "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. +var ( + _ SingleSignOn = &Basic{} +) + +// Basic implements the SingleSignOn interface and authenticates requests (API requests +// only) by looking for Basic authentication data or "x-oauth-basic" token in the "Authorization" +// header. +type Basic struct { +} + +// Init does nothing as the Basic implementation does not need to allocate any resources +func (b *Basic) Init() error { + return nil +} + +// Free does nothing as the Basic implementation does not have to release any resources +func (b *Basic) Free() error { + return nil +} + +// IsEnabled returns true as this plugin is enabled by default and its not possible to disable +// it from settings. +func (b *Basic) IsEnabled() bool { + return setting.Service.EnableBasicAuth +} + +// VerifyAuthData extracts and validates Basic data (username and password/token) from the +// "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") + if len(baHead) == 0 { + return nil + } + + auths := strings.Fields(baHead) + if len(auths) != 2 || auths[0] != "Basic" { + return nil + } + + var u *models.User + uname, passwd, _ := base.BasicAuthDecode(auths[1]) + + // Check if username or password is a token + isUsernameToken := len(passwd) == 0 || passwd == "x-oauth-basic" + // Assume username is token + authToken := uname + if !isUsernameToken { + // Assume password is token + authToken = passwd + } + + uid := CheckOAuthAccessToken(authToken) + if uid != 0 { + var err error + ctx.Data["IsApiToken"] = true + + u, err = models.GetUserByID(uid) + if err != nil { + log.Error("GetUserByID: %v", err) + return nil + } + } + token, err := models.GetAccessTokenBySHA(authToken) + if err == nil { + if isUsernameToken { + u, err = models.GetUserByID(token.UID) + if err != nil { + log.Error("GetUserByID: %v", err) + return nil + } + } else { + u, err = models.GetUserByName(uname) + if err != nil { + log.Error("GetUserByID: %v", err) + return nil + } + if u.ID != token.UID { + return nil + } + } + token.UpdatedUnix = timeutil.TimeStampNow() + if err = models.UpdateAccessToken(token); err != nil { + log.Error("UpdateAccessToken: %v", err) + } + } else if !models.IsErrAccessTokenNotExist(err) && !models.IsErrAccessTokenEmpty(err) { + log.Error("GetAccessTokenBySha: %v", err) + } + + if u == nil { + u, err = models.UserSignIn(uname, passwd) + if err != nil { + if !models.IsErrUserNotExist(err) { + log.Error("UserSignIn: %v", err) + } + return nil + } + } else { + ctx.Data["IsApiToken"] = true + } + + return u +} |