Add user IP to its token
This commit is contained in:
parent
5e81b17e28
commit
bd20a87548
@ -71,7 +71,7 @@ func (a *Authorizer) GenHash(password string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Login cheks password and creates a jwt token
|
// Login cheks password and creates a jwt token
|
||||||
func (a *Authorizer) Login(username, password string) (*tokens.Token, error) {
|
func (a *Authorizer) Login(r *http.Request, username, password string) (*tokens.Token, error) {
|
||||||
u, err := a.Backend.GetUser(username)
|
u, err := a.Backend.GetUser(username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -104,6 +104,7 @@ func (a *Authorizer) Login(username, password string) (*tokens.Token, error) {
|
|||||||
t := &tokens.Token{
|
t := &tokens.Token{
|
||||||
Token: ss,
|
Token: ss,
|
||||||
Username: u.GetName(),
|
Username: u.GetName(),
|
||||||
|
IP: getIPFromRequest(r),
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := t.Add(a.db); err != nil {
|
if err := t.Add(a.db); err != nil {
|
||||||
@ -168,6 +169,7 @@ func (a *Authorizer) CurrentUser(rw http.ResponseWriter, req *http.Request) (Use
|
|||||||
}
|
}
|
||||||
|
|
||||||
token.UserAgent = req.UserAgent()
|
token.UserAgent = req.UserAgent()
|
||||||
|
token.IP = getIPFromRequest(req)
|
||||||
if err := token.Update(a.db); err != nil {
|
if err := token.Update(a.db); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -2,19 +2,21 @@ package auth
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ipContextKey string
|
||||||
|
type authContextKey string
|
||||||
|
|
||||||
// Middleware get User from session and put it in context
|
// Middleware get User from session and put it in context
|
||||||
type Middleware struct {
|
type Middleware struct {
|
||||||
authorizer *Authorizer
|
authorizer *Authorizer
|
||||||
log *logrus.Entry
|
log *logrus.Entry
|
||||||
}
|
}
|
||||||
|
|
||||||
type authContextKey string
|
|
||||||
|
|
||||||
// NewMiddleware returns a new authentication middleware
|
// NewMiddleware returns a new authentication middleware
|
||||||
func NewMiddleware(authorizer *Authorizer, log *logrus.Entry) *Middleware {
|
func NewMiddleware(authorizer *Authorizer, log *logrus.Entry) *Middleware {
|
||||||
return &Middleware{
|
return &Middleware{
|
||||||
@ -101,3 +103,57 @@ func GetCurrentUser(r *http.Request, log *logrus.Entry) User {
|
|||||||
}
|
}
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IPMiddleware set the IP in the request context
|
||||||
|
type IPMiddleware struct {
|
||||||
|
log *logrus.Entry
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewIPMiddleware returns a new ip middleware
|
||||||
|
func NewIPMiddleware(log *logrus.Entry) *IPMiddleware {
|
||||||
|
return &IPMiddleware{
|
||||||
|
log: log.WithField("middleware", "ip"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *IPMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||||
|
ip := getRequestIP(r)
|
||||||
|
|
||||||
|
ctxKey := ipContextKey("ip")
|
||||||
|
ctx := context.WithValue(r.Context(), ctxKey, ip)
|
||||||
|
r = r.WithContext(ctx)
|
||||||
|
|
||||||
|
next(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRequestIP(req *http.Request) string {
|
||||||
|
// Try to get the IP from this header
|
||||||
|
var ip = req.Header.Get("X-Real-IP")
|
||||||
|
if ip != "" {
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
|
||||||
|
// Or from this one
|
||||||
|
ip = req.Header.Get("X-Forwarded-For")
|
||||||
|
if ip != "" {
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
|
||||||
|
host, _, err := net.SplitHostPort(req.RemoteAddr)
|
||||||
|
if err != nil {
|
||||||
|
// fake result
|
||||||
|
return "0.0.0.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
hostIP := net.ParseIP(host)
|
||||||
|
if host == "" {
|
||||||
|
return "0.0.0.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default to the IP from the request
|
||||||
|
return hostIP.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getIPFromRequest(r *http.Request) string {
|
||||||
|
return r.Context().Value(ipContextKey("ip")).(string)
|
||||||
|
}
|
||||||
|
@ -89,6 +89,8 @@ func main() {
|
|||||||
defer c.Stop()
|
defer c.Stop()
|
||||||
|
|
||||||
n := negroni.Classic()
|
n := negroni.Classic()
|
||||||
|
// Middleware for setting ips
|
||||||
|
n.Use(auth.NewIPMiddleware(log))
|
||||||
// Middleware for authentication
|
// Middleware for authentication
|
||||||
n.Use(authMiddleware)
|
n.Use(authMiddleware)
|
||||||
// Serve static files
|
// Serve static files
|
||||||
|
@ -4,18 +4,19 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"gitlab.quimbo.fr/odwrtw/canape/backend/sqly"
|
"gitlab.quimbo.fr/odwrtw/canape/backend/sqly"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
addTokenQuery = `INSERT INTO tokens (token, username) VALUES ($1, $2);`
|
addTokenQuery = `INSERT INTO tokens (token, username, ip) VALUES ($1, $2, $3);`
|
||||||
getTokenQuery = `SELECT * FROM tokens WHERE token=$1;`
|
getTokenQuery = `SELECT * FROM tokens WHERE token=$1;`
|
||||||
getUserTokenQuery = `SELECT * FROM tokens WHERE username=$1 and token=$2;`
|
getUserTokenQuery = `SELECT * FROM tokens WHERE username=$1 and token=$2;`
|
||||||
getUserTokensQuery = `SELECT * FROM tokens WHERE username=$1;`
|
getUserTokensQuery = `SELECT * FROM tokens WHERE username=$1;`
|
||||||
deleteTokenQuery = `DELETE FROM tokens WHERE username=$1 AND token=$2;`
|
deleteTokenQuery = `DELETE FROM tokens WHERE username=$1 AND token=$2;`
|
||||||
updateTokenQuery = `UPDATE tokens SET description=:description, user_agent=:user_agent WHERE token=:token RETURNING *;`
|
updateTokenQuery = `UPDATE tokens SET description=:description, user_agent=:user_agent, ip=:ip, last_used=now() WHERE token=:token RETURNING *;`
|
||||||
)
|
)
|
||||||
|
|
||||||
// Custom errors
|
// Custom errors
|
||||||
@ -30,11 +31,13 @@ type Token struct {
|
|||||||
Token string `db:"token" json:"token"`
|
Token string `db:"token" json:"token"`
|
||||||
Description string `db:"description" json:"description"`
|
Description string `db:"description" json:"description"`
|
||||||
UserAgent string `db:"user_agent" json:"user_agent"`
|
UserAgent string `db:"user_agent" json:"user_agent"`
|
||||||
|
IP string `db:"ip" json:"ip"`
|
||||||
|
LastUsed time.Time `db:"last_used" json:"last_used"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a token to the database
|
// Add a token to the database
|
||||||
func (t *Token) Add(db *sqlx.DB) error {
|
func (t *Token) Add(db *sqlx.DB) error {
|
||||||
_, err := db.Queryx(addTokenQuery, t.Token, t.Username)
|
_, err := db.Queryx(addTokenQuery, t.Token, t.Username, t.IP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ func LoginPOSTHandler(e *web.Env, w http.ResponseWriter, r *http.Request) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
token, err := e.Auth.Login(data.Username, data.Password)
|
token, err := e.Auth.Login(r, data.Username, data.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == auth.ErrInvalidPassword || err == ErrUnknownUser {
|
if err == auth.ErrInvalidPassword || err == ErrUnknownUser {
|
||||||
return e.RenderError(w, fmt.Errorf("Error invalid user or password"))
|
return e.RenderError(w, fmt.Errorf("Error invalid user or password"))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user