rewrite auth

don't disclose auth denial reasons in response
This commit is contained in:
Jakob Schrettenbrunner 2017-08-02 21:35:15 +02:00
parent 6e18e4a1ce
commit 3a65f409d1
3 changed files with 75 additions and 39 deletions

View File

@ -2,7 +2,6 @@ package api
import (
"net/http"
"strings"
"github.com/Pterodactyl/wings/config"
"github.com/Pterodactyl/wings/control"
@ -13,53 +12,88 @@ import (
const (
accessTokenHeader = "X-Access-Token"
accessServerHeader = "X-Access-Server"
// ContextVarServer is the gin.Context field containing the requested server (gin.Context.Get())
ContextVarServer = "server"
// ContextVarAuth is the gin.Context field containing the authorizationManager
// for the request (gin.Context.Get())
ContextVarAuth = "auth"
)
type responseError struct {
Error string `json:"error"`
}
// AuthorizationManager handles permission checks
type AuthorizationManager interface {
hasPermission(string) bool
}
type authorizationManager struct {
token string
server control.Server
}
var _ AuthorizationManager = &authorizationManager{}
func newAuthorizationManager(token string, server control.Server) *authorizationManager {
return &authorizationManager{
token: token,
server: server,
}
}
func (a *authorizationManager) hasPermission(permission string) bool {
if permission == "" {
return true
}
prefix := permission[:1]
if prefix == "c" {
return config.Get().ContainsAuthKey(a.token)
}
if a.server == nil {
return false
}
if prefix == "g" {
return config.Get().ContainsAuthKey(a.token)
}
if prefix == "s" {
return a.server.HasPermission(a.token, permission)
}
return false
}
// AuthHandler returns a HandlerFunc that checks request authentication
// permission is a permission string describing the required permission to access the route
func AuthHandler(permission string) gin.HandlerFunc {
return func(c *gin.Context) {
requestToken := c.Request.Header.Get(accessTokenHeader)
requestServer := c.Request.Header.Get(accessServerHeader)
var server control.Server
if requestToken != "" {
// c: master controller, permissions not related to specific server
if strings.HasPrefix(permission, "c:") {
if config.Get().ContainsAuthKey(requestToken) {
return
}
} else {
// All other permission strings not starting with c: require a server to be provided
if requestServer != "" {
server := control.GetServer(requestServer)
if server != nil {
if strings.HasPrefix(permission, "g:") {
if config.Get().ContainsAuthKey(requestToken) {
return
}
}
if strings.HasPrefix(permission, "s:") {
if server.HasPermission(requestToken, permission) {
return
}
}
} else {
c.JSON(http.StatusNotFound, responseError{"Server defined in " + accessServerHeader + " is not known."})
}
} else {
c.JSON(http.StatusBadRequest, responseError{"No " + accessServerHeader + " header provided."})
}
}
} else {
if requestToken == "" {
log.Debug("Token missing in request.")
c.JSON(http.StatusBadRequest, responseError{"No " + accessTokenHeader + " header provided."})
c.JSON(http.StatusBadRequest, responseError{"Missing required " + accessTokenHeader + " header."})
c.Abort()
return
}
c.JSON(http.StatusForbidden, responseError{"You are do not have permission to perform this action."})
if requestServer != "" {
server = control.GetServer(requestServer)
//fmt.Println(server)
if server == nil {
log.WithField("serverUUID", requestServer).Error("Auth: Requested server not found.")
}
}
auth := newAuthorizationManager(requestToken, server)
if auth.hasPermission(permission) {
c.Set(ContextVarServer, server)
c.Set(ContextVarAuth, auth)
return
}
c.JSON(http.StatusForbidden, responseError{"You do not have permission to perform this action."})
c.Abort()
}
}

View File

@ -50,16 +50,16 @@ func TestAuthHandler(t *testing.T) {
responded, rec := requestMiddlewareWith("g:test", "existingkey", "")
assert.False(t, responded)
assert.Equal(t, http.StatusBadRequest, rec.Code)
assert.Equal(t, http.StatusForbidden, rec.Code)
})
t.Run("rejects not existing server", func(t *testing.T) {
loadConfiguration(t, true)
responded, rec := requestMiddlewareWith("g:test", "existingkey", "notexistingserver")
responded, rec := requestMiddlewareWith("g:testnotexisting", "existingkey", "notexistingserver")
assert.False(t, responded)
assert.Equal(t, http.StatusNotFound, rec.Code)
assert.Equal(t, http.StatusForbidden, rec.Code)
})
t.Run("accepts server with existing g: key", func(t *testing.T) {

View File

@ -3,7 +3,6 @@ package control
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"strings"
@ -110,13 +109,16 @@ func loadServerConfiguration(path string) (*server, error) {
if err := json.Unmarshal(file, server); err != nil {
return nil, err
}
fmt.Println(server)
return server, nil
}
// GetServer returns the server identified by the provided uuid
func GetServer(uuid string) Server {
return servers[uuid]
server := servers[uuid]
if server == nil {
return nil // https://golang.org/doc/faq#nil_error
}
return server
}
// NewServer creates a new Server