Improve web layer authentication and session process

This commit is contained in:
Tobie Morgan Hitchcock 2017-11-16 20:52:17 +00:00
parent 1a5267e2e2
commit 2609d761be
4 changed files with 376 additions and 166 deletions

View file

@ -23,6 +23,10 @@ var Settings *Options
type Kind int
func (k Kind) MarshalText() (data []byte, err error) {
return []byte(k.String()), err
}
func (k Kind) String() string {
switch k {
default:
@ -53,7 +57,8 @@ const (
type Auth struct {
Kind Kind
Data map[string]interface{}
Data interface{}
Scope string
Possible struct {
NS string
DB string

View file

@ -28,10 +28,26 @@ import (
"github.com/abcum/surreal/db"
"github.com/abcum/surreal/kvs"
"github.com/abcum/surreal/mem"
"github.com/abcum/surreal/sql"
"github.com/dgrijalva/jwt-go"
"github.com/gorilla/websocket"
)
const (
varKeyIp = "ip"
varKeyNs = "NS"
varKeyDb = "DB"
varKeySc = "SC"
varKeyTk = "TK"
varKeyUs = "US"
varKeyTb = "TB"
varKeyId = "ID"
varKeyAuth = "auth"
varKeyUser = "user"
varKeyPass = "pass"
varKeyOrigin = "origin"
)
func cidr(ip net.IP, networks []*net.IPNet) bool {
for _, network := range networks {
if network.Contains(ip) {
@ -46,13 +62,7 @@ func auth() fibre.MiddlewareFunc {
return func(c *fibre.Context) (err error) {
auth := &cnf.Auth{}
c.Set("auth", auth)
// Ensure that the authentication data
// object is initiated at the beginning
// so it is present when serialized.
auth.Data = make(map[string]interface{})
c.Set(varKeyAuth, auth)
// Start off with an authentication level
// which prevents running any sql queries,
@ -77,7 +87,6 @@ func auth() fibre.MiddlewareFunc {
subs := strings.Split(bits[0], "-")
if len(subs) == 2 {
auth.Kind = cnf.AuthSC
auth.Possible.NS = subs[0]
auth.Selected.NS = subs[0]
auth.Possible.DB = subs[1]
@ -88,8 +97,7 @@ func auth() fibre.MiddlewareFunc {
// the request headers, then mark it as
// the selected namespace.
if ns := c.Request().Header().Get("NS"); len(ns) != 0 {
auth.Kind = cnf.AuthSC
if ns := c.Request().Header().Get(varKeyNs); len(ns) != 0 {
auth.Possible.NS = ns
auth.Selected.NS = ns
}
@ -98,8 +106,7 @@ func auth() fibre.MiddlewareFunc {
// the request headers, then mark it as
// the selected database.
if db := c.Request().Header().Get("DB"); len(db) != 0 {
auth.Kind = cnf.AuthSC
if db := c.Request().Header().Get(varKeyDb); len(db) != 0 {
auth.Possible.DB = db
auth.Selected.DB = db
}
@ -117,7 +124,6 @@ func auth() fibre.MiddlewareFunc {
if len(head) == 0 {
for _, prot := range websocket.Subprotocols(c.Request().Request) {
if len(prot) > 7 && prot[0:7] == "bearer-" {
head = "Bearer " + prot[7:]
return checkBearer(c, prot[7:], func() error {
return h(c)
})
@ -129,8 +135,8 @@ func auth() fibre.MiddlewareFunc {
// is a Basic Auth header, and if it is then
// process this as root authentication.
if len(head) > 0 && head[:5] == "Basic" {
return checkMaster(c, head[6:], func() error {
if len(head) > 6 && head[:5] == "Basic" {
return checkBasics(c, head[6:], func() error {
return h(c)
})
}
@ -139,7 +145,7 @@ func auth() fibre.MiddlewareFunc {
// is a Bearer Auth header, and if it is then
// process this as default authentication.
if len(head) > 0 && head[:6] == "Bearer" {
if len(head) > 7 && head[:6] == "Bearer" {
return checkBearer(c, head[7:], func() error {
return h(c)
})
@ -151,56 +157,90 @@ func auth() fibre.MiddlewareFunc {
}
}
func checkRoot(c *fibre.Context, user, pass string, callback func() error) (err error) {
func checkBasics(c *fibre.Context, info string, callback func() error) (err error) {
auth := c.Get("auth").(*cnf.Auth)
var base []byte
var cred [][]byte
if cidr(c.IP(), cnf.Settings.Auth.Nets) {
if user == cnf.Settings.Auth.User && pass == cnf.Settings.Auth.Pass {
auth.Kind = cnf.AuthKV
auth.Possible.NS = "*"
auth.Possible.DB = "*"
}
}
return callback()
}
func checkMaster(c *fibre.Context, info string, callback func() error) (err error) {
auth := c.Get("auth").(*cnf.Auth)
auth := c.Get(varKeyAuth).(*cnf.Auth)
user := []byte(cnf.Settings.Auth.User)
pass := []byte(cnf.Settings.Auth.Pass)
base, err := base64.StdEncoding.DecodeString(info)
// Parse the base64 encoded basic auth data
if err == nil && cidr(c.IP(), cnf.Settings.Auth.Nets) {
if base, err = base64.StdEncoding.DecodeString(info); err != nil {
return fibre.NewHTTPError(401).WithMessage("Problem with basic auth data")
}
cred := bytes.SplitN(base, []byte(":"), 2)
// Split the basic auth USER and PASS details
if len(cred) == 2 && bytes.Equal(cred[0], user) && bytes.Equal(cred[1], pass) {
if cred = bytes.SplitN(base, []byte(":"), 2); len(cred) != 2 {
return fibre.NewHTTPError(401).WithMessage("Problem with basic auth data")
}
// Check to see if IP, USER, and PASS match server settings
if bytes.Equal(cred[0], user) && bytes.Equal(cred[1], pass) {
if cidr(c.IP(), cnf.Settings.Auth.Nets) {
auth.Kind = cnf.AuthKV
auth.Possible.NS = "*"
auth.Possible.DB = "*"
return callback()
}
return fibre.NewHTTPError(403).WithMessage("IP invalid for root authentication")
}
// If no KV authentication, then try to authenticate as NS user
if auth.Selected.NS != "" {
n := auth.Selected.NS
u := string(cred[0])
p := string(cred[1])
if _, err = signinNS(n, u, p); err == nil {
auth.Kind = cnf.AuthNS
auth.Possible.NS = n
auth.Possible.DB = "*"
return callback()
}
// If no NS authentication, then try to authenticate as DB user
if auth.Selected.DB != "" {
n := auth.Selected.NS
d := auth.Selected.DB
u := string(cred[0])
p := string(cred[1])
if _, err = signinDB(n, d, u, p); err == nil {
auth.Kind = cnf.AuthDB
auth.Possible.NS = n
auth.Possible.DB = d
return callback()
}
}
}
return callback()
return fibre.NewHTTPError(401).WithMessage("Invalid authentication details")
}
func checkBearer(c *fibre.Context, info string, callback func() error) (err error) {
auth := c.Get("auth").(*cnf.Auth)
auth := c.Get(varKeyAuth).(*cnf.Auth)
var txn kvs.TX
var res []*db.Response
var vars jwt.MapClaims
var nok, dok, sok, tok, uok bool
var nsv, dbv, scv, tkv, usv string
var nsk, dbk, sck, tkk, usk, tbk, idk bool
var nsv, dbv, scv, tkv, usv, tbv, idv string
// Start a new read transaction.
@ -212,6 +252,10 @@ func checkBearer(c *fibre.Context, info string, callback func() error) (err erro
defer txn.Cancel()
// Setup the kvs layer cache.
cache := mem.NewWithTX(txn)
// Parse the specified JWT Token.
token, err := jwt.Parse(info, func(token *jwt.Token) (interface{}, error) {
@ -222,15 +266,13 @@ func checkBearer(c *fibre.Context, info string, callback func() error) (err erro
return nil, err
}
if val, ok := vars["auth"].(map[string]interface{}); ok {
auth.Data = val
}
nsv, nok = vars["NS"].(string) // Namespace
dbv, dok = vars["DB"].(string) // Database
scv, sok = vars["SC"].(string) // Scope
tkv, tok = vars["TK"].(string) // Token
usv, uok = vars["US"].(string) // Login
nsv, nsk = vars[varKeyNs].(string) // Namespace
dbv, dbk = vars[varKeyDb].(string) // Database
scv, sck = vars[varKeySc].(string) // Scope
tkv, tkk = vars[varKeyTk].(string) // Token
usv, usk = vars[varKeyUs].(string) // Login
tbv, tbk = vars[varKeyTb].(string) // Table
idv, idk = vars[varKeyId].(string) // Thing
if tkv == "default" {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
@ -238,17 +280,53 @@ func checkBearer(c *fibre.Context, info string, callback func() error) (err erro
}
}
if nok && dok && sok && tok {
if nsk && dbk && sck && tkk {
scp, err := mem.New(txn).GetSC(nsv, dbv, scv)
scp, err := cache.GetSC(nsv, dbv, scv)
if err != nil {
return nil, fmt.Errorf("Credentials failed")
}
auth.Data["scope"] = scp.Name
// Store the authenticated scope.
auth.Scope = scp.Name.ID
// Store the authenticated thing.
auth.Data = sql.NewThing(tbv, idv)
// Check that the scope specifies connect.
if exp, ok := scp.Connect.(*sql.SubExpression); ok {
// Process the scope connect statement.
c := fibre.NewContext(c.Request(), c.Response(), c.Fibre())
c.Set(varKeyAuth, &cnf.Auth{Kind: cnf.AuthDB})
qvars := map[string]interface{}{"id": auth.Data}
query := &sql.Query{Statements: []sql.Statement{exp.Expr}}
// If the query fails then fail authentication.
if res, err = db.Process(c, query, qvars); err != nil {
return nil, fmt.Errorf("Credentials failed")
}
// If the response is not 1 record then fail authentication.
if len(res) != 1 || len(res[0].Result) != 1 {
return nil, fmt.Errorf("Credentials failed")
}
auth.Data = res[0].Result[0]
}
if tkv != "default" {
key, err := mem.New(txn).GetST(nsv, dbv, scv, tkv)
key, err := cache.GetST(nsv, dbv, scv, tkv)
if err != nil {
return nil, fmt.Errorf("Credentials failed")
}
@ -262,10 +340,10 @@ func checkBearer(c *fibre.Context, info string, callback func() error) (err erro
return scp.Code, nil
}
} else if nok && dok && tok {
} else if nsk && dbk && tkk {
if tkv != "default" {
key, err := mem.New(txn).GetDT(nsv, dbv, tkv)
key, err := cache.GetDT(nsv, dbv, tkv)
if err != nil {
return nil, fmt.Errorf("Credentials failed")
}
@ -274,8 +352,8 @@ func checkBearer(c *fibre.Context, info string, callback func() error) (err erro
}
auth.Kind = cnf.AuthDB
return key.Code, nil
} else if uok {
usr, err := mem.New(txn).GetDU(nsv, dbv, usv)
} else if usk {
usr, err := cache.GetDU(nsv, dbv, usv)
if err != nil {
return nil, fmt.Errorf("Credentials failed")
}
@ -283,10 +361,10 @@ func checkBearer(c *fibre.Context, info string, callback func() error) (err erro
return usr.Code, nil
}
} else if nok && tok {
} else if nsk && tkk {
if tkv != "default" {
key, err := mem.New(txn).GetNT(nsv, tkv)
key, err := cache.GetNT(nsv, tkv)
if err != nil {
return nil, fmt.Errorf("Credentials failed")
}
@ -295,8 +373,8 @@ func checkBearer(c *fibre.Context, info string, callback func() error) (err erro
}
auth.Kind = cnf.AuthNS
return key.Code, nil
} else if uok {
usr, err := mem.New(txn).GetNU(nsv, usv)
} else if usk {
usr, err := cache.GetNU(nsv, usv)
if err != nil {
return nil, fmt.Errorf("Credentials failed")
}
@ -332,8 +410,10 @@ func checkBearer(c *fibre.Context, info string, callback func() error) (err erro
auth.Selected.DB = dbv
}
return callback()
}
return callback()
return fibre.NewHTTPError(401).WithMessage("Invalid authentication details")
}

View file

@ -18,11 +18,12 @@ import (
"time"
"github.com/abcum/fibre"
"github.com/abcum/surreal/cnf"
"github.com/abcum/surreal/db"
"github.com/abcum/surreal/kvs"
"github.com/abcum/surreal/mem"
"github.com/abcum/surreal/sql"
"github.com/abcum/surreal/util/data"
"github.com/dgrijalva/jwt-go"
"golang.org/x/crypto/bcrypt"
)
@ -33,9 +34,21 @@ func signin(c *fibre.Context) (err error) {
c.Bind(&vars)
n, nok := vars["NS"].(string)
d, dok := vars["DB"].(string)
s, sok := vars["SC"].(string)
n, nok := vars[varKeyNs].(string)
d, dok := vars[varKeyDb].(string)
s, sok := vars[varKeySc].(string)
// Ensure that the IP address of the
// user signing in is available so that
// it can be used within signin queries.
vars[varKeyIp] = c.IP().String()
// Ensure that the website origin of the
// user signing in is available so that
// it can be used within signin queries.
vars[varKeyOrigin] = c.Origin()
// If we have a namespace, database, and
// scope defined, then we are logging in
@ -43,9 +56,12 @@ func signin(c *fibre.Context) (err error) {
if nok && len(n) > 0 && dok && len(d) > 0 && sok && len(s) > 0 {
var ok bool
var txn kvs.TX
var str string
var doc *sql.Thing
var res []*db.Response
var exp *sql.SubExpression
var scp *sql.DefineScopeStatement
// Start a new read transaction.
@ -60,7 +76,7 @@ func signin(c *fibre.Context) (err error) {
// Get the specified signin scope.
if scp, err = mem.New(txn).GetSC(n, d, s); err != nil {
if scp, err = mem.NewWithTX(txn).GetSC(n, d, s); err != nil {
return fibre.NewHTTPError(403).WithFields(map[string]interface{}{
"ns": n,
"db": d,
@ -68,11 +84,25 @@ func signin(c *fibre.Context) (err error) {
}).WithMessage("Authentication scope does not exist")
}
// Check that the scope allows signin.
if exp, ok = scp.Signin.(*sql.SubExpression); !ok {
return fibre.NewHTTPError(403).WithFields(map[string]interface{}{
"ns": n,
"db": d,
"sc": s,
}).WithMessage("Authentication scope signup was unsuccessful")
}
// Process the scope signin statement.
qury := &sql.Query{Statements: []sql.Statement{scp.Signup}}
c.Set(varKeyAuth, &cnf.Auth{Kind: cnf.AuthDB})
if res, err = db.Process(c, qury, vars); err != nil {
query := &sql.Query{Statements: []sql.Statement{exp.Expr}}
// If the query fails then return a 501 error.
if res, err = db.Process(c, query, vars); err != nil {
return fibre.NewHTTPError(501).WithFields(map[string]interface{}{
"ns": n,
"db": d,
@ -80,7 +110,19 @@ func signin(c *fibre.Context) (err error) {
}).WithMessage("Authentication scope signin was unsuccessful")
}
if len(res) != 1 && len(res[0].Result) != 1 {
// If the response is not 1 record then return a 403 error.
if len(res) != 1 || len(res[0].Result) != 1 {
return fibre.NewHTTPError(403).WithFields(map[string]interface{}{
"ns": n,
"db": d,
"sc": s,
}).WithMessage("Authentication scope signin was unsuccessful")
}
// If the query does not return an id field then return a 403 error.
if doc, ok = data.Consume(res[0].Result[0]).Get("id").Data().(*sql.Thing); !ok {
return fibre.NewHTTPError(403).WithFields(map[string]interface{}{
"ns": n,
"db": d,
@ -91,15 +133,16 @@ func signin(c *fibre.Context) (err error) {
// Create a new token signer with the default claims.
signr := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{
"NS": n,
"DB": d,
"SC": s,
"TK": "default",
"iss": "Surreal",
"iat": time.Now().Unix(),
"nbf": time.Now().Unix(),
"exp": time.Now().Add(scp.Time).Unix(),
"auth": res[0].Result[0],
"NS": n,
"DB": d,
"SC": s,
"TK": "default",
"iss": "Surreal",
"iat": time.Now().Unix(),
"nbf": time.Now().Unix(),
"exp": time.Now().Add(scp.Time).Unix(),
"TB": doc.TB,
"ID": doc.ID,
})
// Try to create the final signed token as a string.
@ -112,7 +155,7 @@ func signin(c *fibre.Context) (err error) {
}).WithMessage("Problem with signing string")
}
return c.Text(200, str)
return c.Send(200, str)
}
@ -122,16 +165,15 @@ func signin(c *fibre.Context) (err error) {
if nok && len(n) > 0 && dok && len(d) > 0 {
var txn kvs.TX
var str string
var usr *sql.DefineLoginStatement
// Get the specified user and password.
u, uok := vars["user"].(string)
p, pok := vars["pass"].(string)
u, uok := vars[varKeyUser].(string)
p, pok := vars[varKeyPass].(string)
if !uok || len(u) == 0 || !pok || len(p) == 0 {
if !uok || !pok {
return fibre.NewHTTPError(403).WithFields(map[string]interface{}{
"ns": n,
"db": d,
@ -141,32 +183,8 @@ func signin(c *fibre.Context) (err error) {
// Start a new read transaction.
if txn, err = db.Begin(false); err != nil {
return fibre.NewHTTPError(500)
}
// Ensure the transaction closes.
defer txn.Cancel()
// Get the specified database login.
if usr, err = mem.New(txn).GetDU(n, d, u); err != nil {
return fibre.NewHTTPError(403).WithFields(map[string]interface{}{
"ns": n,
"db": d,
"du": u,
}).WithMessage("Database login does not exist")
}
// Compare the hashed and stored passwords.
if err = bcrypt.CompareHashAndPassword(usr.Pass, []byte(p)); err != nil {
return fibre.NewHTTPError(403).WithFields(map[string]interface{}{
"ns": n,
"db": d,
"du": u,
}).WithMessage("Database signin was unsuccessful")
if usr, err = signinDB(n, d, u, p); err != nil {
return err
}
// Create a new token signer with the default claims.
@ -189,10 +207,10 @@ func signin(c *fibre.Context) (err error) {
"ns": n,
"db": d,
"du": u,
}).WithMessage("Problem with singing string")
}).WithMessage("Problem with signing string")
}
return c.Text(200, str)
return c.Send(200, str)
}
@ -202,48 +220,23 @@ func signin(c *fibre.Context) (err error) {
if nok && len(n) > 0 {
var txn kvs.TX
var str string
var usr *sql.DefineLoginStatement
// Get the specified user and password.
u, uok := vars["user"].(string)
p, pok := vars["pass"].(string)
u, uok := vars[varKeyUser].(string)
p, pok := vars[varKeyPass].(string)
if !uok || len(u) == 0 || !pok || len(p) == 0 {
if !uok || !pok {
return fibre.NewHTTPError(403).WithFields(map[string]interface{}{
"ns": n,
"nu": u,
}).WithMessage("Database signin was unsuccessful")
}
// Start a new read transaction.
if txn, err = db.Begin(false); err != nil {
return fibre.NewHTTPError(500)
}
// Ensure the transaction closes.
defer txn.Cancel()
// Get the specified namespace login.
if usr, err = mem.New(txn).GetNU(n, u); err != nil {
return fibre.NewHTTPError(403).WithFields(map[string]interface{}{
"ns": n,
"nu": u,
}).WithMessage("Namespace login does not exist")
}
// Compare the hashed and stored passwords.
if err = bcrypt.CompareHashAndPassword(usr.Pass, []byte(p)); err != nil {
return fibre.NewHTTPError(403).WithFields(map[string]interface{}{
"ns": n,
"nu": u,
}).WithMessage("Namespace signin was unsuccessful")
if usr, err = signinNS(n, u, p); err != nil {
return err
}
// Create a new token signer with the default claims.
@ -264,13 +257,103 @@ func signin(c *fibre.Context) (err error) {
return fibre.NewHTTPError(403).WithFields(map[string]interface{}{
"ns": n,
"nu": u,
}).WithMessage("Problem with singing string")
}).WithMessage("Problem with signing string")
}
return c.Text(200, str)
return c.Send(200, str)
}
return fibre.NewHTTPError(403)
}
func signinDB(n, d, u, p string) (usr *sql.DefineLoginStatement, err error) {
var txn kvs.TX
// Start a new read transaction.
if txn, err = db.Begin(false); err != nil {
return nil, fibre.NewHTTPError(500)
}
// Ensure the transaction closes.
defer txn.Cancel()
// Get the specified user and password.
if len(u) == 0 || len(p) == 0 {
return nil, fibre.NewHTTPError(403).WithFields(map[string]interface{}{
"ns": n,
"nu": u,
}).WithMessage("Database signin was unsuccessful")
}
// Get the specified namespace login.
if usr, err = mem.NewWithTX(txn).GetDU(n, d, u); err != nil {
return nil, fibre.NewHTTPError(403).WithFields(map[string]interface{}{
"ns": n,
"nu": u,
}).WithMessage("Database login does not exist")
}
// Compare the hashed and stored passwords.
if err = bcrypt.CompareHashAndPassword(usr.Pass, []byte(p)); err != nil {
return nil, fibre.NewHTTPError(403).WithFields(map[string]interface{}{
"ns": n,
"nu": u,
}).WithMessage("Database signin was unsuccessful")
}
return
}
func signinNS(n, u, p string) (usr *sql.DefineLoginStatement, err error) {
var txn kvs.TX
// Start a new read transaction.
if txn, err = db.Begin(false); err != nil {
return nil, fibre.NewHTTPError(500)
}
// Ensure the transaction closes.
defer txn.Cancel()
// Get the specified user and password.
if len(u) == 0 || len(p) == 0 {
return nil, fibre.NewHTTPError(403).WithFields(map[string]interface{}{
"ns": n,
"nu": u,
}).WithMessage("Database signin was unsuccessful")
}
// Get the specified namespace login.
if usr, err = mem.NewWithTX(txn).GetNU(n, u); err != nil {
return nil, fibre.NewHTTPError(403).WithFields(map[string]interface{}{
"ns": n,
"nu": u,
}).WithMessage("Namespace login does not exist")
}
// Compare the hashed and stored passwords.
if err = bcrypt.CompareHashAndPassword(usr.Pass, []byte(p)); err != nil {
return nil, fibre.NewHTTPError(403).WithFields(map[string]interface{}{
"ns": n,
"nu": u,
}).WithMessage("Namespace signin was unsuccessful")
}
return
}

View file

@ -16,10 +16,12 @@ package web
import (
"github.com/abcum/fibre"
"github.com/abcum/surreal/cnf"
"github.com/abcum/surreal/db"
"github.com/abcum/surreal/kvs"
"github.com/abcum/surreal/mem"
"github.com/abcum/surreal/sql"
"github.com/abcum/surreal/util/data"
)
func signup(c *fibre.Context) (err error) {
@ -28,9 +30,21 @@ func signup(c *fibre.Context) (err error) {
c.Bind(&vars)
n, nok := vars["NS"].(string)
d, dok := vars["DB"].(string)
s, sok := vars["SC"].(string)
n, nok := vars[varKeyNs].(string)
d, dok := vars[varKeyDb].(string)
s, sok := vars[varKeySc].(string)
// Ensure that the IP address of the
// user signing up is available so that
// it can be used within signup queries.
vars[varKeyIp] = c.IP().String()
// Ensure that the website origin of the
// user signing up is available so that
// it can be used within signup queries.
vars[varKeyOrigin] = c.Origin()
// If we have a namespace, database, and
// scope defined, then we are logging in
@ -38,8 +52,10 @@ func signup(c *fibre.Context) (err error) {
if nok && len(n) > 0 && dok && len(d) > 0 && sok && len(s) > 0 {
var ok bool
var txn kvs.TX
var res []*db.Response
var exp *sql.SubExpression
var scp *sql.DefineScopeStatement
// Start a new read transaction.
@ -54,7 +70,7 @@ func signup(c *fibre.Context) (err error) {
// Get the specified signin scope.
if scp, err = mem.New(txn).GetSC(n, d, s); err != nil {
if scp, err = mem.NewWithTX(txn).GetSC(n, d, s); err != nil {
return fibre.NewHTTPError(403).WithFields(map[string]interface{}{
"ns": n,
"db": d,
@ -62,19 +78,9 @@ func signup(c *fibre.Context) (err error) {
}).WithMessage("Authentication scope does not exist")
}
// Process the scope signup statement.
// Check that the scope allows signup.
qury := &sql.Query{Statements: []sql.Statement{scp.Signup}}
if res, err = db.Process(c, qury, vars); err != nil {
return fibre.NewHTTPError(501).WithFields(map[string]interface{}{
"ns": n,
"db": d,
"sc": s,
}).WithMessage("Authentication scope signup was unsuccessful")
}
if len(res) != 1 && len(res[0].Result) != 1 {
if exp, ok = scp.Signup.(*sql.SubExpression); !ok {
return fibre.NewHTTPError(403).WithFields(map[string]interface{}{
"ns": n,
"db": d,
@ -82,10 +88,46 @@ func signup(c *fibre.Context) (err error) {
}).WithMessage("Authentication scope signup was unsuccessful")
}
return c.Code(200)
// Process the scope signup statement.
c.Set(varKeyAuth, &cnf.Auth{Kind: cnf.AuthDB})
query := &sql.Query{Statements: []sql.Statement{exp.Expr}}
// If the query fails then return a 501 error.
if res, err = db.Process(c, query, vars); err != nil {
return fibre.NewHTTPError(501).WithFields(map[string]interface{}{
"ns": n,
"db": d,
"sc": s,
}).WithMessage("Authentication scope signup was unsuccessful")
}
// If the response is not 1 record then return a 403 error.
if len(res) != 1 || len(res[0].Result) != 1 {
return fibre.NewHTTPError(403).WithFields(map[string]interface{}{
"ns": n,
"db": d,
"sc": s,
}).WithMessage("Authentication scope signup was unsuccessful")
}
// If the query does not return an id field then return a 403 error.
if _, ok = data.Consume(res[0].Result[0]).Get("id").Data().(*sql.Thing); !ok {
return fibre.NewHTTPError(403).WithFields(map[string]interface{}{
"ns": n,
"db": d,
"sc": s,
}).WithMessage("Authentication scope signup was unsuccessful")
}
return c.Code(204)
}
return fibre.NewHTTPError(401)
return fibre.NewHTTPError(403)
}