2019-11-23 02:33:31 +03:00
// 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.
2021-06-09 20:53:16 +03:00
package auth
2019-11-23 02:33:31 +03:00
import (
2021-01-05 16:05:40 +03:00
"net/http"
2019-11-23 02:33:31 +03:00
"strings"
"code.gitea.io/gitea/models"
2021-11-24 12:49:20 +03:00
user_model "code.gitea.io/gitea/models/user"
2019-11-23 02:33:31 +03:00
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
2021-05-15 18:32:09 +03:00
"code.gitea.io/gitea/modules/web/middleware"
2019-11-23 02:33:31 +03:00
)
// Ensure the struct implements the interface.
var (
2021-07-24 13:16:34 +03:00
_ Method = & Basic { }
_ Named = & Basic { }
2019-11-23 02:33:31 +03:00
)
2021-11-20 18:33:18 +03:00
// BasicMethodName is the constant name of the basic authentication method
const BasicMethodName = "basic"
2021-06-09 20:53:16 +03:00
// Basic implements the Auth interface and authenticates requests (API requests
2019-11-23 02:33:31 +03:00
// only) by looking for Basic authentication data or "x-oauth-basic" token in the "Authorization"
// header.
type Basic struct {
}
2021-06-09 20:53:16 +03:00
// Name represents the name of auth method
func ( b * Basic ) Name ( ) string {
2021-11-20 18:33:18 +03:00
return BasicMethodName
2021-06-09 20:53:16 +03:00
}
// Verify extracts and validates Basic data (username and password/token) from the
2019-11-23 02:33:31 +03:00
// "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.
2021-11-24 12:49:20 +03:00
func ( b * Basic ) Verify ( req * http . Request , w http . ResponseWriter , store DataStore , sess SessionStore ) * user_model . User {
2021-05-15 18:32:09 +03:00
// Basic authentication should only fire on API, Download or on Git or LFSPaths
2021-09-02 18:48:48 +03:00
if ! middleware . IsAPIPath ( req ) && ! isAttachmentDownload ( req ) && ! isGitRawReleaseOrLFSPath ( req ) {
2021-05-15 18:32:09 +03:00
return nil
}
2021-01-05 16:05:40 +03:00
baHead := req . Header . Get ( "Authorization" )
2019-11-23 02:33:31 +03:00
if len ( baHead ) == 0 {
return nil
}
2021-05-15 18:32:09 +03:00
auths := strings . SplitN ( baHead , " " , 2 )
2021-11-13 02:27:18 +03:00
if len ( auths ) != 2 || ( strings . ToLower ( auths [ 0 ] ) != "basic" ) {
2019-11-23 02:33:31 +03:00
return nil
}
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 {
2021-05-09 19:04:53 +03:00
log . Trace ( "Basic Authorization: Attempting login for: %s" , uname )
2019-11-23 02:33:31 +03:00
// Assume password is token
authToken = passwd
2021-05-09 19:04:53 +03:00
} else {
log . Trace ( "Basic Authorization: Attempting login with username as token" )
2019-11-23 02:33:31 +03:00
}
uid := CheckOAuthAccessToken ( authToken )
if uid != 0 {
2021-05-09 19:04:53 +03:00
log . Trace ( "Basic Authorization: Valid OAuthAccessToken for user[%d]" , uid )
2019-11-23 02:33:31 +03:00
2021-11-24 12:49:20 +03:00
u , err := user_model . GetUserByID ( uid )
2019-11-23 02:33:31 +03:00
if err != nil {
log . Error ( "GetUserByID: %v" , err )
return nil
}
2021-05-15 18:32:09 +03:00
store . GetData ( ) [ "IsApiToken" ] = true
return u
2019-11-23 02:33:31 +03:00
}
2021-05-15 18:32:09 +03:00
2019-11-23 02:33:31 +03:00
token , err := models . GetAccessTokenBySHA ( authToken )
if err == nil {
2021-05-09 19:04:53 +03:00
log . Trace ( "Basic Authorization: Valid AccessToken for user[%d]" , uid )
2021-11-24 12:49:20 +03:00
u , err := user_model . GetUserByID ( token . UID )
2020-04-14 21:32:03 +03:00
if err != nil {
log . Error ( "GetUserByID: %v" , err )
return nil
2019-11-23 02:33:31 +03:00
}
2020-04-14 21:32:03 +03:00
2019-11-23 02:33:31 +03:00
token . UpdatedUnix = timeutil . TimeStampNow ( )
if err = models . UpdateAccessToken ( token ) ; err != nil {
log . Error ( "UpdateAccessToken: %v" , err )
}
2021-05-15 18:32:09 +03:00
store . GetData ( ) [ "IsApiToken" ] = true
return u
2019-11-23 02:33:31 +03:00
} else if ! models . IsErrAccessTokenNotExist ( err ) && ! models . IsErrAccessTokenEmpty ( err ) {
log . Error ( "GetAccessTokenBySha: %v" , err )
}
2021-05-15 18:32:09 +03:00
if ! setting . Service . EnableBasicAuth {
return nil
}
2021-05-09 19:04:53 +03:00
2021-05-15 18:32:09 +03:00
log . Trace ( "Basic Authorization: Attempting SignIn for %s" , uname )
2021-09-17 14:43:47 +03:00
u , source , err := UserSignIn ( uname , passwd )
2021-05-15 18:32:09 +03:00
if err != nil {
2021-11-24 12:49:20 +03:00
if ! user_model . IsErrUserNotExist ( err ) {
2021-05-15 18:32:09 +03:00
log . Error ( "UserSignIn: %v" , err )
2019-11-23 02:33:31 +03:00
}
2021-05-15 18:32:09 +03:00
return nil
2019-11-23 02:33:31 +03:00
}
2021-09-17 14:43:47 +03:00
if skipper , ok := source . Cfg . ( LocalTwoFASkipper ) ; ok && skipper . IsSkipLocalTwoFA ( ) {
store . GetData ( ) [ "SkipLocalTwoFA" ] = true
}
2021-05-09 19:04:53 +03:00
log . Trace ( "Basic Authorization: Logged in user %-v" , u )
2019-11-23 02:33:31 +03:00
return u
}