Fix bug with remote join example

This commit is contained in:
Vikram Rangnekar 2019-12-02 23:08:35 -05:00
parent 3a14a644ce
commit 679dd1fc83
4 changed files with 31 additions and 21 deletions

View File

@ -1042,11 +1042,18 @@ We can get the JWT token either from the `authorization` header where we expect
For validation a `secret` or a public key (ecdsa or rsa) is required. When using public keys they have to be in a PEM format file.
## Role based Access Control
## Access Control
It's a common usecase for APIs to control what information they return or insert based on the role of the user. For example when fetching a list of users, a normal user can only fetch his own entry while a manager can fetch all the users within a company and an admin user can fetch everyone. Or when creating a new user an an admin user can set a users role while the user himself cannot set or change it. This is called role based access control or RBAC.
It's common for APIs to control what information they return or insert based on the role of the user. In Super Graph we have two primary roles `user` and `anon` the first for users where a `user_id` is available the latter for users where it's not.
::: tip
An authenticated request is one where Super Graph can extract an `user_id` based on the configured authentication method (jwt, rails cookies, etc).
:::
The `user` role can be divided up into further roles based on attributes in the database. For example when fetching a list of users, a normal user can only fetch his own entry while an admin can fetch all the users within a company and an admin user can fetch everyone. In some places this is called Attribute based access control. So in way we support both. Role based access control and Attribute based access control.
Super Graph allows you to create roles dynamically using a `roles_query` and ` match` config values.
Super Graph allows you to set access control rules based on dynamically defined roles. You can create as many roles as you wish. The only two default (built-in) roles are `user` for authenticated requests and `anon` for unauthenticated. An authenticated request is one where Super Graph can extract an `user_id` based on the configured authenication method (jwt, rails cookies, etc).
### Configure RBAC
@ -1085,8 +1092,7 @@ roles:
filters: []
```
This configuration is relatively simple to follow the `roles_query` parameter is the query that
must be run to help figure out a users role. This query can be as complex as you like and include joins with other tables.
This configuration is relatively simple to follow the `roles_query` parameter is the query that must be run to help figure out a users role. This query can be as complex as you like and include joins with other tables.
The individual roles are defined under the `roles` parameter and this includes each table the role has a custom setting for. The role is dynamically matched using the `match` parameter for example in the above case `users.id = 1` means that when the `roles_query` is executed a user with the id `1` willbe assigned the admin role and those that don't match get the `user` role if authenticated successfully or the `anon` role.

View File

@ -63,4 +63,6 @@ Rails.application.configure do
config.web_console.whitelisted_ips = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16']
config.hosts << "rails_app"
end

View File

@ -81,14 +81,14 @@ func (c *coreContext) resolvePreparedSQL() ([]byte, *stmt, error) {
useTx := useRoleQuery || conf.DB.SetUserID
if useTx {
if tx, err = db.Begin(context.Background()); err != nil {
if tx, err = db.Begin(c.Context); err != nil {
return nil, nil, err
}
defer tx.Rollback(c) //nolint: errcheck
}
if conf.DB.SetUserID {
if err := setLocalUserID(c, tx); err != nil {
if err := setLocalUserID(c.Context, tx); err != nil {
return nil, nil, err
}
}
@ -122,9 +122,9 @@ func (c *coreContext) resolvePreparedSQL() ([]byte, *stmt, error) {
}
if useTx {
row = tx.QueryRow(context.Background(), ps.sd.SQL, vars...)
row = tx.QueryRow(c.Context, ps.sd.SQL, vars...)
} else {
row = db.QueryRow(context.Background(), ps.sd.SQL, vars...)
row = db.QueryRow(c.Context, ps.sd.SQL, vars...)
}
if mutation || anonQuery {
@ -146,7 +146,7 @@ func (c *coreContext) resolvePreparedSQL() ([]byte, *stmt, error) {
c.req.role = role
if useTx {
if err := tx.Commit(context.Background()); err != nil {
if err := tx.Commit(c.Context); err != nil {
return nil, nil, err
}
}
@ -166,14 +166,14 @@ func (c *coreContext) resolveSQL() ([]byte, *stmt, error) {
useTx := useRoleQuery || conf.DB.SetUserID
if useTx {
if tx, err = db.Begin(context.Background()); err != nil {
if tx, err = db.Begin(c.Context); err != nil {
return nil, nil, err
}
defer tx.Rollback(context.Background()) //nolint: errcheck
defer tx.Rollback(c.Context) //nolint: errcheck
}
if conf.DB.SetUserID {
if err := setLocalUserID(c, tx); err != nil {
if err := setLocalUserID(c.Context, tx); err != nil {
return nil, nil, err
}
}
@ -215,9 +215,9 @@ func (c *coreContext) resolveSQL() ([]byte, *stmt, error) {
defaultRole := c.req.role
if useTx {
row = tx.QueryRow(context.Background(), finalSQL)
row = tx.QueryRow(c.Context, finalSQL)
} else {
row = db.QueryRow(context.Background(), finalSQL)
row = db.QueryRow(c.Context, finalSQL)
}
if len(stmts) == 1 {
@ -237,7 +237,7 @@ func (c *coreContext) resolveSQL() ([]byte, *stmt, error) {
}
if useTx {
if err := tx.Commit(context.Background()); err != nil {
if err := tx.Commit(c.Context); err != nil {
return nil, nil, err
}
}
@ -263,7 +263,7 @@ func (c *coreContext) resolveSQL() ([]byte, *stmt, error) {
func (c *coreContext) executeRoleQuery(tx pgx.Tx) (string, error) {
var role string
row := tx.QueryRow(context.Background(), "_sg_get_role", c.req.role, 1)
row := tx.QueryRow(c.Context, "_sg_get_role", c.req.role, 1)
if err := row.Scan(&role); err != nil {
return "", err

View File

@ -103,6 +103,10 @@ func buildFn(r configRemote) func(http.Header, []byte) ([]byte, error) {
return nil, err
}
if host, ok := hdr["Host"]; ok {
req.Host = host[0]
}
for _, v := range r.SetHeaders {
req.Header.Set(v.Name, v.Value)
}
@ -111,9 +115,7 @@ func buildFn(r configRemote) func(http.Header, []byte) ([]byte, error) {
req.Header.Set(v, hdr.Get(v))
}
if host, ok := hdr["Host"]; ok {
req.Host = host[0]
}
logger.Debug().Str("uri", uri).Msg("Remote Join")
res, err := client.Do(req)
if err != nil {
@ -133,7 +135,7 @@ func buildFn(r configRemote) func(http.Header, []byte) ([]byte, error) {
return nil, err
}
logger.Warn().Msgf("Remote Request Debug:\n%s\n%s",
logger.Debug().Msgf("Remote Request Debug:\n%s\n%s",
reqDump, resDump)
}