mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2025-05-02 22:12:53 +03:00
Pull request: 2826 auth block
Merge in DNS/adguard-home from 2826-auth-block to master Updates #2826. Squashed commit of the following: commit ae87360379270012869ad2bc4e528e07eb9af91e Author: Eugene Burkov <e.burkov@adguard.com> Date: Tue Apr 27 15:35:49 2021 +0300 home: fix mistake commit dfa2ab05e9a8e70ac1bec36c4eb8ef3b02283b92 Author: Eugene Burkov <e.burkov@adguard.com> Date: Tue Apr 27 15:31:53 2021 +0300 home: imp code commit ff4220d3c3d92ae604e92a0c5c274d9527350d99 Author: Eugene Burkov <e.burkov@adguard.com> Date: Tue Apr 27 15:14:20 2021 +0300 home: imp authratelimiter commit c73a407d8652d64957e35046dbae7168aa45202f Author: Eugene Burkov <e.burkov@adguard.com> Date: Tue Apr 27 14:20:17 2021 +0300 home: fix authratelimiter commit 724db4380928b055f9995006cf421cbe9c5363e7 Author: Eugene Burkov <e.burkov@adguard.com> Date: Fri Apr 23 12:15:48 2021 +0300 home: introduce auth blocker
This commit is contained in:
parent
3f1b71fdf3
commit
f603c21b55
9 changed files with 415 additions and 22 deletions
internal/home
|
@ -8,6 +8,7 @@ import (
|
|||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -62,6 +63,7 @@ func (s *session) deserialize(data []byte) bool {
|
|||
// Auth - global object
|
||||
type Auth struct {
|
||||
db *bbolt.DB
|
||||
blocker *authRateLimiter
|
||||
sessions map[string]*session
|
||||
users []User
|
||||
lock sync.Mutex
|
||||
|
@ -75,12 +77,15 @@ type User struct {
|
|||
}
|
||||
|
||||
// InitAuth - create a global object
|
||||
func InitAuth(dbFilename string, users []User, sessionTTL uint32) *Auth {
|
||||
func InitAuth(dbFilename string, users []User, sessionTTL uint32, blocker *authRateLimiter) *Auth {
|
||||
log.Info("Initializing auth module: %s", dbFilename)
|
||||
|
||||
a := Auth{}
|
||||
a.sessionTTL = sessionTTL
|
||||
a.sessions = make(map[string]*session)
|
||||
a := &Auth{
|
||||
sessionTTL: sessionTTL,
|
||||
blocker: blocker,
|
||||
sessions: make(map[string]*session),
|
||||
users: users,
|
||||
}
|
||||
var err error
|
||||
a.db, err = bbolt.Open(dbFilename, 0o644, nil)
|
||||
if err != nil {
|
||||
|
@ -92,10 +97,9 @@ func InitAuth(dbFilename string, users []User, sessionTTL uint32) *Auth {
|
|||
return nil
|
||||
}
|
||||
a.loadSessions()
|
||||
a.users = users
|
||||
log.Info("auth: initialized. users:%d sessions:%d", len(a.users), len(a.sessions))
|
||||
|
||||
return &a
|
||||
return a
|
||||
}
|
||||
|
||||
// Close - close module
|
||||
|
@ -330,13 +334,23 @@ func cookieExpiryFormat(exp time.Time) (formatted string) {
|
|||
return exp.Format(cookieTimeFormat)
|
||||
}
|
||||
|
||||
func (a *Auth) httpCookie(req loginJSON) (string, error) {
|
||||
func (a *Auth) httpCookie(req loginJSON, addr string) (cookie string, err error) {
|
||||
blocker := a.blocker
|
||||
u := a.UserFind(req.Name, req.Password)
|
||||
if len(u.Name) == 0 {
|
||||
return "", nil
|
||||
if blocker != nil {
|
||||
blocker.inc(addr)
|
||||
}
|
||||
|
||||
return "", err
|
||||
}
|
||||
|
||||
sess, err := newSessionToken()
|
||||
if blocker != nil {
|
||||
blocker.remove(addr)
|
||||
}
|
||||
|
||||
var sess []byte
|
||||
sess, err = newSessionToken()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -404,10 +418,38 @@ func handleLogin(w http.ResponseWriter, r *http.Request) {
|
|||
err := json.NewDecoder(r.Body).Decode(&req)
|
||||
if err != nil {
|
||||
httpError(w, http.StatusBadRequest, "json decode: %s", err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
cookie, err := Context.auth.httpCookie(req)
|
||||
var remoteAddr string
|
||||
// The realIP couldn't be used here due to security issues.
|
||||
//
|
||||
// See https://github.com/AdguardTeam/AdGuardHome/issues/2799.
|
||||
//
|
||||
// TODO(e.burkov): Use realIP when the issue will be fixed.
|
||||
if remoteAddr, err = aghnet.SplitHost(r.RemoteAddr); err != nil {
|
||||
httpError(w, http.StatusBadRequest, "auth: getting remote address: %s", err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if blocker := Context.auth.blocker; blocker != nil {
|
||||
if left := blocker.check(remoteAddr); left > 0 {
|
||||
w.Header().Set("Retry-After", strconv.Itoa(int(left.Seconds())))
|
||||
httpError(
|
||||
w,
|
||||
http.StatusTooManyRequests,
|
||||
"auth: blocked for %s",
|
||||
left,
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var cookie string
|
||||
cookie, err = Context.auth.httpCookie(req, remoteAddr)
|
||||
if err != nil {
|
||||
httpError(w, http.StatusBadRequest, "crypto rand reader: %s", err)
|
||||
|
||||
|
@ -425,7 +467,6 @@ func handleLogin(w http.ResponseWriter, r *http.Request) {
|
|||
} else {
|
||||
log.Info("auth: failed to login user %q from ip %q", req.Name, ip)
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
http.Error(w, "invalid username or password", http.StatusBadRequest)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue