Skip to content

Commit

Permalink
Unbeta permission (#673)
Browse files Browse the repository at this point in the history
* beta_granted_permissions -> granted_permissions

* betaGrantedPermissions -> grantedPermissions

* request.BetaGrantedPermissions -> request.GrantedPermissions

* beta_required_permission -> required_permission

* betaRequiredPermission -> requiredPermission

* request.BetaRequiredPermission -> request.RequiredPermission

* beta_insufficient_permissions -> insufficient_permissions, errors.BetaInsufficientPermissions -> errors.InsufficientPermissions

* beta_permissions_map_file -> permissions_map_file

* beta_permissions_map -> permissions_map

* beta_permissions_claim -> permissions_claim

* beta_roles_map_file -> roles_map_file

* beta_roles_map -> roles_map

* beta_roles_claim -> roles_claim

* changelog entry

Co-authored-by: Marcel Ludwig <[email protected]>
  • Loading branch information
johakoch and malud authored Jan 27, 2023
1 parent 5c732dd commit 4bea282
Show file tree
Hide file tree
Showing 32 changed files with 253 additions and 248 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,15 @@ Unreleased changes are available as `avenga/couper:edge` container.
* Use nested `jwt_signing_profile` block in [`oauth2` block](https://docs.couper.io/configuration/block/oauth2) for `grant_type` `"urn:ietf:params:oauth:grant-type:jwt-bearer"` in absence of `assertion` attribute ([#619](https://github.com/avenga/couper/pull/619))
* Improved the way an SPA `bootstrap_file` gets cached and served in combination with `bootstrap_data` ([#656](https://github.com/avenga/couper/pull/656))
* Harmonized and improved logged error information for references to undefined blocks ([#651](https://github.com/avenga/couper/pull/651))
* Unbeta permission features: ([#673](https://github.com/avenga/couper/pull/673))
* `beta_required_permission` attribute for [`api`](https://docs.couper.io/configuration/block/api#attribute-beta_required_permission) and [`endpoint`](https://docs.couper.io/configuration/block/endpoint#attribute-beta_required_permission) blocks,
* `beta_granted_permissions` and `beta_required_permission` [request context variables](https://docs.couper.io/configuration/variables#request),
* `beta_insufficient_permissions` [error type](https://docs.couper.io/configuration/error-handling/#api-error-types),
* `beta_permissions_claim`, `beta_permissions_map`, `beta_permissions_map_file`, `beta_roles_claim`, `beta_roles_map` and `beta_roles_map_file` attributes for [`jwt` block](https://docs.couper.io/configuration/block/jwt#attributes).

* **Fixed**
* Loop with evaluation error in [`custom_log_fields`](https://docs.couper.io/observation/logging#custom-logging) if log level is `"debug"` ([#659](https://github.com/avenga/couper/pull/659))
* Use of [backend-related variables](https://docs.couper.io/configuration/variables#backend) in [`custom_log_fields`](https://docs.couper.io/observation/logging#custom-logging) within a [`backend` block](https://docs.couper.io/configuration/block/backend) ([#658](https://github.com/avenga/couper/pull/658))
* Loop with evaluation error in [`custom_log_fields`](https://docs.couper.io/observation/logging#custom-logging) if log level is `"debug"` ([#659](https://github.com/avenga/couper/pull/659))

---

Expand Down
6 changes: 3 additions & 3 deletions accesscontrol/jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ func newJWT(options *JWTOptions) (*JWT, error) {
}

if options.RolesClaim != "" && options.RolesMap == nil {
return nil, fmt.Errorf("missing beta_roles_map")
return nil, fmt.Errorf("missing roles_map")
}

jwtAC := &JWT{
Expand Down Expand Up @@ -257,11 +257,11 @@ func (j *JWT) Validate(req *http.Request) error {
log := req.Context().Value(request.LogEntry).(*logrus.Entry).WithContext(req.Context())
jwtGrantedPermissions := j.getGrantedPermissions(tokenClaims, log)

grantedPermissions, _ := ctx.Value(request.BetaGrantedPermissions).([]string)
grantedPermissions, _ := ctx.Value(request.GrantedPermissions).([]string)

grantedPermissions = append(grantedPermissions, jwtGrantedPermissions...)

ctx = context.WithValue(ctx, request.BetaGrantedPermissions, grantedPermissions)
ctx = context.WithValue(ctx, request.GrantedPermissions, grantedPermissions)

*req = *req.WithContext(ctx)

Expand Down
22 changes: 11 additions & 11 deletions accesscontrol/jwt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ func Test_JWT_yields_permissions(t *testing.T) {
return
}

grantedPermissionsList, ok := req.Context().Value(request.BetaGrantedPermissions).([]string)
grantedPermissionsList, ok := req.Context().Value(request.GrantedPermissions).([]string)
if !ok {
subT.Errorf("Expected granted permissions within request context")
} else {
Expand Down Expand Up @@ -715,62 +715,62 @@ func TestJwtConfig(t *testing.T) {
"configuration error: myac: jwt key: read error: configured attribute and file",
},
{
"signature_algorithm, both beta_roles_map and beta_roles_map_file",
"signature_algorithm, both roles_map and roles_map_file",
`
server "test" {}
definitions {
jwt "myac" {
signature_algorithm = "HS256"
header = "..."
key = "..."
beta_roles_map = {}
beta_roles_map_file = "testdata/map.json"
roles_map = {}
roles_map_file = "testdata/map.json"
}
}
`,
"configuration error: myac: jwt roles map: read error: configured attribute and file",
},
{
"signature_algorithm, beta_roles_map_file not found",
"signature_algorithm, roles_map_file not found",
`
server "test" {}
definitions {
jwt "myac" {
signature_algorithm = "HS256"
header = "..."
key = "..."
beta_roles_map_file = "file_not_found"
roles_map_file = "file_not_found"
}
}
`,
"configuration error: myac: roles map: read error: open .*/testdata/file_not_found: no such file or directory",
},
{
"signature_algorithm, both beta_permissions_map and beta_permissions_map_file",
"signature_algorithm, both permissions_map and permissions_map_file",
`
server "test" {}
definitions {
jwt "myac" {
signature_algorithm = "HS256"
header = "..."
key = "..."
beta_permissions_map = {}
beta_permissions_map_file = "testdata/map.json"
permissions_map = {}
permissions_map_file = "testdata/map.json"
}
}
`,
"configuration error: myac: jwt permissions map: read error: configured attribute and file",
},
{
"signature_algorithm, beta_permissions_map_file not found",
"signature_algorithm, permissions_map_file not found",
`
server "test" {}
definitions {
jwt "myac" {
signature_algorithm = "HS256"
header = "..."
key = "..."
beta_permissions_map_file = "file_not_found"
permissions_map_file = "file_not_found"
}
}
`,
Expand Down
10 changes: 5 additions & 5 deletions accesscontrol/permissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (r *requiredPermissions) getPermission(method string) (string, error) {

permission, exists := r.permissions[method]
if !exists {
return "", errors.MethodNotAllowed.Messagef("method %s not allowed by beta_required_permission", method)
return "", errors.MethodNotAllowed.Messagef("method %s not allowed by required_permission", method)
}
return permission, nil
}
Expand Down Expand Up @@ -93,18 +93,18 @@ func (p *PermissionsControl) Validate(req *http.Request) error {
}

ctx := req.Context()
ctx = context.WithValue(ctx, request.BetaRequiredPermission, requiredPermission)
ctx = context.WithValue(ctx, request.RequiredPermission, requiredPermission)
*req = *req.WithContext(ctx)

evalCtx := eval.ContextFromRequest(req)
*req = *req.WithContext(evalCtx.WithClientRequest(req))

grantedPermission, ok := ctx.Value(request.BetaGrantedPermissions).([]string)
grantedPermission, ok := ctx.Value(request.GrantedPermissions).([]string)
if !ok {
return errors.BetaInsufficientPermissions.Messagef("no permissions granted")
return errors.InsufficientPermissions.Messagef("no permissions granted")
}
if !hasGrantedPermission(grantedPermission, requiredPermission) {
return errors.BetaInsufficientPermissions.Messagef("required permission %q not granted", requiredPermission)
return errors.InsufficientPermissions.Messagef("required permission %q not granted", requiredPermission)
}
return nil
}
Expand Down
10 changes: 5 additions & 5 deletions accesscontrol/permissions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,15 @@ func Test_PermissionsControl(t *testing.T) {
map[string]string{},
http.MethodGet,
nil,
"method not allowed error: method GET not allowed by beta_required_permission",
"method not allowed error: method GET not allowed by required_permission",
},
{
"no method permitted, permission granted",
"",
map[string]string{},
http.MethodPost,
[]string{"read"},
"method not allowed error: method POST not allowed by beta_required_permission",
"method not allowed error: method POST not allowed by required_permission",
},
{
"method permitted, no permission required, no permission granted",
Expand Down Expand Up @@ -184,15 +184,15 @@ func Test_PermissionsControl(t *testing.T) {
map[string]string{"*": "read"},
"BREW",
[]string{"read"},
"method not allowed error: method BREW not allowed by beta_required_permission",
"method not allowed error: method BREW not allowed by required_permission",
},
{
"standard method not allowed",
"",
map[string]string{http.MethodGet: ""},
http.MethodPost,
nil,
"method not allowed error: method POST not allowed by beta_required_permission",
"method not allowed error: method POST not allowed by required_permission",
},
{
"method permitted, permission required, no permissions granted",
Expand Down Expand Up @@ -256,7 +256,7 @@ func Test_PermissionsControl(t *testing.T) {
req := httptest.NewRequest(tt.method, "/", nil)
if tt.grantedPermissions != nil {
ctx := req.Context()
ctx = context.WithValue(ctx, request.BetaGrantedPermissions, tt.grantedPermissions)
ctx = context.WithValue(ctx, request.GrantedPermissions, tt.grantedPermissions)
*req = *req.WithContext(ctx)
}
err := pc.Validate(req)
Expand Down
12 changes: 6 additions & 6 deletions config/ac_jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ type JWT struct {
KeyFile string `hcl:"key_file,optional" docs:"Reference to file containing verification key. Mutually exclusive with {key}. See {key} for more information."`
Name string `hcl:"name,label"`
Remain hcl.Body `hcl:",remain"`
RolesClaim string `hcl:"beta_roles_claim,optional" docs:"Name of claim specifying the roles of the user represented by the token. The claim value must either be a string containing a space-separated list of role values or a list of string role values."`
RolesMap map[string][]string `hcl:"beta_roles_map,optional" docs:"Mapping of roles to granted permissions. Non-mapped roles can be assigned with {*} to specific permissions. Mutually exclusive with {beta_roles_map_file}."`
RolesMapFile string `hcl:"beta_roles_map_file,optional" docs:"Reference to JSON file containing role mappings. Mutually exclusive with {beta_roles_map}. See {beta_roles_map} for more information."`
PermissionsClaim string `hcl:"beta_permissions_claim,optional" docs:"Name of claim containing the granted permissions. The claim value must either be a string containing a space-separated list of permissions or a list of string permissions."`
PermissionsMap map[string][]string `hcl:"beta_permissions_map,optional" docs:"Mapping of granted permissions to additional granted permissions. Maps values from {beta_permissions_claim} and those created from {beta_roles_map}. The map is called recursively. Mutually exclusive with {beta_permissions_map_file}."`
PermissionsMapFile string `hcl:"beta_permissions_map_file,optional" docs:"Reference to JSON file containing permission mappings. Mutually exclusive with {beta_permissions_map}. See {beta_permissions_map} for more information."`
RolesClaim string `hcl:"roles_claim,optional" docs:"Name of claim specifying the roles of the user represented by the token. The claim value must either be a string containing a space-separated list of role values or a list of string role values."`
RolesMap map[string][]string `hcl:"roles_map,optional" docs:"Mapping of roles to granted permissions. Non-mapped roles can be assigned with {*} to specific permissions. Mutually exclusive with {roles_map_file}."`
RolesMapFile string `hcl:"roles_map_file,optional" docs:"Reference to JSON file containing role mappings. Mutually exclusive with {roles_map}. See {roles_map} for more information."`
PermissionsClaim string `hcl:"permissions_claim,optional" docs:"Name of claim containing the granted permissions. The claim value must either be a string containing a space-separated list of permissions or a list of string permissions."`
PermissionsMap map[string][]string `hcl:"permissions_map,optional" docs:"Mapping of granted permissions to additional granted permissions. Maps values from {permissions_claim} and those created from {roles_map}. The map is called recursively. Mutually exclusive with {permissions_map_file}."`
PermissionsMapFile string `hcl:"permissions_map_file,optional" docs:"Reference to JSON file containing permission mappings. Mutually exclusive with {permissions_map}. See {permissions_map} for more information."`
SignatureAlgorithm string `hcl:"signature_algorithm,optional" docs:"Valid values: {RS256}, {RS384}, {RS512}, {HS256}, {HS384}, {HS512}, {ES256}, {ES384}, {ES512}"`
SigningKey string `hcl:"signing_key,optional" docs:"Private key (in PEM format) for {RS*} and {ES*} variants. Mutually exclusive with {signing_key_file}."`
SigningKeyFile string `hcl:"signing_key_file,optional" docs:"Reference to file containing signing key. Mutually exclusive with {signing_key}. See {signing_key} for more information."`
Expand Down
2 changes: 1 addition & 1 deletion config/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func (a API) Inline() interface{} {
type Inline struct {
meta.ResponseHeadersAttributes
meta.LogFieldsAttribute
RequiredPermission hcl.Expression `hcl:"beta_required_permission,optional" docs:"Permission required to use this API (see [error type](/configuration/error-handling#error-types) {beta_insufficient_permissions})." type:"string or object (string)"`
RequiredPermission hcl.Expression `hcl:"required_permission,optional" docs:"Permission required to use this API (see [error type](/configuration/error-handling#error-types) {insufficient_permissions})." type:"string or object (string)"`
}

return &Inline{}
Expand Down
2 changes: 1 addition & 1 deletion config/configload/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func refineEndpoints(helper *helper, endpoints config.Endpoints, checkPathPatter
}
}

rp := endpointBody.Attributes["beta_required_permission"]
rp := endpointBody.Attributes["required_permission"]
if rp != nil {
ep.RequiredPermission = rp.Expr
}
Expand Down
2 changes: 1 addition & 1 deletion config/configload/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ func LoadConfig(body *hclsyntax.Body) (*config.Couper, error) {
return nil, err
}

rp := apiBody.Attributes["beta_required_permission"]
rp := apiBody.Attributes["required_permission"]
if rp != nil {
apiConfig.RequiredPermission = rp.Expr
}
Expand Down
2 changes: 1 addition & 1 deletion config/configload/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ func completeSchemaComponents(body hcl.Body, schema *hcl.BodySchema,

keyName := seetie.ValueToString(k)
switch name {
case "add_request_headers", "add_response_headers", "beta_required_permission", "headers", "set_request_headers", "set_response_headers":
case "add_request_headers", "add_response_headers", "required_permission", "headers", "set_request_headers", "set_response_headers":
// header field names, method names: handle object keys case-insensitively
keyName = strings.ToLower(keyName)
}
Expand Down
Loading

0 comments on commit 4bea282

Please sign in to comment.