Improve rpc authentication methods
This commit is contained in:
parent
c47fe55ffb
commit
2249086887
3 changed files with 149 additions and 38 deletions
38
web/rpc.go
38
web/rpc.go
|
@ -25,26 +25,38 @@ import (
|
|||
|
||||
type rpc struct{}
|
||||
|
||||
// --------------------------------------------------
|
||||
// Methods for authentication
|
||||
// --------------------------------------------------
|
||||
|
||||
func (r *rpc) Uniq(c *fibre.Context) (interface{}, error) {
|
||||
return rand.String(128), nil
|
||||
return rand.String(64), nil
|
||||
}
|
||||
|
||||
func (r *rpc) Info(c *fibre.Context) (interface{}, error) {
|
||||
return c.Get("auth").(*cnf.Auth).Data, nil
|
||||
}
|
||||
|
||||
func (r *rpc) Auth(c *fibre.Context, auth string) (interface{}, error) {
|
||||
return c.Get("auth").(*cnf.Auth).Data, checkBearer(c, auth, ignore)
|
||||
func (r *rpc) Signup(c *fibre.Context, vars map[string]interface{}) (interface{}, error) {
|
||||
return signupRpc(c, vars)
|
||||
}
|
||||
|
||||
func (r *rpc) Let(c *fibre.Context, key string, val interface{}) (interface{}, error) {
|
||||
return c.Get("keep").(*data.Doc).Set(val, key)
|
||||
func (r *rpc) Signin(c *fibre.Context, vars map[string]interface{}) (interface{}, error) {
|
||||
return signinRpc(c, vars)
|
||||
}
|
||||
|
||||
func (r *rpc) Query(c *fibre.Context, sql string, vars map[string]interface{}) (interface{}, error) {
|
||||
return db.Execute(c, sql, vars)
|
||||
func (r *rpc) Invalidate(c *fibre.Context) (interface{}, error) {
|
||||
return c.Get("auth").(*cnf.Auth).Reset().Data, nil
|
||||
}
|
||||
|
||||
func (r *rpc) Authenticate(c *fibre.Context, auth string) (interface{}, error) {
|
||||
return c.Get("auth").(*cnf.Auth).Reset().Data, checkBearer(c, auth, ignore)
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// Methods for live queries
|
||||
// --------------------------------------------------
|
||||
|
||||
func (r *rpc) Kill(c *fibre.Context, query string) (interface{}, error) {
|
||||
return db.Execute(c, "KILL $query", map[string]interface{}{
|
||||
"query": query,
|
||||
|
@ -57,6 +69,18 @@ func (r *rpc) Live(c *fibre.Context, class string) (interface{}, error) {
|
|||
})
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// Methods for static queries
|
||||
// --------------------------------------------------
|
||||
|
||||
func (r *rpc) Let(c *fibre.Context, key string, val interface{}) (interface{}, error) {
|
||||
return c.Get("keep").(*data.Doc).Set(val, key)
|
||||
}
|
||||
|
||||
func (r *rpc) Query(c *fibre.Context, sql string, vars map[string]interface{}) (interface{}, error) {
|
||||
return db.Execute(c, sql, vars)
|
||||
}
|
||||
|
||||
func (r *rpc) Select(c *fibre.Context, class string, thing interface{}) (interface{}, error) {
|
||||
switch thing := thing.(type) {
|
||||
case *fibre.RPCNull:
|
||||
|
|
|
@ -34,6 +34,37 @@ func signin(c *fibre.Context) (err error) {
|
|||
|
||||
c.Bind(&vars)
|
||||
|
||||
str, err := signinInternal(c, vars)
|
||||
|
||||
switch err {
|
||||
case nil:
|
||||
return c.Send(200, str)
|
||||
default:
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func signinRpc(c *fibre.Context, vars map[string]interface{}) (res interface{}, err error) {
|
||||
|
||||
var str string
|
||||
|
||||
str, err = signinInternal(c, vars)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = checkBearer(c, str, ignore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return str, nil
|
||||
|
||||
}
|
||||
|
||||
func signinInternal(c *fibre.Context, vars map[string]interface{}) (str string, err error) {
|
||||
|
||||
n, nok := vars[varKeyNs].(string)
|
||||
d, dok := vars[varKeyDb].(string)
|
||||
s, sok := vars[varKeySc].(string)
|
||||
|
@ -58,7 +89,6 @@ func signin(c *fibre.Context) (err error) {
|
|||
|
||||
var ok bool
|
||||
var txn kvs.TX
|
||||
var str string
|
||||
var doc *sql.Thing
|
||||
var res []*db.Response
|
||||
var exp *sql.SubExpression
|
||||
|
@ -67,7 +97,7 @@ func signin(c *fibre.Context) (err error) {
|
|||
// Start a new read transaction.
|
||||
|
||||
if txn, err = db.Begin(false); err != nil {
|
||||
return fibre.NewHTTPError(500)
|
||||
return str, fibre.NewHTTPError(500)
|
||||
}
|
||||
|
||||
// Ensure the transaction closes.
|
||||
|
@ -82,14 +112,14 @@ func signin(c *fibre.Context) (err error) {
|
|||
|
||||
if scp, err = mem.NewWithTX(txn).GetSC(n, d, s); err != nil {
|
||||
m := "Authentication scope does not exist"
|
||||
return fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
}
|
||||
|
||||
// Check that the scope allows signin.
|
||||
|
||||
if exp, ok = scp.Signin.(*sql.SubExpression); !ok {
|
||||
m := "Authentication scope does not allow signin"
|
||||
return fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
}
|
||||
|
||||
// Process the scope signin statement.
|
||||
|
@ -102,35 +132,35 @@ func signin(c *fibre.Context) (err error) {
|
|||
|
||||
if res, err = db.Process(c, query, vars); err != nil {
|
||||
m := "Authentication scope signin was unsuccessful: Query failed"
|
||||
return fibre.NewHTTPError(501).WithFields(f).WithMessage(m)
|
||||
return str, fibre.NewHTTPError(501).WithFields(f).WithMessage(m)
|
||||
}
|
||||
|
||||
// If the response is not 1 record then return a 403 error.
|
||||
|
||||
if len(res) != 1 {
|
||||
m := "Authentication scope signin was unsuccessful: Query failed"
|
||||
return fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
}
|
||||
|
||||
// If the response has an error set then return a 403 error.
|
||||
|
||||
if res[0].Status != "OK" {
|
||||
m := "Authentication scope signin was unsuccessful: " + res[0].Detail
|
||||
return fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
}
|
||||
|
||||
// If the response has no record set then return a 403 error.
|
||||
|
||||
if len(res[0].Result) != 1 {
|
||||
m := "Authentication scope signin was unsuccessful: No record returned"
|
||||
return fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
m := "Authentication scope signin was unsuccessful: No id field found"
|
||||
return fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
}
|
||||
|
||||
// Create a new token signer with the default claims.
|
||||
|
@ -152,10 +182,10 @@ func signin(c *fibre.Context) (err error) {
|
|||
|
||||
if str, err = signr.SignedString(scp.Code); err != nil {
|
||||
m := "Problem with signing method: " + err.Error()
|
||||
return fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
}
|
||||
|
||||
return c.Send(200, str)
|
||||
return str, err
|
||||
|
||||
}
|
||||
|
||||
|
@ -181,13 +211,13 @@ func signin(c *fibre.Context) (err error) {
|
|||
|
||||
if !uok || !pok {
|
||||
m := "Username or password is missing"
|
||||
return fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
}
|
||||
|
||||
// Start a new read transaction.
|
||||
|
||||
if usr, err = signinDB(n, d, u, p); err != nil {
|
||||
return err
|
||||
return str, err
|
||||
}
|
||||
|
||||
// Create a new token signer with the default claims.
|
||||
|
@ -207,10 +237,10 @@ func signin(c *fibre.Context) (err error) {
|
|||
|
||||
if str, err = signr.SignedString(usr.Code); err != nil {
|
||||
m := "Problem with signing method: " + err.Error()
|
||||
return fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
}
|
||||
|
||||
return c.Send(200, str)
|
||||
return str, err
|
||||
|
||||
}
|
||||
|
||||
|
@ -236,11 +266,11 @@ func signin(c *fibre.Context) (err error) {
|
|||
|
||||
if !uok || !pok {
|
||||
m := "Username or password is missing"
|
||||
return fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
}
|
||||
|
||||
if usr, err = signinNS(n, u, p); err != nil {
|
||||
return err
|
||||
return str, err
|
||||
}
|
||||
|
||||
// Create a new token signer with the default claims.
|
||||
|
@ -259,14 +289,14 @@ func signin(c *fibre.Context) (err error) {
|
|||
|
||||
if str, err = signr.SignedString(usr.Code); err != nil {
|
||||
m := "Problem with signing method: " + err.Error()
|
||||
return fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
}
|
||||
|
||||
return c.Send(200, str)
|
||||
return str, err
|
||||
|
||||
}
|
||||
|
||||
return fibre.NewHTTPError(403)
|
||||
return str, fibre.NewHTTPError(403)
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
package web
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/abcum/fibre"
|
||||
"github.com/abcum/surreal/cnf"
|
||||
"github.com/abcum/surreal/db"
|
||||
|
@ -22,6 +24,7 @@ import (
|
|||
"github.com/abcum/surreal/mem"
|
||||
"github.com/abcum/surreal/sql"
|
||||
"github.com/abcum/surreal/util/data"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
)
|
||||
|
||||
func signup(c *fibre.Context) (err error) {
|
||||
|
@ -30,6 +33,37 @@ func signup(c *fibre.Context) (err error) {
|
|||
|
||||
c.Bind(&vars)
|
||||
|
||||
str, err := signinInternal(c, vars)
|
||||
|
||||
switch err {
|
||||
case nil:
|
||||
return c.Send(200, str)
|
||||
default:
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func signupRpc(c *fibre.Context, vars map[string]interface{}) (res interface{}, err error) {
|
||||
|
||||
var str string
|
||||
|
||||
str, err = signupInternal(c, vars)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = checkBearer(c, str, ignore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return str, nil
|
||||
|
||||
}
|
||||
|
||||
func signupInternal(c *fibre.Context, vars map[string]interface{}) (str string, err error) {
|
||||
|
||||
n, nok := vars[varKeyNs].(string)
|
||||
d, dok := vars[varKeyDb].(string)
|
||||
s, sok := vars[varKeySc].(string)
|
||||
|
@ -54,6 +88,7 @@ func signup(c *fibre.Context) (err error) {
|
|||
|
||||
var ok bool
|
||||
var txn kvs.TX
|
||||
var doc *sql.Thing
|
||||
var res []*db.Response
|
||||
var exp *sql.SubExpression
|
||||
var scp *sql.DefineScopeStatement
|
||||
|
@ -61,7 +96,7 @@ func signup(c *fibre.Context) (err error) {
|
|||
// Start a new read transaction.
|
||||
|
||||
if txn, err = db.Begin(false); err != nil {
|
||||
return fibre.NewHTTPError(500)
|
||||
return str, fibre.NewHTTPError(500)
|
||||
}
|
||||
|
||||
// Ensure the transaction closes.
|
||||
|
@ -76,14 +111,14 @@ func signup(c *fibre.Context) (err error) {
|
|||
|
||||
if scp, err = mem.NewWithTX(txn).GetSC(n, d, s); err != nil {
|
||||
m := "Authentication scope does not exist"
|
||||
return fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
}
|
||||
|
||||
// Check that the scope allows signup.
|
||||
|
||||
if exp, ok = scp.Signup.(*sql.SubExpression); !ok {
|
||||
m := "Authentication scope does not allow signup"
|
||||
return fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
}
|
||||
|
||||
// Process the scope signup statement.
|
||||
|
@ -96,41 +131,63 @@ func signup(c *fibre.Context) (err error) {
|
|||
|
||||
if res, err = db.Process(c, query, vars); err != nil {
|
||||
m := "Authentication scope signup was unsuccessful: Query failed"
|
||||
return fibre.NewHTTPError(501).WithFields(f).WithMessage(m)
|
||||
return str, fibre.NewHTTPError(501).WithFields(f).WithMessage(m)
|
||||
}
|
||||
|
||||
// If the response is not 1 record then return a 403 error.
|
||||
|
||||
if len(res) != 1 {
|
||||
m := "Authentication scope signup was unsuccessful: Query failed"
|
||||
return fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
}
|
||||
|
||||
// If the response has an error set then return a 403 error.
|
||||
|
||||
if res[0].Status != "OK" {
|
||||
m := "Authentication scope signin was unsuccessful: " + res[0].Detail
|
||||
return fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
}
|
||||
|
||||
// If the response has no record set then return a 403 error.
|
||||
|
||||
if len(res[0].Result) != 1 {
|
||||
m := "Authentication scope signup was unsuccessful: No record created"
|
||||
return fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if doc, ok = data.Consume(res[0].Result[0]).Get("id").Data().(*sql.Thing); !ok {
|
||||
m := "Authentication scope signup was unsuccessful: No id field found"
|
||||
return fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
}
|
||||
|
||||
return c.Code(204)
|
||||
// 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(),
|
||||
"TB": doc.TB,
|
||||
"ID": doc.ID,
|
||||
})
|
||||
|
||||
// Try to create the final signed token as a string.
|
||||
|
||||
if str, err = signr.SignedString(scp.Code); err != nil {
|
||||
m := "Problem with signing method: " + err.Error()
|
||||
return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m)
|
||||
}
|
||||
|
||||
return str, err
|
||||
|
||||
}
|
||||
|
||||
return fibre.NewHTTPError(403)
|
||||
return str, fibre.NewHTTPError(403)
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue