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 (
"net/http"
"reflect"
2014-07-26 08:24:27 +04:00
"strings"
2014-03-06 11:21:44 +04:00
2014-10-15 19:19:20 +04:00
"github.com/Unknwon/macaron"
"github.com/macaron-contrib/binding"
2014-07-26 08:24:27 +04:00
"github.com/macaron-contrib/session"
2014-03-06 11:21:44 +04:00
2014-07-26 08:24:27 +04:00
"github.com/gogits/gogs/models"
2014-11-10 13:30:07 +03:00
"github.com/gogits/gogs/modules/base"
2014-07-26 08:24:27 +04:00
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
2014-12-06 02:08:09 +03:00
"github.com/gogits/gogs/modules/uuid"
2014-03-06 11:21:44 +04:00
)
2014-07-26 08:24:27 +04:00
// SignedInId returns the id of signed in user.
2014-11-12 14:48:50 +03:00
func SignedInId ( req * http . Request , sess session . Store ) int64 {
2014-07-26 08:24:27 +04:00
if ! models . HasEngine {
return 0
}
2014-11-13 10:32:18 +03:00
// API calls need to check access token.
2014-11-12 14:48:50 +03:00
if strings . HasPrefix ( req . URL . Path , "/api/" ) {
auHead := req . Header . Get ( "Authorization" )
if len ( auHead ) > 0 {
auths := strings . Fields ( auHead )
if len ( auths ) == 2 && auths [ 0 ] == "token" {
t , err := models . GetAccessTokenBySha ( auths [ 1 ] )
if err != nil {
if err != models . ErrAccessTokenNotExist {
log . Error ( 4 , "GetAccessTokenBySha: %v" , err )
}
return 0
}
return t . Uid
}
}
}
2014-11-13 10:32:18 +03:00
uid := sess . Get ( "uid" )
if uid == nil {
return 0
}
if id , ok := uid . ( int64 ) ; ok {
if _ , err := models . GetUserById ( id ) ; err != nil {
if err != models . ErrUserNotExist {
log . Error ( 4 , "GetUserById: %v" , err )
}
return 0
}
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.
2014-11-18 19:07:16 +03:00
func SignedInUser ( req * http . Request , 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
}
2014-11-12 14:48:50 +03:00
uid := SignedInId ( req , sess )
2014-11-10 13:30:07 +03:00
2014-07-26 08:24:27 +04:00
if uid <= 0 {
2014-11-10 13:30:07 +03:00
if setting . Service . EnableReverseProxyAuth {
2014-11-12 14:48:50 +03:00
webAuthUser := req . Header . Get ( setting . ReverseProxyAuthUser )
2014-11-10 13:30:07 +03:00
if len ( webAuthUser ) > 0 {
u , err := models . GetUserByName ( webAuthUser )
if err != nil {
if err != models . ErrUserNotExist {
log . Error ( 4 , "GetUserByName: %v" , err )
2014-12-06 01:54:57 +03:00
return nil , false
}
2014-12-07 04:22:48 +03:00
// Check if enabled auto-registration.
2014-12-06 01:54:57 +03:00
if setting . Service . EnableReverseProxyAutoRegister {
u := & models . User {
Name : webAuthUser ,
2014-12-06 02:08:09 +03:00
Email : uuid . NewV4 ( ) . String ( ) + "@localhost" ,
2014-12-06 01:54:57 +03:00
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
} else {
return u , false
}
2014-11-10 13:30:07 +03:00
}
}
2014-11-18 19:07:16 +03:00
return u , false
2014-11-10 13:30:07 +03:00
}
}
// Check with basic auth.
2014-11-12 14:48:50 +03:00
baHead := req . Header . Get ( "Authorization" )
2014-11-10 13:30:07 +03:00
if len ( baHead ) > 0 {
auths := strings . Fields ( baHead )
if len ( auths ) == 2 && auths [ 0 ] == "Basic" {
uname , passwd , _ := base . BasicAuthDecode ( auths [ 1 ] )
u , err := models . GetUserByName ( uname )
if err != nil {
if err != models . ErrUserNotExist {
log . Error ( 4 , "GetUserByName: %v" , err )
}
2014-11-18 19:07:16 +03:00
return nil , false
2014-11-10 13:30:07 +03:00
}
if u . ValidtePassword ( passwd ) {
2014-11-18 19:07:16 +03:00
return u , true
2014-11-10 13:30:07 +03:00
}
}
}
2014-11-18 19:07:16 +03:00
return nil , false
2014-07-26 08:24:27 +04:00
}
u , err := models . GetUserById ( uid )
if err != nil {
log . Error ( 4 , "GetUserById: %v" , err )
2014-11-18 19:07:16 +03:00
return nil , false
2014-07-26 08:24:27 +04:00
}
2014-11-18 19:07:16 +03:00
return u , false
2014-03-29 02:40:31 +04:00
}
2014-10-15 19:19:20 +04:00
type Form interface {
binding . Validator
}
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
}
data [ fieldName ] = val . Field ( i ) . Interface ( )
}
}
2014-08-01 14:12:14 +04:00
func getSize ( 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 ) {
2014-07-26 08:24:27 +04:00
return rule [ 8 : len ( rule ) - 1 ]
}
}
return ""
}
2014-08-01 14:12:14 +04:00
func GetMinSize ( field reflect . StructField ) string {
return getSize ( field , "MinSize(" )
}
func GetMaxSize ( field reflect . StructField ) string {
return getSize ( field , "MaxSize(" )
}
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 {
2014-07-26 08:24:27 +04:00
data [ "Err_" + field . Name ] = true
trName := l . Tr ( "form." + field . Name )
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" )
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" )
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
}