From a8d6daaa6cb938252a508290de54a05b36f507da Mon Sep 17 00:00:00 2001 From: Guilherme Cassolato Date: Mon, 25 Nov 2024 20:20:31 +0100 Subject: [PATCH 1/5] docs: Common Expression Language (CEL) Signed-off-by: Guilherme Cassolato --- docs/architecture.md | 2 +- docs/features.md | 210 ++++++++---------- ...ed-rate-limiting-envoy-dynamic-metadata.md | 4 +- .../deny-with-redirect-to-login.md | 8 +- docs/user-guides/external-metadata.md | 7 +- docs/user-guides/http-basic-authentication.md | 6 +- docs/user-guides/injecting-data.md | 9 +- .../json-pattern-matching-authorization.md | 11 +- 8 files changed, 112 insertions(+), 145 deletions(-) diff --git a/docs/architecture.md b/docs/architecture.md index 677de8ac..62eb61ac 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -286,7 +286,7 @@ After phase (iii), Authorino appends to the authorization JSON the results of th [Festival Wristbands](./features.md#festival-wristband-tokens-responsesuccessheadersdynamicmetadatawristband) and [Dynamic JSON](./features.md#json-injection-responsesuccessheadersdynamicmetadatajson) responses can include dynamic values (custom claims/properties) fetched from the authorization JSON. These can be returned to the external authorization client in added HTTP headers or as Envoy [Well Known Dynamic Metadata](https://www.envoyproxy.io/docs/envoy/latest/configuration/advanced/well_known_dynamic_metadata). Check out [Custom response features](./features.md#custom-response-features-response) for details. -For information about reading and fetching data from the Authorization JSON (syntax, functions, etc), check out [JSON paths](./features.md#common-feature-json-paths-selector). +For information about reading and fetching data from the Authorization JSON (syntax, functions, etc), check out [Common Expression Language (CEL)](./features.md#common-feature-common-expression-language-cel). ## Raw HTTP Authorization interface diff --git a/docs/features.md b/docs/features.md index 4978dc39..cf448288 100644 --- a/docs/features.md +++ b/docs/features.md @@ -14,6 +14,8 @@ You can also learn about Authorino features by using the [`kubectl explain`](htt ## Common feature: JSON paths ([`selector`](https://pkg.go.dev/github.com/kuadrant/authorino/api/v1beta2?utm_source=gopls#ValueOrSelector)) +> **Deprecated:** Prefer `predicate` and `expression`, based on [Common Expression Language (CEL)](#common-feature-common-expression-language-cel), instead. + The first feature of Authorino to learn about is a common functionality used in the specification of many other features. _JSON paths_ are selectors of data from the [Authorization JSON](./architecture.md#the-authorization-json) used in parts of an AuthConfig for referring to dynamic values of each authorization request. Usage examples of JSON paths are: dynamic URLs and request parameters when fetching metadata from external sources, dynamic authorization policy rules, and dynamic authorization response attributes (e.g. injected HTTP headers, Festival Wristband token claims, etc). @@ -72,6 +74,18 @@ In combination with `@extract`, `@base64` can be used to extract the username in _JSON paths_ can be interpolated into strings to build template-like dynamic values. E.g. `"Hello, {auth.identity.name}!"`. +## Common feature: Common Expression Language (CEL) + +Similar to [JSON Paths](#common-feature-json-paths-selector), Authorino supports [Common Expression Language (CEL)](https://cel.dev/) for selecting data from the [Authorization JSON](./architecture.md#the-authorization-json) and representing predicates. This is a more powerful, properly typed alternative to JSON Paths, with a well-documented [syntax](https://github.com/google/cel-spec/blob/master/doc/langdef.md). + +[String extension functions](https://pkg.go.dev/github.com/google/cel-go/ext#readme-strings), such as `split`, `substring`, `indexOf`, etc, are also supported. + +Use the `expression` field for selecting values from the [Authorization JSON](./architecture.md#the-authorization-json). The type of the selected value will be converted to a JSON-compatible equivalent. Complex types without a direct JSON equivalent may be converted to objects. + +The most common applications of `expression` are for building dynamic URLs and request parameters when fetching metadata from external sources, extending properties of identity objects, and dynamic authorization response attributes (e.g. injected HTTP headers, etc). + +Use `predicate` for expressions that return a boolean value, such as in [`when`](#common-feature-conditions-when) conditions and pattern-matching authorization rules. + ## Identity verification & authentication features ([`authentication`](https://pkg.go.dev/github.com/kuadrant/authorino/api/v1beta2?utm_source=gopls#AuthenticationSpec)) ### API key ([`authentication.apiKey`](https://pkg.go.dev/github.com/kuadrant/authorino/api/v1beta2?utm_source=gopls#ApiKeyAuthenticationSpec)) @@ -237,7 +251,7 @@ The identity object resolved out of a client x509 certificate is equal to the su Authorino can read plain identity objects, based on authentication tokens provided and verified beforehand using other means (e.g. Envoy [JWT Authentication filter](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/jwt_authn_filter#config-http-filters-jwt-authn), Kubernetes API server authentication), and injected into the payload to the external authorization service. -The plain identity object is retrieved from the Authorization JSON based on a [JSON path](#common-feature-json-paths-selector) specified in the `AuthConfig`. +The plain identity object is retrieved from the Authorization JSON. See [Common Expression Language (CEL)](./features.md#common-feature-common-expression-language-cel). This feature is particularly useful in cases where authentication/identity verification is handled before invoking the authorization service and its resolved value injected in the payload can be trusted. Examples of applications for this feature include: - Authentication handled in Envoy leveraging the Envoy JWT Authentication filter (decoded JWT injected as 'metadata_context') @@ -250,7 +264,7 @@ spec: authentication: "pre-validated-jwt": plain: - selector: context.metadata_context.filter_metadata.envoy\.filters\.http\.jwt_authn|verified_jwt + expression: metadata.filter_metadata.envoy['filters.http.jwt_authn'].verified_jwt ``` If the specified JSON path does not exist in the Authorization JSON or the value is `null`, the identity verification will fail and, unless other identity config succeeds, Authorino will halt the Auth Pipeline with the usual `401 Unauthorized`. @@ -277,14 +291,10 @@ spec: authorization: "read-only-access-if-authn-fails": when: - - selector: auth.identity.anonymous - operator: eq - value: "true" + - predicate: auth.identity.anonymous patternMatching: patterns: - - selector: context.request.http.method - operator: eq - value: GET + - predicate: request.method == 'GET' ``` ### Festival Wristband authentication @@ -380,10 +390,13 @@ The resources data is added as metadata of the authorization payload and passed Grant/deny access based on simple pattern-matching expressions ("patterns") compared against values selected from the Authorization JSON. -Each expression is a tuple composed of: -- a `selector`, to fetch from the Authorization JSON – see [Common feature: JSON paths](#common-feature-json-paths-selector) for details about syntax; -- an `operator` – `eq` (_equals_), `neq` (_not equal_); `incl` (_includes_) and `excl` (_excludes_), for arrays; and `matches`, for regular expressions; -- a fixed comparable `value` +Each expression is composed of exactly one of the following options: +1. a `predicate` field - [Common Expression Language (CEL)](./features.md#common-feature-common-expression-language-cel) expression that evaluates to a boolean value; +2. a tuple composed of: + - `selector`: a [JSON path](#common-feature-json-paths-selector) to fetch a value from the Authorization JSON + - `operator`: one of: `eq` (_equals_), `neq` (_not equal_); `incl` (_includes_) and `excl` (_excludes_), for arrays; and `matches`, for regular expressions + - `value`: a static string value to compare the value selected from the Authorization JSON with; +3. a `patternRef` field – value that maps to a predefined set of `{ selector, operator, value }` tuples stored at the top-level of the AuthConfig spec (`patterns`). Rules can mix and combine literal expressions and references to expression sets ("named patterns") defined at the upper level of the `AuthConfig` spec. (See [Common feature: Conditions](#common-feature-conditions-when)) @@ -393,9 +406,7 @@ spec: "my-simple-json-pattern-matching-policy": patternMatching: patterns: # All patterns must match for access to be granted - - selector: auth.identity.email_verified - operator: eq - value: "true" + - predicate: auth.identity.email_verified - patternRef: admin patterns: @@ -461,7 +472,7 @@ authorization: "kubernetes-rbac": kubernetesSubjectAccessReview: user: # values of the parameter can be fixed (`value`) or fetched from the Authorization JSON (`selector`) - selector: auth.identity.metadata.annotations.userid + expression: auth.identity.metadata.annotations.userid groups: [] # user groups to test for. @@ -475,9 +486,9 @@ authorization: resource: value: pets # the resource kind name: - selector: context.request.http.path.@extract:{"sep":"/","pos":2} # resource name – e.g., the {id} in `/pets/{id}` + expression: request.path.split('/')[2] # resource name – e.g., the {id} in `/pets/{id}` verb: - selector: context.request.http.method.@case:lower # api operation – e.g., copying from the context to use the same http method of the request + expression: request.method.lowerAscii() # api operation – e.g., copying from the context to use the same http method of the request ``` `user` and properties of `resourceAttributes` can be defined from fixed values or patterns of the Authorization JSON. @@ -504,14 +515,14 @@ spec: kind: value: blog/user name: - selector: auth.identity.sub + expression: auth.identity.sub resource: kind: value: blog/post name: - selector: context.request.http.path.@extract:{"sep":"/","pos":2} # /posts/{id} + expression: request.path.split('/')[2] # /posts/{id} permission: - selector: context.request.http.method + expression: request.method ``` ## Custom response features ([`response`](https://pkg.go.dev/github.com/kuadrant/authorino/api/v1beta2?utm_source=gopls#Response)) @@ -596,7 +607,7 @@ response: headers: "x-username": plain: - selector: auth.identity.username + expression: auth.identity.username ``` #### JSON injection ([`response.success..json`](https://pkg.go.dev/github.com/kuadrant/authorino/api/v1beta2?utm_source=gopls#JsonAuthResponseSpec)) @@ -632,7 +643,7 @@ spec: "prop1": value: value1 "prop2": - selector: some.path.within.auth.json + expression: some.path.within.auth.json "x-ext-auth-other-json": json: properties: @@ -644,9 +655,9 @@ spec: json: properties: "api-key-ns": - seletor: auth.identity.metadata.namespace + expression: auth.identity.metadata.namespace "api-key-name": - selector: auth.identity.metadata.name + expression: auth.identity.metadata.name ``` #### Festival Wristband tokens ([`response.success..wristband`](https://pkg.go.dev/github.com/kuadrant/authorino/api/v1beta2?utm_source=gopls#WristbandAuthResponseSpec)) @@ -682,8 +693,8 @@ spec: customClaims: "aud": value: internal - "born": - selector: auth.identity.metadata.creationTimestamp + "age": + expression: int(request.time.seconds) - (timestamp(auth.identity.metadata.creationTimestamp) - timestamp("1970-01-01T00:00:00Z")).getSeconds() tokenDuration: 300 signingKeyRefs: - name: my-signing-key @@ -721,15 +732,14 @@ spec: url: http://logsys method: POST body: - selector: | - \{"requestId":context.request.http.id,"username":"{auth.identity.username}","authorizationResult":{auth.authorization}\} + expression: | + { "requestId": request.id, "username": auth.identity.username, "authorizationResult": auth.authorization } "important-forbidden": when: - - selector: auth.authorization.important-policy - operator: eq - value: "false" + - predicate: "!auth.authorization.important-policy" http: - url: "http://monitoring/important?forbidden-user={auth.identity.username}" + urlExpression: | + "http://monitoring/important?forbidden-user=" + auth.identity.username ``` ## Common feature: Priorities @@ -787,23 +797,13 @@ spec: authorization: "allowed-endpoints": when: - - selector: context.request.http.path - operator: neq - value: /hi - - selector: context.request.http.path - operator: neq - value: /hello - - selector: context.request.http.path - operator: neq - value: /aloha - - selector: context.request.http.path - operator: neq - value: /ciao + - predicate: request.path != '/hi' + - predicate: request.path != '/hello' + - predicate: request.path != '/aloha' + - predicate: request.path != '/ciao' patternMatching: patterns: - - selector: deny - operator: eq - value: "true" + - pattern: "true" "more-expensive-policy": # no point in evaluating this one if it's not an allowed endpoint priority: 1 opa: @@ -816,13 +816,13 @@ spec: json: properties: "tier": - selector: auth.identity.metadata.labels.tier + expression: auth.identity.metadata.labels.tier "first-uuid": - selector: auth.metadata.first.uuid + expression: auth.metadata.first.uuid "second-uuid": - selector: auth.metadata.second.uuid + expression: auth.metadata.second.uuid "second-path": - selector: auth.metadata.second.path + expression: auth.metadata.second.path ``` For the `AuthConfig` above, @@ -835,17 +835,18 @@ For the `AuthConfig` above, ## Common feature: Conditions (`when`) -_Conditions_, named `when` in the AuthConfig API, are logical expressions, composed of patterns and logical operator AND and OR, that can be used to condition the evaluation of a particular auth rule within an AuthConfig, as well as of the AuthConfig altogether ("top-level conditions"). +_Conditions_, identified by the `when` field in the AuthConfig API, are logical expressions ("predicates") that can be used to condition the evaluation of a particular auth rule, as well as of the AuthConfig altogether ("top-level conditions"). -The patterns are evaluated against the [Authorization JSON](./architecture.md#the-authorization-json), where each pattern is a tuple composed of: -- `selector`: a [JSON path](#common-feature-json-paths-selector) to fetch a value from the Authorization JSON -- `operator`: one of: `eq` (_equals_); `neq` (_not equal_); `incl` (_includes_) and `excl` (_excludes_), for when the value fetched from the Authorization JSON is expected to be an array; `matches`, for regular expressions -- `value`: a static string value to compare the value selected from the Authorization JSON with. +The predicates are evaluated against the [Authorization JSON](./architecture.md#the-authorization-json), where each predicate is composed of exactly one of the following options: +1. a `predicate` field – [CEL expression](#common-feature-common-expression-language-cel) that evaluates to a boolean value; +2. a tuple composed of: + - `selector`: a [JSON path](#common-feature-json-paths-selector) to fetch a value from the Authorization JSON + - `operator`: one of: `eq` (_equals_); `neq` (_not equal_); `incl` (_includes_) and `excl` (_excludes_), for when the value fetched from the Authorization JSON is expected to be an array; `matches`, for regular expressions + - `value`: a static string value to compare the value selected from the Authorization JSON with; +3. a `patternRef` field – value that maps to a predefined set of `{ selector, operator, value }` tuples stored at the top-level of the AuthConfig spec (`patterns`). An expression contains one or more patterns and they must either all evaluate to true ("AND" operator, declared by grouping the patterns within an `all` block) or at least one of the patterns must be true ("OR" operator, when grouped within an `any` block.) Patterns not explicitly grouped are AND'ed by default. -To avoid repetitions when listing patterns, any set of literal `{ pattern, operator, value }` tuples can be stored at the top-level of the AuthConfig spec, indexed by name, and later referred within an expression by including a `patternRef` in the block of conditions. - **Examples of `when` conditions** i) to skip an entire `AuthConfig` based on the context (AND operator assumed by default): @@ -853,79 +854,65 @@ i) to skip an entire `AuthConfig` based on the context (AND operator assumed by ```yaml spec: when: # auth enforced only on requests to POST /resources/* - - selector: context.request.http.method - operator: eq - value: POST - - selector: context.request.http.path - operator: matches - value: ^/resources/.* + - predicate: request.method == 'POST' && request.path.matches("^/resources/.*") ``` -ii) equivalent to the above with explicit AND operator (i.e., `all` block): +ii) equivalent to the above using `{ selector, operator, value }` tuples and an explicit AND operator (`all`): ```yaml spec: when: # auth enforced only on requests to POST /resources/* - all: - - selector: context.request.http.method + - selector: request.method operator: eq value: POST - - selector: context.request.http.path + - selector: request.path operator: matches value: ^/resources/.* ``` -iii) OR condition (i.e., `any` block): +iii) OR condition (`any`) using `{ selector, operator, value }` tuples: ```yaml spec: when: # auth enforced only on requests with HTTP method equals to POST or PUT - any: - - selector: context.request.http.method + - selector: request.method operator: eq value: POST - - selector: context.request.http.method + - selector: request.method operator: eq value: PUT ``` -iv) complex expression with nested operations: +iv) complex expression with nested operations using `{ selector, operator, value }` tuples: ```yaml spec: when: # auth enforced only on requests to POST /resources/* or PUT /resources/* - any: - all: - - selector: context.request.http.method + - selector: request.method operator: eq value: POST - - selector: context.request.http.path + - selector: request.path operator: matches value: ^/resources/.* - all: - - selector: context.request.http.method + - selector: request.method operator: eq value: PUT - - selector: context.request.http.path + - selector: request.path operator: matches value: ^/resources/.* ``` -v) more concise equivalent of the above (with implicit AND operator at the top level): +v) more concise equivalent of the above using CEL: ```yaml spec: when: # auth enforced only on requests to /resources/* path with method equals to POST or PUT - - selector: context.request.http.path - operator: matches - value: ^/resources/.* - - any: - - selector: context.request.http.method - operator: eq - value: POST - - selector: context.request.http.method - operator: eq - value: PUT + - predicate: request.path .matches("^/resources/.*") && request.method in ['POST', 'PUT'] ``` vi) to skip part of an AuthConfig (i.e., a specific auth rule): @@ -937,9 +924,7 @@ spec: http: url: https://my-metadata-source.io when: # only fetch the external metadata if the context is HTTP method other than OPTIONS - - selector: context.request.http.method - operator: neq - value: OPTIONS + - predicate: request.method != 'OPTIONS' ``` vii) skipping part of an AuthConfig will not affect other auth rules: @@ -950,12 +935,7 @@ spec: "authn-meth-1": apiKey: {…} # this auth rule only triggers for POST requests to /foo[/*] when: - - selector: context.request.http.method - operator: eq - value: POST - - selector: context.request.http.path - operator: matches - value: ^/foo(/.*)?$ + - predicate: request.method == 'POST' && request.path.matches("^/foo(/.*)?$") "authn-meth-2": # this auth rule triggerred regardless jwt: {…} @@ -968,16 +948,12 @@ spec: authentication: "jwt": when: - - selector: context.request.http.headers.authorization - operator: matches - value: JWT .+ + - predicate: request.headers['authorization'].startsWith('JWT') jwt: {…} "api-key": when: - - selector: context.request.http.headers.authorization - operator: matches - value: APIKEY .+ + - predicate: request.headers['authorization'].startsWith('APIKEY') apiKey: {…} ``` @@ -996,7 +972,8 @@ spec: when: - patternRef: a-pet http: - url: https://pets-info.io?petId={context.request.http.path.@extract:{"sep":"/","pos":2}} + urlExpression: | + "https://pets-info.io?petId=" + request.path.split('/')[2] authorization: "pets-owners-only": @@ -1013,7 +990,7 @@ x) combining literals and refs – concrete case: authentication required for se spec: patterns: api-base-path: - - selector: context.request.http.path + - selector: request.path operator: matches value: ^/api/.* @@ -1035,18 +1012,8 @@ spec: authorization: api-write-access-requires-authentication: # POST/PUT/DELETE requests to /api/* path cannot be anonymous when: - - all: - - patternRef: api-base-path - - any: - - selector: context.request.http.method - operator: eq - value: POST - - selector: context.request.http.method - operator: eq - value: PUT - - selector: context.request.http.method - operator: eq - value: DELETE + - patternRef: api-base-path + - predicate: request.method in ['POST', 'PUT', 'DELETE'] opa: patternMatching: rules: @@ -1061,7 +1028,7 @@ spec: json: properties: jwt-claims: - selector: auth.identity + expression: auth.identity ``` ## Common feature: Caching (`cache`) @@ -1082,10 +1049,11 @@ spec: metadata: "external-metadata": http: - url: http://my-external-source?search={context.request.http.path} + urlExpression: | + "http://my-external-source?search=" + request.path cache: key: - selector: context.request.http.path + expression: request.path ttl: 300 authorization: @@ -1095,7 +1063,7 @@ spec: url: http://my-policy-registry cache: key: - selector: "{auth.identity.group}-{context.request.http.method}-{context.request.http.path}" + expression: auth.identity.group + '-' + request.method + '-' + request.path ttl: 60 ``` @@ -1125,7 +1093,7 @@ spec: metadata: "my-external-metadata": http: - url: http://my-external-source?search={context.request.http.path} + url: http://my-external-source?search={request.path} metrics: true ``` diff --git a/docs/user-guides/authenticated-rate-limiting-envoy-dynamic-metadata.md b/docs/user-guides/authenticated-rate-limiting-envoy-dynamic-metadata.md index be3cd7e1..8ed7776f 100644 --- a/docs/user-guides/authenticated-rate-limiting-envoy-dynamic-metadata.md +++ b/docs/user-guides/authenticated-rate-limiting-envoy-dynamic-metadata.md @@ -163,12 +163,12 @@ spec: json: properties: "username": - selector: auth.identity.metadata.annotations.auth-data\/username + expression: auth.identity.metadata.annotations['auth-data/username'] key: ext_auth_data # how this bit of dynamic metadata from the ext authz service is named in the Envoy config EOF ``` -Check out the docs for information about the common feature [JSON paths](../features.md#common-feature-json-paths-selector) for reading from the [Authorization JSON](../architecture.md#the-authorization-json). +Check out the docs about using [Common Expression Language (CEL)](./features.md#common-feature-common-expression-language-cel) for reading from the [Authorization JSON](../architecture.md#the-authorization-json). ## ❼ Create the API keys diff --git a/docs/user-guides/deny-with-redirect-to-login.md b/docs/user-guides/deny-with-redirect-to-login.md index 20cec349..fa63319b 100644 --- a/docs/user-guides/deny-with-redirect-to-login.md +++ b/docs/user-guides/deny-with-redirect-to-login.md @@ -157,11 +157,12 @@ spec: code: 302 headers: "Location": - selector: "http://matrix-quotes.127.0.0.1.nip.io:8000/login.html?redirect_to={request.path}" + expression: | + 'http://matrix-quotes.127.0.0.1.nip.io:8000/login.html?redirect_to=' + request.path EOF ``` -Check out the docs for information about the common feature [JSON paths](../features.md#common-feature-json-paths-selector) for reading from the [Authorization JSON](../architecture.md#the-authorization-json). +Check out the docs about using [Common Expression Language (CEL)](./features.md#common-feature-common-expression-language-cel) for reading from the [Authorization JSON](../architecture.md#the-authorization-json). ## ❻ Create an API key @@ -259,7 +260,8 @@ spec: code: 302 headers: "Location": - selector: "http://keycloak:8080/realms/kuadrant/protocol/openid-connect/auth?client_id=matrix-quotes&redirect_uri=http://matrix-quotes.127.0.0.1.nip.io:8000/auth?redirect_to={request.path}&scope=openid&response_type=code" + expression: | + 'http://keycloak:8080/realms/kuadrant/protocol/openid-connect/auth?client_id=matrix-quotes&redirect_uri=http://matrix-quotes.127.0.0.1.nip.io:8000/auth?redirect_to=' + request.path + '&scope=openid&response_type=code' EOF ``` diff --git a/docs/user-guides/external-metadata.md b/docs/user-guides/external-metadata.md index 0d793df8..27b8c82c 100644 --- a/docs/user-guides/external-metadata.md +++ b/docs/user-guides/external-metadata.md @@ -153,10 +153,11 @@ spec: metadata: "geo": http: - url: 'http://ip-api.com/json/{context.request.http.headers.x-forwarded-for.@extract:{"sep":","}}?fields=countryCode' + urlExpression: | + 'http://ip-api.com/json/' + request.headers['x-forwarded-for'].split(',')[0] + '?fields=countryCode' headers: "Accept": - value: application/json + expression: '"application/json"' authorization: "geofence": opa: @@ -171,7 +172,7 @@ spec: EOF ``` -Check out the docs for information about the common feature [JSON paths](../features.md#common-feature-json-paths-selector) for reading from the [Authorization JSON](../architecture.md#the-authorization-json), including the description of the `@extract` string modifier. +Check out the docs about using [Common Expression Language (CEL)](./features.md#common-feature-common-expression-language-cel) for reading from the [Authorization JSON](../architecture.md#the-authorization-json). ## ❻ Create an API key diff --git a/docs/user-guides/http-basic-authentication.md b/docs/user-guides/http-basic-authentication.md index da90861c..0ae891eb 100644 --- a/docs/user-guides/http-basic-authentication.md +++ b/docs/user-guides/http-basic-authentication.md @@ -150,9 +150,7 @@ spec: authorization: "acl": when: - - selector: context.request.http.path - operator: eq - value: /bye + - predicate: request.path == '/bye' patternMatching: patterns: - selector: context.request.http.headers.authorization.@extract:{"pos":1}|@base64:decode|@extract:{"sep":":"} @@ -161,7 +159,7 @@ spec: EOF ``` -Check out the docs for information about the common feature [JSON paths](../features.md#common-feature-json-paths-selector) for reading from the [Authorization JSON](../architecture.md#the-authorization-json), including the description of the string modifiers `@extract` and `@case` used above. Check out as well the common feature [Conditions](../features.md#common-feature-conditions-when) about skipping parts of an `AuthConfig` in the auth pipeline based on context. +Check out the docs about using [Common Expression Language (CEL)](./features.md#common-feature-common-expression-language-cel) for reading from the [Authorization JSON](../architecture.md#the-authorization-json). Check out as well the common feature [Conditions](../features.md#common-feature-conditions-when) about skipping parts of an `AuthConfig` in the auth pipeline based on context. ## ❻ Create user credentials diff --git a/docs/user-guides/injecting-data.md b/docs/user-guides/injecting-data.md index cd3849e4..76f32f16 100644 --- a/docs/user-guides/injecting-data.md +++ b/docs/user-guides/injecting-data.md @@ -155,15 +155,16 @@ spec: json: properties: "authorized": - value: true + expression: "true" "request-time": - selector: context.request.time.seconds + expression: request.time.seconds "greeting-message": - selector: Hello, {auth.identity.metadata.annotations.auth-data\/name}! + expression: | + 'Hello, ' + auth.identity.metadata.annotations['auth-data/name'] EOF ``` -Check out the docs for information about the common feature [JSON paths](../features.md#common-feature-json-paths-selector) for reading from the [Authorization JSON](../architecture.md#the-authorization-json). +Check out the docs about using [Common Expression Language (CEL)](./features.md#common-feature-common-expression-language-cel) for reading from the [Authorization JSON](../architecture.md#the-authorization-json). ## ❻ Create an API key diff --git a/docs/user-guides/json-pattern-matching-authorization.md b/docs/user-guides/json-pattern-matching-authorization.md index 704c7da3..8a23263a 100644 --- a/docs/user-guides/json-pattern-matching-authorization.md +++ b/docs/user-guides/json-pattern-matching-authorization.md @@ -156,18 +156,15 @@ spec: authorization: "email-verified-only": when: - - selector: "context.request.http.headers.x-forwarded-for.@extract:{\"sep\": \",\"}" - operator: matches - value: 192\\.168\\.1\\.\\d+ + - predicate: | + request.headers['x-forwarded-for'].split(',')[0].matches("^192\\\.168\\\.1\\\.\\\d+$") patternMatching: patterns: - - selector: auth.identity.email_verified - operator: eq - value: "true" + - predicate: auth.identity.email_verified EOF ``` -Check out the docs for information about semantics and operators supported by the [JSON pattern-matching authorization](../features.md#pattern-matching-authorization-authorizationpatternmatching) feature, as well the common feature [JSON paths](../features.md#common-feature-json-paths-selector) for reading from the [Authorization JSON](../architecture.md#the-authorization-json), including the description of the string modifier `@extract` used above. Check out as well the common feature [Conditions](../features.md#common-feature-conditions-when) about skipping parts of an `AuthConfig` in the auth pipeline based on context. +Check out the doc about using [Common Expression Language (CEL)](./features.md#common-feature-common-expression-language-cel) for reading from the [Authorization JSON](../architecture.md#the-authorization-json). Check out as well the common feature [Conditions](../features.md#common-feature-conditions-when) about skipping parts of an `AuthConfig` in the auth pipeline based on context. ## ❻ Obtain an access token and consume the API From 274c8d2a935e35cfae4eed7dd82ea543acf2a2d6 Mon Sep 17 00:00:00 2001 From: Guilherme Cassolato Date: Tue, 26 Nov 2024 16:27:15 +0100 Subject: [PATCH 2/5] fix metadata.filter_metadata example Signed-off-by: Guilherme Cassolato --- docs/features.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features.md b/docs/features.md index cf448288..3637df43 100644 --- a/docs/features.md +++ b/docs/features.md @@ -264,7 +264,7 @@ spec: authentication: "pre-validated-jwt": plain: - expression: metadata.filter_metadata.envoy['filters.http.jwt_authn'].verified_jwt + expression: metadata.filter_metadata['envoy.filters.http.jwt_authn'].verified_jwt ``` If the specified JSON path does not exist in the Authorization JSON or the value is `null`, the identity verification will fail and, unless other identity config succeeds, Authorino will halt the Auth Pipeline with the usual `401 Unauthorized`. From 9d169bb1aefcefba0756d73d3fcb16c54f5c1443 Mon Sep 17 00:00:00 2001 From: Guilherme Cassolato Date: Tue, 26 Nov 2024 16:27:33 +0100 Subject: [PATCH 3/5] fix has(auth.identity.anonymous) Signed-off-by: Guilherme Cassolato --- docs/features.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features.md b/docs/features.md index 3637df43..297bf51d 100644 --- a/docs/features.md +++ b/docs/features.md @@ -291,7 +291,7 @@ spec: authorization: "read-only-access-if-authn-fails": when: - - predicate: auth.identity.anonymous + - predicate: has(auth.identity.anonymous) && auth.identity.anonymous patternMatching: patterns: - predicate: request.method == 'GET' From 4813252a74f145720f020c4fed25aa5b4aa562c9 Mon Sep 17 00:00:00 2001 From: Guilherme Cassolato Date: Tue, 26 Nov 2024 16:39:48 +0100 Subject: [PATCH 4/5] note on converting google.golang.org/protobuf/types/known/timestamppb.Timestamp Signed-off-by: Guilherme Cassolato --- docs/features.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features.md b/docs/features.md index 297bf51d..52f92463 100644 --- a/docs/features.md +++ b/docs/features.md @@ -80,7 +80,7 @@ Similar to [JSON Paths](#common-feature-json-paths-selector), Authorino supports [String extension functions](https://pkg.go.dev/github.com/google/cel-go/ext#readme-strings), such as `split`, `substring`, `indexOf`, etc, are also supported. -Use the `expression` field for selecting values from the [Authorization JSON](./architecture.md#the-authorization-json). The type of the selected value will be converted to a JSON-compatible equivalent. Complex types without a direct JSON equivalent may be converted to objects. +Use the `expression` field for selecting values from the [Authorization JSON](./architecture.md#the-authorization-json). The type of the selected value will be converted to a JSON-compatible equivalent. Complex types without a direct JSON equivalent may be converted to objects (e.g. `google.golang.org/protobuf/types/known/timestamppb.Timestamp` gets converted to `{ "seconds": Number, "nanos": Number }`) The most common applications of `expression` are for building dynamic URLs and request parameters when fetching metadata from external sources, extending properties of identity objects, and dynamic authorization response attributes (e.g. injected HTTP headers, etc). From 9217e6ff3f7f4f5f38af395ef5f90052d043279c Mon Sep 17 00:00:00 2001 From: Guilherme Cassolato Date: Tue, 26 Nov 2024 16:43:58 +0100 Subject: [PATCH 5/5] simpler predicate for chcking request.path not in set Signed-off-by: Guilherme Cassolato --- docs/features.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/features.md b/docs/features.md index 52f92463..9667e5a4 100644 --- a/docs/features.md +++ b/docs/features.md @@ -797,10 +797,8 @@ spec: authorization: "allowed-endpoints": when: - - predicate: request.path != '/hi' - - predicate: request.path != '/hello' - - predicate: request.path != '/aloha' - - predicate: request.path != '/ciao' + - predicate: | + !(request.path in ['/hi', '/hello', '/aloha', '/ciao']) patternMatching: patterns: - pattern: "true"