2016-07-21 00:29:00 +02:00
package middlewares
import (
"fmt"
2017-02-23 21:46:50 -05:00
"io/ioutil"
2016-12-30 09:21:13 +01:00
"net/http"
"strings"
2016-07-21 00:29:00 +02:00
"github.com/abbot/go-http-auth"
"github.com/codegangsta/negroni"
2016-09-23 18:27:01 +02:00
"github.com/containous/traefik/log"
2016-07-21 00:29:00 +02:00
"github.com/containous/traefik/types"
)
// Authenticator is a middleware that provides HTTP basic and digest authentication
type Authenticator struct {
handler negroni . Handler
users map [ string ] string
}
// NewAuthenticator builds a new Autenticator given a config
func NewAuthenticator ( authConfig * types . Auth ) ( * Authenticator , error ) {
if authConfig == nil {
return nil , fmt . Errorf ( "Error creating Authenticator: auth is nil" )
}
var err error
authenticator := Authenticator { }
if authConfig . Basic != nil {
2017-02-23 21:46:50 -05:00
authenticator . users , err = parserBasicUsers ( authConfig . Basic )
2016-07-21 00:29:00 +02:00
if err != nil {
return nil , err
}
basicAuth := auth . NewBasicAuthenticator ( "traefik" , authenticator . secretBasic )
authenticator . handler = negroni . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request , next http . HandlerFunc ) {
if username := basicAuth . CheckAuth ( r ) ; username == "" {
2016-12-16 07:42:51 -08:00
log . Debugf ( "Basic auth failed..." )
2016-07-21 00:29:00 +02:00
basicAuth . RequireAuth ( w , r )
} else {
2016-12-16 07:42:51 -08:00
log . Debugf ( "Basic auth success..." )
if authConfig . HeaderField != "" {
r . Header [ authConfig . HeaderField ] = [ ] string { username }
}
2016-07-21 00:29:00 +02:00
next . ServeHTTP ( w , r )
}
} )
} else if authConfig . Digest != nil {
2017-02-23 21:46:50 -05:00
authenticator . users , err = parserDigestUsers ( authConfig . Digest )
2016-07-21 00:29:00 +02:00
if err != nil {
return nil , err
}
digestAuth := auth . NewDigestAuthenticator ( "traefik" , authenticator . secretDigest )
authenticator . handler = negroni . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request , next http . HandlerFunc ) {
if username , _ := digestAuth . CheckAuth ( r ) ; username == "" {
2016-12-16 07:42:51 -08:00
log . Debugf ( "Digest auth failed..." )
2016-07-21 00:29:00 +02:00
digestAuth . RequireAuth ( w , r )
} else {
2016-12-16 07:42:51 -08:00
log . Debugf ( "Digest auth success..." )
if authConfig . HeaderField != "" {
r . Header [ authConfig . HeaderField ] = [ ] string { username }
}
2016-07-21 00:29:00 +02:00
next . ServeHTTP ( w , r )
}
} )
}
return & authenticator , nil
}
2017-02-23 21:46:50 -05:00
func parserBasicUsers ( basic * types . Basic ) ( map [ string ] string , error ) {
var userStrs [ ] string
if basic . UsersFile != "" {
var err error
if userStrs , err = getLinesFromFile ( basic . UsersFile ) ; err != nil {
return nil , err
}
}
userStrs = append ( basic . Users , userStrs ... )
2016-07-21 00:29:00 +02:00
userMap := make ( map [ string ] string )
2017-02-23 21:46:50 -05:00
for _ , user := range userStrs {
2016-07-21 00:29:00 +02:00
split := strings . Split ( user , ":" )
if len ( split ) != 2 {
return nil , fmt . Errorf ( "Error parsing Authenticator user: %v" , user )
}
userMap [ split [ 0 ] ] = split [ 1 ]
}
return userMap , nil
}
2017-02-23 21:46:50 -05:00
func parserDigestUsers ( digest * types . Digest ) ( map [ string ] string , error ) {
var userStrs [ ] string
if digest . UsersFile != "" {
var err error
if userStrs , err = getLinesFromFile ( digest . UsersFile ) ; err != nil {
return nil , err
}
}
userStrs = append ( digest . Users , userStrs ... )
2016-07-21 00:29:00 +02:00
userMap := make ( map [ string ] string )
2017-02-23 21:46:50 -05:00
for _ , user := range userStrs {
2016-07-21 00:29:00 +02:00
split := strings . Split ( user , ":" )
if len ( split ) != 3 {
return nil , fmt . Errorf ( "Error parsing Authenticator user: %v" , user )
}
userMap [ split [ 0 ] + ":" + split [ 1 ] ] = split [ 2 ]
}
return userMap , nil
}
2017-02-23 21:46:50 -05:00
func getLinesFromFile ( filename string ) ( [ ] string , error ) {
dat , err := ioutil . ReadFile ( filename )
if err != nil {
return nil , err
}
// Trim lines and filter out blanks
rawLines := strings . Split ( string ( dat ) , "\n" )
var filteredLines [ ] string
for _ , rawLine := range rawLines {
line := strings . TrimSpace ( rawLine )
if line != "" {
filteredLines = append ( filteredLines , line )
}
}
return filteredLines , nil
}
2016-07-21 00:29:00 +02:00
func ( a * Authenticator ) secretBasic ( user , realm string ) string {
if secret , ok := a . users [ user ] ; ok {
return secret
}
log . Debugf ( "User not found: %s" , user )
return ""
}
func ( a * Authenticator ) secretDigest ( user , realm string ) string {
if secret , ok := a . users [ user + ":" + realm ] ; ok {
return secret
}
log . Debugf ( "User not found: %s:%s" , user , realm )
return ""
}
func ( a * Authenticator ) ServeHTTP ( rw http . ResponseWriter , r * http . Request , next http . HandlerFunc ) {
a . handler . ServeHTTP ( rw , r , next )
}