Initial cloud-services repo - gateway service + pkg modules
This commit is contained in:
166
pkg/httphandlers/auth_jwttoken.go
Normal file
166
pkg/httphandlers/auth_jwttoken.go
Normal file
@@ -0,0 +1,166 @@
|
||||
package httphandlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"fiskerinc.com/modules/adminroles"
|
||||
"fiskerinc.com/modules/common/authproviders"
|
||||
c "fiskerinc.com/modules/common/context"
|
||||
"fiskerinc.com/modules/db/queries"
|
||||
"fiskerinc.com/modules/jwt"
|
||||
"fiskerinc.com/modules/logger"
|
||||
"fiskerinc.com/modules/utils"
|
||||
)
|
||||
|
||||
var errNoUsername = errors.New("no username")
|
||||
|
||||
type AuthCheckerInterface interface {
|
||||
GetHandler(requiredRoles map[string][]adminroles.RoleID, next http.HandlerFunc) http.HandlerFunc
|
||||
Check(requiredRoles map[string][]adminroles.RoleID, r *http.Request) (context.Context, error)
|
||||
GetValidator() jwt.JWTValidatorInterface
|
||||
SetGroupKey(string)
|
||||
Close()
|
||||
}
|
||||
|
||||
type AuthJWTToken struct {
|
||||
groupkey string
|
||||
apiCalls queries.APICallsInterface
|
||||
validator jwt.JWTValidatorInterface
|
||||
AuthBase
|
||||
}
|
||||
|
||||
func (a *AuthJWTToken) GetValidator() jwt.JWTValidatorInterface {
|
||||
if a.validator == nil {
|
||||
a.validator = jwt.NewJWTValidator("")
|
||||
}
|
||||
return a.validator
|
||||
}
|
||||
|
||||
func (a *AuthJWTToken) GroupKey() string {
|
||||
if len(a.groupkey) == 0 {
|
||||
return "custom:groups"
|
||||
}
|
||||
|
||||
return a.groupkey
|
||||
}
|
||||
|
||||
func (a *AuthJWTToken) SetGroupKey(gp string) {
|
||||
a.groupkey = gp
|
||||
}
|
||||
|
||||
func (a *AuthJWTToken) GetHandler(requiredRoles map[string][]adminroles.RoleID, next http.HandlerFunc) http.HandlerFunc {
|
||||
wrapper := func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, err := a.Check(requiredRoles, r)
|
||||
if err != nil {
|
||||
logger.Warn().Msgf("AuthJWTToken %s %s '%v'", r.Method, r.RequestURI, err)
|
||||
utils.RespError(w, http.StatusUnauthorized, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if ctx != nil {
|
||||
r = r.WithContext(ctx)
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
return wrapper
|
||||
}
|
||||
|
||||
func (a *AuthJWTToken) Check(requiredRoles map[string][]adminroles.RoleID, r *http.Request) (context.Context, error) {
|
||||
// if there are no required roles, anyone can access
|
||||
if !a.hasRoles(requiredRoles) {
|
||||
return r.Context(), nil
|
||||
}
|
||||
|
||||
token, err := jwt.GetAuthorizationHeader(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
payload, err := a.GetValidator().ValidateToken(token.Token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if username, ok := a.getUsername(payload); ok && username != "" {
|
||||
ctx := context.WithValue(r.Context(), ClientIDContextKey, username)
|
||||
*r = *r.WithContext(ctx)
|
||||
} else {
|
||||
return nil, errNoUsername
|
||||
}
|
||||
|
||||
provider := a.getProvider(payload)
|
||||
roles, ok := a.getRolesForProvider(provider, requiredRoles)
|
||||
if !ok {
|
||||
return nil, errors.New(adminroles.MissingPermissionError)
|
||||
}
|
||||
|
||||
checker := adminroles.RolesChecker{}
|
||||
checker.SetRequiredRoles(roles)
|
||||
err = checker.CheckGroups(payload[a.GroupKey()])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx := a.addContext(r.Context(), c.ProviderKey, provider)
|
||||
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
func (a *AuthJWTToken) getProvider(payload map[string]interface{}) string {
|
||||
var ok bool
|
||||
var data interface{}
|
||||
var identities []interface{}
|
||||
var identity map[string]interface{}
|
||||
var provider string
|
||||
|
||||
if data, ok = payload["identities"]; !ok {
|
||||
return authproviders.Default
|
||||
}
|
||||
|
||||
if identities, ok = data.([]interface{}); !ok || len(identities) != 1 {
|
||||
return authproviders.Default
|
||||
}
|
||||
|
||||
if identity, ok = identities[0].(map[string]interface{}); !ok {
|
||||
return authproviders.Default
|
||||
}
|
||||
|
||||
if provider, ok = identity["providerName"].(string); !ok {
|
||||
return authproviders.Default
|
||||
}
|
||||
|
||||
return provider
|
||||
|
||||
}
|
||||
|
||||
func (a *AuthJWTToken) Close() {
|
||||
// nothing to dispose here
|
||||
}
|
||||
|
||||
func (a *AuthJWTToken) getUsername(payload map[string]interface{}) (string, bool) {
|
||||
username, ok := payload["cognito:username"].(string)
|
||||
if ok && username != "" {
|
||||
return username, true
|
||||
}
|
||||
|
||||
username, ok = payload["username"].(string)
|
||||
if ok && username != "" {
|
||||
return username, true
|
||||
}
|
||||
|
||||
username, ok = payload["preferred_username"].(string)
|
||||
if ok && username != "" {
|
||||
return username, true
|
||||
}
|
||||
|
||||
username, ok = payload["email"].(string)
|
||||
if ok && username != "" {
|
||||
return username, true
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
Reference in New Issue
Block a user