mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 18:51:03 +01:00
158 lines
4.2 KiB
Go
158 lines
4.2 KiB
Go
|
package basicauth
|
||
|
|
||
|
import (
|
||
|
"encoding/base64"
|
||
|
"strconv"
|
||
|
|
||
|
"time"
|
||
|
|
||
|
"github.com/kataras/iris"
|
||
|
"github.com/kataras/iris/config"
|
||
|
)
|
||
|
|
||
|
type (
|
||
|
encodedUser struct {
|
||
|
HeaderValue string
|
||
|
Username string
|
||
|
logged bool
|
||
|
expires time.Time
|
||
|
}
|
||
|
encodedUsers []encodedUser
|
||
|
|
||
|
basicAuthMiddleware struct {
|
||
|
config config.BasicAuth
|
||
|
// these are filled from the config.Users map at the startup
|
||
|
auth encodedUsers
|
||
|
realmHeaderValue string
|
||
|
expireEnabled bool // if the config.Expires is a valid date, default disabled
|
||
|
}
|
||
|
)
|
||
|
|
||
|
//
|
||
|
|
||
|
// New takes one parameter, the config.BasicAuth returns a HandlerFunc
|
||
|
// use: iris.UseFunc(New(...)), iris.Get(...,New(...),...)
|
||
|
func New(c config.BasicAuth) iris.HandlerFunc {
|
||
|
return NewHandler(c).Serve
|
||
|
}
|
||
|
|
||
|
// NewHandler takes one parameter, the config.BasicAuth returns a Handler
|
||
|
// use: iris.Use(NewHandler(...)), iris.Get(...,iris.HandlerFunc(NewHandler(...)),...)
|
||
|
func NewHandler(c config.BasicAuth) iris.Handler {
|
||
|
b := &basicAuthMiddleware{config: config.DefaultBasicAuth().MergeSingle(c)}
|
||
|
b.init()
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
// Default takes one parameter, the users returns a HandlerFunc
|
||
|
// use: iris.UseFunc(Default(...)), iris.Get(...,Default(...),...)
|
||
|
func Default(users map[string]string) iris.HandlerFunc {
|
||
|
return DefaultHandler(users).Serve
|
||
|
}
|
||
|
|
||
|
// DefaultHandler takes one parameter, the users returns a Handler
|
||
|
// use: iris.Use(DefaultHandler(...)), iris.Get(...,iris.HandlerFunc(Default(...)),...)
|
||
|
func DefaultHandler(users map[string]string) iris.Handler {
|
||
|
c := config.DefaultBasicAuth()
|
||
|
c.Users = users
|
||
|
return NewHandler(c)
|
||
|
}
|
||
|
|
||
|
//
|
||
|
|
||
|
func (b *basicAuthMiddleware) init() {
|
||
|
// pass the encoded users from the user's config's Users value
|
||
|
b.auth = make(encodedUsers, 0, len(b.config.Users))
|
||
|
|
||
|
for k, v := range b.config.Users {
|
||
|
fullUser := k + ":" + v
|
||
|
header := "Basic " + base64.StdEncoding.EncodeToString([]byte(fullUser))
|
||
|
b.auth = append(b.auth, encodedUser{HeaderValue: header, Username: k, logged: false, expires: config.CookieExpireNever})
|
||
|
}
|
||
|
|
||
|
// set the auth realm header's value
|
||
|
b.realmHeaderValue = "Basic realm=" + strconv.Quote(b.config.Realm)
|
||
|
|
||
|
if b.config.Expires > 0 {
|
||
|
b.expireEnabled = true
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (b *basicAuthMiddleware) findAuth(headerValue string) (auth *encodedUser, found bool) {
|
||
|
if len(headerValue) == 0 {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
for _, user := range b.auth {
|
||
|
if user.HeaderValue == headerValue {
|
||
|
auth = &user
|
||
|
found = true
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (b *basicAuthMiddleware) askForCredentials(ctx *iris.Context) {
|
||
|
ctx.SetHeader("WWW-Authenticate", b.realmHeaderValue)
|
||
|
ctx.SetStatusCode(iris.StatusUnauthorized)
|
||
|
}
|
||
|
|
||
|
// Serve the actual middleware
|
||
|
func (b *basicAuthMiddleware) Serve(ctx *iris.Context) {
|
||
|
|
||
|
if auth, found := b.findAuth(ctx.RequestHeader("Authorization")); !found {
|
||
|
/* I spent time for nothing
|
||
|
if b.banEnabled && auth != nil { // this propably never work
|
||
|
|
||
|
if auth.tries == b.config.MaxTries {
|
||
|
auth.bannedTime = time.Now()
|
||
|
auth.unbanTime = time.Now().Add(b.config.BanDuration) // set the unban time
|
||
|
auth.tries++ // we plus them in order to check if already banned later
|
||
|
// client is banned send a forbidden status and don't continue
|
||
|
ctx.SetStatusCode(iris.StatusForbidden)
|
||
|
return
|
||
|
} else if auth.tries > b.config.MaxTries { // it's already banned, so check the ban duration with the bannedTime
|
||
|
if time.Now().After(auth.unbanTime) { // here we unban the client
|
||
|
auth.tries = 0
|
||
|
auth.bannedTime = config.CookieExpireNever
|
||
|
auth.unbanTime = config.CookieExpireNever
|
||
|
// continue and askCredentials as normal
|
||
|
} else {
|
||
|
// client is banned send a forbidden status and don't continue
|
||
|
ctx.SetStatusCode(iris.StatusForbidden)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
if auth != nil {
|
||
|
auth.tries++
|
||
|
}*/
|
||
|
|
||
|
b.askForCredentials(ctx)
|
||
|
// don't continue to the next handler
|
||
|
} else {
|
||
|
// all ok set the context's value in order to be getable from the next handler
|
||
|
ctx.Set(b.config.ContextKey, auth.Username)
|
||
|
if b.expireEnabled {
|
||
|
|
||
|
if auth.logged == false {
|
||
|
auth.expires = time.Now().Add(b.config.Expires)
|
||
|
auth.logged = true
|
||
|
}
|
||
|
|
||
|
if time.Now().Before(auth.expires) {
|
||
|
b.askForCredentials(ctx) // ask for authentication again
|
||
|
return
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
//auth.tries = 0
|
||
|
ctx.Next() // continue
|
||
|
}
|
||
|
|
||
|
}
|