130 lines
3.0 KiB
Go
130 lines
3.0 KiB
Go
package server
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
|
|
"github.com/dgrijalva/jwt-go"
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
func (cfg Unit) enableAuthorization() func(handler http.Handler) http.Handler {
|
|
var handlers []AuthHandlerFunc
|
|
if cfg.Authorization.JWT.Enable {
|
|
handlers = append(handlers, cfg.Authorization.JWT.Create())
|
|
}
|
|
if cfg.Authorization.QueryToken.Enable {
|
|
handlers = append(handlers, cfg.Authorization.QueryToken.Create())
|
|
}
|
|
if cfg.Authorization.HeaderToken.Enable {
|
|
handlers = append(handlers, cfg.Authorization.HeaderToken.Create())
|
|
}
|
|
if cfg.Authorization.Basic.Enable {
|
|
handlers = append(handlers, cfg.Authorization.Basic.Create())
|
|
}
|
|
if len(handlers) == 0 {
|
|
return func(handler http.Handler) http.Handler {
|
|
return handler
|
|
}
|
|
}
|
|
return func(handler http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
|
var authorized bool
|
|
for _, h := range handlers {
|
|
if h(request) {
|
|
authorized = true
|
|
break
|
|
}
|
|
}
|
|
if !authorized {
|
|
writer.WriteHeader(http.StatusForbidden)
|
|
return
|
|
}
|
|
handler.ServeHTTP(writer, request)
|
|
})
|
|
}
|
|
}
|
|
|
|
type AuthHandlerFunc func(req *http.Request) bool
|
|
|
|
type JWT struct {
|
|
Header string `yaml:"header"` // JWT header - by default Authorization
|
|
Secret string `yaml:"secret"` // key to verify JWT
|
|
}
|
|
|
|
func (cfg JWT) Create() AuthHandlerFunc {
|
|
header := cfg.Header
|
|
if header == "" {
|
|
header = "Authorization"
|
|
}
|
|
|
|
return func(req *http.Request) bool {
|
|
rawToken := req.Header.Get(header)
|
|
t, err := jwt.Parse(rawToken, func(token *jwt.Token) (interface{}, error) {
|
|
if token.Method != jwt.SigningMethodHS256 {
|
|
return nil, errors.New("unknown method")
|
|
}
|
|
return []byte(cfg.Secret), nil
|
|
})
|
|
return err == nil && t.Valid
|
|
}
|
|
}
|
|
|
|
type QueryToken struct {
|
|
Param string `yaml:"param"` // query name - by default 'token'
|
|
Tokens []string `yaml:"tokens"` // allowed tokens
|
|
}
|
|
|
|
func (cfg QueryToken) Create() AuthHandlerFunc {
|
|
param := cfg.Param
|
|
if param == "" {
|
|
param = "token"
|
|
}
|
|
tokens := map[string]bool{}
|
|
for _, k := range cfg.Tokens {
|
|
tokens[k] = true
|
|
}
|
|
return func(req *http.Request) bool {
|
|
token := req.URL.Query().Get(param)
|
|
return tokens[token]
|
|
}
|
|
}
|
|
|
|
type HeaderToken struct {
|
|
Header string `yaml:"header"` // header name - by default X-Api-Token
|
|
Tokens []string `yaml:"tokens"` // allowed tokens
|
|
}
|
|
|
|
func (cfg HeaderToken) Create() AuthHandlerFunc {
|
|
header := cfg.Header
|
|
if header == "" {
|
|
header = "X-Api-Token"
|
|
}
|
|
tokens := map[string]bool{}
|
|
for _, k := range cfg.Tokens {
|
|
tokens[k] = true
|
|
}
|
|
return func(req *http.Request) bool {
|
|
token := req.URL.Query().Get(header)
|
|
return tokens[token]
|
|
}
|
|
}
|
|
|
|
type Basic struct {
|
|
Users map[string]string `yaml:"users"` // users -> bcrypted password map
|
|
}
|
|
|
|
func (cfg Basic) Create() AuthHandlerFunc {
|
|
return func(req *http.Request) bool {
|
|
u, p, ok := req.BasicAuth()
|
|
if !ok {
|
|
return false
|
|
}
|
|
h, ok := cfg.Users[u]
|
|
if !ok {
|
|
return false
|
|
}
|
|
return bcrypt.CompareHashAndPassword([]byte(h), []byte(p)) == nil
|
|
}
|
|
}
|