2014-06-09 01:53:53 +04:00
// Copyright 2014 The Gogs Authors. All rights reserved.
2014-05-05 13:32:47 +04:00
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
2014-04-26 10:21:04 +04:00
package models
2014-05-03 06:48:14 +04:00
import (
2014-05-15 22:46:04 +04:00
"crypto/tls"
2014-05-03 06:48:14 +04:00
"encoding/json"
2014-05-05 12:40:25 +04:00
"errors"
2014-05-11 11:49:36 +04:00
"fmt"
"net/smtp"
2015-12-12 02:57:45 +03:00
"net/textproto"
2014-05-11 10:12:45 +04:00
"strings"
2014-05-03 06:48:14 +04:00
"time"
2014-04-26 10:21:04 +04:00
2015-09-11 19:03:08 +03:00
"github.com/Unknwon/com"
2016-07-12 02:07:57 +03:00
"github.com/go-macaron/binding"
2014-05-03 06:48:14 +04:00
"github.com/go-xorm/core"
2014-05-05 12:40:25 +04:00
"github.com/go-xorm/xorm"
2014-05-05 13:32:47 +04:00
2014-05-03 06:48:14 +04:00
"github.com/gogits/gogs/modules/auth/ldap"
2015-04-23 14:58:57 +03:00
"github.com/gogits/gogs/modules/auth/pam"
2014-05-15 18:34:36 +04:00
"github.com/gogits/gogs/modules/log"
2014-05-03 06:48:14 +04:00
)
2014-04-26 10:21:04 +04:00
2016-07-08 02:25:09 +03:00
var (
ErrAuthenticationAlreadyExist = errors . New ( "Authentication already exist" )
ErrAuthenticationUserUsed = errors . New ( "Authentication has been used by some users" )
)
2014-06-09 01:53:53 +04:00
type LoginType int
2015-09-10 22:03:14 +03:00
// Note: new type must be added at the end of list to maintain compatibility.
2014-05-05 12:40:25 +04:00
const (
2015-12-11 03:02:57 +03:00
LOGIN_NOTYPE LoginType = iota
2016-02-20 22:56:27 +03:00
LOGIN_PLAIN // 1
LOGIN_LDAP // 2
LOGIN_SMTP // 3
LOGIN_PAM // 4
LOGIN_DLDAP // 5
2014-05-05 12:40:25 +04:00
)
2015-09-11 00:11:41 +03:00
var LoginNames = map [ LoginType ] string {
2015-12-11 03:02:57 +03:00
LOGIN_LDAP : "LDAP (via BindDN)" ,
2016-02-20 22:56:27 +03:00
LOGIN_DLDAP : "LDAP (simple auth)" , // Via direct bind
2015-12-11 03:02:57 +03:00
LOGIN_SMTP : "SMTP" ,
LOGIN_PAM : "PAM" ,
2014-05-05 12:40:25 +04:00
}
2014-04-26 10:21:04 +04:00
2016-07-08 02:25:09 +03:00
var SecurityProtocolNames = map [ ldap . SecurityProtocol ] string {
ldap . SECURITY_PROTOCOL_UNENCRYPTED : "Unencrypted" ,
ldap . SECURITY_PROTOCOL_LDAPS : "LDAPS" ,
ldap . SECURITY_PROTOCOL_START_TLS : "StartTLS" ,
}
2014-12-07 04:22:48 +03:00
// Ensure structs implemented interface.
2014-05-12 19:02:36 +04:00
var (
_ core . Conversion = & LDAPConfig { }
_ core . Conversion = & SMTPConfig { }
2015-04-23 14:58:57 +03:00
_ core . Conversion = & PAMConfig { }
2014-05-12 19:02:36 +04:00
)
2014-04-26 10:21:04 +04:00
type LDAPConfig struct {
2015-09-14 22:48:51 +03:00
* ldap . Source
2014-04-26 10:21:04 +04:00
}
func ( cfg * LDAPConfig ) FromDB ( bs [ ] byte ) error {
2015-09-14 22:48:51 +03:00
return json . Unmarshal ( bs , & cfg )
2014-04-26 10:21:04 +04:00
}
func ( cfg * LDAPConfig ) ToDB ( ) ( [ ] byte , error ) {
2015-09-14 22:48:51 +03:00
return json . Marshal ( cfg )
2014-04-26 10:21:04 +04:00
}
2016-07-08 02:25:09 +03:00
func ( cfg * LDAPConfig ) SecurityProtocolName ( ) string {
return SecurityProtocolNames [ cfg . SecurityProtocol ]
}
2014-05-11 11:49:36 +04:00
type SMTPConfig struct {
2015-09-11 20:32:33 +03:00
Auth string
Host string
Port int
AllowedDomains string ` xorm:"TEXT" `
TLS bool
SkipVerify bool
2014-05-11 11:49:36 +04:00
}
func ( cfg * SMTPConfig ) FromDB ( bs [ ] byte ) error {
return json . Unmarshal ( bs , cfg )
}
func ( cfg * SMTPConfig ) ToDB ( ) ( [ ] byte , error ) {
return json . Marshal ( cfg )
}
2015-04-23 14:58:57 +03:00
type PAMConfig struct {
ServiceName string // pam service (e.g. system-auth)
}
func ( cfg * PAMConfig ) FromDB ( bs [ ] byte ) error {
return json . Unmarshal ( bs , & cfg )
}
func ( cfg * PAMConfig ) ToDB ( ) ( [ ] byte , error ) {
return json . Marshal ( cfg )
}
2014-04-26 10:21:04 +04:00
type LoginSource struct {
2015-09-13 03:58:51 +03:00
ID int64 ` xorm:"pk autoincr" `
Type LoginType
Name string ` xorm:"UNIQUE" `
IsActived bool ` xorm:"NOT NULL DEFAULT false" `
Cfg core . Conversion ` xorm:"TEXT" `
2016-03-10 03:53:30 +03:00
Created time . Time ` xorm:"-" `
CreatedUnix int64
Updated time . Time ` xorm:"-" `
UpdatedUnix int64
}
func ( s * LoginSource ) BeforeInsert ( ) {
2016-07-23 15:24:44 +03:00
s . CreatedUnix = time . Now ( ) . Unix ( )
2016-03-10 03:53:30 +03:00
s . UpdatedUnix = s . CreatedUnix
}
func ( s * LoginSource ) BeforeUpdate ( ) {
2016-07-23 15:24:44 +03:00
s . UpdatedUnix = time . Now ( ) . Unix ( )
2014-05-03 06:48:14 +04:00
}
2016-01-11 09:34:32 +03:00
// Cell2Int64 converts a xorm.Cell type to int64,
// and handles possible irregular cases.
func Cell2Int64 ( val xorm . Cell ) int64 {
switch ( * val ) . ( type ) {
2016-01-11 10:47:23 +03:00
case [ ] uint8 :
log . Trace ( "Cell2Int64 ([]uint8): %v" , * val )
return com . StrTo ( string ( ( * val ) . ( [ ] uint8 ) ) ) . MustInt64 ( )
2016-01-11 09:34:32 +03:00
}
return ( * val ) . ( int64 )
}
2015-08-29 10:45:58 +03:00
func ( source * LoginSource ) BeforeSet ( colName string , val xorm . Cell ) {
switch colName {
case "type" :
2016-01-11 09:34:32 +03:00
switch LoginType ( Cell2Int64 ( val ) ) {
2015-12-11 03:02:57 +03:00
case LOGIN_LDAP , LOGIN_DLDAP :
2015-08-29 10:45:58 +03:00
source . Cfg = new ( LDAPConfig )
2015-12-11 03:02:57 +03:00
case LOGIN_SMTP :
2015-08-29 10:45:58 +03:00
source . Cfg = new ( SMTPConfig )
2015-12-11 03:02:57 +03:00
case LOGIN_PAM :
2015-08-29 10:45:58 +03:00
source . Cfg = new ( PAMConfig )
2015-09-11 19:03:08 +03:00
default :
panic ( "unrecognized login source type: " + com . ToStr ( * val ) )
2015-08-29 10:45:58 +03:00
}
}
}
2016-03-10 03:53:30 +03:00
func ( s * LoginSource ) AfterSet ( colName string , _ xorm . Cell ) {
switch colName {
case "created_unix" :
s . Created = time . Unix ( s . CreatedUnix , 0 ) . Local ( )
case "updated_unix" :
s . Updated = time . Unix ( s . UpdatedUnix , 0 ) . Local ( )
}
}
2015-09-11 00:11:41 +03:00
func ( source * LoginSource ) TypeName ( ) string {
return LoginNames [ source . Type ]
2014-05-05 12:40:25 +04:00
}
2015-09-11 19:03:08 +03:00
func ( source * LoginSource ) IsLDAP ( ) bool {
2015-12-11 03:02:57 +03:00
return source . Type == LOGIN_LDAP
2015-09-11 19:03:08 +03:00
}
func ( source * LoginSource ) IsDLDAP ( ) bool {
2015-12-11 03:02:57 +03:00
return source . Type == LOGIN_DLDAP
2015-09-11 19:03:08 +03:00
}
func ( source * LoginSource ) IsSMTP ( ) bool {
2015-12-11 03:02:57 +03:00
return source . Type == LOGIN_SMTP
2015-09-11 19:03:08 +03:00
}
func ( source * LoginSource ) IsPAM ( ) bool {
2015-12-11 03:02:57 +03:00
return source . Type == LOGIN_PAM
2015-09-11 19:03:08 +03:00
}
2016-07-08 02:25:09 +03:00
func ( source * LoginSource ) HasTLS ( ) bool {
return ( ( source . IsLDAP ( ) || source . IsDLDAP ( ) ) &&
source . LDAP ( ) . SecurityProtocol > ldap . SECURITY_PROTOCOL_UNENCRYPTED ) ||
source . IsSMTP ( )
}
2015-09-11 19:03:08 +03:00
func ( source * LoginSource ) UseTLS ( ) bool {
switch source . Type {
2015-12-11 03:02:57 +03:00
case LOGIN_LDAP , LOGIN_DLDAP :
2016-07-08 02:25:09 +03:00
return source . LDAP ( ) . SecurityProtocol != ldap . SECURITY_PROTOCOL_UNENCRYPTED
2015-12-11 03:02:57 +03:00
case LOGIN_SMTP :
2015-09-11 19:03:08 +03:00
return source . SMTP ( ) . TLS
}
return false
}
2015-09-14 22:48:51 +03:00
func ( source * LoginSource ) SkipVerify ( ) bool {
switch source . Type {
2015-12-11 03:02:57 +03:00
case LOGIN_LDAP , LOGIN_DLDAP :
2015-09-14 22:48:51 +03:00
return source . LDAP ( ) . SkipVerify
2015-12-11 03:02:57 +03:00
case LOGIN_SMTP :
2015-09-14 22:48:51 +03:00
return source . SMTP ( ) . SkipVerify
}
return false
}
2014-05-05 12:40:25 +04:00
func ( source * LoginSource ) LDAP ( ) * LDAPConfig {
return source . Cfg . ( * LDAPConfig )
}
2014-05-11 11:49:36 +04:00
func ( source * LoginSource ) SMTP ( ) * SMTPConfig {
return source . Cfg . ( * SMTPConfig )
}
2015-04-23 14:58:57 +03:00
func ( source * LoginSource ) PAM ( ) * PAMConfig {
return source . Cfg . ( * PAMConfig )
}
2015-09-10 22:45:03 +03:00
// CountLoginSources returns number of login sources.
func CountLoginSources ( ) int64 {
count , _ := x . Count ( new ( LoginSource ) )
return count
}
2014-06-09 01:53:53 +04:00
func CreateSource ( source * LoginSource ) error {
2014-06-21 08:51:41 +04:00
_ , err := x . Insert ( source )
2014-06-09 01:53:53 +04:00
return err
}
2015-09-13 16:51:51 +03:00
func LoginSources ( ) ( [ ] * LoginSource , error ) {
2015-08-29 10:45:58 +03:00
auths := make ( [ ] * LoginSource , 0 , 5 )
return auths , x . Find ( & auths )
2014-05-03 06:48:14 +04:00
}
2015-12-06 01:13:13 +03:00
// GetLoginSourceByID returns login source by given ID.
2015-08-29 10:45:58 +03:00
func GetLoginSourceByID ( id int64 ) ( * LoginSource , error ) {
2014-05-05 12:40:25 +04:00
source := new ( LoginSource )
2014-06-21 08:51:41 +04:00
has , err := x . Id ( id ) . Get ( source )
2014-05-05 12:40:25 +04:00
if err != nil {
return nil , err
2014-06-09 01:53:53 +04:00
} else if ! has {
2015-12-06 01:13:13 +03:00
return nil , ErrAuthenticationNotExist { id }
2014-05-05 12:40:25 +04:00
}
return source , nil
}
2014-05-11 14:10:37 +04:00
func UpdateSource ( source * LoginSource ) error {
2015-08-29 10:45:58 +03:00
_ , err := x . Id ( source . ID ) . AllCols ( ) . Update ( source )
2014-05-03 06:48:14 +04:00
return err
}
2015-09-11 19:03:08 +03:00
func DeleteSource ( source * LoginSource ) error {
count , err := x . Count ( & User { LoginSource : source . ID } )
2014-05-05 12:40:25 +04:00
if err != nil {
return err
2015-09-11 19:03:08 +03:00
} else if count > 0 {
2014-05-05 12:40:25 +04:00
return ErrAuthenticationUserUsed
}
2015-09-11 19:03:08 +03:00
_ , err = x . Id ( source . ID ) . Delete ( new ( LoginSource ) )
2014-05-03 06:48:14 +04:00
return err
2014-04-26 10:21:04 +04:00
}
2014-05-11 10:12:45 +04:00
2015-09-13 03:58:51 +03:00
// .____ ________ _____ __________
// | | \______ \ / _ \\______ \
// | | | | \ / /_\ \| ___/
// | |___ | ` \/ | \ |
// |_______ \/_______ /\____|__ /____|
// \/ \/ \/
2014-05-11 10:12:45 +04:00
2015-12-01 16:49:49 +03:00
// LoginUserLDAPSource queries if loginName/passwd can login against the LDAP directory pool,
2015-11-21 20:58:31 +03:00
// and create a local user if success when enabled.
// It returns the same LoginUserPlain semantic.
2015-12-01 16:49:49 +03:00
func LoginUserLDAPSource ( u * User , loginName , passwd string , source * LoginSource , autoRegister bool ) ( * User , error ) {
2015-09-05 06:39:23 +03:00
cfg := source . Cfg . ( * LDAPConfig )
2015-12-11 03:02:57 +03:00
directBind := ( source . Type == LOGIN_DLDAP )
2016-07-12 02:07:57 +03:00
username , fn , sn , mail , isAdmin , logged := cfg . SearchEntry ( loginName , passwd , directBind )
2014-05-11 10:12:45 +04:00
if ! logged {
2014-12-06 02:08:09 +03:00
// User not in LDAP, do nothing
2015-12-01 16:49:49 +03:00
return nil , ErrUserNotExist { 0 , loginName }
2014-05-11 10:12:45 +04:00
}
2015-08-13 02:58:27 +03:00
2014-05-11 10:12:45 +04:00
if ! autoRegister {
2014-07-26 08:24:27 +04:00
return u , nil
2014-05-11 10:12:45 +04:00
}
2014-12-06 02:08:09 +03:00
// Fallback.
2016-07-12 02:07:57 +03:00
if len ( username ) == 0 {
username = loginName
2015-12-01 16:49:49 +03:00
}
2016-07-12 02:07:57 +03:00
// Validate username make sure it satisfies requirement.
2016-07-21 09:15:04 +03:00
if binding . AlphaDashDotPattern . MatchString ( username ) {
2016-07-12 02:07:57 +03:00
return nil , fmt . Errorf ( "Invalid pattern for attribute 'username' [%s]: must be valid alpha or numeric or dash(-_) or dot characters" , username )
}
2014-12-06 02:08:09 +03:00
if len ( mail ) == 0 {
2016-07-12 02:07:57 +03:00
mail = fmt . Sprintf ( "%s@localhost" , username )
2014-12-06 02:08:09 +03:00
}
2014-07-26 08:24:27 +04:00
u = & User {
2016-07-12 02:07:57 +03:00
LowerName : strings . ToLower ( username ) ,
Name : username ,
FullName : composeFullName ( fn , sn , username ) ,
2015-09-05 06:39:23 +03:00
LoginType : source . Type ,
LoginSource : source . ID ,
2015-12-01 16:49:49 +03:00
LoginName : loginName ,
2014-05-11 10:12:45 +04:00
Email : mail ,
2016-07-12 02:07:57 +03:00
IsAdmin : isAdmin ,
2014-12-06 02:08:09 +03:00
IsActive : true ,
2014-05-11 10:12:45 +04:00
}
2014-12-06 02:08:09 +03:00
return u , CreateUser ( u )
2014-05-11 10:12:45 +04:00
}
2014-05-11 11:49:36 +04:00
2016-07-12 02:07:57 +03:00
func composeFullName ( firstname , surname , username string ) string {
2015-12-01 16:49:49 +03:00
switch {
2016-07-12 02:07:57 +03:00
case len ( firstname ) == 0 && len ( surname ) == 0 :
return username
case len ( firstname ) == 0 :
return surname
case len ( surname ) == 0 :
return firstname
2015-12-01 16:49:49 +03:00
default :
2016-07-12 02:07:57 +03:00
return firstname + " " + surname
2015-12-01 16:49:49 +03:00
}
}
2015-09-13 03:58:51 +03:00
// _________ __________________________
// / _____/ / \__ ___/\______ \
// \_____ \ / \ / \| | | ___/
// / \/ Y \ | | |
// /_______ /\____|__ /____| |____|
// \/ \/
2014-05-11 11:49:36 +04:00
type loginAuth struct {
username , password string
}
func LoginAuth ( username , password string ) smtp . Auth {
return & loginAuth { username , password }
}
func ( a * loginAuth ) Start ( server * smtp . ServerInfo ) ( string , [ ] byte , error ) {
return "LOGIN" , [ ] byte ( a . username ) , nil
}
func ( a * loginAuth ) Next ( fromServer [ ] byte , more bool ) ( [ ] byte , error ) {
if more {
switch string ( fromServer ) {
case "Username:" :
return [ ] byte ( a . username ) , nil
case "Password:" :
return [ ] byte ( a . password ) , nil
}
}
return nil , nil
}
2015-08-29 10:45:58 +03:00
const (
2014-05-11 14:10:37 +04:00
SMTP_PLAIN = "PLAIN"
SMTP_LOGIN = "LOGIN"
2014-05-11 11:49:36 +04:00
)
2015-09-11 00:11:41 +03:00
var SMTPAuths = [ ] string { SMTP_PLAIN , SMTP_LOGIN }
2015-08-29 10:45:58 +03:00
func SMTPAuth ( a smtp . Auth , cfg * SMTPConfig ) error {
c , err := smtp . Dial ( fmt . Sprintf ( "%s:%d" , cfg . Host , cfg . Port ) )
2014-05-11 11:49:36 +04:00
if err != nil {
return err
}
defer c . Close ( )
2014-05-15 22:46:04 +04:00
if err = c . Hello ( "gogs" ) ; err != nil {
return err
}
2015-08-29 10:45:58 +03:00
if cfg . TLS {
2014-05-11 16:04:28 +04:00
if ok , _ := c . Extension ( "STARTTLS" ) ; ok {
2015-08-29 10:45:58 +03:00
if err = c . StartTLS ( & tls . Config {
InsecureSkipVerify : cfg . SkipVerify ,
ServerName : cfg . Host ,
} ) ; err != nil {
2014-05-11 16:04:28 +04:00
return err
}
} else {
2014-05-16 07:03:26 +04:00
return errors . New ( "SMTP server unsupports TLS" )
2014-05-11 11:49:36 +04:00
}
}
if ok , _ := c . Extension ( "AUTH" ) ; ok {
if err = c . Auth ( a ) ; err != nil {
return err
}
return nil
}
2014-06-09 01:53:53 +04:00
return ErrUnsupportedLoginType
2014-05-11 11:49:36 +04:00
}
2014-12-07 04:22:48 +03:00
// Query if name/passwd can login against the LDAP directory pool
2014-05-11 11:49:36 +04:00
// Create a local user if success
// Return the same LoginUserPlain semantic
2015-12-11 03:02:57 +03:00
func LoginUserSMTPSource ( u * User , name , passwd string , sourceID int64 , cfg * SMTPConfig , autoRegister bool ) ( * User , error ) {
2015-09-11 20:32:33 +03:00
// Verify allowed domains.
if len ( cfg . AllowedDomains ) > 0 {
idx := strings . Index ( name , "@" )
if idx == - 1 {
return nil , ErrUserNotExist { 0 , name }
} else if ! com . IsSliceContainsStr ( strings . Split ( cfg . AllowedDomains , "," ) , name [ idx + 1 : ] ) {
return nil , ErrUserNotExist { 0 , name }
}
}
2014-05-11 11:49:36 +04:00
var auth smtp . Auth
2014-05-11 14:10:37 +04:00
if cfg . Auth == SMTP_PLAIN {
2014-05-11 11:49:36 +04:00
auth = smtp . PlainAuth ( "" , name , passwd , cfg . Host )
2014-05-11 14:10:37 +04:00
} else if cfg . Auth == SMTP_LOGIN {
2014-05-11 11:49:36 +04:00
auth = LoginAuth ( name , passwd )
2014-05-11 16:04:28 +04:00
} else {
2014-05-15 22:46:04 +04:00
return nil , errors . New ( "Unsupported SMTP auth type" )
2014-05-11 11:49:36 +04:00
}
2015-08-29 10:45:58 +03:00
if err := SMTPAuth ( auth , cfg ) ; err != nil {
2015-12-12 02:57:45 +03:00
// Check standard error format first,
// then fallback to worse case.
tperr , ok := err . ( * textproto . Error )
if ( ok && tperr . Code == 535 ) ||
strings . Contains ( err . Error ( ) , "Username and Password not accepted" ) {
2015-09-11 20:32:33 +03:00
return nil , ErrUserNotExist { 0 , name }
2014-05-15 22:46:04 +04:00
}
2014-05-11 11:49:36 +04:00
return nil , err
}
if ! autoRegister {
2014-07-26 08:24:27 +04:00
return u , nil
2014-05-11 11:49:36 +04:00
}
2014-05-11 16:04:28 +04:00
var loginName = name
idx := strings . Index ( name , "@" )
if idx > - 1 {
loginName = name [ : idx ]
}
2014-05-11 11:49:36 +04:00
// fake a local user creation
2014-07-26 08:24:27 +04:00
u = & User {
2014-05-11 16:04:28 +04:00
LowerName : strings . ToLower ( loginName ) ,
Name : strings . ToLower ( loginName ) ,
2015-12-11 03:02:57 +03:00
LoginType : LOGIN_SMTP ,
LoginSource : sourceID ,
2014-05-11 11:49:36 +04:00
LoginName : name ,
IsActive : true ,
Passwd : passwd ,
Email : name ,
}
2014-07-26 08:24:27 +04:00
err := CreateUser ( u )
return u , err
2014-05-11 11:49:36 +04:00
}
2015-04-23 14:58:57 +03:00
2015-09-13 03:58:51 +03:00
// __________ _____ _____
// \______ \/ _ \ / \
// | ___/ /_\ \ / \ / \
// | | / | \/ Y \
// |____| \____|__ /\____|__ /
// \/ \/
2015-04-23 14:58:57 +03:00
// Query if name/passwd can login against PAM
// Create a local user if success
// Return the same LoginUserPlain semantic
2015-12-11 03:02:57 +03:00
func LoginUserPAMSource ( u * User , name , passwd string , sourceID int64 , cfg * PAMConfig , autoRegister bool ) ( * User , error ) {
2015-04-23 14:58:57 +03:00
if err := pam . PAMAuth ( cfg . ServiceName , name , passwd ) ; err != nil {
if strings . Contains ( err . Error ( ) , "Authentication failure" ) {
2015-09-14 18:03:42 +03:00
return nil , ErrUserNotExist { 0 , name }
2015-04-23 14:58:57 +03:00
}
return nil , err
}
if ! autoRegister {
return u , nil
}
// fake a local user creation
u = & User {
LowerName : strings . ToLower ( name ) ,
2015-11-24 04:43:04 +03:00
Name : name ,
2015-12-11 03:02:57 +03:00
LoginType : LOGIN_PAM ,
LoginSource : sourceID ,
2015-04-23 14:58:57 +03:00
LoginName : name ,
IsActive : true ,
Passwd : passwd ,
Email : name ,
}
2015-11-24 04:43:04 +03:00
return u , CreateUser ( u )
2015-04-23 14:58:57 +03:00
}
2015-09-13 03:58:51 +03:00
func ExternalUserLogin ( u * User , name , passwd string , source * LoginSource , autoRegister bool ) ( * User , error ) {
if ! source . IsActived {
return nil , ErrLoginSourceNotActived
}
switch source . Type {
2015-12-11 03:02:57 +03:00
case LOGIN_LDAP , LOGIN_DLDAP :
2015-09-13 03:58:51 +03:00
return LoginUserLDAPSource ( u , name , passwd , source , autoRegister )
2015-12-11 03:02:57 +03:00
case LOGIN_SMTP :
2015-09-13 03:58:51 +03:00
return LoginUserSMTPSource ( u , name , passwd , source . ID , source . Cfg . ( * SMTPConfig ) , autoRegister )
2015-12-11 03:02:57 +03:00
case LOGIN_PAM :
2015-09-13 03:58:51 +03:00
return LoginUserPAMSource ( u , name , passwd , source . ID , source . Cfg . ( * PAMConfig ) , autoRegister )
}
return nil , ErrUnsupportedLoginType
}
// UserSignIn validates user name and password.
func UserSignIn ( uname , passwd string ) ( * User , error ) {
var u * User
if strings . Contains ( uname , "@" ) {
2015-11-24 04:43:04 +03:00
u = & User { Email : strings . ToLower ( uname ) }
2015-09-13 03:58:51 +03:00
} else {
u = & User { LowerName : strings . ToLower ( uname ) }
}
userExists , err := x . Get ( u )
if err != nil {
return nil , err
}
if userExists {
switch u . LoginType {
2015-12-11 03:02:57 +03:00
case LOGIN_NOTYPE , LOGIN_PLAIN :
2015-09-13 03:58:51 +03:00
if u . ValidatePassword ( passwd ) {
return u , nil
}
2016-07-23 20:08:22 +03:00
return nil , ErrUserNotExist { u . ID , u . Name }
2015-09-13 03:58:51 +03:00
default :
var source LoginSource
hasSource , err := x . Id ( u . LoginSource ) . Get ( & source )
if err != nil {
return nil , err
} else if ! hasSource {
return nil , ErrLoginSourceNotExist
}
return ExternalUserLogin ( u , u . LoginName , passwd , & source , false )
}
}
var sources [ ] LoginSource
if err = x . UseBool ( ) . Find ( & sources , & LoginSource { IsActived : true } ) ; err != nil {
return nil , err
}
for _ , source := range sources {
u , err := ExternalUserLogin ( nil , uname , passwd , & source , true )
if err == nil {
return u , nil
}
log . Warn ( "Failed to login '%s' via '%s': %v" , uname , source . Name , err )
}
2016-07-23 20:08:22 +03:00
return nil , ErrUserNotExist { u . ID , u . Name }
2015-09-13 03:58:51 +03:00
}