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.
package sso
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"
"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 (
_ 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 {
2021-05-15 18:32:09 +03:00
return true
2019-11-23 02:33:31 +03:00
}
// 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.
2021-01-06 04:38:00 +03:00
func ( b * Basic ) VerifyAuthData ( req * http . Request , w http . ResponseWriter , store DataStore , sess SessionStore ) * models . User {
2021-05-15 18:32:09 +03:00
// Basic authentication should only fire on API, Download or on Git or LFSPaths
2021-05-27 21:46:11 +03:00
if middleware . IsInternalPath ( req ) || ! middleware . IsAPIPath ( req ) && ! isAttachmentDownload ( req ) && ! isGitRawOrLFSPath ( 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 )
2020-12-23 22:52:46 +03:00
if len ( auths ) != 2 || ( auths [ 0 ] != "Basic" && 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-05-15 18:32:09 +03:00
u , err := models . 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-05-15 18:32:09 +03:00
u , err := models . 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 )
u , err := models . UserSignIn ( uname , passwd )
if err != nil {
if ! models . IsErrUserNotExist ( err ) {
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-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
}