Fix bug with remote join example
This commit is contained in:
parent
3a14a644ce
commit
679dd1fc83
|
@ -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.
|
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
|
### Configure RBAC
|
||||||
|
|
||||||
|
@ -1085,8 +1092,7 @@ roles:
|
||||||
filters: []
|
filters: []
|
||||||
```
|
```
|
||||||
|
|
||||||
This configuration is relatively simple to follow the `roles_query` parameter is the query that
|
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.
|
||||||
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.
|
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.
|
||||||
|
|
||||||
|
|
|
@ -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.web_console.whitelisted_ips = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16']
|
||||||
|
|
||||||
|
config.hosts << "rails_app"
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
24
serv/core.go
24
serv/core.go
|
@ -81,14 +81,14 @@ func (c *coreContext) resolvePreparedSQL() ([]byte, *stmt, error) {
|
||||||
useTx := useRoleQuery || conf.DB.SetUserID
|
useTx := useRoleQuery || conf.DB.SetUserID
|
||||||
|
|
||||||
if useTx {
|
if useTx {
|
||||||
if tx, err = db.Begin(context.Background()); err != nil {
|
if tx, err = db.Begin(c.Context); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
defer tx.Rollback(c) //nolint: errcheck
|
defer tx.Rollback(c) //nolint: errcheck
|
||||||
}
|
}
|
||||||
|
|
||||||
if conf.DB.SetUserID {
|
if conf.DB.SetUserID {
|
||||||
if err := setLocalUserID(c, tx); err != nil {
|
if err := setLocalUserID(c.Context, tx); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,9 +122,9 @@ func (c *coreContext) resolvePreparedSQL() ([]byte, *stmt, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if useTx {
|
if useTx {
|
||||||
row = tx.QueryRow(context.Background(), ps.sd.SQL, vars...)
|
row = tx.QueryRow(c.Context, ps.sd.SQL, vars...)
|
||||||
} else {
|
} else {
|
||||||
row = db.QueryRow(context.Background(), ps.sd.SQL, vars...)
|
row = db.QueryRow(c.Context, ps.sd.SQL, vars...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if mutation || anonQuery {
|
if mutation || anonQuery {
|
||||||
|
@ -146,7 +146,7 @@ func (c *coreContext) resolvePreparedSQL() ([]byte, *stmt, error) {
|
||||||
c.req.role = role
|
c.req.role = role
|
||||||
|
|
||||||
if useTx {
|
if useTx {
|
||||||
if err := tx.Commit(context.Background()); err != nil {
|
if err := tx.Commit(c.Context); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,14 +166,14 @@ func (c *coreContext) resolveSQL() ([]byte, *stmt, error) {
|
||||||
useTx := useRoleQuery || conf.DB.SetUserID
|
useTx := useRoleQuery || conf.DB.SetUserID
|
||||||
|
|
||||||
if useTx {
|
if useTx {
|
||||||
if tx, err = db.Begin(context.Background()); err != nil {
|
if tx, err = db.Begin(c.Context); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
defer tx.Rollback(context.Background()) //nolint: errcheck
|
defer tx.Rollback(c.Context) //nolint: errcheck
|
||||||
}
|
}
|
||||||
|
|
||||||
if conf.DB.SetUserID {
|
if conf.DB.SetUserID {
|
||||||
if err := setLocalUserID(c, tx); err != nil {
|
if err := setLocalUserID(c.Context, tx); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,9 +215,9 @@ func (c *coreContext) resolveSQL() ([]byte, *stmt, error) {
|
||||||
defaultRole := c.req.role
|
defaultRole := c.req.role
|
||||||
|
|
||||||
if useTx {
|
if useTx {
|
||||||
row = tx.QueryRow(context.Background(), finalSQL)
|
row = tx.QueryRow(c.Context, finalSQL)
|
||||||
} else {
|
} else {
|
||||||
row = db.QueryRow(context.Background(), finalSQL)
|
row = db.QueryRow(c.Context, finalSQL)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(stmts) == 1 {
|
if len(stmts) == 1 {
|
||||||
|
@ -237,7 +237,7 @@ func (c *coreContext) resolveSQL() ([]byte, *stmt, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if useTx {
|
if useTx {
|
||||||
if err := tx.Commit(context.Background()); err != nil {
|
if err := tx.Commit(c.Context); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -263,7 +263,7 @@ func (c *coreContext) resolveSQL() ([]byte, *stmt, error) {
|
||||||
|
|
||||||
func (c *coreContext) executeRoleQuery(tx pgx.Tx) (string, error) {
|
func (c *coreContext) executeRoleQuery(tx pgx.Tx) (string, error) {
|
||||||
var role string
|
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 {
|
if err := row.Scan(&role); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
10
serv/reso.go
10
serv/reso.go
|
@ -103,6 +103,10 @@ func buildFn(r configRemote) func(http.Header, []byte) ([]byte, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if host, ok := hdr["Host"]; ok {
|
||||||
|
req.Host = host[0]
|
||||||
|
}
|
||||||
|
|
||||||
for _, v := range r.SetHeaders {
|
for _, v := range r.SetHeaders {
|
||||||
req.Header.Set(v.Name, v.Value)
|
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))
|
req.Header.Set(v, hdr.Get(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
if host, ok := hdr["Host"]; ok {
|
logger.Debug().Str("uri", uri).Msg("Remote Join")
|
||||||
req.Host = host[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := client.Do(req)
|
res, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -133,7 +135,7 @@ func buildFn(r configRemote) func(http.Header, []byte) ([]byte, error) {
|
||||||
return nil, err
|
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)
|
reqDump, resDump)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue