2014-03-06 11:21:44 +04:00
// Copyright 2014 The Gogs 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 auth
import (
"reflect"
2014-07-26 08:24:27 +04:00
"strings"
2014-03-06 11:21:44 +04:00
2015-02-01 20:41:03 +03:00
"github.com/Unknwon/com"
2015-10-16 04:28:12 +03:00
"github.com/go-macaron/binding"
"github.com/go-macaron/session"
2016-02-21 02:13:12 +03:00
gouuid "github.com/satori/go.uuid"
2015-10-16 04:28:12 +03:00
"gopkg.in/macaron.v1"
2014-03-06 11:21:44 +04:00
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
2017-12-11 07:37:04 +03:00
"code.gitea.io/gitea/modules/util"
2017-04-19 06:02:20 +03:00
"code.gitea.io/gitea/modules/validation"
2014-03-06 11:21:44 +04:00
)
2016-11-27 09:03:59 +03:00
// IsAPIPath if URL is an api path
2015-07-15 14:17:57 +03:00
func IsAPIPath ( url string ) bool {
return strings . HasPrefix ( url , "/api/" )
}
2015-09-02 09:40:15 +03:00
// SignedInID returns the id of signed in user.
func SignedInID ( ctx * macaron . Context , sess session . Store ) int64 {
2014-07-26 08:24:27 +04:00
if ! models . HasEngine {
return 0
}
2015-09-02 09:40:15 +03:00
// Check access token.
2015-09-02 09:45:01 +03:00
if IsAPIPath ( ctx . Req . URL . Path ) {
tokenSHA := ctx . Query ( "token" )
2016-10-07 20:17:27 +03:00
if len ( tokenSHA ) <= 0 {
tokenSHA = ctx . Query ( "access_token" )
}
2015-09-02 09:45:01 +03:00
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" {
tokenSHA = auths [ 1 ]
}
2015-09-02 09:40:15 +03:00
}
}
2015-09-02 09:45:01 +03:00
// Let's see if token is valid.
if len ( tokenSHA ) > 0 {
t , err := models . GetAccessTokenBySHA ( tokenSHA )
if err != nil {
2016-06-27 12:02:39 +03:00
if models . IsErrAccessTokenNotExist ( err ) || models . IsErrAccessTokenEmpty ( err ) {
2015-09-02 09:45:01 +03:00
log . Error ( 4 , "GetAccessTokenBySHA: %v" , err )
}
return 0
2014-11-12 14:48:50 +03:00
}
2017-12-11 07:37:04 +03:00
t . UpdatedUnix = util . TimeStampNow ( )
2016-01-06 22:41:42 +03:00
if err = models . UpdateAccessToken ( t ) ; err != nil {
log . Error ( 4 , "UpdateAccessToken: %v" , err )
2015-09-02 09:45:01 +03:00
}
return t . UID
2014-11-12 14:48:50 +03:00
}
}
2014-11-13 10:32:18 +03:00
uid := sess . Get ( "uid" )
if uid == nil {
return 0
2017-02-05 16:10:46 +03:00
} else if id , ok := uid . ( int64 ) ; ok {
2014-11-13 10:32:18 +03:00
return id
}
2014-07-26 08:24:27 +04:00
return 0
2014-07-03 00:42:16 +04:00
}
2014-07-26 08:24:27 +04:00
// SignedInUser returns the user object of signed user.
2014-12-06 01:54:57 +03:00
// It returns a bool value to indicate whether user uses basic auth or not.
2015-09-02 09:40:15 +03:00
func SignedInUser ( ctx * macaron . Context , sess session . Store ) ( * models . User , bool ) {
2014-11-10 13:30:07 +03:00
if ! models . HasEngine {
2014-11-18 19:07:16 +03:00
return nil , false
2014-11-10 13:30:07 +03:00
}
2017-02-05 16:10:46 +03:00
if uid := SignedInID ( ctx , sess ) ; uid > 0 {
user , err := models . GetUserByID ( uid )
if err == nil {
return user , false
} else if ! models . IsErrUserNotExist ( err ) {
log . Error ( 4 , "GetUserById: %v" , err )
}
}
2014-11-10 13:30:07 +03:00
2017-02-05 16:10:46 +03:00
if setting . Service . EnableReverseProxyAuth {
webAuthUser := ctx . Req . Header . Get ( setting . ReverseProxyAuthUser )
if len ( webAuthUser ) > 0 {
u , err := models . GetUserByName ( webAuthUser )
if err != nil {
if ! models . IsErrUserNotExist ( err ) {
log . Error ( 4 , "GetUserByName: %v" , err )
return nil , false
}
2014-12-06 01:54:57 +03:00
2017-02-05 16:10:46 +03:00
// Check if enabled auto-registration.
if setting . Service . EnableReverseProxyAutoRegister {
u := & models . User {
Name : webAuthUser ,
Email : gouuid . NewV4 ( ) . String ( ) + "@localhost" ,
Passwd : webAuthUser ,
IsActive : true ,
}
if err = models . CreateUser ( u ) ; err != nil {
// FIXME: should I create a system notice?
log . Error ( 4 , "CreateUser: %v" , err )
return nil , false
2014-11-10 13:30:07 +03:00
}
2017-02-05 16:10:46 +03:00
return u , false
2014-11-10 13:30:07 +03:00
}
}
2017-02-05 16:10:46 +03:00
return u , false
2014-11-10 13:30:07 +03:00
}
2017-02-05 16:10:46 +03:00
}
2014-11-10 13:30:07 +03:00
2017-02-05 16:10:46 +03:00
// Check with basic auth.
baHead := ctx . Req . Header . Get ( "Authorization" )
if len ( baHead ) > 0 {
auths := strings . Fields ( baHead )
if len ( auths ) == 2 && auths [ 0 ] == "Basic" {
uname , passwd , _ := base . BasicAuthDecode ( auths [ 1 ] )
2014-11-10 13:30:07 +03:00
2017-02-05 16:10:46 +03:00
u , err := models . UserSignIn ( uname , passwd )
if err != nil {
if ! models . IsErrUserNotExist ( err ) {
log . Error ( 4 , "UserSignIn: %v" , err )
}
return nil , false
2014-11-10 13:30:07 +03:00
}
2014-07-26 08:24:27 +04:00
2017-02-05 16:10:46 +03:00
return u , true
}
2014-07-26 08:24:27 +04:00
}
2017-02-05 16:10:46 +03:00
return nil , false
2014-03-29 02:40:31 +04:00
}
2016-11-27 09:03:59 +03:00
// Form form binding interface
2014-10-15 19:19:20 +04:00
type Form interface {
binding . Validator
}
2015-02-01 20:41:03 +03:00
func init ( ) {
binding . SetNameMapper ( com . ToSnakeCase )
}
2014-07-26 08:24:27 +04:00
// AssignForm assign form values back to the template data.
func AssignForm ( form interface { } , data map [ string ] interface { } ) {
typ := reflect . TypeOf ( form )
val := reflect . ValueOf ( form )
if typ . Kind ( ) == reflect . Ptr {
typ = typ . Elem ( )
val = val . Elem ( )
}
for i := 0 ; i < typ . NumField ( ) ; i ++ {
field := typ . Field ( i )
fieldName := field . Tag . Get ( "form" )
// Allow ignored fields in the struct
if fieldName == "-" {
continue
2015-02-01 20:41:03 +03:00
} else if len ( fieldName ) == 0 {
fieldName = com . ToSnakeCase ( field . Name )
2014-07-26 08:24:27 +04:00
}
data [ fieldName ] = val . Field ( i ) . Interface ( )
}
}
2015-10-30 04:09:48 +03:00
func getRuleBody ( field reflect . StructField , prefix string ) string {
2014-07-26 08:24:27 +04:00
for _ , rule := range strings . Split ( field . Tag . Get ( "binding" ) , ";" ) {
2014-08-01 14:12:14 +04:00
if strings . HasPrefix ( rule , prefix ) {
2017-03-03 11:21:31 +03:00
return rule [ len ( prefix ) : len ( rule ) - 1 ]
2014-07-26 08:24:27 +04:00
}
}
return ""
}
2016-11-27 09:03:59 +03:00
// GetSize get size int form tag
2015-07-24 16:02:49 +03:00
func GetSize ( field reflect . StructField ) string {
2015-10-30 04:09:48 +03:00
return getRuleBody ( field , "Size(" )
2015-07-24 16:02:49 +03:00
}
2016-11-27 09:03:59 +03:00
// GetMinSize get minimal size in form tag
2014-08-01 14:12:14 +04:00
func GetMinSize ( field reflect . StructField ) string {
2015-10-30 04:09:48 +03:00
return getRuleBody ( field , "MinSize(" )
2014-08-01 14:12:14 +04:00
}
2016-11-27 09:03:59 +03:00
// GetMaxSize get max size in form tag
2014-08-01 14:12:14 +04:00
func GetMaxSize ( field reflect . StructField ) string {
2015-10-30 04:09:48 +03:00
return getRuleBody ( field , "MaxSize(" )
}
2016-11-27 09:03:59 +03:00
// GetInclude get include in form tag
2015-10-30 04:09:48 +03:00
func GetInclude ( field reflect . StructField ) string {
return getRuleBody ( field , "Include(" )
2014-08-01 14:12:14 +04:00
}
2015-08-28 13:33:09 +03:00
// FIXME: struct contains a struct
func validateStruct ( obj interface { } ) binding . Errors {
return nil
}
2014-10-15 19:19:20 +04:00
func validate ( errs binding . Errors , data map [ string ] interface { } , f Form , l macaron . Locale ) binding . Errors {
if errs . Len ( ) == 0 {
return errs
2014-07-26 08:24:27 +04:00
}
data [ "HasError" ] = true
AssignForm ( f , data )
typ := reflect . TypeOf ( f )
val := reflect . ValueOf ( f )
if typ . Kind ( ) == reflect . Ptr {
typ = typ . Elem ( )
val = val . Elem ( )
}
for i := 0 ; i < typ . NumField ( ) ; i ++ {
field := typ . Field ( i )
fieldName := field . Tag . Get ( "form" )
// Allow ignored fields in the struct
if fieldName == "-" {
continue
}
2014-10-15 19:19:20 +04:00
if errs [ 0 ] . FieldNames [ 0 ] == field . Name {
2017-03-03 11:21:31 +03:00
data [ "Err_" + field . Name ] = true
2015-07-08 14:47:56 +03:00
trName := field . Tag . Get ( "locale" )
if len ( trName ) == 0 {
trName = l . Tr ( "form." + field . Name )
} else {
trName = l . Tr ( trName )
}
2014-10-15 19:19:20 +04:00
switch errs [ 0 ] . Classification {
2014-12-15 09:49:59 +03:00
case binding . ERR_REQUIRED :
2014-07-26 08:24:27 +04:00
data [ "ErrorMsg" ] = trName + l . Tr ( "form.require_error" )
2014-12-15 09:49:59 +03:00
case binding . ERR_ALPHA_DASH :
2014-07-26 08:24:27 +04:00
data [ "ErrorMsg" ] = trName + l . Tr ( "form.alpha_dash_error" )
2014-12-15 09:49:59 +03:00
case binding . ERR_ALPHA_DASH_DOT :
2014-07-26 08:24:27 +04:00
data [ "ErrorMsg" ] = trName + l . Tr ( "form.alpha_dash_dot_error" )
2017-04-19 06:02:20 +03:00
case validation . ErrGitRefName :
data [ "ErrorMsg" ] = trName + l . Tr ( "form.git_ref_name_error" )
2015-07-24 16:02:49 +03:00
case binding . ERR_SIZE :
data [ "ErrorMsg" ] = trName + l . Tr ( "form.size_error" , GetSize ( field ) )
2014-12-15 09:49:59 +03:00
case binding . ERR_MIN_SIZE :
2014-08-01 14:12:14 +04:00
data [ "ErrorMsg" ] = trName + l . Tr ( "form.min_size_error" , GetMinSize ( field ) )
2014-12-15 09:49:59 +03:00
case binding . ERR_MAX_SIZE :
2014-08-01 14:12:14 +04:00
data [ "ErrorMsg" ] = trName + l . Tr ( "form.max_size_error" , GetMaxSize ( field ) )
2014-12-15 09:49:59 +03:00
case binding . ERR_EMAIL :
2014-07-26 08:24:27 +04:00
data [ "ErrorMsg" ] = trName + l . Tr ( "form.email_error" )
2014-12-15 09:49:59 +03:00
case binding . ERR_URL :
2014-07-26 08:24:27 +04:00
data [ "ErrorMsg" ] = trName + l . Tr ( "form.url_error" )
2015-10-30 04:09:48 +03:00
case binding . ERR_INCLUDE :
data [ "ErrorMsg" ] = trName + l . Tr ( "form.include_error" , GetInclude ( field ) )
2014-07-26 08:24:27 +04:00
default :
2014-10-15 19:19:20 +04:00
data [ "ErrorMsg" ] = l . Tr ( "form.unknown_error" ) + " " + errs [ 0 ] . Classification
2014-07-26 08:24:27 +04:00
}
2014-10-15 19:19:20 +04:00
return errs
2014-07-26 08:24:27 +04:00
}
}
2014-10-15 19:19:20 +04:00
return errs
2014-03-29 02:40:31 +04:00
}